Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use sdk_uuid for payment and setup intents #551

Merged
merged 12 commits into from
Oct 16, 2023
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -146,17 +146,18 @@ internal fun mapToDiscoveryMethod(method: String?): DiscoveryMethod? {
}
}

internal fun mapFromPaymentIntent(paymentIntent: PaymentIntent): ReadableMap = nativeMapOf {
internal fun mapFromPaymentIntent(paymentIntent: PaymentIntent, uuid: String): ReadableMap = nativeMapOf {
putInt("amount", paymentIntent.amount.toInt())
putString("currency", paymentIntent.currency)
putString("id", paymentIntent.id)
putString("description", paymentIntent.description)
putString("status", mapFromPaymentIntentStatus(paymentIntent.status))
putArray("charges", mapFromChargesList(paymentIntent.getCharges()))
putString("created", convertToUnixTimestamp(paymentIntent.created))
putString("sdk_uuid", uuid)
}

internal fun mapFromSetupIntent(setupIntent: SetupIntent): ReadableMap = nativeMapOf {
internal fun mapFromSetupIntent(setupIntent: SetupIntent, uuid: String): ReadableMap = nativeMapOf {
putString("created", convertToUnixTimestamp(setupIntent.created))
putString("id", setupIntent.id)
putString("status", mapFromSetupIntentStatus(setupIntent.status))
Expand All @@ -169,6 +170,7 @@ internal fun mapFromSetupIntent(setupIntent: SetupIntent): ReadableMap = nativeM
putString("onBehalfOfId", setupIntent.onBehalfOfId)
putString("paymentMethodId", setupIntent.paymentMethodId)
putString("singleUseMandateId", setupIntent.singleUseMandateId)
putString("sdk_uuid", uuid)
}

internal fun mapFromSetupAttempt(attempt: SetupAttempt?): ReadableMap? = attempt?.let {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.stripeterminalreactnative

import android.annotation.SuppressLint
import android.app.Application
import android.content.ComponentCallbacks2
import android.content.res.Configuration
Expand Down Expand Up @@ -51,6 +52,8 @@ import com.stripeterminalreactnative.listener.RNUsbReaderListener
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.util.UUID
import kotlin.collections.HashMap


class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) :
Expand Down Expand Up @@ -160,6 +163,7 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) :
promise.resolve(null)
}

@SuppressLint("MissingPermission")
@ReactMethod
@Suppress("unused")
fun discoverReaders(params: ReadableMap, promise: Promise) = withExceptionResolver(promise) {
Expand Down Expand Up @@ -396,8 +400,10 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) :
}
}

