Updated on 2026-08-14

This commit is contained in:
Tangem 2026-07-15 04:50:41 -07:00
parent 5c293e71ec
commit 6caeea3576
22 changed files with 243 additions and 135 deletions

View file

@ -38,6 +38,7 @@ data class CustomerMeResponse(
@Json(name = "id") val id: String?, @Json(name = "id") val id: String?,
@Json(name = "type") val type: String?, @Json(name = "type") val type: String?,
@Json(name = "name") val name: String?, @Json(name = "name") val name: String?,
@Json(name = "program_name") val programName: String?,
@Json(name = "description_items") val descriptionItems: List<DescriptionItem>?, @Json(name = "description_items") val descriptionItems: List<DescriptionItem>?,
@Json(name = "images") val images: List<Image>? = null, @Json(name = "images") val images: List<Image>? = null,
@Json(name = "fees") val fees: List<Fee>? = null, @Json(name = "fees") val fees: List<Fee>? = null,

View file

@ -98,15 +98,22 @@
<string name="address_book_add_address">Agregar dirección</string> <string name="address_book_add_address">Agregar dirección</string>
<string name="address_book_add_address_description">Agregue la dirección y seleccione la red</string> <string name="address_book_add_address_description">Agregue la dirección y seleccione la red</string>
<string name="address_book_add_contact">Añadir contacto</string> <string name="address_book_add_contact">Añadir contacto</string>
<string name="address_book_address_copied">Dirección copiada</string>
<string name="address_book_address_taken_error">Esta dirección ya está guardada como %1$s</string>
<plurals name="address_book_addresses"> <plurals name="address_book_addresses">
<item quantity="one">%d dirección</item> <item quantity="one">%d dirección</item>
<item quantity="other">%d direcciones</item> <item quantity="other">%d direcciones</item>
</plurals> </plurals>
<string name="address_book_choose_address">Seleccione una dirección</string>
<string name="address_book_clear_all_networks">Borrar todo</string>
<string name="address_book_contact">Contacto</string> <string name="address_book_contact">Contacto</string>
<string name="address_book_contact_name">Nombre de contacto</string> <string name="address_book_contact_name">Nombre de contacto</string>
<string name="address_book_copy_address">Copiar dirección</string> <string name="address_book_copy_address">Copiar dirección</string>
<string name="address_book_create_success_message">Contacto guardado</string>
<string name="address_book_creating_error">No se pudo crear el contacto. Inténtelo de nuevo más tarde.</string> <string name="address_book_creating_error">No se pudo crear el contacto. Inténtelo de nuevo más tarde.</string>
<string name="address_book_delete_contact">Eliminar contacto</string>
<string name="address_book_delete_contact_description">Este contacto se eliminará de todas sus libretas de direcciones</string> <string name="address_book_delete_contact_description">Este contacto se eliminará de todas sus libretas de direcciones</string>
<string name="address_book_delete_last_address">"%1$s\" tiene solo una dirección. Si la eliminas, también se eliminará el contacto. ¿Continuar?"</string>
<string name="address_book_deleting_error">No se pudo eliminar el contacto. Inténtelo de nuevo más tarde.</string> <string name="address_book_deleting_error">No se pudo eliminar el contacto. Inténtelo de nuevo más tarde.</string>
<string name="address_book_description">Gestionar contactos y direcciones</string> <string name="address_book_description">Gestionar contactos y direcciones</string>
<string name="address_book_discard">Descartar</string> <string name="address_book_discard">Descartar</string>
@ -114,11 +121,22 @@
<string name="address_book_enter_address">Introduzca la dirección</string> <string name="address_book_enter_address">Introduzca la dirección</string>
<string name="address_book_invalid_address_error">Dirección no válida</string> <string name="address_book_invalid_address_error">Dirección no válida</string>
<string name="address_book_keep_editing">Seguir editando</string> <string name="address_book_keep_editing">Seguir editando</string>
<string name="address_book_max_networks_alert_description">No puede crear más de 20 direcciones. Elimine una para añadir una nueva.</string>
<string name="address_book_max_networks_alert_title">No se puede agregar una nueva dirección</string>
<string name="address_book_name_empty_error">Se requiere el nombre del contacto.</string>
<string name="address_book_name_invalid_chars_error">El nombre del contacto contiene caracteres no válidos.</string>
<string name="address_book_name_max_chars_error">El nombre de contacto no debe superar los 50 caracteres</string>
<string name="address_book_name_taken_error">Ese nombre ya está en uso en esta billetera</string>
<string name="address_book_new_contact">Nuevo contacto</string> <string name="address_book_new_contact">Nuevo contacto</string>
<string name="address_book_no_contacts">Aún no hay contactos</string> <string name="address_book_no_contacts">Aún no hay contactos</string>
<string name="address_book_no_contacts_description">Los contactos añadidos aparecerán aquí</string> <string name="address_book_no_contacts_description">Los contactos añadidos aparecerán aquí</string>
<string name="address_book_remove_address">Eliminar dirección</string> <string name="address_book_remove_address">Eliminar dirección</string>
<string name="address_book_save_address">Guardar dirección</string>
<string name="address_book_save_contact">Guardar contacto</string>
<string name="address_book_save_to_wallet_title">Guardar en la billetera</string>
<string name="address_book_save_wallet_to_description">Este contacto se añadirá a la agenda de esta billetera.</string> <string name="address_book_save_wallet_to_description">Este contacto se añadirá a la agenda de esta billetera.</string>
<string name="address_book_search_no_results">No se encontraron resultados.\nPruebe con otro nombre.</string>
<string name="address_book_select_all_networks">Seleccionar todo</string>
<string name="address_book_select_network">Seleccionar red</string> <string name="address_book_select_network">Seleccionar red</string>
<string name="address_book_title">Libreta de direcciones</string> <string name="address_book_title">Libreta de direcciones</string>
<string name="address_book_unsaved_changes">Cambios no guardados</string> <string name="address_book_unsaved_changes">Cambios no guardados</string>

View file

@ -1864,6 +1864,9 @@
<string name="tangempay_card_details_add_funds">Add funds</string> <string name="tangempay_card_details_add_funds">Add funds</string>
<string name="tangempay_card_details_add_funds_subtitle">Top-up options</string> <string name="tangempay_card_details_add_funds_subtitle">Top-up options</string>
<string name="tangempay_card_details_add_to_wallet_button_text">Add to Google Wallet</string> <string name="tangempay_card_details_add_to_wallet_button_text">Add to Google Wallet</string>
<string name="tangempay_card_details_awaiting_deposit_cancel_button">Cancel %1$s, move to %2$s</string>
<string name="tangempay_card_details_awaiting_deposit_subtitle">To pay monthly fee for plan and start use card</string>
<string name="tangempay_card_details_awaiting_deposit_title">Top-up your account on %1$s</string>
<string name="tangempay_card_details_card_number">Card Number</string> <string name="tangempay_card_details_card_number">Card Number</string>
<string name="tangempay_card_details_change_pin">PIN code</string> <string name="tangempay_card_details_change_pin">PIN code</string>
<string name="tangempay_card_details_change_pin_success_description">The card is fully ready for payments.</string> <string name="tangempay_card_details_change_pin_success_description">The card is fully ready for payments.</string>
@ -1898,6 +1901,8 @@
<string name="tangempay_card_details_rename_card_placeholder">Card name</string> <string name="tangempay_card_details_rename_card_placeholder">Card name</string>
<string name="tangempay_card_details_reveal_text">Reveal</string> <string name="tangempay_card_details_reveal_text">Reveal</string>
<string name="tangempay_card_details_show_details">Details</string> <string name="tangempay_card_details_show_details">Details</string>
<string name="tangempay_card_details_system_downgrade_subtitle">If it will remain below zero your %1$s cards will be closed on %2$s</string>
<string name="tangempay_card_details_system_downgrade_title">Top up your account shortly</string>
<string name="tangempay_card_details_title">Details</string> <string name="tangempay_card_details_title">Details</string>
<string name="tangempay_card_details_unable_to_rename_card_description">Please try again later</string> <string name="tangempay_card_details_unable_to_rename_card_description">Please try again later</string>
<string name="tangempay_card_details_unfreeze_card">Unfreeze Card</string> <string name="tangempay_card_details_unfreeze_card">Unfreeze Card</string>
@ -1933,9 +1938,14 @@
<string name="tangempay_come_back_if_forget_pin">Come back to the app if you forget it.</string> <string name="tangempay_come_back_if_forget_pin">Come back to the app if you forget it.</string>
<string name="tangempay_common_card">Card</string> <string name="tangempay_common_card">Card</string>
<string name="tangempay_common_error_loading">Error loading</string> <string name="tangempay_common_error_loading">Error loading</string>
<string name="tangempay_current_plan_active_till_notification">Your %1$s plan is active till %2$s, then we will move you to %3$s. %4$s won\'t be charged.</string>
<string name="tangempay_current_plan_change">Change plan</string> <string name="tangempay_current_plan_change">Change plan</string>
<string name="tangempay_current_plan_fee_charged_notification">%1$s monthly fee will be charged on %2$s</string>
<string name="tangempay_current_plan_section_card">Card related</string> <string name="tangempay_current_plan_section_card">Card related</string>
<string name="tangempay_current_plan_section_plan">Plan related</string> <string name="tangempay_current_plan_section_plan">Plan related</string>
<string name="tangempay_current_plan_stay_button">Stay on %1$s</string>
<string name="tangempay_current_plan_stay_sheet_body">Your transition on %1$s will be canceled</string>
<string name="tangempay_current_plan_stay_sheet_title">Do you want to stay on %1$s?</string>
<string name="tangempay_current_plan_title">Current plan</string> <string name="tangempay_current_plan_title">Current plan</string>
<string name="tangempay_daily_limit_hint" formatted="false">Set a limit from %s to %s</string> <string name="tangempay_daily_limit_hint" formatted="false">Set a limit from %s to %s</string>
<string name="tangempay_daily_limit_set_button">Set limits</string> <string name="tangempay_daily_limit_set_button">Set limits</string>
@ -2047,7 +2057,16 @@
<string name="tangempay_select_plan_btn_select">Select</string> <string name="tangempay_select_plan_btn_select">Select</string>
<string name="tangempay_select_plan_btn_upgrade">Upgrade plan</string> <string name="tangempay_select_plan_btn_upgrade">Upgrade plan</string>
<string name="tangempay_select_plan_compare">Compare plans</string> <string name="tangempay_select_plan_compare">Compare plans</string>
<string name="tangempay_select_plan_confirm_downgrade_title">Your %1$s plan and %2$s cards will be active till %3$s</string>
<string name="tangempay_select_plan_confirm_point_cancel_till">You can cancel this transition till %1$s</string>
<string name="tangempay_select_plan_confirm_point_cards_closed">Your %1$s cards will be closed</string>
<string name="tangempay_select_plan_confirm_point_monthly_fee">%1$s monthly fee will be taken from your account</string>
<string name="tangempay_select_plan_confirm_point_move_on_date">On %1$s we will move you to %2$s plan</string>
<string name="tangempay_select_plan_confirm_point_no_fee">No fee applied</string>
<string name="tangempay_select_plan_confirm_point_virtual_card">You will get your virtual %1$s in minutes</string>
<string name="tangempay_select_plan_confirm_switch_title">You are switching to %1$s</string>
<string name="tangempay_select_plan_confirm_title">Confirm selection</string> <string name="tangempay_select_plan_confirm_title">Confirm selection</string>
<string name="tangempay_select_plan_confirm_upgrade_title">We will issue %1$s for you</string>
<string name="tangempay_select_plan_title">Select plan</string> <string name="tangempay_select_plan_title">Select plan</string>
<string name="tangempay_service_unavailable_description">Were fixing a technical issue. Please try again later.</string> <string name="tangempay_service_unavailable_description">Were fixing a technical issue. Please try again later.</string>
<string name="tangempay_service_unavailable_title">Service temporarily unavailable</string> <string name="tangempay_service_unavailable_title">Service temporarily unavailable</string>

View file

@ -2,16 +2,29 @@ package com.tangem.data.pay.converter
import com.tangem.datasource.api.pay.models.response.CustomerMeResponse import com.tangem.datasource.api.pay.models.response.CustomerMeResponse
import com.tangem.domain.models.account.TangemPayTariffPlan import com.tangem.domain.models.account.TangemPayTariffPlan
import java.util.Locale
internal object TangemPayTariffPlanConverter { internal object TangemPayTariffPlanConverter {
fun convert(value: CustomerMeResponse.TariffPlan?): TangemPayTariffPlan? { fun convert(value: CustomerMeResponse.TariffPlan?): TangemPayTariffPlan? {
val id = value?.id ?: return null val id = value?.id ?: return null
val name = value.name ?: return null val name = value.name ?: return null
val programName = value.programName ?: return null
// We cannot base our logic on knowledge what exact tier type is it.
// Use it only as identifier to get data from other responses
val tierId = value.type ?: return null
// Basic tier is a default tier. We can base some features on it.
// Other tiers are adjusted from admin panel. It is not guaranteed to have it in future
val isBasicTier = tierId.uppercase(Locale.US) == "BASIC"
return TangemPayTariffPlan( return TangemPayTariffPlan(
id = id, id = id,
type = TangemPayTariffPlan.Type.fromString(value.type), tierId = tierId,
isBasicTier = isBasicTier,
name = name, name = name,
programName = programName,
descriptionItems = value.descriptionItems.orEmpty().mapNotNull(::convertDescriptionItem), descriptionItems = value.descriptionItems.orEmpty().mapNotNull(::convertDescriptionItem),
images = value.images.orEmpty().mapNotNull(::convertImage), images = value.images.orEmpty().mapNotNull(::convertImage),
fees = value.fees.orEmpty().mapNotNull(::convertFee), fees = value.fees.orEmpty().mapNotNull(::convertFee),

View file

@ -27,6 +27,30 @@ internal class TangemPayTariffPlanConverterTest {
assertThat(TangemPayTariffPlanConverter.convert(value)).isNull() assertThat(TangemPayTariffPlanConverter.convert(value)).isNull()
} }
@Test
fun `GIVEN missing type WHEN convert THEN returns null`() {
val value = tariffPlan(type = null)
assertThat(TangemPayTariffPlanConverter.convert(value)).isNull()
}
@Test
fun `GIVEN missing programName WHEN convert THEN returns null`() {
val value = tariffPlan(programName = null)
assertThat(TangemPayTariffPlanConverter.convert(value)).isNull()
}
@Test
fun `GIVEN basic tier in mixed case WHEN convert THEN isBasicTier is true`() {
val value = tariffPlan(type = "Basic")
val result = TangemPayTariffPlanConverter.convert(value)
assertThat(result?.tierId).isEqualTo("Basic")
assertThat(result?.isBasicTier).isTrue()
}
@Test @Test
fun `GIVEN full valid plan WHEN convert THEN maps all fields`() { fun `GIVEN full valid plan WHEN convert THEN maps all fields`() {
// GIVEN // GIVEN
@ -58,8 +82,10 @@ internal class TangemPayTariffPlanConverterTest {
// THEN // THEN
val expected = TangemPayTariffPlan( val expected = TangemPayTariffPlan(
id = PLAN_ID, id = PLAN_ID,
type = TangemPayTariffPlan.Type.PLUS, tierId = "PLUS",
isBasicTier = false,
name = PLAN_NAME, name = PLAN_NAME,
programName = PROGRAM_NAME,
descriptionItems = listOf( descriptionItems = listOf(
TangemPayTariffPlan.DescriptionItem( TangemPayTariffPlan.DescriptionItem(
section = TangemPayTariffPlan.Section.PLAN_RELATED, section = TangemPayTariffPlan.Section.PLAN_RELATED,
@ -110,8 +136,10 @@ internal class TangemPayTariffPlanConverterTest {
// THEN // THEN
val expected = TangemPayTariffPlan( val expected = TangemPayTariffPlan(
id = PLAN_ID, id = PLAN_ID,
type = TangemPayTariffPlan.Type.UNKNOWN, tierId = "SOMETHING_NEW",
isBasicTier = false,
name = PLAN_NAME, name = PLAN_NAME,
programName = PROGRAM_NAME,
descriptionItems = listOf( descriptionItems = listOf(
TangemPayTariffPlan.DescriptionItem( TangemPayTariffPlan.DescriptionItem(
section = TangemPayTariffPlan.Section.UNKNOWN, section = TangemPayTariffPlan.Section.UNKNOWN,
@ -168,6 +196,7 @@ internal class TangemPayTariffPlanConverterTest {
id: String? = PLAN_ID, id: String? = PLAN_ID,
type: String? = "BASIC", type: String? = "BASIC",
name: String? = PLAN_NAME, name: String? = PLAN_NAME,
programName: String? = PROGRAM_NAME,
descriptionItems: List<CustomerMeResponse.DescriptionItem>? = null, descriptionItems: List<CustomerMeResponse.DescriptionItem>? = null,
images: List<CustomerMeResponse.Image>? = null, images: List<CustomerMeResponse.Image>? = null,
fees: List<CustomerMeResponse.Fee>? = null, fees: List<CustomerMeResponse.Fee>? = null,
@ -175,6 +204,7 @@ internal class TangemPayTariffPlanConverterTest {
id = id, id = id,
type = type, type = type,
name = name, name = name,
programName = programName,
descriptionItems = descriptionItems, descriptionItems = descriptionItems,
images = images, images = images,
fees = fees, fees = fees,
@ -183,5 +213,6 @@ internal class TangemPayTariffPlanConverterTest {
private companion object { private companion object {
const val PLAN_ID = "plan-1" const val PLAN_ID = "plan-1"
const val PLAN_NAME = "Plus" const val PLAN_NAME = "Plus"
const val PROGRAM_NAME = "program-1"
} }
} }

View file

@ -120,8 +120,10 @@ internal class DefaultPaymentAccountStatusFetcherTest {
private val basicPlan = TangemPayTariffPlan( private val basicPlan = TangemPayTariffPlan(
id = "plan_basic", id = "plan_basic",
type = TangemPayTariffPlan.Type.BASIC, tierId = "BASIC",
isBasicTier = true,
name = "Basic", name = "Basic",
programName = "program_basic",
descriptionItems = emptyList(), descriptionItems = emptyList(),
images = emptyList(), images = emptyList(),
fees = emptyList(), fees = emptyList(),

View file

@ -91,8 +91,10 @@ internal class DefaultTariffPlanTransitionsRepositoryTest {
type = TangemPayTariffPlanTransition.Type.UPGRADE, type = TangemPayTariffPlanTransition.Type.UPGRADE,
plan = TangemPayTariffPlan( plan = TangemPayTariffPlan(
id = PLAN_ID, id = PLAN_ID,
type = TangemPayTariffPlan.Type.PLUS, tierId = "PLUS",
isBasicTier = false,
name = PLAN_NAME, name = PLAN_NAME,
programName = PROGRAM_NAME,
descriptionItems = emptyList(), descriptionItems = emptyList(),
images = emptyList(), images = emptyList(),
fees = emptyList(), fees = emptyList(),
@ -187,6 +189,7 @@ internal class DefaultTariffPlanTransitionsRepositoryTest {
id = id, id = id,
type = "PLUS", type = "PLUS",
name = PLAN_NAME, name = PLAN_NAME,
programName = PROGRAM_NAME,
descriptionItems = null, descriptionItems = null,
images = null, images = null,
fees = null, fees = null,
@ -197,6 +200,7 @@ internal class DefaultTariffPlanTransitionsRepositoryTest {
const val AUTH_HEADER = "auth-header" const val AUTH_HEADER = "auth-header"
const val PLAN_ID = "plan-plus" const val PLAN_ID = "plan-plus"
const val PLAN_NAME = "Plus" const val PLAN_NAME = "Plus"
const val PROGRAM_NAME = "program-plus"
const val PENDING_PLAN_ID = "plan-basic" const val PENDING_PLAN_ID = "plan-basic"
} }
} }

View file

@ -8,8 +8,10 @@ import java.util.Locale
@Serializable @Serializable
data class TangemPayTariffPlan( data class TangemPayTariffPlan(
@SerialName("id") val id: String, @SerialName("id") val id: String,
@SerialName("type") val type: Type, @SerialName("tier_id") val tierId: String,
@SerialName("is_basic_tier") val isBasicTier: Boolean,
@SerialName("name") val name: String, @SerialName("name") val name: String,
@SerialName("program_name") val programName: String,
@SerialName("description_items") val descriptionItems: List<DescriptionItem>, @SerialName("description_items") val descriptionItems: List<DescriptionItem>,
@SerialName("images") val images: List<Image> = emptyList(), @SerialName("images") val images: List<Image> = emptyList(),
@SerialName("fees") val fees: List<Fee> = emptyList(), @SerialName("fees") val fees: List<Fee> = emptyList(),
@ -100,31 +102,6 @@ data class TangemPayTariffPlan(
} }
} }
@Serializable
enum class Type {
@SerialName("BASIC")
BASIC,
@SerialName("PLUS")
PLUS,
@SerialName("PLUS_FF")
PLUS_FF,
@SerialName("UNKNOWN")
UNKNOWN,
;
companion object {
fun fromString(value: String?) = when (value?.uppercase(Locale.US)) {
"BASIC" -> BASIC
"PLUS" -> PLUS
"PLUS_FF" -> PLUS_FF
else -> UNKNOWN
}
}
}
@Serializable @Serializable
enum class Section { enum class Section {
@SerialName("CARD_RELATED") @SerialName("CARD_RELATED")

View file

@ -153,14 +153,18 @@ internal class GetTangemPayTariffPlanStateUseCaseTest {
val CURRENT_PLAN = TangemPayTariffPlan( val CURRENT_PLAN = TangemPayTariffPlan(
id = "plan-basic", id = "plan-basic",
type = TangemPayTariffPlan.Type.BASIC, tierId = "BASIC",
isBasicTier = true,
name = "Basic", name = "Basic",
programName = "program-basic",
descriptionItems = emptyList(), descriptionItems = emptyList(),
) )
val TARGET_PLAN = TangemPayTariffPlan( val TARGET_PLAN = TangemPayTariffPlan(
id = TARGET_PLAN_ID, id = TARGET_PLAN_ID,
type = TangemPayTariffPlan.Type.PLUS, tierId = "PLUS",
isBasicTier = false,
name = "Plus", name = "Plus",
programName = "program-plus",
descriptionItems = emptyList(), descriptionItems = emptyList(),
) )
val CUSTOMER_TARIFF = TangemPayCustomerTariffPlan( val CUSTOMER_TARIFF = TangemPayCustomerTariffPlan(

View file

@ -1,10 +1,8 @@
package com.tangem.features.tangempay.cashback.impl.model package com.tangem.features.tangempay.cashback.impl.model
import com.tangem.domain.models.account.TangemPayTariffPlan
/** Cashback program tier, mapped once from the domain and shared by the rate tile and the details sheet. */ /** Cashback program tier, mapped once from the domain and shared by the rate tile and the details sheet. */
internal data class CashbackTier( internal data class CashbackTier(
val planType: TangemPayTariffPlan.Type, val tierId: String,
val rate: Int?, val rate: Int?,
val label: String, val label: String,
val scope: String, val scope: String,

View file

@ -12,17 +12,13 @@ internal class TangemPayCashbackInfoTilesConverter(
) { ) {
// TODO([REDACTED_TASK_KEY]): move hardcoded strings to string resources // TODO([REDACTED_TASK_KEY]): move hardcoded strings to string resources
fun convert( fun convert(tiers: List<CashbackTier>, currentPlan: TangemPayTariffPlan?): TangemPayCashbackInfoTilesUM {
tiers: List<CashbackTier>, val rate = tiers.selectTier(currentPlan?.tierId)?.rate
currentPlanType: TangemPayTariffPlan.Type,
currentPlanName: String?,
): TangemPayCashbackInfoTilesUM {
val rate = tiers.selectTier(currentPlanType)?.rate
return TangemPayCashbackInfoTilesUM( return TangemPayCashbackInfoTilesUM(
rate = TangemPayCashbackInfoTilesUM.Tile( rate = TangemPayCashbackInfoTilesUM.Tile(
iconRes = R.drawable.ic_percent_24, iconRes = R.drawable.ic_percent_24,
title = stringReference(if (rate != null) "Cashback $rate%" else "Cashback"), title = stringReference(if (rate != null) "Cashback $rate%" else "Cashback"),
subtitle = currentPlanName?.let { stringReference("With your $it plan") } ?: TextReference.EMPTY, subtitle = currentPlan?.name?.let { stringReference("With your $it plan") } ?: TextReference.EMPTY,
onClick = onRateClick, onClick = onRateClick,
), ),
accruals = TangemPayCashbackInfoTilesUM.Tile( accruals = TangemPayCashbackInfoTilesUM.Tile(
@ -34,9 +30,7 @@ internal class TangemPayCashbackInfoTilesConverter(
) )
} }
private fun List<CashbackTier>.selectTier(planType: TangemPayTariffPlan.Type): CashbackTier? { private fun List<CashbackTier>.selectTier(tierId: String?): CashbackTier? {
return firstOrNull { return firstOrNull { it.tierId == tierId } ?: firstOrNull()
planType != TangemPayTariffPlan.Type.UNKNOWN && it.planType == planType
} ?: firstOrNull()
} }
} }

View file

@ -86,8 +86,7 @@ internal class TangemPayCashbackModel @Inject constructor(
infoTiles = promotions?.let { infoTiles = promotions?.let {
infoTilesConverter.convert( infoTilesConverter.convert(
tiers = tiers, tiers = tiers,
currentPlanType = plan?.type ?: TangemPayTariffPlan.Type.UNKNOWN, currentPlan = plan,
currentPlanName = plan?.name,
) )
}, },
) )

View file

@ -4,7 +4,6 @@ import com.tangem.core.ui.format.bigdecimal.fiat
import com.tangem.core.ui.format.bigdecimal.format import com.tangem.core.ui.format.bigdecimal.format
import com.tangem.core.ui.format.bigdecimal.getJavaCurrencyByCode import com.tangem.core.ui.format.bigdecimal.getJavaCurrencyByCode
import com.tangem.core.ui.format.bigdecimal.optionalDecimals import com.tangem.core.ui.format.bigdecimal.optionalDecimals
import com.tangem.domain.models.account.TangemPayTariffPlan
import com.tangem.domain.pay.model.CashbackPromotions import com.tangem.domain.pay.model.CashbackPromotions
import com.tangem.utils.converter.Converter import com.tangem.utils.converter.Converter
import java.math.BigDecimal import java.math.BigDecimal
@ -14,7 +13,7 @@ internal class TangemPayCashbackTiersConverter : Converter<CashbackPromotions, L
override fun convert(value: CashbackPromotions): List<CashbackTier> { override fun convert(value: CashbackPromotions): List<CashbackTier> {
return value.cardTiers.map { tier -> return value.cardTiers.map { tier ->
CashbackTier( CashbackTier(
planType = TangemPayTariffPlan.Type.fromString(tier.tier), tierId = tier.tier,
rate = CashbackRates.forTier(tier.tier), rate = CashbackRates.forTier(tier.tier),
label = tier.label, label = tier.label,
scope = tier.scope, scope = tier.scope,

View file

@ -2,7 +2,7 @@ package com.tangem.features.tangempay.entity
import com.tangem.core.ui.components.notifications.NotificationConfig import com.tangem.core.ui.components.notifications.NotificationConfig
import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.extensions.wrappedList
import com.tangem.domain.models.account.PaymentAccountStatusValue import com.tangem.domain.models.account.PaymentAccountStatusValue
import com.tangem.domain.models.account.TangemPayCustomerTariffPlan import com.tangem.domain.models.account.TangemPayCustomerTariffPlan
import com.tangem.domain.models.account.TangemPayTariffPlanState import com.tangem.domain.models.account.TangemPayTariffPlanState
@ -37,7 +37,6 @@ internal class TangemPayDetailsNotificationFactory(
}, },
) )
// TODO v_rodionov: #[REDACTED_TASK_KEY] fix hardcoded strings
fun createAwaitingDepositConfig(tariffPlan: TangemPayTariffPlanState?): NotificationConfig? { fun createAwaitingDepositConfig(tariffPlan: TangemPayTariffPlanState?): NotificationConfig? {
if (!isTiersPlusPlanEnabled) return null if (!isTiersPlusPlanEnabled) return null
if (tariffPlan == null) return null if (tariffPlan == null) return null
@ -52,13 +51,15 @@ internal class TangemPayDetailsNotificationFactory(
val feeText = orderStep.toPlan.formatRecurringFeeOrNull() ?: return null val feeText = orderStep.toPlan.formatRecurringFeeOrNull() ?: return null
val title = "Top-up your account on $feeText"
return NotificationConfig( return NotificationConfig(
title = stringReference(title), title = resourceReference(R.string.tangempay_card_details_awaiting_deposit_title, wrappedList(feeText)),
subtitle = stringReference("To pay monthly fee for plan and start use card"), subtitle = resourceReference(R.string.tangempay_card_details_awaiting_deposit_subtitle),
iconResId = R.drawable.ic_alert_circle_24, iconResId = R.drawable.ic_alert_circle_24,
buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig( buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
text = stringReference("Cancel ${orderStep.toPlan.name}, move to ${orderStep.fromPlan.name}"), text = resourceReference(
R.string.tangempay_card_details_awaiting_deposit_cancel_button,
wrappedList(orderStep.toPlan.name, orderStep.fromPlan.name),
),
onClick = { intents.onCancelPlusTransition(order.orderId) }, onClick = { intents.onCancelPlusTransition(order.orderId) },
), ),
) )
@ -81,16 +82,18 @@ internal class TangemPayDetailsNotificationFactory(
iconResId = if (isRedesignEnabled) R.drawable.ic_alert_circle_24 else R.drawable.img_attention_20, iconResId = if (isRedesignEnabled) R.drawable.ic_alert_circle_24 else R.drawable.img_attention_20,
) )
// TODO v_rodionov: #[REDACTED_TASK_KEY] fix hardcoded strings
private fun createTariffSystemDownGradePendingConfig(tariffPlan: TangemPayTariffPlanState): NotificationConfig? { private fun createTariffSystemDownGradePendingConfig(tariffPlan: TangemPayTariffPlanState): NotificationConfig? {
val date = tariffPlan.tariff.formatNextBillingDateOrNull() ?: return null val date = tariffPlan.tariff.formatNextBillingDateOrNull() ?: return null
val planName = tariffPlan.tariff.plan.name val planName = tariffPlan.tariff.plan.name
return NotificationConfig( return NotificationConfig(
title = stringReference("Top up your account shortly"), title = resourceReference(R.string.tangempay_card_details_system_downgrade_title),
subtitle = stringReference("If it will remain below zero your $planName cards will be closed on $date"), subtitle = resourceReference(
R.string.tangempay_card_details_system_downgrade_subtitle,
wrappedList(planName, date),
),
iconResId = R.drawable.ic_alert_circle_24, iconResId = R.drawable.ic_alert_circle_24,
buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig( buttonsState = NotificationConfig.ButtonsState.SecondaryButtonConfig(
text = stringReference("Add funds"), text = resourceReference(R.string.tangempay_card_details_add_funds),
onClick = intents::onClickAddFunds, onClick = intents::onClickAddFunds,
), ),
) )

View file

@ -12,7 +12,6 @@ import com.tangem.core.ui.res.generated.icons.Icons
import com.tangem.core.ui.res.generated.icons.ic_document_20 import com.tangem.core.ui.res.generated.icons.ic_document_20
import com.tangem.domain.models.account.PaymentAccountStatusValue import com.tangem.domain.models.account.PaymentAccountStatusValue
import com.tangem.domain.models.account.TangemPayCustomerTariffPlan import com.tangem.domain.models.account.TangemPayCustomerTariffPlan
import com.tangem.domain.models.account.TangemPayTariffPlan
import com.tangem.domain.models.account.TangemPayTariffPlanState import com.tangem.domain.models.account.TangemPayTariffPlanState
import com.tangem.domain.models.pay.TangemPayCard import com.tangem.domain.models.pay.TangemPayCard
import com.tangem.domain.models.pay.TangemPayCardFrozenState import com.tangem.domain.models.pay.TangemPayCardFrozenState
@ -286,10 +285,7 @@ internal class TangemPayDetailsStateFactory(
), ),
) )
} }
if (isTiersPlusPlanEnabled && if (isTiersPlusPlanEnabled && tariffPlan != null && !tariffPlan.tariff.plan.isBasicTier) {
tariffPlan != null &&
tariffPlan.tariff.plan.type != TangemPayTariffPlan.Type.BASIC
) {
add( add(
TangemPayDropDownItemUM( TangemPayDropDownItemUM(
title = resourceReference(R.string.tangempay_visa_benefits), title = resourceReference(R.string.tangempay_visa_benefits),

View file

@ -7,6 +7,7 @@ import com.tangem.core.decompose.model.ParamsContainer
import com.tangem.core.decompose.navigation.Router import com.tangem.core.decompose.navigation.Router
import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.ui.utils.DateTimeFormatters import com.tangem.core.ui.utils.DateTimeFormatters
import com.tangem.domain.models.account.TangemPayCustomerTariffPlan import com.tangem.domain.models.account.TangemPayCustomerTariffPlan
@ -50,7 +51,6 @@ internal class TangemPayCurrentPlanModel @Inject constructor(
onChangePlanClick = { router.push(TangemPayAccountDetailsInnerRoute.SelectPlan(params.tariffPlan)) }, onChangePlanClick = { router.push(TangemPayAccountDetailsInnerRoute.SelectPlan(params.tariffPlan)) },
) )
// TODO v_rodionov: #[REDACTED_TASK_KEY] fix hardcoded strings
private fun createNotification(customerPlan: TangemPayCustomerTariffPlan): TangemPayCurrentPlanUM.Notification? { private fun createNotification(customerPlan: TangemPayCustomerTariffPlan): TangemPayCurrentPlanUM.Notification? {
val date = customerPlan.formatNextBillingDateOrNull(formatter = DateTimeFormatters.dateMMMd) ?: return null val date = customerPlan.formatNextBillingDateOrNull(formatter = DateTimeFormatters.dateMMMd) ?: return null
val feeText = customerPlan.plan.formatRecurringFeeOrNull() ?: return null val feeText = customerPlan.plan.formatRecurringFeeOrNull() ?: return null
@ -58,19 +58,25 @@ internal class TangemPayCurrentPlanModel @Inject constructor(
TangemPayCustomerTariffPlan.Status.DOWNGRADE_PENDING -> { TangemPayCustomerTariffPlan.Status.DOWNGRADE_PENDING -> {
val targetPlan = customerPlan.pendingPlan ?: return null val targetPlan = customerPlan.pendingPlan ?: return null
TangemPayCurrentPlanUM.Notification( TangemPayCurrentPlanUM.Notification(
text = stringReference( text = resourceReference(
"Your ${customerPlan.plan.name} plan is active till $date, then we will move you to " + R.string.tangempay_current_plan_active_till_notification,
"${targetPlan.name}. $feeText won't be charged.", wrappedList(customerPlan.plan.name, date, targetPlan.name, feeText),
), ),
button = TangemPayCurrentPlanUM.Notification.Button( button = TangemPayCurrentPlanUM.Notification.Button(
text = stringReference("Stay on ${customerPlan.plan.name}"), text = resourceReference(
R.string.tangempay_current_plan_stay_button,
wrappedList(customerPlan.plan.name),
),
isProcessing = isProcessing, isProcessing = isProcessing,
onClick = ::onStayOnPlanClick, onClick = ::onStayOnPlanClick,
), ),
) )
} }
TangemPayCustomerTariffPlan.Status.ACTIVE -> TangemPayCurrentPlanUM.Notification( TangemPayCustomerTariffPlan.Status.ACTIVE -> TangemPayCurrentPlanUM.Notification(
text = stringReference("$feeText monthly fee will be charged on $date"), text = resourceReference(
R.string.tangempay_current_plan_fee_charged_notification,
wrappedList(feeText, date),
),
) )
else -> null else -> null
} }

View file

@ -9,6 +9,7 @@ import com.tangem.core.decompose.navigation.Router
import com.tangem.core.decompose.ui.UiMessageSender import com.tangem.core.decompose.ui.UiMessageSender
import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.extensions.stringReference
import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.utils.DateTimeFormatters import com.tangem.core.ui.utils.DateTimeFormatters
import com.tangem.domain.models.account.TangemPayTariffPlan import com.tangem.domain.models.account.TangemPayTariffPlan
import com.tangem.domain.models.account.TangemPayTariffPlanTransition import com.tangem.domain.models.account.TangemPayTariffPlanTransition
@ -189,28 +190,34 @@ internal class TangemPaySelectPlanModel @Inject constructor(
) )
} }
// TODO v_rodionov: #[REDACTED_TASK_KEY] fix hardcoded strings
private fun buildConfirmContent(): TangemPaySelectPlanUM.Content { private fun buildConfirmContent(): TangemPaySelectPlanUM.Content {
val transition = allowedTransitions.getOrNull(selectedIndex) ?: return buildSelectContent() val transition = allowedTransitions.getOrNull(selectedIndex) ?: return buildSelectContent()
val targetProgramme = transition.plan.name val targetPlanName = transition.plan.name
val programName = transition.plan.programName
return TangemPaySelectPlanUM.Content.Confirm( return TangemPaySelectPlanUM.Content.Confirm(
title = when (transition.type) { title = when (transition.type) {
TangemPayTariffPlanTransition.Type.UPGRADE -> stringReference( TangemPayTariffPlanTransition.Type.UPGRADE -> resourceReference(
"We will issue Visa $targetProgramme for you", R.string.tangempay_select_plan_confirm_upgrade_title,
wrappedList(programName),
) )
TangemPayTariffPlanTransition.Type.DOWNGRADE -> { TangemPayTariffPlanTransition.Type.DOWNGRADE -> {
val nextBillingDate = nextBillingDate() val nextBillingDate = nextBillingDate()
if (nextBillingDate != null) { if (nextBillingDate != null) {
val programName = "UNKNOWN" // TODO v_rodionov: #[REDACTED_TASK_KEY] fix hardcoded strings resourceReference(
val planName = params.tariffPlan.plan.name R.string.tangempay_select_plan_confirm_downgrade_title,
stringReference( wrappedList(params.tariffPlan.plan.name, programName, nextBillingDate),
"Your $planName plan and $programName cards will be active till $nextBillingDate",
) )
} else { } else {
stringReference("You are switching to $targetProgramme") resourceReference(
R.string.tangempay_select_plan_confirm_switch_title,
wrappedList(targetPlanName),
)
} }
} }
else -> stringReference("You are switching to $targetProgramme") else -> resourceReference(
R.string.tangempay_select_plan_confirm_switch_title,
wrappedList(targetPlanName),
)
}, },
points = buildConfirmPoints(transition), points = buildConfirmPoints(transition),
confirmButtonText = resourceReference( confirmButtonText = resourceReference(
@ -226,18 +233,27 @@ internal class TangemPaySelectPlanModel @Inject constructor(
) )
} }
// TODO v_rodionov: #[REDACTED_TASK_KEY] fix hardcoded strings
private fun buildConfirmPoints( private fun buildConfirmPoints(
transition: TangemPayTariffPlanTransition, transition: TangemPayTariffPlanTransition,
): ImmutableList<TangemPaySelectPlanUM.PointUM> { ): ImmutableList<TangemPaySelectPlanUM.PointUM> {
val programName = "UNKNOWN" // TODO v_rodionov: #[REDACTED_TASK_KEY] fix hardcoded strings val programName = transition.plan.programName
return when (transition.type) { return when (transition.type) {
TangemPayTariffPlanTransition.Type.UPGRADE -> { TangemPayTariffPlanTransition.Type.UPGRADE -> {
val feeText = transition.plan.formatRecurringFeeOrNull() val feeText = transition.plan.formatRecurringFeeOrNull()
buildList { buildList {
add("You will get your virtual Visa $programName in minutes") add(
resourceReference(
R.string.tangempay_select_plan_confirm_point_virtual_card,
wrappedList(programName),
),
)
if (feeText != null) { if (feeText != null) {
add("$feeText monthly fee will be taken from your account") add(
resourceReference(
R.string.tangempay_select_plan_confirm_point_monthly_fee,
wrappedList(feeText),
),
)
} }
} }
} }
@ -245,18 +261,33 @@ internal class TangemPaySelectPlanModel @Inject constructor(
val date = nextBillingDate() val date = nextBillingDate()
buildList { buildList {
if (date != null) { if (date != null) {
add("On $date we will move you to ${transition.plan.name} plan") add(
resourceReference(
R.string.tangempay_select_plan_confirm_point_move_on_date,
wrappedList(date, transition.plan.name),
),
)
} }
add("Your Visa $programName cards will be closed") add(
resourceReference(
R.string.tangempay_select_plan_confirm_point_cards_closed,
wrappedList(programName),
),
)
if (date != null) { if (date != null) {
add("You can cancel this transition till $date") add(
resourceReference(
R.string.tangempay_select_plan_confirm_point_cancel_till,
wrappedList(date),
),
)
} }
add("No fee applied") add(resourceReference(R.string.tangempay_select_plan_confirm_point_no_fee))
} }
} }
else -> listOf("No fee applied") else -> listOf(resourceReference(R.string.tangempay_select_plan_confirm_point_no_fee))
} }
.map { TangemPaySelectPlanUM.PointUM(title = stringReference(it), body = null) } .map { TangemPaySelectPlanUM.PointUM(title = it, body = null) }
.toImmutableList() .toImmutableList()
} }

View file

@ -4,7 +4,7 @@ import com.tangem.core.ui.R
import com.tangem.core.ui.components.bottomsheets.message.* import com.tangem.core.ui.components.bottomsheets.message.*
import com.tangem.core.ui.extensions.TextReference import com.tangem.core.ui.extensions.TextReference
import com.tangem.core.ui.extensions.resourceReference import com.tangem.core.ui.extensions.resourceReference
import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.extensions.wrappedList
import com.tangem.core.ui.message.BottomSheetMessage import com.tangem.core.ui.message.BottomSheetMessage
import com.tangem.core.ui.message.DialogMessage import com.tangem.core.ui.message.DialogMessage
import com.tangem.core.ui.message.bottomSheetMessage import com.tangem.core.ui.message.bottomSheetMessage
@ -149,7 +149,6 @@ internal object TangemPayMessagesFactory {
} }
} }
// TODO v_rodionov: #[REDACTED_TASK_KEY] fix hardcoded strings
fun createStayOnPlanMessage( fun createStayOnPlanMessage(
planName: String, planName: String,
targetPlanName: String, targetPlanName: String,
@ -161,15 +160,18 @@ internal object TangemPayMessagesFactory {
type = MessageBottomSheetUM.Icon.Type.Informative type = MessageBottomSheetUM.Icon.Type.Informative
backgroundType = MessageBottomSheetUM.Icon.BackgroundType.Informative backgroundType = MessageBottomSheetUM.Icon.BackgroundType.Informative
} }
title = stringReference("Do you want to stay on $planName?") title = resourceReference(R.string.tangempay_current_plan_stay_sheet_title, wrappedList(planName))
body = stringReference("Your transition on $targetPlanName will be canceled") body = resourceReference(
R.string.tangempay_current_plan_stay_sheet_body,
wrappedList(targetPlanName),
)
} }
secondaryButton { secondaryButton {
text = resourceReference(R.string.common_cancel) text = resourceReference(R.string.common_cancel)
onClick { closeBs() } onClick { closeBs() }
} }
primaryButton { primaryButton {
text = stringReference("Stay on $planName") text = resourceReference(R.string.tangempay_current_plan_stay_button, wrappedList(planName))
onClick { onClick {
onStayClick() onStayClick()
closeBs() closeBs()

View file

@ -2,7 +2,6 @@ package com.tangem.features.tangempay.cashback.impl.model
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import com.tangem.core.ui.extensions.stringReference import com.tangem.core.ui.extensions.stringReference
import com.tangem.domain.models.account.TangemPayTariffPlan
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
internal class TangemPayCashbackDetailsConverterTest { internal class TangemPayCashbackDetailsConverterTest {
@ -81,7 +80,7 @@ internal class TangemPayCashbackDetailsConverterTest {
min: String? = null, min: String? = null,
cap: String? = null, cap: String? = null,
) = CashbackTier( ) = CashbackTier(
planType = TangemPayTariffPlan.Type.UNKNOWN, tierId = "basic",
rate = rate, rate = rate,
label = label, label = label,
scope = scope, scope = scope,

View file

@ -21,7 +21,7 @@ internal class TangemPayCashbackInfoTilesConverterTest {
@MethodSource("rateSelectionModels") @MethodSource("rateSelectionModels")
fun `GIVEN plan WHEN convert THEN rate tile shows the tier rate and the plan subtitle`(model: RateSelectionModel) { fun `GIVEN plan WHEN convert THEN rate tile shows the tier rate and the plan subtitle`(model: RateSelectionModel) {
// Act // Act
val result = converter.convert(twoTiers(), model.plan, model.planName) val result = converter.convert(twoTiers(), model.plan)
// Assert // Assert
assertThat(result.rate.title).isEqualTo(stringReference(model.expectedTitle)) assertThat(result.rate.title).isEqualTo(stringReference(model.expectedTitle))
@ -29,9 +29,9 @@ internal class TangemPayCashbackInfoTilesConverterTest {
} }
@Test @Test
fun `GIVEN empty tiers and unknown plan WHEN convert THEN rate tile has no percent and empty subtitle`() { fun `GIVEN empty tiers and no plan WHEN convert THEN rate tile has no percent and empty subtitle`() {
// Act // Act
val result = converter.convert(emptyList(), TangemPayTariffPlan.Type.UNKNOWN, currentPlanName = null) val result = converter.convert(emptyList(), currentPlan = null)
// Assert // Assert
assertThat(result.rate.title).isEqualTo(stringReference("Cashback")) assertThat(result.rate.title).isEqualTo(stringReference("Cashback"))
@ -41,7 +41,7 @@ internal class TangemPayCashbackInfoTilesConverterTest {
@Test @Test
fun `GIVEN any tiers WHEN convert THEN accruals tile is static`() { fun `GIVEN any tiers WHEN convert THEN accruals tile is static`() {
// Act // Act
val result = converter.convert(twoTiers(), TangemPayTariffPlan.Type.BASIC, currentPlanName = "Basic") val result = converter.convert(twoTiers(), plan(tierId = "basic", name = "Basic"))
// Assert // Assert
assertThat(result.accruals.title).isEqualTo(stringReference("Accruals")) assertThat(result.accruals.title).isEqualTo(stringReference("Accruals"))
@ -50,43 +50,52 @@ internal class TangemPayCashbackInfoTilesConverterTest {
private fun rateSelectionModels() = listOf( private fun rateSelectionModels() = listOf(
RateSelectionModel( RateSelectionModel(
plan = TangemPayTariffPlan.Type.PLUS, plan = plan(tierId = "plus", name = "Plus"),
planName = "Plus",
expectedTitle = "Cashback 2%", expectedTitle = "Cashback 2%",
expectedSubtitle = stringReference("With your Plus plan"), expectedSubtitle = stringReference("With your Plus plan"),
), ),
RateSelectionModel( RateSelectionModel(
plan = TangemPayTariffPlan.Type.BASIC, plan = plan(tierId = "basic", name = "Basic"),
planName = "Basic",
expectedTitle = "Cashback 1%", expectedTitle = "Cashback 1%",
expectedSubtitle = stringReference("With your Basic plan"), expectedSubtitle = stringReference("With your Basic plan"),
), ),
RateSelectionModel( RateSelectionModel(
plan = TangemPayTariffPlan.Type.UNKNOWN, plan = plan(tierId = "gold", name = "Gold"),
planName = null, expectedTitle = "Cashback 1%",
expectedSubtitle = stringReference("With your Gold plan"),
),
RateSelectionModel(
plan = null,
expectedTitle = "Cashback 1%", expectedTitle = "Cashback 1%",
expectedSubtitle = TextReference.EMPTY, expectedSubtitle = TextReference.EMPTY,
), ),
) )
private fun twoTiers() = listOf( private fun twoTiers() = listOf(
tier(TangemPayTariffPlan.Type.BASIC, rate = 1), tier(tierId = "basic", rate = 1),
tier(TangemPayTariffPlan.Type.PLUS, rate = 2), tier(tierId = "plus", rate = 2),
) )
private fun tier(planType: TangemPayTariffPlan.Type = TangemPayTariffPlan.Type.UNKNOWN, rate: Int? = null) = private fun tier(tierId: String, rate: Int? = null) = CashbackTier(
CashbackTier( tierId = tierId,
planType = planType, rate = rate,
rate = rate, label = "label",
label = "label", scope = "scope",
scope = "scope", minPurchase = null,
minPurchase = null, monthlyCap = null,
monthlyCap = null, )
)
private fun plan(tierId: String, name: String) = TangemPayTariffPlan(
id = "plan-$tierId",
tierId = tierId,
isBasicTier = tierId == "basic",
name = name,
programName = "program",
descriptionItems = emptyList(),
)
data class RateSelectionModel( data class RateSelectionModel(
val plan: TangemPayTariffPlan.Type, val plan: TangemPayTariffPlan?,
val planName: String?,
val expectedTitle: String, val expectedTitle: String,
val expectedSubtitle: TextReference, val expectedSubtitle: TextReference,
) )

View file

@ -45,7 +45,7 @@ internal class TangemPayCashbackModelTest {
coEvery { cashbackRepository.getCashbackPromotions(any()) } returns promotions().right() coEvery { cashbackRepository.getCashbackPromotions(any()) } returns promotions().right()
coEvery { cashbackRepository.getCashbackAccrualDocs(any()) } returns docs().right() coEvery { cashbackRepository.getCashbackAccrualDocs(any()) } returns docs().right()
coEvery { onboardingRepository.getCustomerInfo(any()) } returns coEvery { onboardingRepository.getCustomerInfo(any()) } returns
customerInfo(TangemPayTariffPlan.Type.BASIC).right() customerInfo(tierId = "basic", planName = "Basic").right()
} }
@AfterEach @AfterEach
@ -69,7 +69,7 @@ internal class TangemPayCashbackModelTest {
fun `GIVEN PLUS plan WHEN model created THEN rate tile shows the Plus tier rate`() { fun `GIVEN PLUS plan WHEN model created THEN rate tile shows the Plus tier rate`() {
// Arrange // Arrange
coEvery { onboardingRepository.getCustomerInfo(any()) } returns coEvery { onboardingRepository.getCustomerInfo(any()) } returns
customerInfo(TangemPayTariffPlan.Type.PLUS).right() customerInfo(tierId = "plus", planName = "Plus").right()
// Act // Act
val model = createModel() val model = createModel()
@ -162,12 +162,16 @@ internal class TangemPayCashbackModelTest {
CashbackDocument(id = "terms", title = "Full terms of cashback program", url = "https://x/terms.pdf"), CashbackDocument(id = "terms", title = "Full terms of cashback program", url = "https://x/terms.pdf"),
) )
private fun customerInfo(planType: TangemPayTariffPlan.Type): CustomerInfo { private fun customerInfo(tierId: String, planName: String): CustomerInfo {
val tariffPlanMock = mockk<TangemPayTariffPlan> { val currentPlan = TangemPayTariffPlan(
every { type } returns planType id = "plan-$tierId",
every { name } returns planType.name tierId = tierId,
} isBasicTier = tierId == "basic",
val customerTariffPlanMock = mockk<TangemPayCustomerTariffPlan> { every { plan } returns tariffPlanMock } name = planName,
programName = "program",
descriptionItems = emptyList(),
)
val customerTariffPlanMock = mockk<TangemPayCustomerTariffPlan> { every { plan } returns currentPlan }
return mockk { every { tariffPlan } returns customerTariffPlanMock } return mockk { every { tariffPlan } returns customerTariffPlanMock }
} }
} }

View file

@ -1,7 +1,6 @@
package com.tangem.features.tangempay.cashback.impl.model package com.tangem.features.tangempay.cashback.impl.model
import com.google.common.truth.Truth.assertThat import com.google.common.truth.Truth.assertThat
import com.tangem.domain.models.account.TangemPayTariffPlan
import com.tangem.domain.pay.model.CashbackPromotions import com.tangem.domain.pay.model.CashbackPromotions
import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.BeforeEach
@ -38,7 +37,7 @@ internal class TangemPayCashbackTiersConverterTest {
// Assert // Assert
assertThat(result).containsExactly( assertThat(result).containsExactly(
CashbackTier( CashbackTier(
planType = TangemPayTariffPlan.Type.BASIC, tierId = "basic",
rate = 1, rate = 1,
label = "Basic cards", label = "Basic cards",
scope = "All purchases", scope = "All purchases",
@ -46,7 +45,7 @@ internal class TangemPayCashbackTiersConverterTest {
monthlyCap = "$100", monthlyCap = "$100",
), ),
CashbackTier( CashbackTier(
planType = TangemPayTariffPlan.Type.PLUS, tierId = "plus",
rate = 2, rate = 2,
label = "Plus cards", label = "Plus cards",
scope = "Everywhere", scope = "Everywhere",
@ -57,7 +56,7 @@ internal class TangemPayCashbackTiersConverterTest {
} }
@Test @Test
fun `GIVEN unknown tier WHEN convert THEN rate null and plan type UNKNOWN`() { fun `GIVEN unknown tier WHEN convert THEN rate is null and tier id kept`() {
// Arrange // Arrange
val promotions = promotions(tier(id = "gold", label = "Gold", scope = "All", min = null, cap = null)) val promotions = promotions(tier(id = "gold", label = "Gold", scope = "All", min = null, cap = null))
@ -67,7 +66,7 @@ internal class TangemPayCashbackTiersConverterTest {
// Assert // Assert
assertThat(result).containsExactly( assertThat(result).containsExactly(
CashbackTier( CashbackTier(
planType = TangemPayTariffPlan.Type.UNKNOWN, tierId = "gold",
rate = null, rate = null,
label = "Gold", label = "Gold",
scope = "All", scope = "All",