Skip to content

Commit

Permalink
Merge pull request #108 from Tinkoff/2.9.0
Browse files Browse the repository at this point in the history
2.9.0 Added ability to launch 3DS authentication via `ThreeDsHelper`
  • Loading branch information
IlnarH authored Sep 8, 2022
2 parents 1204eef + d4e5c96 commit f04b168
Show file tree
Hide file tree
Showing 27 changed files with 545 additions and 233 deletions.
8 changes: 7 additions & 1 deletion changelog.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
## 2.9.0

#### Fixed
#### Changes
Added ability to launch 3DS authentication via `ThreeDsHelper`
#### Additions

## 2.8.2

#### Fixed
#### Changes
Send `software_version` and `device_model` in Init request
#### Additions


## 2.8.1

#### Fixed
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
VERSION_NAME=2.8.2
VERSION_NAME=2.9.0
VERSION_CODE=15
GROUP=ru.tinkoff.acquiring

Expand Down
4 changes: 2 additions & 2 deletions gradle/versions.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ ext {
gradlePluginVersion = '7.1.2'
dokkaVersion = '1.7.10'

appCompatVersion = '1.1.0'
appCompatVersion = '1.4.0'
preferenceVersion = '1.1.1'
lifecycleExtensionsVersion = '2.2.0'
lifecycleExtensionsVersion = '2.5.1'
cardIoVersion = '5.5.1'
gsonVersion = '2.8.6'
coreNfcVersion = '1.0.2'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package ru.tinkoff.acquiring.sample.ui

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.DialogFragment
import kotlinx.android.synthetic.main.dialog_attach_card_manually.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import ru.tinkoff.acquiring.sample.R
import ru.tinkoff.acquiring.sample.SampleApplication
import ru.tinkoff.acquiring.sample.ui.MainActivity.Companion.toast
import ru.tinkoff.acquiring.sample.utils.SessionParams
import ru.tinkoff.acquiring.sample.utils.SettingsSdkManager
import ru.tinkoff.acquiring.sdk.models.enums.ResponseStatus
import ru.tinkoff.acquiring.sdk.models.options.screen.BaseAcquiringOptions
import ru.tinkoff.acquiring.sdk.models.paysources.CardData
import ru.tinkoff.acquiring.sdk.threeds.ThreeDsHelper

class AttachCardManuallyDialogFragment : DialogFragment() {

private val coroutineScope = CoroutineScope(Dispatchers.Main)

private val sdk = SampleApplication.tinkoffAcquiring.sdk

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.dialog_attach_card_manually, container, false)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

close.setOnClickListener { dismiss() }

attach.setOnClickListener {
val cardData = CardData(pan.text.toString(), date.text.toString(), cvv.text.toString())
try {
cardData.validate()
} catch (e: Throwable) {
requireActivity().toast(e.message!!)
return@setOnClickListener
}
addCardManually(cardData)
}
}

private fun addCardManually(cardData: CardData) {
val settings = SettingsSdkManager(requireContext())
val params = SessionParams[settings.terminalKey]

val addCard = sdk.addCard {
customerKey = params.customerKey
checkType = "3DS"
}

coroutineScope.launch(Dispatchers.IO) {
addCard.execute({
attachCardManually(params, it.requestKey!!, cardData)
}, { })
}
}

private fun attachCardManually(params: SessionParams, requestKey: String, cardData: CardData) {
val attachCard = sdk.attachCard {
this.requestKey = requestKey
this.cardData = cardData
}
val options = BaseAcquiringOptions().apply {
setTerminalParams(params.terminalKey, params.publicKey)
}

coroutineScope.launch(Dispatchers.IO) {
attachCard.execute({
when (it.status) {
ResponseStatus.THREE_DS_CHECKING -> ThreeDsHelper.Launch.launchBrowserBased(
requireActivity(), MainActivity.THREE_DS_REQUEST_CODE, options, it.getThreeDsData())
null -> {
requireActivity().toast("Attach success")
dismiss()
}
else -> requireActivity().toast("Attach failure: ${it.status}")
}
}, { requireActivity().toast("Attach failure: ${it.message}") })
}
}