terminal.createPaymentIntent(intentParams.build(), RNPaymentIntentCallback(promise) { pi ->
(pi.id ?: pi.offlineDetails?.id)?.let { paymentIntents[it] = pi }
val uuid = UUID.randomUUID().toString()

terminal.createPaymentIntent(intentParams.build(), RNPaymentIntentCallback(promise, uuid) { pi ->
paymentIntents[uuid] = pi
})
}

Expand All @@ -406,11 +412,14 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) :
@Suppress("unused")
fun collectPaymentMethod(params: ReadableMap, promise: Promise) =
withExceptionResolver(promise) {
val paymentIntentId = requireParam(params.getString("paymentIntentId")) {
"You must provide a paymentIntentId"
val paymentIntentJson = requireParam(params.getMap("paymentIntent")) {
"You must provide a paymentIntent"
}
val uuid = requireParam(paymentIntentJson.getString("sdk_uuid")) {
"You must provide a sdk_uuid"
}
val paymentIntent = requireParam(paymentIntents[paymentIntentId]) {
"There is no associated paymentIntent with id $paymentIntentId"
val paymentIntent = requireParam(paymentIntents[uuid]) {
"There is no associated paymentIntent with id $uuid"
}

val configBuilder = CollectConfiguration.Builder()
Expand All @@ -432,8 +441,8 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) :

collectPaymentMethodCancelable = terminal.collectPaymentMethod(
paymentIntent,
RNPaymentIntentCallback(promise) { pi ->
(pi.id ?: pi.offlineDetails?.id)?.let { paymentIntents[it] = pi }
RNPaymentIntentCallback(promise, uuid) { pi ->
paymentIntents[uuid] = pi
},
config
)
Expand All @@ -443,19 +452,23 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) :
@ReactMethod
@Suppress("unused")
fun retrievePaymentIntent(clientSecret: String, promise: Promise) {
terminal.retrievePaymentIntent(clientSecret, RNPaymentIntentCallback(promise) { pi ->
(pi.id ?: pi.offlineDetails?.id)?.let { paymentIntents[it] = pi }
val uuid = UUID.randomUUID().toString()
terminal.retrievePaymentIntent(clientSecret, RNPaymentIntentCallback(promise, uuid) { pi ->
paymentIntents[uuid] = pi
})
}

@ReactMethod
@Suppress("unused")
fun confirmPaymentIntent(paymentIntentId: String, promise: Promise) = withExceptionResolver(promise) {
val paymentIntent = requireParam(paymentIntents[paymentIntentId]) {
"There is no associated paymentIntent with id $paymentIntentId"
fun confirmPaymentIntent(paymentIntent: ReadableMap, promise: Promise) = withExceptionResolver(promise) {
val uuid = requireParam(paymentIntent.getString("sdk_uuid")) {
"You must provide a sdk_uuid"
}
val paymentIntent = requireParam(paymentIntents[uuid]) {
"There is no associated paymentIntent with id $uuid"
}

terminal.confirmPaymentIntent(paymentIntent, RNPaymentIntentCallback(promise) {
terminal.confirmPaymentIntent(paymentIntent, RNPaymentIntentCallback(promise, uuid) {
paymentIntents.clear()
})
}
Expand All @@ -478,29 +491,35 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) :
SetupIntentParameters.Builder().setCustomer(customerId).build()
} ?: SetupIntentParameters.NULL

terminal.createSetupIntent(intentParams, RNSetupIntentCallback(promise) {
setupIntents[it.id] = it
val uuid = UUID.randomUUID().toString()
terminal.createSetupIntent(intentParams, RNSetupIntentCallback(promise, uuid) {
setupIntents[uuid] = it
})
}

@ReactMethod
@Suppress("unused")
fun retrieveSetupIntent(clientSecret: String, promise: Promise) {
terminal.retrieveSetupIntent(clientSecret, RNSetupIntentCallback(promise) {
setupIntents[it.id] = it
val uuid = UUID.randomUUID().toString()
terminal.retrieveSetupIntent(clientSecret, RNSetupIntentCallback(promise, uuid) {
setupIntents[uuid] = it
})
}

@OptIn(OfflineMode::class)
@ReactMethod
@Suppress("unused")
fun cancelPaymentIntent(paymentIntentId: String, promise: Promise) =
fun cancelPaymentIntent(paymentIntent: ReadableMap, promise: Promise) =
withExceptionResolver(promise) {
val paymentIntent = requireParam(paymentIntents[paymentIntentId]) {
"There is no associated paymentIntent with id $paymentIntentId"
val uuid = requireParam(paymentIntent.getString("sdk_uuid")) {
"You must provide a sdk_uuid"
}
terminal.cancelPaymentIntent(paymentIntent, RNPaymentIntentCallback(promise) { pi ->
(pi.id ?: pi.offlineDetails?.id)?.let { paymentIntents[it] = null }
val paymentIntent = requireParam(paymentIntents[uuid]) {
"There is no associated paymentIntent with id $uuid"
}

terminal.cancelPaymentIntent(paymentIntent, RNPaymentIntentCallback(promise, uuid) {
paymentIntents[uuid] = null
})
}

Expand All @@ -514,19 +533,25 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) :
@Suppress("unused")
fun collectSetupIntentPaymentMethod(params: ReadableMap, promise: Promise) =
withExceptionResolver(promise) {
val setupIntentId = params.getString("setupIntentId")
val setupIntentJson = requireParam(params.getMap("setupIntent")) {
"You must provide a setupIntent"
}
val uuid = requireParam(setupIntentJson.getString("sdk_uuid")) {
"You must provide a sdk_uuid"
}
val setupIntent = requireParam(setupIntents[uuid]) {
"There is no associated setupIntent with id $uuid"
}

val customerConsentCollected = getBoolean(params, "customerConsentCollected")

val setupIntent = requireParam(setupIntents[setupIntentId]) {
"There is no created setupIntent with id $setupIntentId"
}
collectSetupIntentCancelable = terminal.collectSetupIntentPaymentMethod(
setupIntent,
customerConsentCollected,
SetupIntentConfiguration.Builder()
.setEnableCustomerCancellation(false)
.build(),
RNSetupIntentCallback(promise) { setupIntents[it.id] = it }
RNSetupIntentCallback(promise, uuid) { setupIntents[uuid] = it }
)
}

Expand Down Expand Up @@ -571,28 +596,34 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) :

@ReactMethod
@Suppress("unused")
fun cancelSetupIntent(setupIntentId: String, promise: Promise) =
fun cancelSetupIntent(setupIntent: ReadableMap, promise: Promise) =
withExceptionResolver(promise) {
val setupIntent = requireParam(setupIntents[setupIntentId]) {
"There is no associated setupIntent with id $setupIntentId"
val uuid = requireParam(setupIntent.getString("sdk_uuid")) {
"You must provide a sdk_uuid"
}
val setupIntent = requireParam(setupIntents[uuid]) {
"There is no associated setupIntent with id $uuid"
}

val params = SetupIntentCancellationParameters.Builder().build()

terminal.cancelSetupIntent(setupIntent, params, RNSetupIntentCallback(promise) {
terminal.cancelSetupIntent(setupIntent, params, RNSetupIntentCallback(promise, uuid) {
setupIntents[setupIntent.id] = null
})
}

@ReactMethod
@Suppress("unused")
fun confirmSetupIntent(setupIntentId: String, promise: Promise) =
fun confirmSetupIntent(setupIntent: ReadableMap, promise: Promise) =
withExceptionResolver(promise) {
val setupIntent = requireParam(setupIntents[setupIntentId]) {
"There is no associated setupIntent with id $setupIntentId"
val uuid = requireParam(setupIntent.getString("sdk_uuid")) {
"You must provide a sdk_uuid"
}
val setupIntent = requireParam(setupIntents[uuid]) {
"There is no associated setupIntent with id $uuid"
}

terminal.confirmSetupIntent(setupIntent, RNSetupIntentCallback(promise) {
terminal.confirmSetupIntent(setupIntent, RNSetupIntentCallback(promise, uuid) {
setupIntents[it.id] = null
})
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ import com.stripeterminalreactnative.nativeMapOf

class RNPaymentIntentCallback(
private val promise: Promise,
private val uuid: String,
private val onPaymentIntentSuccess: (PaymentIntent) -> Unit = {}
): PaymentIntentCallback {

override fun onSuccess(paymentIntent: PaymentIntent) {
onPaymentIntentSuccess(paymentIntent)
promise.resolve(nativeMapOf {
putMap("paymentIntent", mapFromPaymentIntent(paymentIntent))
putMap("paymentIntent", mapFromPaymentIntent(paymentIntent, uuid))
})
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,14 @@ import com.stripeterminalreactnative.nativeMapOf

class RNSetupIntentCallback(
private val promise: Promise,
private val uuid: String,
private val onSetupIntentSuccess: (SetupIntent) -> Unit = {}
): SetupIntentCallback {

override fun onSuccess(setupIntent: SetupIntent) {
onSetupIntentSuccess(setupIntent)
promise.resolve(nativeMapOf {
putMap("setupIntent", mapFromSetupIntent(setupIntent))
putMap("setupIntent", mapFromSetupIntent(setupIntent, uuid))
})
}

Expand Down
2 changes: 1 addition & 1 deletion bitrise.yml
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ workflows:
- content: |-
set -e
# This is a terrible hack, as I haven't worked out how Bitrise's `pod install` step interacts with the rbenv set in this app. You definitely shouldn't copy this.
cd dev-app/ios && asdf install ruby 2.7.4 && bundle install && \
cd dev-app/ios && asdf install ruby 3.2.2 && bundle install && \
gem install cocoapods -v 1.12.1 && pod install && cd - && \
echo "Checking for diffs in pod lockfile, if this fails please ensure all dependencies are up to date" && \
git diff --exit-code
Expand Down
2 changes: 1 addition & 1 deletion dev-app/.ruby-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.7.4
3.2.2
3 changes: 2 additions & 1 deletion dev-app/Gemfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
source 'https://rubygems.org'
# You may use http://rbenv.org/ or https://rvm.io/ to install and use this version
ruby '2.7.4'
ruby '3.2.2'
gem 'cocoapods', '~> 1.11', '>= 1.12.1'
gem 'activesupport', '~> 7.0', '<= 7.0.8'
7 changes: 4 additions & 3 deletions dev-app/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ GEM
specs:
CFPropertyList (3.0.6)
rexml
activesupport (7.0.7.2)
activesupport (7.0.8)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
Expand Down Expand Up @@ -65,7 +65,7 @@ GEM
i18n (1.14.1)
concurrent-ruby (~> 1.0)
json (2.6.3)
minitest (5.19.0)
minitest (5.20.0)
molinillo (0.8.0)
nanaimo (0.3.0)
nap (1.1.0)
Expand All @@ -89,10 +89,11 @@ PLATFORMS
ruby

DEPENDENCIES
activesupport (~> 7.0, <= 7.0.8)
cocoapods (~> 1.11, >= 1.12.1)

RUBY VERSION
ruby 2.7.4p191
ruby 3.2.2p53

BUNDLED WITH
2.1.4
1 change: 0 additions & 1 deletion dev-app/src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,6 @@ export class Api {
Authorization: `Bearer ${secretKey}`,
},
});

const data = await result.json();

if ('error' in data) {
Expand Down
10 changes: 5 additions & 5 deletions dev-app/src/screens/CollectCardPaymentScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -254,10 +254,10 @@ export default function CollectCardPaymentScreen() {
],
});

return await _collectPaymentMethod(paymentIntent.id);
return await _collectPaymentMethod(paymentIntent);
};

const _collectPaymentMethod = async (paymentIntentId: string) => {
const _collectPaymentMethod = async (pi: PaymentIntent.Type) => {
// @ts-ignore
setCancel((prev) => ({ ...prev, isDisabled: false }));
addLogs({
Expand All @@ -266,13 +266,13 @@ export default function CollectCardPaymentScreen() {
{
name: 'Collect',
description: 'terminal.collectPaymentMethod',
metadata: { paymentIntentId },
metadata: { paymentIntentId: pi.id },
onBack: cancelCollectPaymentMethod,
},
],
});
const { paymentIntent, error } = await collectPaymentMethod({
paymentIntentId: paymentIntentId,
paymentIntent: pi,
skipTipping: skipTipping,
tipEligibleAmount: tipEligibleAmount
? Number(tipEligibleAmount)
Expand Down Expand Up @@ -331,7 +331,7 @@ export default function CollectCardPaymentScreen() {
});

const { paymentIntent, error } = await confirmPaymentIntent(
collectedPaymentIntent.id
collectedPaymentIntent
);

if (error) {
Expand Down
Loading