Updated on 2026-08-14

This commit is contained in:
Tangem 2022-11-02 11:56:53 +05:00
parent bd3ecd6e1a
commit c204af2973
7 changed files with 72 additions and 80 deletions

View file

@ -11,6 +11,7 @@ import com.tangem.tap.common.analytics.api.ErrorEventLogger
import com.tangem.tap.common.analytics.api.ShopifyOrderEventHandler
import com.tangem.tap.common.analytics.events.AnalyticsEvent
import com.tangem.tap.common.extensions.filterNotNull
import com.tangem.tap.common.shop.data.ProductType
/**
[REDACTED_AUTHOR]
@ -85,9 +86,9 @@ object Analytics : GlobalAnalyticsEventHandler {
}
}
override fun send(order: Storefront.Order) {
override fun send(order: Storefront.Order, productType: ProductType) {
analyticsHandlers.filterIsInstance<ShopifyOrderEventHandler>().forEach {
it.send(order)
it.send(order, productType)
}
}

View file

@ -13,6 +13,7 @@ import com.tangem.tap.common.analytics.AnalyticsParamAnOld
import com.tangem.tap.common.analytics.events.AnalyticsEvent
import com.tangem.tap.common.analytics.events.AnalyticsParam
import com.tangem.tap.common.extensions.filterNotNull
import com.tangem.tap.common.shop.data.ProductType
import com.tangem.tap.domain.configurable.config.Config
/**
@ -83,7 +84,7 @@ interface BlockchainSdkErrorEventHandler {
}
interface ShopifyOrderEventHandler {
fun send(order: Storefront.Order)
fun send(order: Storefront.Order, productType: ProductType)
}
interface AnalyticsHandlerBuilder {

View file

@ -1,5 +1,10 @@
package com.tangem.tap.common.analytics.events
import com.shopify.buy3.Storefront
import com.tangem.common.Converter
import com.tangem.tap.common.extensions.filterNotNull
import com.tangem.tap.common.shop.data.ProductType
/**
[REDACTED_AUTHOR]
*/
@ -10,13 +15,36 @@ sealed class Shop(
class ScreenOpened : IntroductionProcess("Shop Screen Opened")
class Purchased(productSku: String) : Shop(
class Purchased(params: Map<String, String>) : Shop(
event = "Purchased",
params = mapOf("SKU" to productSku),
params = params,
)
class Redirected(partnerName: String) : Shop(
event = "Redirected",
params = mapOf("Partner" to partnerName),
)
}
}
class OrderToParamsConverter : Converter<Pair<Storefront.Order, ProductType>, Map<String, String>> {
override fun convert(value: Pair<Storefront.Order, ProductType>): Map<String, String> {
val order = value.first
val productType = value.second
val code = (order.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)?.code
val sku = order.lineItems.edges.firstOrNull()?.node?.variant?.sku ?: productType.sku
val count = when (productType) {
ProductType.WALLET_2_CARDS -> "2"
ProductType.WALLET_3_CARDS -> "3"
}
val amount = "${order.totalPriceV2.amount} ${order.totalPriceV2.currencyCode.name}"
return mapOf(
"Coupon Code" to code,
"SKU" to sku,
"Count" to count,
"Amount" to amount,
).filterNotNull()
}
}

View file

