swell-js 5.9.4 → 5.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -0
- package/dist/api.mjs +21 -1
- package/dist/payment.mjs +700 -76
- package/dist/swell.cjs +721 -77
- package/dist/swell.cjs.map +1 -1
- package/dist/swell.umd.min.js +721 -77
- package/dist/swell.umd.min.js.map +1 -1
- package/package.json +1 -1
- package/types/index.d.cts +2 -0
- package/types/index.d.ts +14 -1
- package/types/payment/index.ts +42 -3
package/dist/payment.mjs
CHANGED
|
@@ -677,25 +677,184 @@ async function createPaymentMethod(stripe, cardElement, cart) {
|
|
|
677
677
|
billing_details: billingDetails,
|
|
678
678
|
});
|
|
679
679
|
|
|
680
|
-
return error
|
|
681
|
-
? { error }
|
|
682
|
-
: {
|
|
683
|
-
gateway: 'stripe',
|
|
684
|
-
token: paymentMethod.id,
|
|
685
|
-
last4: paymentMethod.card.last4,
|
|
686
|
-
exp_month: paymentMethod.card.exp_month,
|
|
687
|
-
exp_year: paymentMethod.card.exp_year,
|
|
688
|
-
brand: paymentMethod.card.brand,
|
|
689
|
-
display_brand: paymentMethod.card.display_brand,
|
|
690
|
-
address_check: paymentMethod.card.checks.address_line1_check,
|
|
691
|
-
cvc_check: paymentMethod.card.checks.cvc_check,
|
|
692
|
-
zip_check: paymentMethod.card.checks.address_postal_code_check,
|
|
693
|
-
};
|
|
680
|
+
return error ? { error } : mapCardPaymentMethod(paymentMethod);
|
|
694
681
|
}
|
|
695
682
|
|
|
696
683
|
/**
|
|
684
|
+
* Elements group options of the card Payment Element for the cart amount,
|
|
685
|
+
* matching the intent StripeCardPayment#_createIntent creates.
|
|
686
|
+
*
|
|
687
|
+
* @param {Cart} cart
|
|
688
|
+
* @returns {import('@stripe/stripe-js').StripeElementsOptionsMode}
|
|
689
|
+
*/
|
|
690
|
+
function getCardElementsOptions(cart) {
|
|
691
|
+
const { capture_total, auth_total } = cart;
|
|
692
|
+
const currency = cart.currency || 'USD';
|
|
693
|
+
const stripeCurrency = currency.toLowerCase();
|
|
694
|
+
|
|
695
|
+
// the card is only stored when the amount is not chargeable, no intent is created
|
|
696
|
+
if (!isStripeChargeableAmount(capture_total, cart.currency)) {
|
|
697
|
+
return {
|
|
698
|
+
mode: 'setup',
|
|
699
|
+
currency: stripeCurrency,
|
|
700
|
+
paymentMethodTypes: ['card'],
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
return {
|
|
705
|
+
mode: 'payment',
|
|
706
|
+
amount: stripeAmountByCurrency(currency, capture_total + (auth_total || 0)),
|
|
707
|
+
currency: stripeCurrency,
|
|
708
|
+
captureMethod: 'manual',
|
|
709
|
+
setupFutureUsage: 'off_session',
|
|
710
|
+
paymentMethodTypes: ['card'],
|
|
711
|
+
};
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
/**
|
|
715
|
+
* Elements group options of the iDEAL Payment Element,
|
|
716
|
+
* matching the intent StripeIDealPayment#_createIntent creates.
|
|
717
|
+
*
|
|
718
|
+
* @param {Cart} cart
|
|
719
|
+
* @returns {import('@stripe/stripe-js').StripeElementsOptionsMode}
|
|
720
|
+
*/
|
|
721
|
+
function getIDealElementsOptions(cart) {
|
|
722
|
+
const { capture_total } = cart;
|
|
723
|
+
const currency = cart.currency || 'EUR';
|
|
724
|
+
|
|
725
|
+
return {
|
|
726
|
+
mode: 'payment',
|
|
727
|
+
amount: stripeAmountByCurrency(currency, capture_total),
|
|
728
|
+
currency: currency.toLowerCase(),
|
|
729
|
+
paymentMethodTypes: ['ideal'],
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
/**
|
|
734
|
+
* Creates an Elements group without an intent and mounts the Payment Element
|
|
735
|
+
* into `#${params.elementId || 'payment-element'}`.
|
|
736
|
+
*
|
|
737
|
+
* @param {Stripe} stripe
|
|
738
|
+
* @param {import('@stripe/stripe-js').StripeElementsOptionsMode} elementsOptions
|
|
739
|
+
* @param {object} params
|
|
740
|
+
* @returns {import('@stripe/stripe-js').StripeElements}
|
|
741
|
+
*/
|
|
742
|
+
function createPaymentElements(stripe, elementsOptions, params) {
|
|
743
|
+
const elements = stripe.elements({
|
|
744
|
+
...params.config,
|
|
745
|
+
...elementsOptions,
|
|
746
|
+
// lets stripe.createPaymentMethod read the Payment Element
|
|
747
|
+
paymentMethodCreation: 'manual',
|
|
748
|
+
...(params.appearance && { appearance: params.appearance }),
|
|
749
|
+
});
|
|
750
|
+
|
|
751
|
+
createElement('payment', elements, {
|
|
752
|
+
...params,
|
|
753
|
+
options: {
|
|
754
|
+
layout: 'tabs',
|
|
755
|
+
fields: { billingDetails: 'never' },
|
|
756
|
+
// wallets are separate express buttons
|
|
757
|
+
wallets: { applePay: 'never', googlePay: 'never' },
|
|
758
|
+
...params.options,
|
|
759
|
+
},
|
|
760
|
+
});
|
|
761
|
+
|
|
762
|
+
return elements;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
/**
|
|
766
|
+
* Creates a PaymentMethod from the Payment Element.
|
|
767
|
+
* Brings the Elements amount up to date with the cart first.
|
|
768
|
+
*
|
|
697
769
|
* @param {Stripe} stripe
|
|
698
|
-
* @param {import('@stripe/stripe-js').
|
|
770
|
+
* @param {import('@stripe/stripe-js').StripeElements} elements
|
|
771
|
+
* @param {import('@stripe/stripe-js').StripeElementsOptionsMode} elementsOptions
|
|
772
|
+
* @param {Cart} cart
|
|
773
|
+
* @returns {Promise<import('@stripe/stripe-js').PaymentMethodResult>}
|
|
774
|
+
*/
|
|
775
|
+
async function createPaymentMethodFromElements(
|
|
776
|
+
stripe,
|
|
777
|
+
elements,
|
|
778
|
+
elementsOptions,
|
|
779
|
+
cart,
|
|
780
|
+
) {
|
|
781
|
+
// setup mode stores the card without an intent, there is no amount to update
|
|
782
|
+
if (elementsOptions.mode === 'payment') {
|
|
783
|
+
await elements.update(elementsOptions);
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
const { error } = await elements.submit();
|
|
787
|
+
|
|
788
|
+
if (error) {
|
|
789
|
+
return { error };
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
const { address, ...details } = getBillingDetails(cart);
|
|
793
|
+
|
|
794
|
+
// fields the Payment Element does not collect must all be passed, null when unknown
|
|
795
|
+
return stripe.createPaymentMethod({
|
|
796
|
+
elements,
|
|
797
|
+
params: {
|
|
798
|
+
billing_details: {
|
|
799
|
+
name: null,
|
|
800
|
+
email: null,
|
|
801
|
+
phone: null,
|
|
802
|
+
...details,
|
|
803
|
+
address: {
|
|
804
|
+
line1: null,
|
|
805
|
+
line2: null,
|
|
806
|
+
city: null,
|
|
807
|
+
state: null,
|
|
808
|
+
postal_code: null,
|
|
809
|
+
country: null,
|
|
810
|
+
...address,
|
|
811
|
+
},
|
|
812
|
+
},
|
|
813
|
+
},
|
|
814
|
+
});
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
/**
|
|
818
|
+
* @param {Stripe} stripe
|
|
819
|
+
* @param {import('@stripe/stripe-js').StripeElements} elements
|
|
820
|
+
* @param {Cart} cart
|
|
821
|
+
*/
|
|
822
|
+
async function createCardPaymentMethodFromElements(
|
|
823
|
+
stripe,
|
|
824
|
+
elements,
|
|
825
|
+
cart,
|
|
826
|
+
) {
|
|
827
|
+
const { paymentMethod, error } = await createPaymentMethodFromElements(
|
|
828
|
+
stripe,
|
|
829
|
+
elements,
|
|
830
|
+
getCardElementsOptions(cart),
|
|
831
|
+
cart,
|
|
832
|
+
);
|
|
833
|
+
|
|
834
|
+
return error ? { error } : mapCardPaymentMethod(paymentMethod);
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
/**
|
|
838
|
+
* @param {import('@stripe/stripe-js').PaymentMethod} paymentMethod
|
|
839
|
+
*/
|
|
840
|
+
function mapCardPaymentMethod(paymentMethod) {
|
|
841
|
+
return {
|
|
842
|
+
gateway: 'stripe',
|
|
843
|
+
token: paymentMethod.id,
|
|
844
|
+
last4: paymentMethod.card.last4,
|
|
845
|
+
exp_month: paymentMethod.card.exp_month,
|
|
846
|
+
exp_year: paymentMethod.card.exp_year,
|
|
847
|
+
brand: paymentMethod.card.brand,
|
|
848
|
+
display_brand: paymentMethod.card.display_brand,
|
|
849
|
+
address_check: paymentMethod.card.checks.address_line1_check,
|
|
850
|
+
cvc_check: paymentMethod.card.checks.cvc_check,
|
|
851
|
+
zip_check: paymentMethod.card.checks.address_postal_code_check,
|
|
852
|
+
};
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
/**
|
|
856
|
+
* @param {Stripe} stripe
|
|
857
|
+
* @param {import('@stripe/stripe-js').StripeIdealBankElement | {}} element `{}` when there is no idealBank element
|
|
699
858
|
* @param {Cart} cart
|
|
700
859
|
*/
|
|
701
860
|
async function createIDealPaymentMethod(stripe, element, cart) {
|
|
@@ -883,6 +1042,29 @@ function isStripeChargeableAmount(amount, currency) {
|
|
|
883
1042
|
return !minAmount || amount >= minAmount;
|
|
884
1043
|
}
|
|
885
1044
|
|
|
1045
|
+
// The cart keeps what checkout v1 keeps, so the next tokenize can retrieve and reuse
|
|
1046
|
+
// the intent; the vault cancels the replaced ones when the order is paid
|
|
1047
|
+
const cartIntent = (cart, intent) => {
|
|
1048
|
+
const exIntent = cart.billing?.intent?.stripe;
|
|
1049
|
+
|
|
1050
|
+
return {
|
|
1051
|
+
id: intent.id,
|
|
1052
|
+
client_secret: intent.client_secret,
|
|
1053
|
+
amount: intent.amount,
|
|
1054
|
+
currency: intent.currency,
|
|
1055
|
+
...(Boolean(cart.auth_total) && { auth_amount: cart.auth_total }),
|
|
1056
|
+
...(exIntent?.id &&
|
|
1057
|
+
exIntent.id !== intent.id && {
|
|
1058
|
+
canceled: [...(exIntent.canceled || []), exIntent.id],
|
|
1059
|
+
}),
|
|
1060
|
+
};
|
|
1061
|
+
};
|
|
1062
|
+
|
|
1063
|
+
const intentAmount = ({ currency, capture_total, auth_total }) =>
|
|
1064
|
+
stripeAmountByCurrency(currency, capture_total + auth_total);
|
|
1065
|
+
|
|
1066
|
+
const intentCurrency = ({ currency }) => (currency || 'USD').toLowerCase();
|
|
1067
|
+
|
|
886
1068
|
/** @typedef {import('@stripe/stripe-js').Stripe} Stripe */
|
|
887
1069
|
/** @typedef {import('@stripe/stripe-js').StripeCardElement} StripeCardElement */
|
|
888
1070
|
/** @typedef {import('@stripe/stripe-js').StripeCardNumberElement} StripeCardNumberElement */
|
|
@@ -926,9 +1108,30 @@ class StripeCardPayment extends Payment {
|
|
|
926
1108
|
StripeCardPayment.stripeElement = stripeElement;
|
|
927
1109
|
}
|
|
928
1110
|
|
|
929
|
-
|
|
1111
|
+
/** @returns {import('@stripe/stripe-js').StripeElements} */
|
|
1112
|
+
get stripeElements() {
|
|
1113
|
+
return StripeCardPayment.stripeElements;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
/** @param {import('@stripe/stripe-js').StripeElements} stripeElements */
|
|
1117
|
+
set stripeElements(stripeElements) {
|
|
1118
|
+
StripeCardPayment.stripeElements = stripeElements;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
/** @param {import('../../../types').Cart} cart */
|
|
1122
|
+
async createElements(cart) {
|
|
930
1123
|
await this.loadScripts(this.scripts);
|
|
931
1124
|
|
|
1125
|
+
if (this.params.paymentElement) {
|
|
1126
|
+
this.stripeElements = createPaymentElements(
|
|
1127
|
+
this.stripe,
|
|
1128
|
+
getCardElementsOptions(cart),
|
|
1129
|
+
this.params,
|
|
1130
|
+
);
|
|
1131
|
+
|
|
1132
|
+
return;
|
|
1133
|
+
}
|
|
1134
|
+
|
|
932
1135
|
const elements = this.stripe.elements(this.params.config);
|
|
933
1136
|
|
|
934
1137
|
if (this.params.separateElements) {
|
|
@@ -941,18 +1144,26 @@ class StripeCardPayment extends Payment {
|
|
|
941
1144
|
}
|
|
942
1145
|
|
|
943
1146
|
async tokenize() {
|
|
944
|
-
|
|
1147
|
+
const { paymentElement, paymentMethod: token } = this.params;
|
|
1148
|
+
|
|
1149
|
+
if (token) {
|
|
1150
|
+
return this._authorizePaymentMethod(token);
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
if (!(paymentElement ? this.stripeElements : this.stripeElement)) {
|
|
945
1154
|
throw new Error('Stripe payment element is not defined');
|
|
946
1155
|
}
|
|
947
1156
|
|
|
948
1157
|
await this.loadScripts(this.scripts);
|
|
949
1158
|
|
|
950
1159
|
const cart = await this.getCart();
|
|
951
|
-
const paymentMethod =
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
1160
|
+
const paymentMethod = paymentElement
|
|
1161
|
+
? await createCardPaymentMethodFromElements(
|
|
1162
|
+
this.stripe,
|
|
1163
|
+
this.stripeElements,
|
|
1164
|
+
cart,
|
|
1165
|
+
)
|
|
1166
|
+
: await createPaymentMethod(this.stripe, this.stripeElement, cart);
|
|
956
1167
|
|
|
957
1168
|
if (paymentMethod.error) {
|
|
958
1169
|
throw new Error(paymentMethod.error.message);
|
|
@@ -962,8 +1173,12 @@ class StripeCardPayment extends Payment {
|
|
|
962
1173
|
paymentMethod.test = true;
|
|
963
1174
|
}
|
|
964
1175
|
|
|
965
|
-
// should save payment method data when payment amount is not chargeable
|
|
966
|
-
|
|
1176
|
+
// should save payment method data when payment amount is not chargeable,
|
|
1177
|
+
// or when the host collects the card without authorizing it now
|
|
1178
|
+
if (
|
|
1179
|
+
!isStripeChargeableAmount(cart.capture_total, cart.currency) ||
|
|
1180
|
+
this.params.createIntent === false
|
|
1181
|
+
) {
|
|
967
1182
|
await this.updateCart({
|
|
968
1183
|
billing: {
|
|
969
1184
|
method: 'card',
|
|
@@ -974,60 +1189,129 @@ class StripeCardPayment extends Payment {
|
|
|
974
1189
|
return this.onSuccess();
|
|
975
1190
|
}
|
|
976
1191
|
|
|
977
|
-
const intent = await this.
|
|
1192
|
+
const intent = await this._authorizeIntent(cart, paymentMethod.token);
|
|
978
1193
|
|
|
979
1194
|
await this.updateCart({
|
|
980
1195
|
billing: {
|
|
981
1196
|
method: 'card',
|
|
982
1197
|
card: paymentMethod,
|
|
983
|
-
intent: {
|
|
984
|
-
stripe: {
|
|
985
|
-
id: intent.id,
|
|
986
|
-
...(Boolean(cart.auth_total) && {
|
|
987
|
-
auth_amount: cart.auth_total,
|
|
988
|
-
}),
|
|
989
|
-
},
|
|
990
|
-
},
|
|
1198
|
+
intent: { stripe: cartIntent(cart, intent) },
|
|
991
1199
|
},
|
|
992
1200
|
});
|
|
993
1201
|
|
|
994
1202
|
this.onSuccess();
|
|
995
1203
|
}
|
|
996
1204
|
|
|
997
|
-
|
|
998
|
-
|
|
1205
|
+
// A card the shopper already has (a saved card, a wallet's payment method) gets
|
|
1206
|
+
// the intent and 3-D Secure of a new one; other cards are authorized with the order
|
|
1207
|
+
async _authorizePaymentMethod(token) {
|
|
1208
|
+
const cart = await this.getCart();
|
|
999
1209
|
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1210
|
+
if (
|
|
1211
|
+
token.startsWith('pm_') &&
|
|
1212
|
+
isStripeChargeableAmount(cart.capture_total, cart.currency) &&
|
|
1213
|
+
this.params.createIntent !== false
|
|
1214
|
+
) {
|
|
1215
|
+
await this.loadScripts(this.scripts);
|
|
1216
|
+
|
|
1217
|
+
const intent = await this._authorizeIntent(cart, token);
|
|
1004
1218
|
|
|
1005
|
-
|
|
1006
|
-
|
|
1219
|
+
if (intent.id !== cart.billing?.intent?.stripe?.id) {
|
|
1220
|
+
await this.updateCart({
|
|
1221
|
+
billing: {
|
|
1222
|
+
method: 'card',
|
|
1223
|
+
intent: { stripe: cartIntent(cart, intent) },
|
|
1224
|
+
},
|
|
1225
|
+
});
|
|
1226
|
+
}
|
|
1007
1227
|
}
|
|
1008
1228
|
|
|
1009
|
-
|
|
1229
|
+
this.onSuccess();
|
|
1230
|
+
}
|
|
1010
1231
|
|
|
1232
|
+
// Reuses the cart's intent while Stripe still has it for this card and amount
|
|
1233
|
+
async _authorizeIntent(cart, token) {
|
|
1234
|
+
const exIntent = cart.billing?.intent?.stripe;
|
|
1235
|
+
const intent =
|
|
1236
|
+
(exIntent?.client_secret &&
|
|
1237
|
+
(await this._retrieveIntent(cart, exIntent, token))) ||
|
|
1238
|
+
(await this._createIntent(cart, token));
|
|
1239
|
+
|
|
1240
|
+
switch (intent.status) {
|
|
1241
|
+
case 'requires_capture':
|
|
1242
|
+
break;
|
|
1243
|
+
|
|
1244
|
+
case 'requires_confirmation':
|
|
1245
|
+
await this._confirmCardPayment(intent);
|
|
1246
|
+
break;
|
|
1247
|
+
|
|
1248
|
+
case 'requires_action':
|
|
1249
|
+
case 'requires_source_action': {
|
|
1250
|
+
const actionResult = await this.stripe.handleCardAction(
|
|
1251
|
+
intent.client_secret,
|
|
1252
|
+
);
|
|
1253
|
+
|
|
1254
|
+
if (actionResult.error) {
|
|
1255
|
+
throw new Error(actionResult.error.message);
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
break;
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
default:
|
|
1262
|
+
throw new Error(`Unsupported intent status: ${intent.status}`);
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
return intent;
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
async _retrieveIntent(cart, exIntent, token) {
|
|
1269
|
+
const { paymentIntent: intent, error } =
|
|
1270
|
+
await this.stripe.retrievePaymentIntent(exIntent.client_secret);
|
|
1271
|
+
|
|
1272
|
+
const matches =
|
|
1273
|
+
!error &&
|
|
1274
|
+
intent.amount === intentAmount(cart) &&
|
|
1275
|
+
intent.currency === intentCurrency(cart) &&
|
|
1276
|
+
intent.payment_method === token &&
|
|
1277
|
+
!['canceled', 'requires_source', 'requires_payment_method'].includes(
|
|
1278
|
+
intent.status,
|
|
1279
|
+
);
|
|
1280
|
+
|
|
1281
|
+
return matches ? intent : null;
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
async authenticate(payment) {
|
|
1285
|
+
const { transaction_id: id, card: { token } = {} } = payment;
|
|
1286
|
+
|
|
1287
|
+
// The payment is re-queried whatever happens here: an intent the shopper
|
|
1288
|
+
// already confirmed can't be updated, and the payment must still learn it
|
|
1011
1289
|
try {
|
|
1012
|
-
const
|
|
1290
|
+
const intent = await this.updateIntent({
|
|
1291
|
+
gateway: 'stripe',
|
|
1292
|
+
intent: { id, payment_method: token },
|
|
1293
|
+
});
|
|
1013
1294
|
|
|
1014
|
-
|
|
1295
|
+
if (intent.error) {
|
|
1296
|
+
throw new Error(intent.error.message);
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
await this.loadScripts(this.scripts);
|
|
1300
|
+
|
|
1301
|
+
return await this._confirmCardPayment(intent);
|
|
1015
1302
|
} finally {
|
|
1016
1303
|
await this.resetAsyncPayment(payment.id);
|
|
1017
1304
|
}
|
|
1018
1305
|
}
|
|
1019
1306
|
|
|
1020
|
-
async _createIntent(cart,
|
|
1021
|
-
const
|
|
1022
|
-
const stripeCustomer = account && account.stripe_customer;
|
|
1023
|
-
const stripeCurrency = (currency || 'USD').toLowerCase();
|
|
1024
|
-
const amount = stripeAmountByCurrency(currency, capture_total + auth_total);
|
|
1307
|
+
async _createIntent(cart, token) {
|
|
1308
|
+
const stripeCustomer = cart.account && cart.account.stripe_customer;
|
|
1025
1309
|
const intent = await this.createIntent({
|
|
1026
1310
|
gateway: 'stripe',
|
|
1027
1311
|
intent: {
|
|
1028
|
-
amount,
|
|
1029
|
-
currency:
|
|
1030
|
-
payment_method:
|
|
1312
|
+
amount: intentAmount(cart),
|
|
1313
|
+
currency: intentCurrency(cart),
|
|
1314
|
+
payment_method: token,
|
|
1031
1315
|
capture_method: 'manual',
|
|
1032
1316
|
setup_future_usage: 'off_session',
|
|
1033
1317
|
...(stripeCustomer ? { customer: stripeCustomer } : {}),
|
|
@@ -1038,20 +1322,6 @@ class StripeCardPayment extends Payment {
|
|
|
1038
1322
|
throw new Error('Stripe payment intent is not defined');
|
|
1039
1323
|
}
|
|
1040
1324
|
|
|
1041
|
-
switch (intent.status) {
|
|
1042
|
-
case 'requires_capture':
|
|
1043
|
-
case 'requires_confirmation':
|
|
1044
|
-
break;
|
|
1045
|
-
|
|
1046
|
-
default:
|
|
1047
|
-
throw new Error(`Unsupported intent status: ${intent.status}`);
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1050
|
-
// Confirm the payment intent
|
|
1051
|
-
if (intent.status === 'requires_confirmation') {
|
|
1052
|
-
await this._confirmCardPayment(intent);
|
|
1053
|
-
}
|
|
1054
|
-
|
|
1055
1325
|
return intent;
|
|
1056
1326
|
}
|
|
1057
1327
|
|
|
@@ -1119,24 +1389,58 @@ class StripeIDealPayment extends Payment {
|
|
|
1119
1389
|
StripeIDealPayment.stripeElement = stripeElement;
|
|
1120
1390
|
}
|
|
1121
1391
|
|
|
1122
|
-
|
|
1392
|
+
/** @returns {import('@stripe/stripe-js').StripeElements} */
|
|
1393
|
+
get stripeElements() {
|
|
1394
|
+
return StripeIDealPayment.stripeElements;
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
/** @param {import('@stripe/stripe-js').StripeElements} stripeElements */
|
|
1398
|
+
set stripeElements(stripeElements) {
|
|
1399
|
+
StripeIDealPayment.stripeElements = stripeElements;
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
/** @param {import('../../../types').Cart} cart */
|
|
1403
|
+
async createElements(cart) {
|
|
1123
1404
|
await this.loadScripts(this.scripts);
|
|
1124
1405
|
|
|
1406
|
+
if (this.params.paymentElement) {
|
|
1407
|
+
this.stripeElements = createPaymentElements(
|
|
1408
|
+
this.stripe,
|
|
1409
|
+
getIDealElementsOptions(cart),
|
|
1410
|
+
this.params,
|
|
1411
|
+
);
|
|
1412
|
+
|
|
1413
|
+
return;
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1125
1416
|
const elements = this.stripe.elements(this.params.config);
|
|
1126
1417
|
|
|
1127
1418
|
this.stripeElement = createElement('idealBank', elements, this.params);
|
|
1128
1419
|
}
|
|
1129
1420
|
|
|
1130
1421
|
async tokenize() {
|
|
1131
|
-
|
|
1422
|
+
const { paymentElement } = this.params;
|
|
1423
|
+
|
|
1424
|
+
if (paymentElement && !this.stripeElements) {
|
|
1132
1425
|
throw new Error('Stripe payment element is not defined');
|
|
1133
1426
|
}
|
|
1134
1427
|
|
|
1135
1428
|
await this.loadScripts(this.scripts);
|
|
1136
1429
|
|
|
1137
1430
|
const cart = await this.getCart();
|
|
1138
|
-
const { paymentMethod, error: paymentMethodError } =
|
|
1139
|
-
await
|
|
1431
|
+
const { paymentMethod, error: paymentMethodError } = paymentElement
|
|
1432
|
+
? await createPaymentMethodFromElements(
|
|
1433
|
+
this.stripe,
|
|
1434
|
+
this.stripeElements,
|
|
1435
|
+
getIDealElementsOptions(cart),
|
|
1436
|
+
cart,
|
|
1437
|
+
)
|
|
1438
|
+
: // without an idealBank element the shopper picks the bank on the iDEAL page
|
|
1439
|
+
await createIDealPaymentMethod(
|
|
1440
|
+
this.stripe,
|
|
1441
|
+
this.stripeElement || {},
|
|
1442
|
+
cart,
|
|
1443
|
+
);
|
|
1140
1444
|
|
|
1141
1445
|
if (paymentMethodError) {
|
|
1142
1446
|
throw new Error(paymentMethodError.message);
|
|
@@ -1147,6 +1451,38 @@ class StripeIDealPayment extends Payment {
|
|
|
1147
1451
|
await this.stripe.handleCardAction(intent.client_secret);
|
|
1148
1452
|
}
|
|
1149
1453
|
|
|
1454
|
+
async handleRedirect(queryParams) {
|
|
1455
|
+
const { redirect_status, payment_intent_client_secret } = queryParams;
|
|
1456
|
+
|
|
1457
|
+
if (redirect_status !== 'succeeded') {
|
|
1458
|
+
throw new UnableAuthenticatePaymentMethodError();
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
await this.loadScripts(this.scripts);
|
|
1462
|
+
|
|
1463
|
+
const { paymentIntent, error } = await this.stripe.retrievePaymentIntent(
|
|
1464
|
+
payment_intent_client_secret,
|
|
1465
|
+
);
|
|
1466
|
+
|
|
1467
|
+
if (error) {
|
|
1468
|
+
throw new Error(error.message);
|
|
1469
|
+
}
|
|
1470
|
+
|
|
1471
|
+
if (
|
|
1472
|
+
!['succeeded', 'requires_capture', 'processing'].includes(
|
|
1473
|
+
paymentIntent.status,
|
|
1474
|
+
)
|
|
1475
|
+
) {
|
|
1476
|
+
throw new Error(
|
|
1477
|
+
paymentIntent.last_payment_error?.message ||
|
|
1478
|
+
`Unsupported intent status (${paymentIntent.status})`,
|
|
1479
|
+
);
|
|
1480
|
+
}
|
|
1481
|
+
|
|
1482
|
+
// the cart's billing was written in `tokenize`
|
|
1483
|
+
this.onSuccess();
|
|
1484
|
+
}
|
|
1485
|
+
|
|
1150
1486
|
/**
|
|
1151
1487
|
* @param {object} cart
|
|
1152
1488
|
* @param {import('@stripe/stripe-js').PaymentMethod} paymentMethod
|
|
@@ -1164,7 +1500,8 @@ class StripeIDealPayment extends Payment {
|
|
|
1164
1500
|
payment_method_types: 'ideal',
|
|
1165
1501
|
confirmation_method: 'manual',
|
|
1166
1502
|
confirm: true,
|
|
1167
|
-
|
|
1503
|
+
// `gateway` lets `handleRedirect` run on return; Stripe appends the intent and `redirect_status`
|
|
1504
|
+
return_url: getReturnUrl(),
|
|
1168
1505
|
},
|
|
1169
1506
|
});
|
|
1170
1507
|
|
|
@@ -1196,6 +1533,14 @@ class StripeIDealPayment extends Payment {
|
|
|
1196
1533
|
}
|
|
1197
1534
|
}
|
|
1198
1535
|
|
|
1536
|
+
function getReturnUrl() {
|
|
1537
|
+
const url = new URL(window.location.href);
|
|
1538
|
+
|
|
1539
|
+
url.searchParams.set('gateway', 'stripe');
|
|
1540
|
+
|
|
1541
|
+
return url.toString();
|
|
1542
|
+
}
|
|
1543
|
+
|
|
1199
1544
|
/** @typedef {import('@stripe/stripe-js').Stripe} Stripe */
|
|
1200
1545
|
|
|
1201
1546
|
class StripeBancontactPayment extends Payment {
|
|
@@ -1515,6 +1860,7 @@ class StripeGooglePayment extends Payment {
|
|
|
1515
1860
|
async _onPaymentMethod(event) {
|
|
1516
1861
|
const {
|
|
1517
1862
|
payerEmail,
|
|
1863
|
+
payerName,
|
|
1518
1864
|
paymentMethod: { id: paymentMethod, card, billing_details },
|
|
1519
1865
|
shippingAddress,
|
|
1520
1866
|
shippingOption,
|
|
@@ -1533,6 +1879,8 @@ class StripeGooglePayment extends Payment {
|
|
|
1533
1879
|
}),
|
|
1534
1880
|
billing: {
|
|
1535
1881
|
...this._mapBillingAddress(billing_details),
|
|
1882
|
+
// a wallet may leave the card's address without a name; the payer's, when asked for, fills it
|
|
1883
|
+
name: billing_details?.name || payerName,
|
|
1536
1884
|
method: 'card',
|
|
1537
1885
|
card: {
|
|
1538
1886
|
gateway: 'stripe',
|
|
@@ -1771,6 +2119,7 @@ class StripeApplePayment extends Payment {
|
|
|
1771
2119
|
async _onPaymentMethod(event) {
|
|
1772
2120
|
const {
|
|
1773
2121
|
payerEmail,
|
|
2122
|
+
payerName,
|
|
1774
2123
|
paymentMethod: { id: paymentMethod, card, billing_details },
|
|
1775
2124
|
shippingAddress,
|
|
1776
2125
|
shippingOption,
|
|
@@ -1789,6 +2138,8 @@ class StripeApplePayment extends Payment {
|
|
|
1789
2138
|
}),
|
|
1790
2139
|
billing: {
|
|
1791
2140
|
...this._mapBillingAddress(billing_details),
|
|
2141
|
+
// a wallet may leave the card's address without a name; the payer's, when asked for, fills it
|
|
2142
|
+
name: billing_details?.name || payerName,
|
|
1792
2143
|
method: 'card',
|
|
1793
2144
|
card: {
|
|
1794
2145
|
gateway: 'stripe',
|
|
@@ -4219,6 +4570,238 @@ class QuickpayCardPayment extends Payment {
|
|
|
4219
4570
|
}
|
|
4220
4571
|
}
|
|
4221
4572
|
|
|
4573
|
+
// Saferpay payment-page brands per Swell method id; a list is joined because the
|
|
4574
|
+
// vault rejects arrays in `PaymentMethods`
|
|
4575
|
+
const PAYMENT_METHODS = {
|
|
4576
|
+
card: [
|
|
4577
|
+
'AMEX',
|
|
4578
|
+
'DINERS',
|
|
4579
|
+
'MAESTRO',
|
|
4580
|
+
'JCB',
|
|
4581
|
+
'VISA',
|
|
4582
|
+
'BANCONTACT',
|
|
4583
|
+
'MASTERCARD',
|
|
4584
|
+
'SAFERPAYTEST',
|
|
4585
|
+
'UNIONPAY',
|
|
4586
|
+
].join(','),
|
|
4587
|
+
twint: 'TWINT',
|
|
4588
|
+
};
|
|
4589
|
+
|
|
4590
|
+
/**
|
|
4591
|
+
* @param {string} method 'card' or 'twint'
|
|
4592
|
+
* @returns {string}
|
|
4593
|
+
*/
|
|
4594
|
+
function getSaferpayPaymentMethods(method) {
|
|
4595
|
+
return PAYMENT_METHODS[method];
|
|
4596
|
+
}
|
|
4597
|
+
|
|
4598
|
+
/**
|
|
4599
|
+
* The Saferpay payment page request for a cart.
|
|
4600
|
+
*
|
|
4601
|
+
* @param {object} cart
|
|
4602
|
+
* @param {string} method 'card' or 'twint'
|
|
4603
|
+
* @returns {object}
|
|
4604
|
+
*/
|
|
4605
|
+
function getSaferpayPaymentPageData(cart, method) {
|
|
4606
|
+
const currency = (cart.currency || 'USD').toUpperCase();
|
|
4607
|
+
const returnUrl = window.location.origin + window.location.pathname;
|
|
4608
|
+
|
|
4609
|
+
return {
|
|
4610
|
+
Payment: {
|
|
4611
|
+
Amount: {
|
|
4612
|
+
Value: amountInCents(currency, cart.grand_total || 0),
|
|
4613
|
+
CurrencyCode: currency,
|
|
4614
|
+
},
|
|
4615
|
+
Description: 'Saferpay payment powered by Swell',
|
|
4616
|
+
},
|
|
4617
|
+
PaymentMethods: getSaferpayPaymentMethods(method),
|
|
4618
|
+
ReturnUrls: {
|
|
4619
|
+
Success: `${returnUrl}?gateway=saferpay&redirect_status=succeeded`,
|
|
4620
|
+
Fail: `${returnUrl}?gateway=saferpay&redirect_status=failed`,
|
|
4621
|
+
Abort: `${returnUrl}?gateway=saferpay&redirect_status=canceled`,
|
|
4622
|
+
},
|
|
4623
|
+
};
|
|
4624
|
+
}
|
|
4625
|
+
|
|
4626
|
+
/**
|
|
4627
|
+
* @param {object} state the Saferpay transaction state
|
|
4628
|
+
* @returns {boolean}
|
|
4629
|
+
*/
|
|
4630
|
+
function isSaferpayCardPayment(state) {
|
|
4631
|
+
const brand = state?.PaymentMeans?.Brand;
|
|
4632
|
+
|
|
4633
|
+
return Boolean(
|
|
4634
|
+
state?.RegistrationResult?.Success &&
|
|
4635
|
+
brand &&
|
|
4636
|
+
PAYMENT_METHODS.card.split(',').includes(brand.PaymentMethod),
|
|
4637
|
+
);
|
|
4638
|
+
}
|
|
4639
|
+
|
|
4640
|
+
/**
|
|
4641
|
+
* @param {object} state the Saferpay transaction state
|
|
4642
|
+
* @returns {boolean}
|
|
4643
|
+
*/
|
|
4644
|
+
function isSaferpayTwintPayment(state) {
|
|
4645
|
+
return state?.PaymentMeans?.Brand?.PaymentMethod === 'TWINT';
|
|
4646
|
+
}
|
|
4647
|
+
|
|
4648
|
+
/**
|
|
4649
|
+
* The card stored on the cart's billing from a Saferpay card state.
|
|
4650
|
+
*
|
|
4651
|
+
* @param {object} state
|
|
4652
|
+
* @returns {object}
|
|
4653
|
+
*/
|
|
4654
|
+
function getSaferpayCard(state) {
|
|
4655
|
+
const {
|
|
4656
|
+
RegistrationResult: {
|
|
4657
|
+
Alias: { Id: token },
|
|
4658
|
+
},
|
|
4659
|
+
PaymentMeans: {
|
|
4660
|
+
Card: { ExpMonth: exp_month, ExpYear: exp_year, MaskedNumber },
|
|
4661
|
+
Brand: { Name: brand },
|
|
4662
|
+
},
|
|
4663
|
+
} = state;
|
|
4664
|
+
|
|
4665
|
+
return {
|
|
4666
|
+
token,
|
|
4667
|
+
exp_month,
|
|
4668
|
+
exp_year,
|
|
4669
|
+
brand,
|
|
4670
|
+
last4: MaskedNumber.slice(-4),
|
|
4671
|
+
gateway: 'saferpay',
|
|
4672
|
+
};
|
|
4673
|
+
}
|
|
4674
|
+
|
|
4675
|
+
/**
|
|
4676
|
+
* @param {object} state
|
|
4677
|
+
* @returns {string | undefined}
|
|
4678
|
+
*/
|
|
4679
|
+
function getSaferpayTransactionId(state) {
|
|
4680
|
+
return state?.Transaction?.Id;
|
|
4681
|
+
}
|
|
4682
|
+
|
|
4683
|
+
/**
|
|
4684
|
+
* Saferpay payment page: `tokenize` sends the shopper to Saferpay, and
|
|
4685
|
+
* `handleRedirect` turns the returned transaction into the cart's billing.
|
|
4686
|
+
* The card and TWINT classes share it; each one handles only the redirect of
|
|
4687
|
+
* the method the cart was tokenized with, so a host can pass both.
|
|
4688
|
+
*/
|
|
4689
|
+
class SaferpayPayment extends Payment {
|
|
4690
|
+
constructor(api, options, params, methods, methodId) {
|
|
4691
|
+
super(api, options, params, methods[methodId]);
|
|
4692
|
+
this.methodId = methodId;
|
|
4693
|
+
this.cardMethod = methods.card;
|
|
4694
|
+
}
|
|
4695
|
+
|
|
4696
|
+
async tokenize() {
|
|
4697
|
+
const cart = await this.getCart();
|
|
4698
|
+
|
|
4699
|
+
// a card Saferpay already registered on this cart pays again without a new page visit
|
|
4700
|
+
if (
|
|
4701
|
+
this.methodId === 'card' &&
|
|
4702
|
+
cart.billing?.card?.gateway === 'saferpay' &&
|
|
4703
|
+
!this.params?.replace
|
|
4704
|
+
) {
|
|
4705
|
+
return this.onSuccess();
|
|
4706
|
+
}
|
|
4707
|
+
|
|
4708
|
+
const intent = await this.createIntent({
|
|
4709
|
+
gateway: 'saferpay',
|
|
4710
|
+
intent: getSaferpayPaymentPageData(cart, this.methodId),
|
|
4711
|
+
});
|
|
4712
|
+
|
|
4713
|
+
if (!intent) {
|
|
4714
|
+
throw new Error('Saferpay payment page is not defined');
|
|
4715
|
+
}
|
|
4716
|
+
|
|
4717
|
+
await this.updateCart({
|
|
4718
|
+
billing: {
|
|
4719
|
+
method: this.methodId,
|
|
4720
|
+
intent: {
|
|
4721
|
+
saferpay: {
|
|
4722
|
+
token: intent.token,
|
|
4723
|
+
},
|
|
4724
|
+
},
|
|
4725
|
+
},
|
|
4726
|
+
});
|
|
4727
|
+
|
|
4728
|
+
window.location.replace(intent.redirect_url);
|
|
4729
|
+
}
|
|
4730
|
+
|
|
4731
|
+
async handleRedirect(queryParams) {
|
|
4732
|
+
const { redirect_status: status } = queryParams;
|
|
4733
|
+
const cart = await this.getCart();
|
|
4734
|
+
|
|
4735
|
+
// another Saferpay method of this host was tokenized: its instance answers
|
|
4736
|
+
if (cart.billing?.method !== this.methodId) {
|
|
4737
|
+
return;
|
|
4738
|
+
}
|
|
4739
|
+
|
|
4740
|
+
switch (status) {
|
|
4741
|
+
case 'succeeded':
|
|
4742
|
+
return this._handleSuccessfulRedirect(cart);
|
|
4743
|
+
case 'canceled':
|
|
4744
|
+
return this.onCancel();
|
|
4745
|
+
case 'failed':
|
|
4746
|
+
throw new UnableAuthenticatePaymentMethodError();
|
|
4747
|
+
default:
|
|
4748
|
+
throw new Error(`Unknown redirect status: ${status}.`);
|
|
4749
|
+
}
|
|
4750
|
+
}
|
|
4751
|
+
|
|
4752
|
+
async _handleSuccessfulRedirect(cart) {
|
|
4753
|
+
const token = cart.billing?.intent?.saferpay?.token;
|
|
4754
|
+
|
|
4755
|
+
if (!token) {
|
|
4756
|
+
throw new Error('Saferpay transaction token is not defined');
|
|
4757
|
+
}
|
|
4758
|
+
|
|
4759
|
+
const intent = await this.updateIntent({
|
|
4760
|
+
gateway: 'saferpay',
|
|
4761
|
+
intent: { token },
|
|
4762
|
+
});
|
|
4763
|
+
|
|
4764
|
+
if (!intent) {
|
|
4765
|
+
throw new Error('Saferpay transaction is not defined');
|
|
4766
|
+
}
|
|
4767
|
+
|
|
4768
|
+
const { state } = intent;
|
|
4769
|
+
const transaction = { transaction_id: getSaferpayTransactionId(state) };
|
|
4770
|
+
|
|
4771
|
+
if (isSaferpayCardPayment(state)) {
|
|
4772
|
+
const card = getSaferpayCard(state);
|
|
4773
|
+
|
|
4774
|
+
if (!isLiveMode(this.cardMethod?.mode)) {
|
|
4775
|
+
card.test = true;
|
|
4776
|
+
}
|
|
4777
|
+
|
|
4778
|
+
await this.updateCart({
|
|
4779
|
+
billing: { method: 'card', card, intent: { saferpay: transaction } },
|
|
4780
|
+
});
|
|
4781
|
+
} else if (isSaferpayTwintPayment(state)) {
|
|
4782
|
+
await this.updateCart({
|
|
4783
|
+
billing: { method: 'twint', intent: { saferpay: transaction } },
|
|
4784
|
+
});
|
|
4785
|
+
} else {
|
|
4786
|
+
throw new Error('Payment method not supported by this gateway.');
|
|
4787
|
+
}
|
|
4788
|
+
|
|
4789
|
+
this.onSuccess();
|
|
4790
|
+
}
|
|
4791
|
+
}
|
|
4792
|
+
|
|
4793
|
+
class SaferpayCardPayment extends SaferpayPayment {
|
|
4794
|
+
constructor(api, options, params, methods) {
|
|
4795
|
+
super(api, options, params, methods, 'card');
|
|
4796
|
+
}
|
|
4797
|
+
}
|
|
4798
|
+
|
|
4799
|
+
class SaferpayTwintPayment extends SaferpayPayment {
|
|
4800
|
+
constructor(api, options, params, methods) {
|
|
4801
|
+
super(api, options, params, methods, 'twint');
|
|
4802
|
+
}
|
|
4803
|
+
}
|
|
4804
|
+
|
|
4222
4805
|
let convesioSettings = null;
|
|
4223
4806
|
|
|
4224
4807
|
function getBaseConvesioApiUrl(mode) {
|
|
@@ -5899,6 +6482,33 @@ class PaymentController {
|
|
|
5899
6482
|
return this.api.request('get', '/payments', id);
|
|
5900
6483
|
}
|
|
5901
6484
|
|
|
6485
|
+
/**
|
|
6486
|
+
* Sends the shopper to the gateway when a submitted order waits for an
|
|
6487
|
+
* asynchronous payment; resolves `true` after starting the redirect.
|
|
6488
|
+
*
|
|
6489
|
+
* @param {object} order the result of `cart.submitOrder()`
|
|
6490
|
+
* @returns {Promise<boolean>}
|
|
6491
|
+
*/
|
|
6492
|
+
async handleAsyncRedirect(order) {
|
|
6493
|
+
const paymentId =
|
|
6494
|
+
order?.authorized_payment_id ?? order?.authorizedPaymentId;
|
|
6495
|
+
|
|
6496
|
+
if (order?.status !== 'payment_pending' || !paymentId) {
|
|
6497
|
+
return false;
|
|
6498
|
+
}
|
|
6499
|
+
|
|
6500
|
+
const payment = await this.get(paymentId);
|
|
6501
|
+
const url = payment?.async_data?.url ?? payment?.asyncData?.url;
|
|
6502
|
+
|
|
6503
|
+
if (!payment || payment.captured || !url) {
|
|
6504
|
+
return false;
|
|
6505
|
+
}
|
|
6506
|
+
|
|
6507
|
+
window.location.replace(url);
|
|
6508
|
+
|
|
6509
|
+
return true;
|
|
6510
|
+
}
|
|
6511
|
+
|
|
5902
6512
|
async methods() {
|
|
5903
6513
|
if (this.methodSettings) {
|
|
5904
6514
|
return this.methodSettings;
|
|
@@ -5916,7 +6526,7 @@ class PaymentController {
|
|
|
5916
6526
|
throw new Error('Payment element parameters are not provided');
|
|
5917
6527
|
}
|
|
5918
6528
|
|
|
5919
|
-
const paymentInstances = await this._createPaymentInstances();
|
|
6529
|
+
const paymentInstances = await this._createPaymentInstances(params);
|
|
5920
6530
|
const cart = await this.payment.getCart();
|
|
5921
6531
|
|
|
5922
6532
|
await this._performPaymentAction(
|
|
@@ -5935,7 +6545,7 @@ class PaymentController {
|
|
|
5935
6545
|
throw new Error('Tokenization parameters are not provided');
|
|
5936
6546
|
}
|
|
5937
6547
|
|
|
5938
|
-
const paymentInstances = await this._createPaymentInstances();
|
|
6548
|
+
const paymentInstances = await this._createPaymentInstances(params);
|
|
5939
6549
|
|
|
5940
6550
|
await this._performPaymentAction(paymentInstances, 'tokenize');
|
|
5941
6551
|
}
|
|
@@ -5955,7 +6565,7 @@ class PaymentController {
|
|
|
5955
6565
|
|
|
5956
6566
|
removeUrlParams();
|
|
5957
6567
|
|
|
5958
|
-
const paymentInstances = await this._createPaymentInstances();
|
|
6568
|
+
const paymentInstances = await this._createPaymentInstances(params);
|
|
5959
6569
|
|
|
5960
6570
|
await this._performPaymentAction(
|
|
5961
6571
|
paymentInstances,
|
|
@@ -6048,9 +6658,10 @@ class PaymentController {
|
|
|
6048
6658
|
/**
|
|
6049
6659
|
* @returns {Promise<Payment[]>}
|
|
6050
6660
|
*/
|
|
6051
|
-
|
|
6661
|
+
// Takes the caller's params: this.params can change while the methods load (two createElements at once)
|
|
6662
|
+
async _createPaymentInstances(callParams) {
|
|
6052
6663
|
const paymentMethods = await this._getPaymentMethods();
|
|
6053
|
-
const params = adjustParams(
|
|
6664
|
+
const params = adjustParams(callParams);
|
|
6054
6665
|
|
|
6055
6666
|
return Object.entries(params).reduce((acc, [method, params]) => {
|
|
6056
6667
|
const methodSettings = paymentMethods[method];
|
|
@@ -6148,6 +6759,8 @@ class PaymentController {
|
|
|
6148
6759
|
return this._getAmazonPaymentClass(gateway);
|
|
6149
6760
|
case 'sezzle':
|
|
6150
6761
|
return this._getSezzlePaymentClass(gateway);
|
|
6762
|
+
case 'twint':
|
|
6763
|
+
return this._getTwintPaymentClass(gateway);
|
|
6151
6764
|
default:
|
|
6152
6765
|
return null;
|
|
6153
6766
|
}
|
|
@@ -6161,6 +6774,17 @@ class PaymentController {
|
|
|
6161
6774
|
return QuickpayCardPayment;
|
|
6162
6775
|
case 'convesiopay':
|
|
6163
6776
|
return ConvesioCardPayment;
|
|
6777
|
+
case 'saferpay':
|
|
6778
|
+
return SaferpayCardPayment;
|
|
6779
|
+
default:
|
|
6780
|
+
return null;
|
|
6781
|
+
}
|
|
6782
|
+
}
|
|
6783
|
+
|
|
6784
|
+
_getTwintPaymentClass(gateway) {
|
|
6785
|
+
switch (gateway) {
|
|
6786
|
+
case 'saferpay':
|
|
6787
|
+
return SaferpayTwintPayment;
|
|
6164
6788
|
default:
|
|
6165
6789
|
return null;
|
|
6166
6790
|
}
|