companion object {

const val TAG = "AttachCardManuallyDialogFragment"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package ru.tinkoff.acquiring.sample.ui

import android.app.Activity
import android.content.Intent
import android.content.IntentFilter
import android.os.Build
Expand All @@ -25,6 +26,8 @@ import android.view.MenuItem
import android.widget.ListView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import ru.tinkoff.acquiring.sample.R
import ru.tinkoff.acquiring.sample.SampleApplication
import ru.tinkoff.acquiring.sample.adapters.BooksListAdapter
Expand All @@ -42,6 +45,8 @@ import ru.tinkoff.acquiring.sdk.localization.Language
import ru.tinkoff.acquiring.sdk.models.options.FeaturesOptions
import ru.tinkoff.acquiring.sdk.models.options.screen.AttachCardOptions
import ru.tinkoff.acquiring.sdk.models.options.screen.SavedCardsOptions
import ru.tinkoff.acquiring.sdk.models.result.CardResult
import ru.tinkoff.acquiring.sdk.threeds.ThreeDsHelper

/**
* @author Mariya Chernyadieva
Expand Down Expand Up @@ -103,6 +108,11 @@ class MainActivity : AppCompatActivity(), BooksListAdapter.BookDetailsClickListe
openAttachCardScreen()
true
}
R.id.menu_action_attach_card_manually -> {
AttachCardManuallyDialogFragment().show(supportFragmentManager,
AttachCardManuallyDialogFragment.TAG)
true
}
R.id.menu_action_saved_cards -> {
openSavedCardsScreen()
true
Expand Down Expand Up @@ -171,6 +181,20 @@ class MainActivity : AppCompatActivity(), BooksListAdapter.BookDetailsClickListe
Toast.LENGTH_SHORT).show()
}
}
THREE_DS_REQUEST_CODE -> {
when (resultCode) {
RESULT_OK -> {
val result = data?.getSerializableExtra(ThreeDsHelper.Launch.RESULT_DATA) as CardResult
toast("Attach success: cardId = ${result.cardId} ")
}
RESULT_CANCELED -> toast("Attach canceled")
RESULT_ERROR -> {
val error = data?.getSerializableExtra(ThreeDsHelper.Launch.ERROR_DATA) as Throwable
error.printStackTrace()
toast("Attach failure: ${error.message}")
}
}
}
else -> super.onActivityResult(requestCode, resultCode, data)
}
}
Expand Down Expand Up @@ -250,7 +274,11 @@ class MainActivity : AppCompatActivity(), BooksListAdapter.BookDetailsClickListe
private const val ATTACH_CARD_REQUEST_CODE = 11
private const val STATIC_QR_REQUEST_CODE = 12
private const val SAVED_CARDS_REQUEST_CODE = 13

const val NOTIFICATION_PAYMENT_REQUEST_CODE = 14
const val THREE_DS_REQUEST_CODE = 15

fun Activity.toast(message: String) = runOnUiThread {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ open class PayableActivity : AppCompatActivity() {
darkThemeMode = settings.resolveDarkThemeMode()
theme = settings.resolvePaymentStyle()
userCanSelectCard = true
duplicateEmailToReceipt = true
}
}
}
Expand Down
67 changes: 67 additions & 0 deletions sample/src/main/res/layout/dialog_attach_card_manually.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="16dp"
android:padding="16dp">

<TextView
android:id="@+id/header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal"
android:text="Example of attaching card without SDK UI" />

<EditText
android:id="@+id/pan"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/header"
android:layout_marginTop="16dp"
android:hint="Card number" />

<LinearLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/pan"
android:layout_marginBottom="16dp"
android:orientation="horizontal">

<EditText
android:id="@+id/date"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="MM/YY" />

<EditText
android:id="@+id/cvv"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:hint="CVV" />

</LinearLayout>

<TextView
android:id="@+id/attach"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/container"
android:layout_alignParentEnd="true"
android:text="ATTACH"
android:textColor="@color/acq_colorAccent"
android:textSize="16sp" />

<TextView
android:id="@+id/close"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/container"
android:layout_marginRight="32dp"
android:layout_toLeftOf="@id/attach"
android:text="CLOSE"
android:textSize="16sp" />

</RelativeLayout>
5 changes: 5 additions & 0 deletions sample/src/main/res/menu/main_menu.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@
android:title="@string/activity_title_settings"
app:showAsAction="never"/>

<item
android:id="@+id/menu_action_attach_card_manually"
android:title="@string/activity_title_attach_card_manually"
app:showAsAction="never"/>

<item
android:id="@+id/menu_action_about"
android:title="@string/activity_title_about"
Expand Down
1 change: 1 addition & 0 deletions sample/src/main/res/values-ru/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<string name="activity_title_details">Книга</string>
<string name="activity_title_cart">Корзина</string>
<string name="activity_title_attach_card">Привязать карту</string>
<string name="activity_title_attach_card_manually">Привязать карту вручную</string>
<string name="activity_title_about">О программе</string>
<string name="activity_title_static_qr">Открыть статический QR код</string>
<string name="activity_title_dynamic_qr">Принять оплату QR</string>
Expand Down
1 change: 1 addition & 0 deletions sample/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<string name="activity_title_details">Book</string>
<string name="activity_title_cart">Cart</string>
<string name="activity_title_attach_card">Attach card</string>
<string name="activity_title_attach_card_manually">Attach card manually</string>
<string name="activity_title_about">About</string>
<string name="activity_title_static_qr">Open static QR code</string>
<string name="activity_title_dynamic_qr">Get QR payment</string>
Expand Down
2 changes: 1 addition & 1 deletion ui/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ android {
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "androidx.appcompat:appcompat:$appCompatVersion"
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycleExtensionsVersion"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycleExtensionsVersion"
implementation "ru.tinkoff.core.components.nfc:nfc:$coreNfcVersion"

implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlinVersion"
Expand Down
5 changes: 3 additions & 2 deletions ui/src/main/java/ru/tinkoff/acquiring/sdk/TinkoffAcquiring.kt
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import ru.tinkoff.acquiring.sdk.models.paysources.CardData
import ru.tinkoff.acquiring.sdk.models.paysources.GooglePay
import ru.tinkoff.acquiring.sdk.payment.PaymentProcess
import ru.tinkoff.acquiring.sdk.responses.TinkoffPayStatusResponse
import ru.tinkoff.acquiring.sdk.threeds.ThreeDsHelper
import ru.tinkoff.acquiring.sdk.ui.activities.AttachCardActivity
import ru.tinkoff.acquiring.sdk.ui.activities.BaseAcquiringActivity
import ru.tinkoff.acquiring.sdk.ui.activities.NotificationPaymentActivity
Expand Down Expand Up @@ -137,7 +138,7 @@ class TinkoffAcquiring(
@JvmOverloads
fun openPaymentScreen(activity: Activity, options: PaymentOptions, requestCode: Int, state: AsdkState = DefaultState) {
if (state is CollectDataState) {
state.data.putAll(ThreeDsActivity.collectData(activity, state.response))
state.data.putAll(ThreeDsHelper.CollectData(activity, state.response))
} else {
options.asdkState = state
val intent = prepareIntent(activity, options, PaymentActivity::class.java)
Expand All @@ -157,7 +158,7 @@ class TinkoffAcquiring(
@JvmOverloads
fun openPaymentScreen(fragment: Fragment, options: PaymentOptions, requestCode: Int, state: AsdkState = DefaultState) {
if (state is CollectDataState) {
state.data.putAll(ThreeDsActivity.collectData(fragment.requireContext(), state.response))
state.data.putAll(ThreeDsHelper.CollectData(fragment.requireContext(), state.response))
} else {
options.asdkState = state
val intent = prepareIntent(fragment.requireContext(), options, PaymentActivity::class.java)
Expand Down
5 changes: 2 additions & 3 deletions ui/src/main/java/ru/tinkoff/acquiring/sdk/models/AsdkState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@

package ru.tinkoff.acquiring.sdk.models

import com.emvco3ds.sdk.spec.Transaction
import ru.tinkoff.acquiring.sdk.AcquiringSdk
import ru.tinkoff.acquiring.sdk.responses.Check3dsVersionResponse
import ru.tinkoff.core.components.threedswrapper.ThreeDSWrapper
import ru.tinkoff.acquiring.sdk.threeds.ThreeDsAppBasedTransaction
import java.io.Serializable

/**
Expand Down Expand Up @@ -56,7 +55,7 @@ object FpsState : AsdkState()
* Состояние проверки 3DS. На экране пользователю будет предложено пройти подтверждение платежа
* по технологии 3D-Secure
*/
class ThreeDsState(val data: ThreeDsData, val threeDSWrapper: ThreeDSWrapper?, val transaction: Transaction?) : AsdkState()
class ThreeDsState(val data: ThreeDsData, val transaction: ThreeDsAppBasedTransaction?) : AsdkState()

/**
* Состояние, когда необходимо собрать информацию об устройстве для прохождения 3DS
Expand Down
5 changes: 2 additions & 3 deletions ui/src/main/java/ru/tinkoff/acquiring/sdk/models/ViewState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@

package ru.tinkoff.acquiring.sdk.models

import com.emvco3ds.sdk.spec.Transaction
import ru.tinkoff.acquiring.sdk.responses.Check3dsVersionResponse
import ru.tinkoff.core.components.threedswrapper.ThreeDSWrapper
import ru.tinkoff.acquiring.sdk.threeds.ThreeDsAppBasedTransaction

/**
* @author Mariya Chernyadieva
Expand All @@ -36,7 +35,7 @@ internal object FpsScreenState: Screen()
internal class BrowseFpsBankScreenState(val paymentId: Long, val deepLink: String, val banks: Set<Any?>?) : Screen()
internal class OpenTinkoffPayBankScreenState(val paymentId: Long, val deepLink: String) : Screen()
internal class RejectedCardScreenState(val cardId: String, val rejectedPaymentId: Long) : Screen()
internal class ThreeDsScreenState(val data: ThreeDsData, val wrapper: ThreeDSWrapper?, val transaction: Transaction?) : Screen()
internal class ThreeDsScreenState(val data: ThreeDsData, val transaction: ThreeDsAppBasedTransaction?) : Screen()
internal class ThreeDsDataCollectScreenState(val response: Check3dsVersionResponse) : Screen()
internal class LoopConfirmationScreenState(val requestKey: String) : Screen()

Expand Down
Loading

0 comments on commit f04b168

Please sign in to comment.