Skip to content

Commit

Permalink
Add captureMethod to createPaymentIntent (#447)
Browse files Browse the repository at this point in the history
* feat: add local mobile support to iOS

* feat: add captureMethod to createPaymentIntent params

* chore: re-add extra whitespace

* feat: update dev-app with captureMethod

* e2e: Fix test failure because we added a new UI element

* CollectCardPaymentScreen: Ensure a capture method is non-null

And always provide one.

* bitrise: Set apple dev connection to "off" (#445)

Attempt to fix build errors like:

> Could not configure Apple Service authentication: 2FA session saved
> in Bitrise Developer Connection is expired, was valid until 2023-03-12
> 21:32:16 +0000 UTC (exit code: 1)

https://app.bitrise.io/build/0565de0f-1eef-4d6c-a660-b6c5c709b6f4

* example-app: Support setting capture method

* StripeTerminalReactNativeModule: Support captureMethod

* dev-app: Support capture method for creating PIs server side

* example-app: Add capture method for server-side PI creation

* example-app: Create API supports setup_future_usage

It's not used yet, but this brings the example-app up-to-date with our
dev-app.

* example-app: Default skip tipping to false

Match our dev app and other example apps.

* example-app: Update native SDK version

* example-app: Remove no-longer-used discovery method enum

* example-app: Revert a handful of commits

Our example-app is pinned to the currently released version of the RN
SDK. So, we can't make these changes yet.

---------

Co-authored-by: Mihail Dunaev <mihail.dunaev91@gmail.com>
  • Loading branch information
billfinn-stripe and mihaildu authored Mar 15, 2023
1 parent 70c84e2 commit 252dcdc
Show file tree
Hide file tree
Showing 8 changed files with 66 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import com.stripe.stripeterminal.TerminalApplicationDelegate.onCreate
import com.stripe.stripeterminal.TerminalApplicationDelegate.onTrimMemory
import com.stripe.stripeterminal.external.callable.Cancelable
import com.stripe.stripeterminal.external.callable.ReaderListenable
import com.stripe.stripeterminal.external.models.CaptureMethod
import com.stripe.stripeterminal.external.models.CardPresentParameters
import com.stripe.stripeterminal.external.models.Cart
import com.stripe.stripeterminal.external.models.CollectConfiguration
Expand Down Expand Up @@ -291,6 +292,7 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) :
val extendedAuth = getBoolean(paymentMethodOptions, "requestExtendedAuthorization")
val incrementalAuth =
getBoolean(paymentMethodOptions, "requestIncrementalAuthorizationSupport")
val captureMethod = params.getString("captureMethod")

val paymentMethodTypes = paymentMethods?.toArrayList()?.mapNotNull {
if (it is String) PaymentMethodType.valueOf(it.uppercase())
Expand Down Expand Up @@ -351,6 +353,13 @@ class StripeTerminalReactNativeModule(reactContext: ReactApplicationContext) :
.build()
)

captureMethod?.let {
when (it) {
"manual" -> intentParams.setCaptureMethod(CaptureMethod.Manual)
else -> intentParams.setCaptureMethod(CaptureMethod.Automatic)
}
}

terminal.createPaymentIntent(intentParams.build(), RNPaymentIntentCallback(promise) {
paymentIntents[it.id] = it
})
Expand Down
3 changes: 2 additions & 1 deletion dev-app/src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,14 +97,15 @@ export class Api {
description = 'Example PaymentIntent',
payment_method_types,
setup_future_usage,
capture_method,
}: Stripe.PaymentIntentCreateParams): Promise<
Stripe.PaymentIntent | { error: Stripe.StripeError }
> {
const formData = new URLSearchParams();
formData.append('amount', amount.toString());
formData.append('currency', currency);
formData.append('description', description);
formData.append('capture_method', 'manual');
formData.append('capture_method', capture_method || 'manual');
if (setup_future_usage) {
formData.append('setup_future_usage', setup_future_usage);
}
Expand Down
29 changes: 29 additions & 0 deletions dev-app/src/screens/CollectCardPaymentScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ const CURRENCIES = [
{ value: 'sek', label: 'SEK' },
];

const CAPTURE_METHODS = [
{ value: 'automatic', label: 'automatic' },
{ value: 'manual', label: 'manual' },
];

export default function CollectCardPaymentScreen() {
const { api, setLastSuccessfulChargeId, account } = useContext(AppContext);

Expand All @@ -38,9 +43,11 @@ export default function CollectCardPaymentScreen() {
applicationFeeAmount?: string;
requestExtendedAuthorization?: boolean;
requestIncrementalAuthorizationSupport?: boolean;
captureMethod: 'automatic' | 'manual';
}>({
amount: '20000',
currency: account?.default_currency || 'usd',
captureMethod: 'manual',
});
const [testCardNumber, setTestCardNumber] = useState('4242424242424242');
const [enableInterac, setEnableInterac] = useState(false);
Expand Down Expand Up @@ -121,6 +128,7 @@ export default function CollectCardPaymentScreen() {
amount: Number(inputValues.amount),
currency: inputValues.currency,
payment_method_types: paymentMethods,
capture_method: inputValues?.captureMethod,
});

if ('error' in resp) {
Expand Down Expand Up @@ -167,6 +175,7 @@ export default function CollectCardPaymentScreen() {
requestIncrementalAuthorizationSupport:
inputValues.requestIncrementalAuthorizationSupport,
},
captureMethod: inputValues?.captureMethod,
});
paymentIntent = response.paymentIntent;
paymentIntentError = response.error;
Expand Down Expand Up @@ -453,6 +462,26 @@ export default function CollectCardPaymentScreen() {
))}
</Picker>
</List>
<List bolded={false} topSpacing={false} title="CAPTURE METHOD">
<Picker
selectedValue={inputValues?.captureMethod}
style={styles.picker}
itemStyle={styles.pickerItem}
testID="select-capture-method-picker"
onValueChange={(value) =>
setInputValues((state) => ({ ...state, captureMethod: value }))
}
>
{CAPTURE_METHODS.map((a) => (
<Picker.Item
key={a.value}
label={a.label}
testID={a.value}
value={a.value}
/>
))}
</Picker>
</List>

