-
Notifications
You must be signed in to change notification settings - Fork 210
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
Add ACSS payment method and refactor payment processing with deferred intent #3805
base: develop
Are you sure you want to change the base?
Changes from 20 commits
3831008
5c7b815
b65e7d2
838f9b3
b2d42b5
09fbf6e
4471721
c6b920c
c409cc1
4984b33
ac22800
b536123
d14ca72
531d2f5
fac59c4
fae34f6
3788184
fe861c3
9542421
af3d876
e166763
e066659
825ecea
c67e0fb
a0ad301
f539b4c
35dd03b
c97dec5
c198db4
87f4feb
8abb06c
0452a55
106d8cd
916996f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,7 @@ | ||
import { __, sprintf } from '@wordpress/i18n'; | ||
import { | ||
appendPaymentMethodIdToForm, | ||
appendPaymentIntentIdToForm, | ||
getPaymentMethodTypes, | ||
initializeUPEAppearance, | ||
isLinkEnabled, | ||
|
@@ -24,11 +25,11 @@ import { | |
} from 'wcstripe/stripe-utils/constants'; | ||
|
||
const gatewayUPEComponents = {}; | ||
|
||
const paymentMethodsConfig = getStripeServerData()?.paymentMethodsConfig; | ||
|
||
for ( const paymentMethodType in paymentMethodsConfig ) { | ||
gatewayUPEComponents[ paymentMethodType ] = { | ||
intentId: null, | ||
elements: null, | ||
upeElement: null, | ||
}; | ||
|
@@ -66,28 +67,46 @@ export function validateElements( elements ) { | |
} | ||
|
||
/** | ||
* Creates a Stripe payment element with the specified payment method type and options. The function | ||
* retrieves the necessary data from the UPE configuration and initializes the appearance. It then creates the | ||
* Stripe elements and the Stripe payment element, which is attached to the gatewayUPEComponents object afterward. | ||
* Creates a Stripe payment element with the specified payment method type and options. | ||
* | ||
* If the payment method doesn't support deferred intent, the intent must be created first. | ||
* Then, the payment element is created with the intent's client secret. | ||
* | ||
* @todo Make paymentMethodType required when Split is implemented. | ||
* Finally, the payment element is mounted and attached to the gatewayUPEComponents object. | ||
* | ||
* @param {Object} api The API object used to create the Stripe payment element. | ||
* @param {string} paymentMethodType The type of Stripe payment method to create. | ||
* @return {Object} A promise that resolves with the created Stripe payment element. | ||
*/ | ||
function createStripePaymentElement( api, paymentMethodType = null ) { | ||
async function createStripePaymentElement( api, paymentMethodType ) { | ||
const amount = Number( getStripeServerData()?.cartTotal ); | ||
const paymentMethodTypes = getPaymentMethodTypes( paymentMethodType ); | ||
const options = { | ||
mode: amount < 1 ? 'setup' : 'payment', | ||
currency: getStripeServerData()?.currency.toLowerCase(), | ||
amount, | ||
paymentMethodCreation: 'manual', | ||
paymentMethodTypes, | ||
appearance: initializeUPEAppearance( api ), | ||
fonts: getFontRulesFromPage(), | ||
}; | ||
const { supportsDeferredIntent } = | ||
paymentMethodsConfig[ paymentMethodType ] || {}; | ||
let options; | ||
|
||
// If the payment method doesn't support deferred intent, the intent must be created here. | ||
if ( ! supportsDeferredIntent ) { | ||
const intent = await api.createIntent( null, paymentMethodType ); | ||
gatewayUPEComponents[ paymentMethodType ].intentId = intent.id; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is similar to how it used to work before #2935, but instead of saving the PI ID to a local variable, we save the intent ID to each specific UPE component object ( |
||
|
||
options = { | ||
appearance: initializeUPEAppearance( api ), | ||
paymentMethodCreation: 'manual', | ||
fonts: getFontRulesFromPage(), | ||
clientSecret: intent.client_secret, | ||
}; | ||
} else { | ||
options = { | ||
mode: amount < 1 ? 'setup' : 'payment', | ||
currency: getStripeServerData()?.currency.toLowerCase(), | ||
amount, | ||
paymentMethodCreation: 'manual', | ||
paymentMethodTypes, | ||
appearance: initializeUPEAppearance( api ), | ||
fonts: getFontRulesFromPage(), | ||
}; | ||
} | ||
|
||
const elements = api.getStripe().elements( options ); | ||
|
||
|
@@ -333,6 +352,11 @@ export const processPayment = ( | |
paymentMethodObject.paymentMethod.id | ||
); | ||
|
||
appendPaymentIntentIdToForm( | ||
jQueryForm, | ||
gatewayUPEComponents[ paymentMethodType ].intentId | ||
); | ||
|
||
let stopFormSubmission = false; | ||
await additionalActionsHandler( | ||
paymentMethodObject.paymentMethod, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -309,6 +309,12 @@ export const appendPaymentMethodIdToForm = ( form, paymentMethodId ) => { | |
); | ||
}; | ||
|
||
export const appendPaymentIntentIdToForm = ( form, paymentIntentId ) => { | ||
form.append( | ||
`<input type="hidden" id="wc_payment_intent_id" name="wc_payment_intent_id" value="${ paymentIntentId }" />` | ||
); | ||
}; | ||
|
||
export const appendSetupIntentToForm = ( form, setupIntent ) => { | ||
form.append( | ||
`<input type="hidden" id="wc-stripe-setup-intent" name="wc-stripe-setup-intent" value="${ setupIntent.id }" />` | ||
|
@@ -554,17 +560,30 @@ export const getPaymentMethodName = ( paymentMethodType ) => { | |
* | ||
* @param {Object} upeElement The selector of the DOM element of particular payment method to mount the UPE element to. | ||
* @return {boolean} Whether the payment method is restricted to selected billing country. | ||
**/ | ||
*/ | ||
export const isPaymentMethodRestrictedToLocation = ( upeElement ) => { | ||
const paymentMethodsConfig = | ||
getStripeServerData()?.paymentMethodsConfig || {}; | ||
const paymentMethodType = upeElement.dataset.paymentMethodType; | ||
return !! paymentMethodsConfig[ paymentMethodType ]?.countries.length; | ||
}; | ||
|
||
/** | ||
* Determines if the payment method supports deferred intent. | ||
* | ||
* @param {Object} upeElement The selector of the DOM element of particular payment method to mount the UPE element to. | ||
* @return {boolean} Whether the payment method supports deferred intent. | ||
*/ | ||
export const paymentMethodSupportsDeferredIntent = ( upeElement ) => { | ||
const paymentMethodsConfig = | ||
getStripeServerData()?.paymentMethodsConfig || {}; | ||
const paymentMethodType = upeElement.dataset.paymentMethodType; | ||
return !! paymentMethodsConfig[ paymentMethodType ]?.supportsDeferredIntent; | ||
}; | ||
|
||
/** | ||
* @param {Object} upeElement The selector of the DOM element of particular payment method to mount the UPE element to. | ||
**/ | ||
*/ | ||
export const togglePaymentMethodForCountry = ( upeElement ) => { | ||
const paymentMethodsConfig = | ||
getStripeServerData()?.paymentMethodsConfig || {}; | ||
|
@@ -585,6 +604,16 @@ export const togglePaymentMethodForCountry = ( upeElement ) => { | |
upeContainer.style.display = 'block'; | ||
} else { | ||
upeContainer.style.display = 'none'; | ||
// Also uncheck the radio button if it's selected. | ||
const radioButton = document.querySelector( | ||
'input[name="payment_method"][value="stripe_' + | ||
paymentMethodType + | ||
'"]' | ||
ricardo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
); | ||
|
||
if ( radioButton ) { | ||
radioButton.checked = false; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a small UX improvement. Before this, the payment method would be hidden, but remain selected, causing an error at checkout. |
||
} | ||
}; | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -338,21 +338,22 @@ public function payment_icons() { | |
'wc_stripe_payment_icons', | ||
[ | ||
WC_Stripe_Payment_Methods::ACH => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/bank-debit.svg" class="stripe-ach-icon stripe-icon" alt="ACH" />', | ||
WC_Stripe_Payment_Methods::ACSS_DEBIT => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/bank-debit.svg" class="stripe-ach-icon stripe-icon" alt="' . __( 'Pre-Authorized Debit', 'woocommerce-gateway-stripe' ) . '" />', | ||
WC_Stripe_Payment_Methods::ALIPAY => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/alipay.svg" class="stripe-alipay-icon stripe-icon" alt="Alipay" />', | ||
WC_Stripe_Payment_Methods::WECHAT_PAY => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/wechat.svg" class="stripe-wechat-icon stripe-icon" alt="Wechat Pay" />', | ||
WC_Stripe_Payment_Methods::BANCONTACT => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/bancontact.svg" class="stripe-bancontact-icon stripe-icon" alt="Bancontact" />', | ||
WC_Stripe_Payment_Methods::IDEAL => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/ideal.svg" class="stripe-ideal-icon stripe-icon" alt="iDEAL" />', | ||
WC_Stripe_Payment_Methods::P24 => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/p24.svg" class="stripe-p24-icon stripe-icon" alt="P24" />', | ||
WC_Stripe_Payment_Methods::GIROPAY => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/giropay.svg" class="stripe-giropay-icon stripe-icon" alt="giropay" />', | ||
WC_Stripe_Payment_Methods::KLARNA => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/klarna.svg" class="stripe-klarna-icon stripe-icon" alt="klarna" />', | ||
WC_Stripe_Payment_Methods::AFFIRM => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/affirm.svg" class="stripe-affirm-icon stripe-icon" alt="affirm" />', | ||
WC_Stripe_Payment_Methods::KLARNA => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/klarna.svg" class="stripe-klarna-icon stripe-icon" alt="Klarna" />', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice! Thanks for fixing this |
||
WC_Stripe_Payment_Methods::AFFIRM => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/affirm.svg" class="stripe-affirm-icon stripe-icon" alt="Affirm" />', | ||
WC_Stripe_Payment_Methods::EPS => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/eps.svg" class="stripe-eps-icon stripe-icon" alt="EPS" />', | ||
WC_Stripe_Payment_Methods::MULTIBANCO => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/multibanco.svg" class="stripe-multibanco-icon stripe-icon" alt="Multibanco" />', | ||
WC_Stripe_Payment_Methods::SOFORT => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/sofort.svg" class="stripe-sofort-icon stripe-icon" alt="Sofort" />', | ||
WC_Stripe_Payment_Methods::SEPA => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/sepa.svg" class="stripe-sepa-icon stripe-icon" alt="SEPA" />', | ||
WC_Stripe_Payment_Methods::BOLETO => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/boleto.svg" class="stripe-boleto-icon stripe-icon" alt="Boleto" />', | ||
WC_Stripe_Payment_Methods::OXXO => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/oxxo.svg" class="stripe-oxxo-icon stripe-icon" alt="OXXO" />', | ||
'cards' => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/cards.svg" class="stripe-cards-icon stripe-icon" alt="credit / debit card" />', | ||
'cards' => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/cards.svg" class="stripe-cards-icon stripe-icon" alt="' . __( 'Credit / Debit Card', 'woocommerce-gateway-stripe' ) . '" />', | ||
WC_Stripe_Payment_Methods::CASHAPP_PAY => '<img src="' . WC_STRIPE_PLUGIN_URL . '/assets/images/cashapp.svg" class="stripe-cashapp-icon stripe-icon" alt="Cash App Pay" />', | ||
] | ||
); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should also rename this file to something more generic since it's now handling non-deferred intents as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another option would be to add a common file that imports the regular deferred-intent.js file and a new one for non-deferred.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think
classic/upe/deferred-intent.js
andclassic/upe/index.js
serve similar purposes right now both adding event listeners to the checkout and having some repeat variables (1, 2), so my question was more ifdeferred-intent
is a good naming?Also,
handleUPECheckout
fromindex.js
apparently is not being used anymore after the split UPE work.Perhaps we should unify all these event listeners into a new
index.js
orcheckout-handler.js
, and keep functions in other files likepayment-processing.js
.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that's a good idea 👍