@ -1,12 +1,12 @@
package com.tangem.tap.common.analytics.handlers.appsFlyer
import com.appsflyer.AFInAppEventParameterName
import com.appsflyer.AFInAppEventType
import com.shopify.buy3.Storefront
import com.tangem.common.Converter
import com.tangem.tap.common.analytics.api.AnalyticsEventHandler
import com.tangem.tap.common.analytics.api.AnalyticsHandlerBuilder
import com.tangem.tap.common.analytics.api.ShopifyOrderEventHandler
import com.tangem.tap.common.analytics.events.OrderToParamsConverter
import com.tangem.tap.common.analytics.events.Shop
import com.tangem.tap.common.shop.data.ProductType
class AppsFlyerAnalyticsHandler(
private val client: AppsFlyerAnalyticsClient,
@ -18,12 +18,12 @@ class AppsFlyerAnalyticsHandler(
client.logEvent(event, params)
}
override fun send(order: Storefront.Order) {
send(ORDER_EVENT, OrderToParamsConverter().convert(order))
override fun send(order: Storefront.Order, productType: ProductType) {
val eventParams = OrderToParamsConverter().convert(order to productType)
send(Shop.Purchased(eventParams))
}
companion object {
const val ORDER_EVENT = AFInAppEventType.PURCHASE
const val ID = "AppsFlyer"
}
@ -34,26 +34,4 @@ class AppsFlyerAnalyticsHandler(
else -> null
}?.let { AppsFlyerAnalyticsHandler(it) }
}
}
private class OrderToParamsConverter : Converter<Storefront.Order, Map<String, String>> {
override fun convert(value: Storefront.Order): Map<String, String> {
val sku = value.lineItems.edges.firstOrNull()?.node?.variant?.sku ?: "unknown"
val discountCode =
(value.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)?.code
val discountParams = if (discountCode != null) {
mapOf(AFInAppEventParameterName.COUPON_CODE to discountCode)
} else {
mapOf()
}
return mapOf(
AFInAppEventParameterName.CONTENT_ID to sku,
AFInAppEventParameterName.REVENUE to value.totalPriceV2.amount,
AFInAppEventParameterName.CURRENCY to value.currencyCode.name,
) + discountParams
}
}

View file

@ -1,9 +1,7 @@
package com.tangem.tap.common.analytics.handlers.firebase
import com.google.firebase.analytics.FirebaseAnalytics
import com.shopify.buy3.Storefront
import com.tangem.blockchain.common.BlockchainError
import com.tangem.common.Converter
import com.tangem.common.card.Card
import com.tangem.common.core.TangemSdkError
import com.tangem.tap.common.analytics.AnalyticsAnOld
@ -15,6 +13,9 @@ import com.tangem.tap.common.analytics.api.SdkErrorEventHandler
import com.tangem.tap.common.analytics.api.ShopifyOrderEventHandler
import com.tangem.tap.common.analytics.converters.BlockchainSdkErrorConverter
import com.tangem.tap.common.analytics.converters.CardSdkErrorConverter
import com.tangem.tap.common.analytics.events.OrderToParamsConverter
import com.tangem.tap.common.analytics.events.Shop
import com.tangem.tap.common.shop.data.ProductType
class FirebaseAnalyticsHandler(
private val client: FirebaseAnalyticsClient,
@ -57,8 +58,9 @@ class FirebaseAnalyticsHandler(
}
}
override fun send(order: Storefront.Order) {
send(FirebaseClient.ORDER_EVENT, OrderToParamsConverter().convert(order))
override fun send(order: Storefront.Order, productType: ProductType) {
val eventParams = OrderToParamsConverter().convert(order to productType)
send(Shop.Purchased(eventParams))
}
companion object {
@ -72,25 +74,4 @@ class FirebaseAnalyticsHandler(
else -> null
}?.let { FirebaseAnalyticsHandler(it) }
}
}
private class OrderToParamsConverter : Converter<Storefront.Order, Map<String, String>> {
override fun convert(value: Storefront.Order): Map<String, String> {
val sku = value.lineItems.edges.firstOrNull()?.node?.variant?.sku ?: "unknown"
val discountCode =
(value.discountApplications.edges.firstOrNull()?.node as? Storefront.DiscountCodeApplication)?.code
val discountParams = if (discountCode != null) {
mapOf(FirebaseAnalytics.Param.DISCOUNT to discountCode)
} else {
mapOf()
}
return mapOf(
FirebaseAnalytics.Param.ITEM_ID to sku,
FirebaseAnalytics.Param.VALUE to value.totalPriceV2.amount,
FirebaseAnalytics.Param.CURRENCY to value.currencyCode.name,
) + discountParams
}
}

View file