<List bolded={false} topSpacing={false} title="INTERAC">
<ListItem
Expand Down
18 changes: 13 additions & 5 deletions e2e/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,10 @@ export const setSelectedCurrency = async (currency = 'USD') => {
await picker.tap();

if (device.getPlatform() === 'ios') {
await element(by.type('UIPickerView')).setColumnToValue(0, currency);
await element(by.id('select-currency-picker')).setColumnToValue(
0,
currency
);
await picker.tap();
} else {
await element(by.text(currency)).tap();
Expand Down Expand Up @@ -147,16 +150,21 @@ export const createInteracPayment = async (reader = 'wisePad3') => {
await waitFor(amountInput).toBeVisible().withTimeout(10000);
await waitFor(cardNumberInput).toBeVisible().withTimeout(10000);

const enableInteracSwitch = element(by.id('enable-interac'));
await waitFor(enableInteracSwitch).toBeVisible().withTimeout(10000);
await enableInteracSwitch.tap();

// set interac test card
await cardNumberInput.replaceText('4506445006931933');
await cardNumberInput.tapReturnKey();

await setSelectedCurrency('CAD');

await waitFor(element(by.id('enable-interac')))
.toBeVisible()
.whileElement(by.id('collect-scroll-view'))
.scroll(50, 'down');

const enableInteracSwitch = element(by.id('enable-interac'));
await waitFor(enableInteracSwitch).toBeVisible().withTimeout(10000);
await enableInteracSwitch.tap();

await element(by.id('collect-scroll-view')).scrollTo('bottom');

const button = element(by.text('Collect payment'));
Expand Down
4 changes: 4 additions & 0 deletions example-app/src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,13 +100,17 @@ export class Api {
currency = 'usd',
description = 'Example PaymentIntent',
payment_method_types,
setup_future_usage,
}: Stripe.PaymentIntentCreateParams): Promise<
Partial<Stripe.PaymentIntent> | { error: Stripe.StripeError }
> {
const formData = new URLSearchParams();
formData.append('amount', amount.toString());
formData.append('currency', currency);
formData.append('description', description);
if (setup_future_usage) {
formData.append('setup_future_usage', setup_future_usage);
}

if (typeof payment_method_types === 'string') {
formData.append('payment_method_types[]', payment_method_types);
Expand Down
2 changes: 1 addition & 1 deletion example-app/src/screens/CollectCardPaymentScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ export default function CollectCardPaymentScreen() {
});
const [testCardNumber, setTestCardNumber] = useState('4242424242424242');
const [enableInterac, setEnableInterac] = useState(false);
const [skipTipping, setSkipTipping] = useState(true);
const [skipTipping, setSkipTipping] = useState(false);
const { params } =
useRoute<RouteProp<RouteParamList, 'CollectCardPayment'>>();
const { simulated, discoveryMethod } = params;
Expand Down
9 changes: 7 additions & 2 deletions ios/StripeTerminalReactNative.swift
Original file line number Diff line number Diff line change
Expand Up @@ -352,9 +352,14 @@ class StripeTerminalReactNative: RCTEventEmitter, DiscoveryDelegate, BluetoothRe
let paymentMethodOptions = params["paymentMethodOptions"] as? [AnyHashable : Any] ?? [:]
let extendedAuth = paymentMethodOptions["requestExtendedAuthorization"] as? Bool ?? false
let incrementalAuth = paymentMethodOptions["requestIncrementalAuthorizationSupport"] as? Bool ?? false
let captureMethod = params["captureMethod"] as? String


let paymentIntentParams = PaymentIntentParameters(amount: UInt(truncating: amount), currency: currency, paymentMethodTypes: paymentMethodTypes)
let paymentIntentParams = PaymentIntentParameters(
amount: UInt(truncating: amount),
currency: currency,
paymentMethodTypes: paymentMethodTypes,
captureMethod: captureMethod == "automatic" ? .automatic : .manual
)

paymentIntentParams.setupFutureUsage = setupFutureUsage
paymentIntentParams.onBehalfOf = onBehalfOf
Expand Down
1 change: 1 addition & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ export type CreatePaymentIntentParams = CreatePaymentIntentIOSParams & {
transferGroup?: string;
metadata?: Record<string, string>;
paymentMethodOptions?: PaymentMethodOptions;
captureMethod?: 'automatic' | 'manual';
};

export type CreatePaymentIntentIOSParams = {
Expand Down

0 comments on commit 252dcdc

Please sign in to comment.