-
Notifications
You must be signed in to change notification settings - Fork 2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Checkout: Decouple existingCardProcessor from checkout (#48069)
* WIP: Move existingCardProcessor to own file * Include transactionOptions with dataForProcessor Eventually we can get rid of transactionOptions entirely. * Move transaction translate functions to translate-cart file They are not types and belong outside the types file. * Add CardProcessorOptions type * Add stripeConfiguration to dataForProcessor * Make TransactionRequestWithLineItems more permissive for falsy values * Remove stripeConfiguration from ExistingCard payment method * Finish existingCardProcessor * Allow stripeConfiguration to be null in CardProcessorOptions This should never happen in production but it's really hard to avoid it in the type. * Apply ExistingCardProcessorData type to processor function call * Guard against missing stripeConfiguration in existingCardProcessor * Move getDomainDetails to own file * Allow siteId to be a number in TransactionRequestWithLineItems * Remove createExistingCardMethod from composite-checkout README * Move getPostalCode to own file * Stop passing total to existing-card payment processor * Add mergeIfObjects helper * Call existingCardProcessor with additional data already included * Make existingCardProcessor require all data as arguments * Make sure siteId is always a string in the existingCardProcessor * Change getDomainDetails to return undefined for missing data * Make siteId a string or undefined in existingCardProcessor * Disallow country being undefined in TransactionRequestWithLineItems * Ensure all required fields are checked in isValidTransactionData * Change mergeIfObjects to support an array of objects * Change usage of mergeIfObjects to array * Remove paymentMethodType from transactionData type as it is added later * Remove saveTransactionResponseToWpcomStore from existingCardProcessor * Change mergeIfObjects to accept variadic args rather than an array * Change isValidTransactionData to throw specific errors * Rename CardProcessorOptions to PaymentProcessorOptions * Organize TransactionRequestWithLineItems properties This also makes all optional props capable of holding `undefined`. * Clarify requried properties in ExistingCardTransactionRequest * Pass stripe/configuration directly to assignNewCardProcessor
- Loading branch information
1 parent
100413f
commit ebcc760
Showing
14 changed files
with
448 additions
and
280 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
101 changes: 101 additions & 0 deletions
101
client/my-sites/checkout/composite-checkout/lib/existing-card-processor.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import debugFactory from 'debug'; | ||
import { makeSuccessResponse, makeRedirectResponse } from '@automattic/composite-checkout'; | ||
import { confirmStripePaymentIntent } from '@automattic/calypso-stripe'; | ||
import type { PaymentProcessorResponse } from '@automattic/composite-checkout'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { createTransactionEndpointRequestPayloadFromLineItems } from './translate-cart'; | ||
import { wpcomTransaction } from '../payment-method-helpers'; | ||
import type { PaymentProcessorOptions } from '../types/payment-processors'; | ||
import type { ExistingCardTransactionRequestWithLineItems } from '../types/transaction-endpoint'; | ||
|
||
const debug = debugFactory( 'calypso:composite-checkout:payment-method-helpers' ); | ||
|
||
export default async function existingCardProcessor( | ||
transactionData: unknown, | ||
dataForProcessor: PaymentProcessorOptions | ||
): Promise< PaymentProcessorResponse > { | ||
if ( ! isValidTransactionData( transactionData ) ) { | ||
throw new Error( 'Required purchase data is missing' ); | ||
} | ||
const { stripeConfiguration, recordEvent } = dataForProcessor; | ||
if ( ! stripeConfiguration ) { | ||
throw new Error( 'Stripe configuration is required' ); | ||
} | ||
return submitExistingCardPayment( transactionData, dataForProcessor ) | ||
.then( ( stripeResponse ) => { | ||
if ( stripeResponse?.message?.payment_intent_client_secret ) { | ||
// 3DS authentication required | ||
recordEvent( { type: 'SHOW_MODAL_AUTHORIZATION' } ); | ||
return confirmStripePaymentIntent( | ||
stripeConfiguration, | ||
stripeResponse?.message?.payment_intent_client_secret | ||
); | ||
} | ||
return stripeResponse; | ||
} ) | ||
.then( ( stripeResponse ) => { | ||
if ( stripeResponse?.redirect_url ) { | ||
return makeRedirectResponse( stripeResponse.redirect_url ); | ||
} | ||
return makeSuccessResponse( stripeResponse ); | ||
} ); | ||
} | ||
|
||
async function submitExistingCardPayment( | ||
transactionData: ExistingCardTransactionRequest, | ||
transactionOptions: PaymentProcessorOptions | ||
) { | ||
debug( 'formatting existing card transaction', transactionData ); | ||
const formattedTransactionData = createTransactionEndpointRequestPayloadFromLineItems( { | ||
...transactionData, | ||
paymentMethodType: 'WPCOM_Billing_MoneyPress_Stored', | ||
} ); | ||
debug( 'submitting existing card transaction', formattedTransactionData ); | ||
|
||
return wpcomTransaction( formattedTransactionData, transactionOptions ); | ||
} | ||
|
||
type ExistingCardTransactionRequest = Omit< | ||
ExistingCardTransactionRequestWithLineItems, | ||
'paymentMethodType' | ||
>; | ||
|
||
function isValidTransactionData( | ||
submitData: unknown | ||
): submitData is ExistingCardTransactionRequest { | ||
const data = submitData as ExistingCardTransactionRequest; | ||
if ( ! ( data?.items?.length > 0 ) ) { | ||
throw new Error( 'Transaction requires items and none were provided' ); | ||
} | ||
// Validate data required for this payment method type. Some other data may | ||
// be required by the server but not required here since the server will give | ||
// a better localized error message than we can provide. | ||
if ( ! data.siteId ) { | ||
throw new Error( 'Transaction requires siteId and none was provided' ); | ||
} | ||
if ( ! data.country ) { | ||
throw new Error( 'Transaction requires country code and none was provided' ); | ||
} | ||
if ( ! data.postalCode ) { | ||
throw new Error( 'Transaction requires postal code and none was provided' ); | ||
} | ||
if ( ! data.storedDetailsId ) { | ||
throw new Error( 'Transaction requires saved card information and none was provided' ); | ||
} | ||
if ( ! data.name ) { | ||
throw new Error( 'Transaction requires cardholder name and none was provided' ); | ||
} | ||
if ( ! data.paymentMethodToken ) { | ||
throw new Error( 'Transaction requires a Stripe token and none was provided' ); | ||
} | ||
if ( ! data.paymentPartnerProcessorId ) { | ||
throw new Error( 'Transaction requires a processor id and none was provided' ); | ||
} | ||
return true; | ||
} |
30 changes: 30 additions & 0 deletions
30
client/my-sites/checkout/composite-checkout/lib/get-domain-details.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { defaultRegistry } from '@automattic/composite-checkout'; | ||
import type { DomainContactDetails } from '@automattic/shopping-cart'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { prepareDomainContactDetailsForTransaction } from 'calypso/my-sites/checkout/composite-checkout/types/wpcom-store-state'; | ||
import type { ManagedContactDetails } from '../types/wpcom-store-state'; | ||
|
||
const { select } = defaultRegistry; | ||
|
||
export default function getDomainDetails( { | ||
includeDomainDetails, | ||
includeGSuiteDetails, | ||
}: { | ||
includeDomainDetails: boolean; | ||
includeGSuiteDetails: boolean; | ||
} ): DomainContactDetails | undefined { | ||
const managedContactDetails: ManagedContactDetails | undefined = select( | ||
'wpcom' | ||
)?.getContactInfo(); | ||
if ( ! managedContactDetails ) { | ||
return undefined; | ||
} | ||
const domainDetails = prepareDomainContactDetailsForTransaction( managedContactDetails ); | ||
return includeDomainDetails || includeGSuiteDetails ? domainDetails : undefined; | ||
} |
24 changes: 24 additions & 0 deletions
24
client/my-sites/checkout/composite-checkout/lib/get-postal-code.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
/** | ||
* External dependencies | ||
*/ | ||
import { defaultRegistry } from '@automattic/composite-checkout'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { tryToGuessPostalCodeFormat } from 'calypso/lib/postal-code'; | ||
import type { ManagedContactDetails } from '../types/wpcom-store-state'; | ||
|
||
const { select } = defaultRegistry; | ||
|
||
export default function getPostalCode(): string { | ||
const managedContactDetails: ManagedContactDetails | undefined = select( | ||
'wpcom' | ||
)?.getContactInfo(); | ||
if ( ! managedContactDetails ) { | ||
return ''; | ||
} | ||
const countryCode = managedContactDetails.countryCode?.value ?? ''; | ||
const postalCode = managedContactDetails.postalCode?.value ?? ''; | ||
return tryToGuessPostalCodeFormat( postalCode.toUpperCase(), countryCode ); | ||
} |
10 changes: 10 additions & 0 deletions
10
client/my-sites/checkout/composite-checkout/lib/merge-if-objects.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
export default function mergeIfObjects( ...objects: unknown[] ): MergedObject { | ||
return objects.reduce( ( merged: MergedObject, obj: unknown ): MergedObject => { | ||
if ( typeof obj !== 'object' ) { | ||
return merged; | ||
} | ||
return { ...merged, ...obj }; | ||
}, {} ); | ||
} | ||
|
||
type MergedObject = Record< string, unknown >; |
Oops, something went wrong.