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

refactor: Add Dynamic Payment Methods handling #4

Merged
merged 17 commits into from
Apr 17, 2024
Merged
Changes from 1 commit
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
bdb2358
refactor: Add shipping address for Afterpay, PaymentIntentUnexpectedS…
julianajlk Feb 9, 2024
3f144a9
feat: Add DynamicPaymentMethodsNotCompatibleError to handle BNPL DPM …
julianajlk Mar 4, 2024
a25976a
refactor: Postal code required for BNPL DPM supported countries since…
julianajlk Mar 4, 2024
4529662
fix: Update stripe checkout function
julianajlk Mar 4, 2024
a8dddd2
refactor: Get paymentMethodType onChange and send shipping address on…
julianajlk Mar 21, 2024
7d2222c
feat: Add PaymentMethodMessagingElement, modify currencySelector, use…
julianajlk Mar 21, 2024
9c00e5f
refactor: Modify checkout function to handleNextAction for DPM payments
julianajlk Mar 25, 2024
eaaed95
fix: Add isPaymentRedirect to selectors for redirect to receipt
julianajlk Mar 25, 2024
a641b79
refactor: Modify PaymentPage to account for redirect from DPM and red…
julianajlk Mar 23, 2024
ee959b4
refactor: Use stripe promise from PaymentPage parent in Checkout
julianajlk Mar 23, 2024
9b81cc0
fix: Update invalid_request_error to include error in missing state a…
julianajlk Mar 29, 2024
fd2bccc
fix: Only Klarna has redirect_status on return_url, cannot rely on it
julianajlk Mar 29, 2024
0a8c584
fix: Remove no longer needed PaymentIntentUnexpectedStateError, handl…
julianajlk Mar 29, 2024
521c606
fix: Reorder error type in handleRequestError from feedback
julianajlk Apr 9, 2024
e1b548d
test: Add more tests
julianajlk Apr 9, 2024
b60c260
fix: Add dpm_enabled query param to receipt URL
julianajlk Apr 10, 2024
7fa34ad
fix: Add stripeSelectedPaymentMethod to payment_selected click event
julianajlk Apr 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
refactor: Add shipping address for Afterpay, PaymentIntentUnexpectedS…
…tateError, WIP
julianajlk committed Apr 9, 2024
commit bdb23583d882d79b5d174c71979baaae5dfc3e0f
4 changes: 4 additions & 0 deletions src/components/formatted-alert-list/FormattedAlertList.jsx
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ import {
EnrollmentCodeQuantityUpdated,
TransactionDeclined,
BasketChangedError,
PaymentIntentUnexpectedStateError,
CaptureKeyTimeoutTwoMinutes,
CaptureKeyTimeoutOneMinute,
} from '../../payment/AlertCodeMessages';
@@ -47,6 +48,9 @@ export const FormattedAlertList = (props) => {
'basket-changed-error-message': (
<BasketChangedError />
),
'payment-intent-unexpected-state': (
<PaymentIntentUnexpectedStateError />
),
'capture-key-2mins-message': (
<CaptureKeyTimeoutTwoMinutes />
),
2 changes: 1 addition & 1 deletion src/feedback/data/sagas.js
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ export function* handleErrors(e, clearExistingMessages) {
if (e.errors !== undefined) {
for (let i = 0; i < e.errors.length; i++) { // eslint-disable-line no-plusplus
const error = e.errors[i];
if (error.code === 'basket-changed-error-message') {
if (error.code === 'basket-changed-error-message' || error.code === 'payment-intent-unexpected-state') {
yield put(addMessage(error.code, error.userMessage, {}, MESSAGE_TYPES.ERROR));
} else if (error.data === undefined && error.messageType === null) {
yield put(addMessage('transaction-declined-message', error.userMessage, {}, MESSAGE_TYPES.ERROR));
9 changes: 9 additions & 0 deletions src/payment/AlertCodeMessages.jsx
Original file line number Diff line number Diff line change
@@ -73,6 +73,15 @@ export const TransactionDeclined = () => (
/>
);

export const PaymentIntentUnexpectedStateError = () => (
// TEMP TODO: temp copy, not approved by Product/UX yet
<FormattedMessage
id="payment.messages.transaction.error.payment_intent_unexpected_state"
defaultMessage="Your previous payment attempt requires action and needs to be processed. Please reach out to your bank of financial institution for further assistance."
description="Notifies the user their payment requires action."
/>
);

export const BasketChangedError = () => (
<FormattedMessage
id="payment.messages.transaction.error.basket_changed"
3 changes: 3 additions & 0 deletions src/payment/data/handleRequestError.js
Original file line number Diff line number Diff line change
@@ -90,6 +90,9 @@ export default function handleRequestError(error) {
handleApiErrors([
{
error_code: 'basket-changed-error-message',
// TEMP TODO: Now that we have different Payment Intent statuses, this type of error can mean different things
// Which message did it say when the basket was already purchased?
// error_code: 'payment-intent-unexpected-state',
user_message: 'error',
},
]);
27 changes: 25 additions & 2 deletions src/payment/payment-methods/stripe/service.js
Original file line number Diff line number Diff line change
@@ -56,6 +56,18 @@ export default async function checkout(
purchased_for_organization: purchasedForOrganization,
},
},
// Shipping is required for processing Afterpay payments
shipping: {
address: {
city,
country,
line1: address,
line2: unit || '',
postal_code: postalCode || '',
state: state || '',
},
name: `${firstName} ${lastName}`,
},
},
});

@@ -67,6 +79,10 @@ export default async function checkout(
const postData = formurlencoded({
payment_intent_id: result.paymentIntent.id,
skus,
// TEMP TODO: hardcoded true temporarily, until we decide if/what logic we want to have here.
// Stripe A/B Tool doesn't have an experiment attribute to signal it's DPM or an experiment.
// Can look the presence of more than just 'card' in payment_method_types
dynamic_payment_methods_enabled: true,
});
await getAuthenticatedHttpClient()
.post(
@@ -76,8 +92,15 @@ export default async function checkout(
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
},
)
.then(response => {
setLocation(response.data.receipt_page_url);
.then(async response => {
if (response.data.receipt_page_url) {
setLocation(response.data.receipt_page_url);
} else {
const { paymentIntent } = await stripe.retrievePaymentIntent(response.data.confirmation_client_secret);
if (paymentIntent && paymentIntent.status !== 'succeeded') {
// TEMP TODO: Payment Intent hasn't been successfully confirmed yet (aka no receipt_page_url)
}
}
})
.catch(error => {
const errorData = error.response ? error.response.data : null;