Skip to content

Commit 86c5c46

Browse files
authored
Autofill support for PAYONE credit card forms (#178)
1 parent 4ef03b6 commit 86c5c46

File tree

8 files changed

+69
-9
lines changed

8 files changed

+69
-9
lines changed

CHANGELOG.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,16 @@ All notable changes to this project will be documented in this file.
44
## UNRELEASED
55
### Added
66
* ui/ui-toolkit: i18n using the Lokalise
7+
* Autofill support for PAYONE credit card forms
78
### Changed
8-
* ui: The `ProductResolver.Builder` now requires a project as constructor param, since the default value has been removed
99
### Removed
1010
* ui: Remove phrase for i18n
1111
### Fixed
12+
13+
## [0.72.5]
14+
### Changed
15+
* ui: The `ProductResolver.Builder` now requires a project as constructor param, since the default value has been removed
16+
### Fixed
1217
* core: Handle `SQLiteDatabaseLockedException` to fix app crash when updating the database
1318
* ui: Avoid npe caused by `isEmpty()` check on a null shopping cart
1419
* ui: Change project reference in `ProductResolver.kt` to get rid of IllegalArgumentException

core/src/main/java/io/snabble/sdk/Snabble.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import io.snabble.sdk.customization.IsMergeable
2121
import io.snabble.sdk.events.Events
2222
import io.snabble.sdk.extensions.getPackageInfoCompat
2323
import io.snabble.sdk.payment.PaymentCredentialsStore
24+
import io.snabble.sdk.payment.data.FormPrefillData
2425
import io.snabble.sdk.utils.*
2526
import okhttp3.OkHttpClient
2627
import java.io.ByteArrayInputStream
@@ -313,6 +314,11 @@ object Snabble {
313314
*/
314315
var isMergeable: IsMergeable? = null
315316

317+
/**
318+
* Set to have PAYONE forms prefilled with the given data.
319+
*/
320+
var formPrefillData: FormPrefillData? = null
321+
316322
/**
317323
* Setup the snabble SDK.
318324
*
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package io.snabble.sdk.payment.data
2+
3+
import android.os.Parcelable
4+
import com.google.gson.annotations.SerializedName
5+
import kotlinx.parcelize.Parcelize
6+
7+
@Parcelize
8+
data class FormPrefillData(
9+
@SerializedName("name") val name: String? = null,
10+
@SerializedName("street") val street: String? = null,
11+
@SerializedName("zip") val zip: String? = null,
12+
@SerializedName("city") val city: String? = null,
13+
@SerializedName("countryCode") val countryCode: String? = null,
14+
@SerializedName("stateCode") val stateCode: String? = null,
15+
@SerializedName("email") val email: String? = null
16+
) : Parcelable

ui/src/main/java/io/snabble/sdk/ui/payment/PaymentInputViewHelper.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ object PaymentInputViewHelper {
3333
if (useDatatrans && paymentMethod != null) {
3434
Datatrans.registerCard(activity, project, paymentMethod)
3535
} else if (usePayone && paymentMethod != null) {
36-
Payone.registerCard(activity, project, paymentMethod)
36+
Payone.registerCard(activity, project, paymentMethod, Snabble.formPrefillData)
3737
} else {
3838
when (paymentMethod) {
3939
PaymentMethod.VISA -> {

ui/src/main/java/io/snabble/sdk/ui/payment/Payone.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ import com.google.gson.annotations.SerializedName
88
import io.snabble.sdk.PaymentMethod
99
import io.snabble.sdk.Project
1010
import io.snabble.sdk.Snabble
11+
import io.snabble.sdk.payment.data.FormPrefillData
1112
import io.snabble.sdk.ui.R
1213
import io.snabble.sdk.ui.SnabbleUI
13-
import io.snabble.sdk.ui.payment.creditcard.data.CreditCardInfo
1414
import io.snabble.sdk.utils.Dispatch
1515
import io.snabble.sdk.utils.Logger
1616
import io.snabble.sdk.utils.SimpleJsonCallback
@@ -72,7 +72,8 @@ object Payone {
7272
fun registerCard(
7373
activity: FragmentActivity,
7474
project: Project,
75-
paymentMethod: PaymentMethod
75+
paymentMethod: PaymentMethod,
76+
formPrefillData: FormPrefillData?
7677
) {
7778
val descriptor = project.paymentMethodDescriptors.find { it.paymentMethod == paymentMethod }
7879
if (descriptor == null) {
@@ -107,6 +108,7 @@ object Payone {
107108
args.putString(PayoneInputView.ARG_PROJECT_ID, project.id)
108109
args.putSerializable(PayoneInputView.ARG_PAYMENT_TYPE, paymentMethod)
109110
args.putParcelable(PayoneInputView.ARG_TOKEN_DATA, response)
111+
args.putParcelable(PayoneInputView.ARG_FORM_PREFILL_DATA, formPrefillData)
110112
Dispatch.mainThread {
111113
SnabbleUI.executeAction(activity, SnabbleUI.Event.SHOW_PAYONE_INPUT, args)
112114
}

ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputFragment.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package io.snabble.sdk.ui.payment
33
import android.os.Bundle
44
import android.view.View
55
import io.snabble.sdk.PaymentMethod
6+
import io.snabble.sdk.payment.data.FormPrefillData
67
import io.snabble.sdk.ui.BaseFragment
78
import io.snabble.sdk.ui.R
89
import io.snabble.sdk.ui.utils.parcelableExtra
@@ -16,22 +17,25 @@ open class PayoneInputFragment : BaseFragment(
1617
const val ARG_PROJECT_ID = PayoneInputView.ARG_PROJECT_ID
1718
const val ARG_PAYMENT_TYPE = PayoneInputView.ARG_PAYMENT_TYPE
1819
const val ARG_TOKEN_DATA = PayoneInputView.ARG_TOKEN_DATA
20+
const val ARG_FORM_PREFILL_DATA = PayoneInputView.ARG_FORM_PREFILL_DATA
1921
}
2022

2123
private lateinit var projectId: String
2224
private lateinit var paymentMethod: PaymentMethod
2325
private lateinit var tokenizationData: Payone.PayoneTokenizationData
26+
private var formPrefillData: FormPrefillData? = null
2427

2528
override fun onCreate(savedInstanceState: Bundle?) {
2629
super.onCreate(savedInstanceState)
2730

2831
projectId = requireNotNull(arguments?.getString(ARG_PROJECT_ID, null))
2932
paymentMethod = requireNotNull(arguments?.serializableExtra(ARG_PAYMENT_TYPE) as? PaymentMethod)
3033
tokenizationData = requireNotNull(arguments?.parcelableExtra(ARG_TOKEN_DATA))
34+
formPrefillData = arguments?.parcelableExtra(ARG_FORM_PREFILL_DATA)
3135
}
3236

3337
override fun onActualViewCreated(view: View, savedInstanceState: Bundle?) {
3438
view.findViewById<PayoneInputView>(R.id.user_payment_method_view)
35-
.load(projectId, paymentMethod, tokenizationData)
39+
.load(projectId, paymentMethod, tokenizationData, formPrefillData)
3640
}
3741
}

ui/src/main/java/io/snabble/sdk/ui/payment/PayoneInputView.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import io.snabble.sdk.PaymentMethod
2727
import io.snabble.sdk.Project
2828
import io.snabble.sdk.Snabble
2929
import io.snabble.sdk.payment.PaymentCredentials
30+
import io.snabble.sdk.payment.data.FormPrefillData
3031
import io.snabble.sdk.ui.Keyguard
3132
import io.snabble.sdk.ui.R
3233
import io.snabble.sdk.ui.SnabbleUI
@@ -62,6 +63,7 @@ class PayoneInputView @JvmOverloads constructor(context: Context, attrs: Attribu
6263
private lateinit var project: Project
6364
private lateinit var tokenizationData: PayoneTokenizationData
6465
private lateinit var threeDHint: TextView
66+
private var formPrefillData: FormPrefillData? = null
6567
private var lastPreAuthResponse: Payone.PreAuthResponse? = null
6668
private var polling = LazyWorker.createLifeCycleAwareJob(context) {
6769
lastPreAuthResponse?.links?.get("preAuthStatus")?.href?.let { statusUrl ->
@@ -169,11 +171,13 @@ class PayoneInputView @JvmOverloads constructor(context: Context, attrs: Attribu
169171
fun load(
170172
projectId: String,
171173
paymentType: PaymentMethod,
172-
tokenizationData: PayoneTokenizationData
174+
tokenizationData: PayoneTokenizationData,
175+
formPrefillData: FormPrefillData?
173176
) {
174177
this.project = Snabble.projects.first { it.id == projectId }
175178
this.paymentType = paymentType
176179
this.tokenizationData = tokenizationData
180+
this.formPrefillData = formPrefillData
177181
inflateView()
178182
}
179183

@@ -418,6 +422,9 @@ class PayoneInputView @JvmOverloads constructor(context: Context, attrs: Attribu
418422
fun log(message: String?) {
419423
Logger.d(message)
420424
}
425+
426+
@JavascriptInterface
427+
fun prefillData(): String = GsonHolder.get().toJson(formPrefillData)
421428
}
422429

423430
override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
@@ -469,6 +476,7 @@ class PayoneInputView @JvmOverloads constructor(context: Context, attrs: Attribu
469476
const val ARG_PROJECT_ID = "projectId"
470477
const val ARG_PAYMENT_TYPE = "paymentType"
471478
const val ARG_TOKEN_DATA = "tokenData"
479+
const val ARG_FORM_PREFILL_DATA = "formPrefillData"
472480
}
473481
}
474482

ui/src/main/res/raw/snabble_payoneform.html

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,6 @@
5959
outline: none;
6060
background-color: transparent;
6161
}
62-
.form-group:has(select:disabled) {
63-
display: none;
64-
}
6562
#submit {
6663
margin: 2rem 0;
6764
background-color:#07b;
@@ -1075,6 +1072,7 @@
10751072
const stateSelect = document.getElementById('stateSelect')
10761073
stateSelect.replaceChildren()
10771074
stateSelect.disabled = !subdivisions[countryCode]
1075+
stateSelect.closest('.form-group').style.display = !subdivisions[countryCode] ? 'none' : 'block'
10781076

10791077
if (!subdivisions[countryCode]) return
10801078

@@ -1109,6 +1107,27 @@
11091107
handleCountrySelect(localeCountryCode);
11101108
}
11111109
countryOptions();
1110+
1111+
function prefillForm() {
1112+
const data = JSON.parse(snabble.prefillData())
1113+
document.getElementById('name').value = data.name || ''
1114+
document.getElementById('street').value = data.street || ''
1115+
document.getElementById('zip').value = data.zip || ''
1116+
document.getElementById('city').value = data.city || ''
1117+
document.getElementById('email').value = data.email || ''
1118+
1119+
if (typeof data.countryCode !== 'undefined') {
1120+
const countrySelect = document.getElementById('countrySelect')
1121+
countrySelect.selectedIndex = countries.findIndex(country => country.code == data.countryCode) + 1
1122+
handleCountrySelect(data.countryCode);
1123+
1124+
if (typeof data.stateCode !== 'undefined') {
1125+
const selectState = document.getElementById('stateSelect')
1126+
selectState.selectedIndex = subdivisions[data.countryCode].findIndex(state => state.code == data.stateCode) + 1
1127+
}
1128+
}
1129+
}
1130+
prefillForm()
11121131
</script>
11131132
</body>
11141133
</html>

0 commit comments

Comments
 (0)