@ -22,7 +22,6 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) {
private val shopifyService = ShopifyService(application, shopifyShop)
private val checkouts = mutableMapOf<ProductType, Storefront.Checkout>()
private val variants = mutableMapOf<ProductType, Storefront.ProductVariant>()
@ -40,24 +39,27 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) {
variants.putAll(availableVariants)
if (variants.size < SKUS_TO_DISPLAY.size) {
return Result.failure(Exception(
"Shopify: products are missing, " +
"\nproducts available: ${variants.keys.map { it.sku }}"))
return Result.failure(
Exception(
"Shopify: products are missing, " +
"\nproducts available: ${variants.keys.map { it.sku }}",
),
)
}
val twoCardsProduct = TangemProduct(
type = ProductType.WALLET_2_CARDS,
totalSum = TotalSum(
finalValue = variants[ProductType.WALLET_2_CARDS]?.priceV2?.format(),
beforeDiscount = variants[ProductType.WALLET_2_CARDS]?.compareAtPriceV2?.format()
)
beforeDiscount = variants[ProductType.WALLET_2_CARDS]?.compareAtPriceV2?.format(),
),
)
val threeCardsProduct = TangemProduct(
type = ProductType.WALLET_3_CARDS,
totalSum = TotalSum(
finalValue = variants[ProductType.WALLET_3_CARDS]?.priceV2?.format(),
beforeDiscount = variants[ProductType.WALLET_3_CARDS]?.compareAtPriceV2?.format()
)
beforeDiscount = variants[ProductType.WALLET_3_CARDS]?.compareAtPriceV2?.format(),
),
)
createCheckouts()
return Result.success(listOf(twoCardsProduct, threeCardsProduct))
@ -85,7 +87,7 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) {
val totalPrice = checkouts[productType]!!.totalPriceV2.amount
googlePayService.payWithGooglePay(
totalPriceCents = totalPrice, currencyCode = checkouts[productType]!!.currencyCode.name,
merchantID = shopifyService.shop.merchantID
merchantID = shopifyService.shop.merchantID,
)
}
@ -104,7 +106,7 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) {
suspend fun handleGooglePayResult(
resultCode: Int,
data: Intent?,
productType: ProductType
productType: ProductType,
): Result<Unit> {
val result = googlePayService.handleResponseFromGooglePay(resultCode, data)
result.onSuccess {
@ -119,7 +121,7 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) {
private suspend fun completeTokenizedPayment(
paymentData: PaymentData,
productType: ProductType
productType: ProductType,
): Result<Storefront.Checkout> {
val checkout = checkouts[productType]!!
val googlePayResponse =
@ -140,19 +142,18 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) {
phone = addressGPay.phoneNumber
}
val payment = Storefront.TokenizedPaymentInputV3(
amount,
idempotencyKey,
address,
paymentData.toJson(),
Storefront.PaymentTokenType.GOOGLE_PAY
Storefront.PaymentTokenType.GOOGLE_PAY,
)
.setTest(true)
return shopifyService.completeWithTokenizedPayment(
payment = payment,
checkoutID = checkout.id
checkoutID = checkout.id,
)
}
@ -181,12 +182,12 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) {
productType,
TotalSum(
finalValue = it.totalPriceV2.format(),
beforeDiscount = variants[productType]!!.compareAtPriceV2.format()
beforeDiscount = variants[productType]!!.compareAtPriceV2.format(),
),
appliedDiscount = it.getAppliedDiscount()
)
appliedDiscount = it.getAppliedDiscount(),
),
)
)
}
return Result.failure(result.exceptionOrNull()!!)
}
@ -197,9 +198,7 @@ class TangemShopService(application: Application, shopifyShop: ShopifyShop) {
suspend fun waitForCheckout(productType: ProductType) {
val result = shopifyService.checkout(true, checkouts[productType]!!.id)
result.onSuccess {
it.order?.let { Analytics.send(it) }
}
result.onSuccess { checkout -> checkout.order?.let { Analytics.send(it, productType) } }
}
companion object {

View file

@ -12,6 +12,8 @@ import androidx.activity.OnBackPressedCallback
import by.kirich1409.viewbindingdelegate.viewBinding
import com.tangem.tap.common.GlobalLayoutStateHandler
import com.tangem.tap.common.KeyboardObserver
import com.tangem.tap.common.analytics.Analytics
import com.tangem.tap.common.analytics.events.Shop
import com.tangem.tap.common.extensions.show
import com.tangem.tap.common.redux.navigation.NavigationAction
import com.tangem.tap.common.shop.data.ProductType
@ -41,6 +43,8 @@ class ShopFragment : BaseStoreFragment(R.layout.fragment_shop), StoreSubscriber<
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Analytics.send(Shop.ScreenOpened())
activity?.onBackPressedDispatcher?.addCallback(this, object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
store.dispatch(NavigationAction.PopBackTo())