Skip to content

Commit

Permalink
Adds token device flow
Browse files Browse the repository at this point in the history
  • Loading branch information
guchito9 committed Dec 20, 2021
1 parent 0a8e662 commit e2de619
Show file tree
Hide file tree
Showing 37 changed files with 404 additions and 208 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ class OneTapFragment : Fragment(), LifecycleListener {
button.setOnClickListener {
activity?.apply {
CardFormWithFragment.Builder.withAccessToken(
"TEST-3510478914010328-072812-fca99ed95a163ad9a0640d390f899c6b-798240981",
"MLA", "test_flow")
"APP_USR-7092-091618-d06c56436d6949fa2c8401f8186074b4-786856560",
"MLB", "test_flow")
.setThirdPartyCard(true, true)
.build()
.start(supportFragmentManager, REQUEST_CODE, R.id.container)
Expand Down
2 changes: 1 addition & 1 deletion buildSrc/src/main/java/Versions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ object Versions {
const val kotlin = "1.3.71"
const val kotlinCoroutines = "1.3.0"
const val picassoDiskCache = "1.+"
const val pxAddons = "4.+"
const val pxAddons = "LOCAL-4.98.0-13122021163435873"
const val andesUi = "3.+"

const val libraryVersion = "2.1.2"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ open class CardForm : Parcelable {
val cardInfo: CardInfoDto?
val acceptThirdPartyCard: Boolean
val activateCard: Boolean
val tokenizationFlowEnabled: Boolean

protected constructor(builder: Builder) {
siteId = builder.siteId
Expand All @@ -41,6 +42,7 @@ open class CardForm : Parcelable {
cardInfo = builder.cardInfo
acceptThirdPartyCard = builder.acceptThirdPartyCard
activateCard = builder.activateCard
tokenizationFlowEnabled = builder.tokenizationFlowEnabled
}

protected constructor(parcel: Parcel) {
Expand All @@ -54,6 +56,7 @@ open class CardForm : Parcelable {
cardInfo = parcel.readParcelable(CardInfoDto::class.java.classLoader)
acceptThirdPartyCard = parcel.readByte() != 0.toByte()
activateCard = parcel.readByte() != 0.toByte()
tokenizationFlowEnabled = parcel.readByte() != 0.toByte()
}

open fun start(activity: AppCompatActivity, requestCode: Int) {
Expand Down Expand Up @@ -110,6 +113,9 @@ open class CardForm : Parcelable {
var activateCard: Boolean = true
private set

var tokenizationFlowEnabled = true
private set

open fun setExcludedTypes(excludedTypes: List<String>) = apply {
this.excludedTypes = excludedTypes
}
Expand All @@ -121,6 +127,8 @@ open class CardForm : Parcelable {
this.activateCard = activateCard
}

open fun setTokenizationFlowEnabled(enabled: Boolean) = apply { tokenizationFlowEnabled = enabled }

fun <T : CardFormService> setCardFormHandler(handlerIntent: CardFormIntent<T>) = apply { cardFormIntent = handlerIntent }

protected fun setPublicKey(publicKey: String) = apply { this.publicKey = publicKey }
Expand Down Expand Up @@ -153,6 +161,7 @@ open class CardForm : Parcelable {
parcel.writeParcelable(cardInfo, flags)
parcel.writeByte(if(acceptThirdPartyCard) 1 else 0)
parcel.writeByte(if(activateCard) 1 else 0)
parcel.writeByte(if(tokenizationFlowEnabled) 1 else 0)
}

override fun describeContents() = 0
Expand All @@ -169,4 +178,4 @@ open class CardForm : Parcelable {
override fun newArray(size: Int) = arrayOfNulls<CardForm?>(size)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.mercadolibre.android.cardform.data.model.response

internal data class AssociatedCard(
internal data class AssociatedCardDM(
val dateCreated: String,
val dateLastTimeUsed: String,
val dateLastUpdated: String,
Expand All @@ -12,5 +12,6 @@ internal data class AssociatedCard(
val paymentMethod: PaymentMethod,
val siteId: String,
val status: String,
val userId: Int
)
val userId: Int,
val enrollmentSuggested: Boolean
)
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.mercadolibre.android.cardform.data.model.response

import android.os.Parcelable
import com.mercadopago.android.px.addons.tokenization.TokenizationResponse
import kotlinx.android.parcel.Parcelize

@Parcelize
data class CardResultDto(
val cardId: String,
val bin: String,
val paymentType: String,
val lastFourDigits: String
) : Parcelable
val lastFourDigits: String,
val tokenizationResponse: TokenizationResponse? = null
) : Parcelable
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ package com.mercadolibre.android.cardform.data.model.response

import com.mercadolibre.android.cardform.data.model.body.CardHolder

internal data class CardToken(
internal data class CardTokenDM(
val cardNumberLength: Int,
val cardholder: CardHolder,
val dateCreated: String,
Expand All @@ -20,4 +20,4 @@ internal data class CardToken(
val securityCodeLength: Int,
val status: String,
val esc: String?
)
)

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ import com.mercadolibre.android.cardform.data.model.body.*
import com.mercadolibre.android.cardform.data.model.body.AssociatedCardBody
import com.mercadolibre.android.cardform.data.model.body.PaymentMethodBody
import com.mercadolibre.android.cardform.data.service.CardAssociationService
import com.mercadolibre.android.cardform.domain.AssociatedCardParam
import com.mercadolibre.android.cardform.domain.AssociateCardParam
import com.mercadolibre.android.cardform.domain.AssociatedCardBM
import com.mercadolibre.android.cardform.domain.CardAssociationRepository
import kotlinx.coroutines.withContext

internal class CardAssociationRepositoryImpl(
Expand All @@ -18,7 +20,7 @@ internal class CardAssociationRepositoryImpl(
private val contextProvider: CoroutineContextProvider = CoroutineContextProvider()
) : CardAssociationRepository {

override suspend fun associateCard(param: AssociatedCardParam) =
override suspend fun associateCard(param: AssociateCardParam) =
withContext(contextProvider.IO) {
runCatching {
associationService.associateCard(
Expand All @@ -34,7 +36,9 @@ internal class CardAssociationRepositoryImpl(
activateCard
)
)
).resolveRetrofitResponse()
).resolveRetrofitResponse().let {
AssociatedCardBM(it.id, it.enrollmentSuggested)
}
}.fold(::Success, ::Failure)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import com.mercadolibre.android.cardform.data.model.response.RegisterCard
import com.mercadolibre.android.cardform.data.service.CardService
import com.mercadolibre.android.cardform.network.exceptions.ExcludePaymentException
import com.mercadolibre.android.cardform.data.model.body.CardInfoDto
import com.mercadolibre.android.cardform.domain.CardRepository
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
Expand Down Expand Up @@ -65,4 +66,4 @@ internal class CardRepositoryImpl(
}
}.await()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,20 @@ import com.mercadolibre.android.cardform.base.Response.Failure
import com.mercadolibre.android.cardform.base.resolveRetrofitResponse
import com.mercadolibre.android.cardform.data.model.body.CardInfoBody
import com.mercadolibre.android.cardform.data.service.TokenizeService
import com.mercadolibre.android.cardform.domain.CardTokenRepository
import kotlinx.coroutines.withContext

internal class TokenizeRepositoryImpl(
internal class CardTokenRepositoryImpl(
private val tokenizeService: TokenizeService,
private val contextProvider: CoroutineContextProvider = CoroutineContextProvider()
) : TokenizeRepository {
) : CardTokenRepository {

override suspend fun tokenizeCard(cardInfoBody: CardInfoBody) =
override suspend fun get(cardInfoBody: CardInfoBody) =
withContext(contextProvider.IO) {
runCatching {
tokenizeService
.createTokenAsync(cardInfoBody)
.resolveRetrofitResponse()
}.fold(::Success, ::Failure)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.mercadolibre.android.cardform.data.repository

import com.mercadolibre.android.cardform.base.Response
import com.mercadolibre.android.cardform.base.ResponseCallback
import com.mercadolibre.android.cardform.domain.TokenDeviceRepository
import com.mercadopago.android.px.addons.TokenDeviceBehaviour
import com.mercadopago.android.px.addons.tokenization.Tokenize

internal class TokenDeviceRepositoryImpl(
private val flowId: String,
private val sessionId: String,
private val tokenDeviceBehaviour: TokenDeviceBehaviour
) : TokenDeviceRepository {

override val isFeatureAvailable: Boolean
get() = tokenDeviceBehaviour.isFeatureAvailable

override fun get(cardId: String): ResponseCallback<Tokenize> {
return Response.Success(tokenDeviceBehaviour.getTokenize(flowId, cardId).sessionId(sessionId))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,16 @@ package com.mercadolibre.android.cardform.data.service

import com.mercadolibre.android.cardform.BuildConfig
import com.mercadolibre.android.cardform.data.model.body.AssociatedCardBody
import com.mercadolibre.android.cardform.data.model.response.AssociatedCard
import com.mercadolibre.android.cardform.data.model.response.AssociatedCardDM
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.POST
import retrofit2.http.Query

private const val ENVIRONMENT = BuildConfig.API_ENVIRONMENT

internal interface CardAssociationService {
@POST("/$ENVIRONMENT/px_mobile/v1/card")
suspend fun associateCard(
@Body associatedCardBody: AssociatedCardBody
): Response<AssociatedCard>
}
): Response<AssociatedCardDM>
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,16 @@ internal interface CardService {

@GET("/{environment}/px_mobile/v1/card")
suspend fun getCardInfoAsync(
@Path("environment") environment : String,
@Query("bin") bin : String,
@Query("site_id") siteId : String,
@Query("excluded_payment_types") excludedPaymentTypes : List<String>? = null,
@Query("odr") odrFlag : Boolean = true
@Path("environment") environment: String,
@Query("bin") bin: String,
@Query("site_id") siteId: String,
@Query("excluded_payment_types") excludedPaymentTypes: List<String>? = null,
@Query("odr") odrFlag: Boolean = true
): Response<RegisterCard>

@POST("/{environment}/px_mobile/v1/card/marketplace")
suspend fun getCardInfoAsyncFromMarketplace(
@Path("environment") environment : String,
@Body cardInfo: CardInfoDto
@Path("environment") environment: String,
@Body cardInfo: CardInfoDto
): Response<RegisterCard>
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ internal interface FinishInscriptionService {
suspend fun getFinishInscription(
@Body finishInscriptionBody: FinishInscriptionBody
): Response<FinishInscriptionData>
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@ import com.mercadolibre.android.cardform.BuildConfig
import com.mercadolibre.android.cardform.data.model.response.initinscription.InscriptionDataModel
import retrofit2.Response
import retrofit2.http.GET
import retrofit2.http.Query

private const val ENVIRONMENT = BuildConfig.API_ENVIRONMENT

internal interface InscriptionService {

@GET("/$ENVIRONMENT/px_mobile/v1/card_webpay/inscription/init")
suspend fun getInscription(
): Response<InscriptionDataModel>
}
suspend fun getInscription(): Response<InscriptionDataModel>
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
package com.mercadolibre.android.cardform.data.service

import com.mercadolibre.android.cardform.data.model.body.CardInfoBody
import com.mercadolibre.android.cardform.data.model.response.CardToken
import com.mercadolibre.android.cardform.data.model.response.CardTokenDM
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.POST
import retrofit2.http.Query

internal interface TokenizeService {
@POST("/v1/card_tokens")
suspend fun createTokenAsync(
@Body cardInfoBody: CardInfoBody
): Response<CardToken>
}
): Response<CardTokenDM>
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@ package com.mercadolibre.android.cardform.di

import android.content.Context
import com.mercadolibre.android.cardform.CardForm
import com.mercadolibre.android.cardform.di.module.*
import com.mercadolibre.android.cardform.di.module.BehaviourModule
import com.mercadolibre.android.cardform.di.module.LocalRepositoryModule
import com.mercadolibre.android.cardform.di.module.NetworkModule
import com.mercadolibre.android.cardform.di.module.RepositoryModule
import com.mercadolibre.android.cardform.di.module.ServiceModule
import com.mercadolibre.android.cardform.di.module.TrackerModule
import com.mercadolibre.android.cardform.di.module.UseCaseModule
import com.mercadolibre.android.cardform.di.module.ViewModelModule

internal class Dependencies {

Expand Down Expand Up @@ -31,11 +38,13 @@ internal class Dependencies {
cardForm.siteId,
cardForm.excludedTypes,
cardForm.flowId,
cardForm.sessionId,
cardForm.cardInfo,
cardForm.acceptThirdPartyCard,
cardForm.activateCard
cardForm.activateCard,
behaviourModule!!
)
useCaseModule = UseCaseModule(repositoryModule!!)
useCaseModule = UseCaseModule(cardForm, repositoryModule!!)
localPreferences = LocalRepositoryModule(context.applicationContext)
trackerModule = TrackerModule(
cardForm.siteId,
Expand Down Expand Up @@ -67,4 +76,4 @@ internal class Dependencies {
companion object {
val instance: Dependencies by lazy { Dependencies() }
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.mercadolibre.android.cardform.di.module

import com.mercadopago.android.px.addons.BehaviourProvider
import com.mercadopago.android.px.addons.TokenDeviceBehaviour

internal class BehaviourModule(sessionId: String) {
val escManager by lazy {
Expand All @@ -9,7 +10,9 @@ internal class BehaviourModule(sessionId: String) {

val trackerBehaviour by lazy { BehaviourProvider.getTrackingBehaviour(CARD_FORM_CONTEXT) }

val tokenDeviceBehaviour: TokenDeviceBehaviour by lazy { BehaviourProvider.getTokenDeviceBehaviour() }

companion object {
private const val CARD_FORM_CONTEXT = "card_form"
}
}
}
Loading

0 comments on commit e2de619

Please sign in to comment.