stripe-react-native icon indicating copy to clipboard operation
stripe-react-native copied to clipboard

Fix issue with captureMethod on iOS.

Open alex-gutev opened this issue 1 year ago • 1 comments

Summary

This pull request fixes a bug where the captureMethod parameter of the intent configuration, for deferred payments, is ignored on iOS. In the Swift code the captureMethod parameter is being retrieved from the intentConfiguration dictionary however the parameter is actually passed in the modeParams dictionary. https://github.com/stripe/stripe-react-native/blob/c1bb2dc990af92f7b8419ead1f092d6a99af1b91/ios/StripeSdk%2BPaymentSheet.swift#L191-L199

This issue does not occur on Android where the captureMethod parameter is being retrieved correctly from the modeParams map. https://github.com/stripe/stripe-react-native/blob/c1bb2dc990af92f7b8419ead1f092d6a99af1b91/android/src/main/java/com/reactnativestripesdk/PaymentSheetFragment.kt#L421-L426

Motivation

The issue appears when collecting payment details before creating a payment intent with a manual capture method. Since the capture method given to the payment sheet's intent configuration is ignored on iOS, there is a mismatch between the actual capture method of the payment intent (manual) and that of the payment sheet's intent configuration (automatic). This results in an error message being shown when the pay button is tapped. On Android the payment proceeds as expected.

To reproduce the bug:

Modify the example from https://docs.stripe.com/payments/accept-a-payment-deferred to specify a manual capture method in the intent configuration:

import { useStripe, PaymentSheet } from '@stripe/stripe-react-native';
import {View, Button} from 'react-native';

export default function CheckoutScreen() {
  const { initPaymentSheet, presentPaymentSheet } = useStripe();

  const initializePaymentSheet = async () => {
    const { error } = await initPaymentSheet({
      merchantDisplayName: "Example, Inc.",
      intentConfiguration: {
        mode: {
          amount: 1099,
          currencyCode: 'USD',
          captureMethod: PaymentSheet.CaptureMethod.Manual
        },
        confirmHandler: confirmHandler
      }
    });
    if (error) {
      // handle error
    }
  };

  useEffect(() => {
    initializePaymentSheet();
  }, []);

  const confirmHandler = async (paymentMethod, shouldSavePaymentMethod, intentCreationCallback) => {
    // explained later
  }

  const didTapCheckoutButton = async () => {
    // implement later
  }
  return (
    <View>
      <Button
        title="Checkout"
        onPress={didTapCheckoutButton}
      />
    </View>
  );
}

The backend should also be changed to create a payment intent with a manual capture method.

Testing

I have not directly tested these changes but I discovered the issue in the flutter_stripe library, which is based on stripe-react-native. A quick review of the code indicates that this library has the same issue.

Documentation

  • [x] This PR does not result in any developer-facing changes.

alex-gutev avatar Nov 30 '24 09:11 alex-gutev

CLA assistant check
All committers have signed the CLA.

cla-assistant[bot] avatar Nov 30 '24 09:11 cla-assistant[bot]