259 lines
8.0 KiB
JavaScript
259 lines
8.0 KiB
JavaScript
/**
|
|
* Internal dependencies
|
|
*/
|
|
import { normalizeLineItems } from '../apple-pay/normalize';
|
|
import { errorTypes, errorCodes } from './constants';
|
|
|
|
/**
|
|
* External dependencies
|
|
*/
|
|
import { getSetting } from '@woocommerce/settings';
|
|
import { __ } from '@wordpress/i18n';
|
|
|
|
/**
|
|
* @typedef {import('./type-defs').StripeServerData} StripeServerData
|
|
* @typedef {import('./type-defs').StripePaymentItem} StripePaymentItem
|
|
* @typedef {import('./type-defs').StripePaymentRequest} StripePaymentRequest
|
|
* @typedef {import('@woocommerce/type-defs/registered-payment-method-props').PreparedCartTotalItem} CartTotalItem
|
|
*/
|
|
|
|
// @todo this can't be in the file because the block might not show up unless it's
|
|
// rendered! (which also means it won't get passed from the server until it is rendered).
|
|
// so we need to work out a loading process for when the cart or checkout hasn't been added to the
|
|
// content yet - definitely don't want to load stripe without the block in the page. So that means
|
|
// checkout will need to have some sort of editor preview for stripe.
|
|
/**
|
|
* Stripe data comes form the server passed on a global object.
|
|
*
|
|
* @return {StripeServerData}
|
|
*/
|
|
const getStripeServerData = () => {
|
|
const stripeServerData = getSetting( 'stripe_data', null );
|
|
if ( ! stripeServerData ) {
|
|
throw new Error( 'Stripe initialization data is not available' );
|
|
}
|
|
return stripeServerData;
|
|
};
|
|
|
|
/**
|
|
* Returns the public api key for the stripe payment method
|
|
*
|
|
* @throws Error
|
|
* @return {string} The public api key for the stripe payment method.
|
|
*/
|
|
const getApiKey = () => {
|
|
const apiKey = getStripeServerData().publicKey;
|
|
if ( ! apiKey ) {
|
|
throw new Error(
|
|
'There is no api key available for stripe. Make sure it is available on the wc.stripe_data.stripe.key property.'
|
|
);
|
|
}
|
|
return apiKey;
|
|
};
|
|
|
|
/**
|
|
* The total PaymentItem object used for the stripe PaymentRequest object.
|
|
*
|
|
* @param {CartTotalItem} total The total amount.
|
|
*
|
|
* @return {StripePaymentItem} The PaymentItem object used for stripe.
|
|
*/
|
|
const getTotalPaymentItem = ( total ) => {
|
|
return {
|
|
label: getStripeServerData().stripeTotalLabel,
|
|
amount: total.value,
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Returns a stripe payment request object
|
|
*
|
|
* @param {Object} config A configuration object for
|
|
* getting the payment request.
|
|
* @param {Object} config.stripe The stripe api.
|
|
* @param {CartTotalItem} config.total The amount for the total
|
|
* (in subunits) provided by
|
|
* checkout/cart.
|
|
* @param {string} config.currencyCode The currency code provided
|
|
* by checkout/cart.
|
|
* @param {string} config.countryCode The country code provided by
|
|
* checkout/cart.
|
|
* @param {boolean} config.shippingRequired Whether or not shipping is
|
|
* required.
|
|
* @param {CartTotalItem[]} config.cartTotalItems Array of line items provided
|
|
* by checkout/cart.
|
|
*
|
|
* @return {StripePaymentRequest} A stripe payment request object
|
|
*/
|
|
const getPaymentRequest = ( {
|
|
stripe,
|
|
total,
|
|
currencyCode,
|
|
countryCode,
|
|
shippingRequired,
|
|
cartTotalItems,
|
|
} ) => {
|
|
const options = {
|
|
total: getTotalPaymentItem( total ),
|
|
currency: currencyCode,
|
|
country: countryCode || 'US',
|
|
requestPayerName: true,
|
|
requestPayerEmail: true,
|
|
requestPayerPhone: true,
|
|
requestShipping: shippingRequired,
|
|
displayItems: normalizeLineItems( cartTotalItems ),
|
|
};
|
|
return stripe.paymentRequest( options );
|
|
};
|
|
|
|
/**
|
|
* Utility function for updating the Stripe PaymentRequest object
|
|
*
|
|
* @param {Object} update An object containing the
|
|
* things needed for the
|
|
* update
|
|
* @param {StripePaymentRequest} update.paymentRequest A Stripe payment request
|
|
* object
|
|
* @param {CartTotalItem} update.total A total line item.
|
|
* @param {string} update.currencyCode The currency code for the
|
|
* amount provided.
|
|
* @param {CartTotalItem[]} update.cartTotalItems An array of line items
|
|
* provided by the
|
|
* cart/checkout.
|
|
*/
|
|
const updatePaymentRequest = ( {
|
|
paymentRequest,
|
|
total,
|
|
currencyCode,
|
|
cartTotalItems,
|
|
} ) => {
|
|
paymentRequest.update( {
|
|
total: getTotalPaymentItem( total ),
|
|
currency: currencyCode,
|
|
displayItems: normalizeLineItems( cartTotalItems ),
|
|
} );
|
|
};
|
|
|
|
/**
|
|
* Returns whether or not the current session can do apple pay.
|
|
*
|
|
* @param {StripePaymentRequest} paymentRequest A Stripe PaymentRequest instance.
|
|
*
|
|
* @return {Promise<boolean>} True means apple pay can be done.
|
|
*/
|
|
const canDoApplePay = ( paymentRequest ) => {
|
|
return new Promise( ( resolve ) => {
|
|
paymentRequest.canMakePayment().then( ( result ) => {
|
|
if ( result && result.applePay ) {
|
|
resolve( true );
|
|
return;
|
|
}
|
|
resolve( false );
|
|
} );
|
|
} );
|
|
};
|
|
|
|
const isNonFriendlyError = ( type ) =>
|
|
[
|
|
errorTypes.INVALID_REQUEST,
|
|
errorTypes.API_CONNECTION,
|
|
errorTypes.API_ERROR,
|
|
errorTypes.AUTHENTICATION_ERROR,
|
|
errorTypes.RATE_LIMIT_ERROR,
|
|
].includes( type );
|
|
|
|
const getErrorMessageForCode = ( code ) => {
|
|
const messages = {
|
|
[ errorCodes.INVALID_NUMBER ]: __(
|
|
'The card number is not a valid credit card number.',
|
|
'woocommerce-gateway-stripe'
|
|
),
|
|
[ errorCodes.INVALID_EXPIRY_MONTH ]: __(
|
|
"The card's expiration month is invalid.",
|
|
'woocommerce-gateway-stripe'
|
|
),
|
|
[ errorCodes.INVALID_EXPIRY_YEAR ]: __(
|
|
"The card's expiration year is invalid.",
|
|
'woocommerce-gateway-stripe'
|
|
),
|
|
[ errorCodes.INVALID_CVC ]: __(
|
|
"The card's security code is invalid.",
|
|
'woocommerce-gateway-stripe'
|
|
),
|
|
[ errorCodes.INCORRECT_NUMBER ]: __(
|
|
'The card number is incorrect.',
|
|
'woocommerce-gateway-stripe'
|
|
),
|
|
[ errorCodes.INCOMPLETE_NUMBER ]: __(
|
|
'The card number is incomplete.',
|
|
'woocommerce-gateway-stripe'
|
|
),
|
|
[ errorCodes.INCOMPLETE_CVC ]: __(
|
|
"The card's security code is incomplete.",
|
|
'woocommerce-gateway-stripe'
|
|
),
|
|
[ errorCodes.INCOMPLETE_EXPIRY ]: __(
|
|
"The card's expiration date is incomplete.",
|
|
'woocommerce-gateway-stripe'
|
|
),
|
|
[ errorCodes.EXPIRED_CARD ]: __(
|
|
'The card has expired.',
|
|
'woocommerce-gateway-stripe'
|
|
),
|
|
[ errorCodes.INCORRECT_CVC ]: __(
|
|
"The card's security code is incorrect.",
|
|
'woocommerce-gateway-stripe'
|
|
),
|
|
[ errorCodes.INCORRECT_ZIP ]: __(
|
|
"The card's zip code failed validation.",
|
|
'woocommerce-gateway-stripe'
|
|
),
|
|
[ errorCodes.INVALID_EXPIRY_YEAR_PAST ]: __(
|
|
"The card's expiration year is in the past",
|
|
'woocommerce-gateway-stripe'
|
|
),
|
|
[ errorCodes.CARD_DECLINED ]: __(
|
|
'The card was declined.',
|
|
'woocommerce-gateway-stripe'
|
|
),
|
|
[ errorCodes.MISSING ]: __(
|
|
'There is no card on a customer that is being charged.',
|
|
'woocommerce-gateway-stripe'
|
|
),
|
|
[ errorCodes.PROCESSING_ERROR ]: __(
|
|
'An error occurred while processing the card.',
|
|
'woocommerce-gateway-stripe'
|
|
),
|
|
};
|
|
return messages[ code ] || '';
|
|
};
|
|
|
|
const getErrorMessageForTypeAndCode = ( type, code = '' ) => {
|
|
switch ( type ) {
|
|
case errorTypes.INVALID_EMAIL:
|
|
return __(
|
|
'Invalid email address, please correct and try again.',
|
|
'woo-gutenberg-product-blocks'
|
|
);
|
|
case isNonFriendlyError( type ):
|
|
return __(
|
|
'Unable to process this payment, please try again or use alternative method.',
|
|
'woo-gutenberg-product-blocks'
|
|
);
|
|
case errorTypes.CARD_ERROR:
|
|
case errorTypes.VALIDATION_ERROR:
|
|
return getErrorMessageForCode( code );
|
|
}
|
|
return '';
|
|
};
|
|
|
|
export {
|
|
getStripeServerData,
|
|
getApiKey,
|
|
getTotalPaymentItem,
|
|
getPaymentRequest,
|
|
updatePaymentRequest,
|
|
canDoApplePay,
|
|
getErrorMessageForTypeAndCode,
|
|
};
|