swell-js 3.12.0 → 3.13.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/dist/api.js +1 -1
- package/dist/currency.js +3 -1
- package/dist/payment.js +202 -50
- package/dist/utils/klarna.js +143 -0
- package/package.json +1 -1
- package/src/currency.js +2 -0
- package/src/currency.test.js +7 -0
- package/src/payment.js +87 -8
- package/src/utils/klarna.js +104 -0
- package/test/page/components/sidebar/sidebar.js +1 -0
- package/test/page/containers/payment/klarna.js +101 -0
- package/test/page/containers/payment/payment.js +10 -0
- package/test/page/containers/payment/stripe.js +114 -19
package/dist/api.js
CHANGED
package/dist/currency.js
CHANGED
|
@@ -110,9 +110,11 @@ function methods(request, opt) {
|
|
|
110
110
|
var formatRate = params.rate || rate;
|
|
111
111
|
var formatLocale = params.locale || this.locale;
|
|
112
112
|
var formatDecimals = typeof params.decimals === 'number' ? params.decimals : decimals;
|
|
113
|
+
var _params$convert = params.convert,
|
|
114
|
+
convert = _params$convert === void 0 ? true : _params$convert;
|
|
113
115
|
var formatAmount = amount;
|
|
114
116
|
|
|
115
|
-
if ((type === 'display' || params.rate) && typeof formatAmount === 'number' && typeof formatRate === 'number') {
|
|
117
|
+
if (convert && (type === 'display' || params.rate) && typeof formatAmount === 'number' && typeof formatRate === 'number') {
|
|
116
118
|
// Convert the price currency into the display currency
|
|
117
119
|
formatAmount = this.applyRounding(amount * formatRate, state);
|
|
118
120
|
}
|
package/dist/payment.js
CHANGED
|
@@ -12,6 +12,12 @@ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (O
|
|
|
12
12
|
|
|
13
13
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
|
14
14
|
|
|
15
|
+
function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
|
|
16
|
+
|
|
17
|
+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
18
|
+
|
|
19
|
+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
|
|
20
|
+
|
|
15
21
|
var get = require('lodash/get');
|
|
16
22
|
|
|
17
23
|
var toLower = require('lodash/toLower');
|
|
@@ -42,6 +48,9 @@ var _require3 = require('./utils/quickpay'),
|
|
|
42
48
|
var _require4 = require('./utils/paysafecard'),
|
|
43
49
|
createPaysafecardPayment = _require4.createPaysafecardPayment;
|
|
44
50
|
|
|
51
|
+
var _require5 = require('./utils/klarna'),
|
|
52
|
+
createKlarnaSession = _require5.createKlarnaSession;
|
|
53
|
+
|
|
45
54
|
var LOADING_SCRIPTS = {};
|
|
46
55
|
var CARD_ELEMENTS = {};
|
|
47
56
|
var API = {};
|
|
@@ -605,7 +614,7 @@ function _stripeElements() {
|
|
|
605
614
|
case 0:
|
|
606
615
|
publishable_key = payMethods.card.publishable_key;
|
|
607
616
|
stripe = window.Stripe(publishable_key);
|
|
608
|
-
elements = stripe.elements();
|
|
617
|
+
elements = stripe.elements(params.config);
|
|
609
618
|
|
|
610
619
|
createElement = function createElement(type) {
|
|
611
620
|
var elementParams = get(params, "card[".concat(type, "]")) || params.card || params.ideal;
|
|
@@ -652,7 +661,7 @@ function payPalButton(_x16, _x17, _x18, _x19) {
|
|
|
652
661
|
|
|
653
662
|
function _payPalButton() {
|
|
654
663
|
_payPalButton = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee11(request, cart, payMethods, params) {
|
|
655
|
-
var paypal, _params$paypal, locale, style, elementId, onError, onSuccess;
|
|
664
|
+
var paypal, _params$paypal, locale, style, elementId, onError, onSuccess, _getTotalsDueRemainin, totalDue;
|
|
656
665
|
|
|
657
666
|
return _regenerator["default"].wrap(function _callee11$(_context11) {
|
|
658
667
|
while (1) {
|
|
@@ -678,6 +687,16 @@ function _payPalButton() {
|
|
|
678
687
|
return isFunction(successHandler) && successHandler();
|
|
679
688
|
};
|
|
680
689
|
|
|
690
|
+
_getTotalsDueRemainin = getTotalsDueRemaining(cart), totalDue = _getTotalsDueRemainin.totalDue;
|
|
691
|
+
|
|
692
|
+
if (totalDue > 0) {
|
|
693
|
+
_context11.next = 9;
|
|
694
|
+
break;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
throw new Error('Invalid PayPal button amount. Value should be greater than zero.');
|
|
698
|
+
|
|
699
|
+
case 9:
|
|
681
700
|
paypal.Buttons({
|
|
682
701
|
locale: locale || 'en_US',
|
|
683
702
|
style: style || {
|
|
@@ -693,7 +712,7 @@ function _payPalButton() {
|
|
|
693
712
|
intent: 'AUTHORIZE',
|
|
694
713
|
purchase_units: [{
|
|
695
714
|
amount: {
|
|
696
|
-
value:
|
|
715
|
+
value: +totalDue.toFixed(2),
|
|
697
716
|
currency_code: cart.currency
|
|
698
717
|
}
|
|
699
718
|
}]
|
|
@@ -704,10 +723,11 @@ function _payPalButton() {
|
|
|
704
723
|
var payer = authorization.payer;
|
|
705
724
|
var shipping = get(authorization, 'purchase_units[0].shipping');
|
|
706
725
|
var authorizationID = get(authorization, 'purchase_units[0].payments.authorizations[0].id');
|
|
707
|
-
return cartApi.methods(request).update({
|
|
726
|
+
return cartApi.methods(request).update(_objectSpread(_objectSpread({}, !cart.account_logged_in && {
|
|
708
727
|
account: {
|
|
709
728
|
email: payer.email_address
|
|
710
|
-
}
|
|
729
|
+
}
|
|
730
|
+
}), {}, {
|
|
711
731
|
billing: {
|
|
712
732
|
method: 'paypal',
|
|
713
733
|
paypal: {
|
|
@@ -723,12 +743,12 @@ function _payPalButton() {
|
|
|
723
743
|
zip: shipping.address.postal_code,
|
|
724
744
|
country: shipping.address.country_code
|
|
725
745
|
}
|
|
726
|
-
});
|
|
746
|
+
}));
|
|
727
747
|
}).then(onSuccess)["catch"](onError);
|
|
728
748
|
}
|
|
729
749
|
}, onError).render(elementId || '#paypal-button');
|
|
730
750
|
|
|
731
|
-
case
|
|
751
|
+
case 10:
|
|
732
752
|
case "end":
|
|
733
753
|
return _context11.stop();
|
|
734
754
|
}
|
|
@@ -830,7 +850,7 @@ function paymentTokenize(_x24, _x25, _x26, _x27) {
|
|
|
830
850
|
|
|
831
851
|
function _paymentTokenize() {
|
|
832
852
|
_paymentTokenize = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee13(request, params, payMethods, cart) {
|
|
833
|
-
var onError, stripe, paymentMethod, currency, amount, stripeCustomer, intent, _yield$stripe$confirm, paymentIntent, error, _intent, _yield$createIDealPay, _error, _paymentMethod, _currency, _amount, _intent2, publishable_key, _stripe, settings, _yield$createKlarnaSo, _error2, source, _publishable_key, _stripe2, _yield$createBanconta, _error3, _source, _intent3;
|
|
853
|
+
var onError, stripe, paymentMethod, currency, amount, stripeCustomer, intent, _yield$stripe$confirm, paymentIntent, error, _intent, _yield$createIDealPay, _error, _paymentMethod, _currency, _amount, _intent2, session, publishable_key, _stripe, settings, _yield$createKlarnaSo, _error2, source, _publishable_key, _stripe2, _yield$createBanconta, _error3, _source, _intent3;
|
|
834
854
|
|
|
835
855
|
return _regenerator["default"].wrap(function _callee13$(_context13) {
|
|
836
856
|
while (1) {
|
|
@@ -999,7 +1019,7 @@ function _paymentTokenize() {
|
|
|
999
1019
|
createQuickpayCard(methods(request).authorizeGateway)["catch"](onError);
|
|
1000
1020
|
|
|
1001
1021
|
case 48:
|
|
1002
|
-
_context13.next =
|
|
1022
|
+
_context13.next = 128;
|
|
1003
1023
|
break;
|
|
1004
1024
|
|
|
1005
1025
|
case 50:
|
|
@@ -1092,44 +1112,59 @@ function _paymentTokenize() {
|
|
|
1092
1112
|
return _context13.abrupt("return", _context13.t5);
|
|
1093
1113
|
|
|
1094
1114
|
case 75:
|
|
1095
|
-
_context13.next =
|
|
1115
|
+
_context13.next = 128;
|
|
1096
1116
|
break;
|
|
1097
1117
|
|
|
1098
1118
|
case 77:
|
|
1099
1119
|
if (!(params.klarna && payMethods.klarna)) {
|
|
1100
|
-
_context13.next =
|
|
1120
|
+
_context13.next = 104;
|
|
1121
|
+
break;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
if (!(payMethods.klarna.gateway === 'klarna')) {
|
|
1125
|
+
_context13.next = 85;
|
|
1101
1126
|
break;
|
|
1102
1127
|
}
|
|
1103
1128
|
|
|
1129
|
+
_context13.next = 81;
|
|
1130
|
+
return createKlarnaSession(cart, methods(request).createIntent)["catch"](function (err) {
|
|
1131
|
+
return onError(err);
|
|
1132
|
+
});
|
|
1133
|
+
|
|
1134
|
+
case 81:
|
|
1135
|
+
session = _context13.sent;
|
|
1136
|
+
return _context13.abrupt("return", session && window.location.replace(session.redirect_url));
|
|
1137
|
+
|
|
1138
|
+
case 85:
|
|
1104
1139
|
if (!(payMethods.card && payMethods.card.gateway === 'stripe')) {
|
|
1105
|
-
_context13.next =
|
|
1140
|
+
_context13.next = 102;
|
|
1106
1141
|
break;
|
|
1107
1142
|
}
|
|
1108
1143
|
|
|
1109
1144
|
if (window.Stripe) {
|
|
1110
|
-
_context13.next =
|
|
1145
|
+
_context13.next = 89;
|
|
1111
1146
|
break;
|
|
1112
1147
|
}
|
|
1113
1148
|
|
|
1114
|
-
_context13.next =
|
|
1149
|
+
_context13.next = 89;
|
|
1115
1150
|
return loadScript('stripe-js', 'https://js.stripe.com/v3/');
|
|
1116
1151
|
|
|
1117
|
-
case
|
|
1152
|
+
case 89:
|
|
1118
1153
|
publishable_key = payMethods.card.publishable_key;
|
|
1119
1154
|
_stripe = window.Stripe(publishable_key);
|
|
1120
1155
|
_context13.t6 = toSnake;
|
|
1121
|
-
_context13.next =
|
|
1156
|
+
_context13.next = 94;
|
|
1122
1157
|
return settingsApi.methods(request, options).get();
|
|
1123
1158
|
|
|
1124
|
-
case
|
|
1159
|
+
case 94:
|
|
1125
1160
|
_context13.t7 = _context13.sent;
|
|
1126
1161
|
settings = (0, _context13.t6)(_context13.t7);
|
|
1127
|
-
_context13.next =
|
|
1162
|
+
_context13.next = 98;
|
|
1128
1163
|
return createKlarnaSource(_stripe, _objectSpread(_objectSpread({}, cart), {}, {
|
|
1129
1164
|
settings: settings.store
|
|
1130
1165
|
}));
|
|
1131
1166
|
|
|
1132
|
-
case
|
|
1167
|
+
case 98:
|
|
1133
1168
|
_yield$createKlarnaSo = _context13.sent;
|
|
1134
1169
|
_error2 = _yield$createKlarnaSo.error;
|
|
1135
1170
|
source = _yield$createKlarnaSo.source;
|
|
@@ -1143,36 +1178,36 @@ function _paymentTokenize() {
|
|
|
1143
1178
|
return onError(err);
|
|
1144
1179
|
}));
|
|
1145
1180
|
|
|
1146
|
-
case
|
|
1147
|
-
_context13.next =
|
|
1181
|
+
case 102:
|
|
1182
|
+
_context13.next = 128;
|
|
1148
1183
|
break;
|
|
1149
1184
|
|
|
1150
|
-
case
|
|
1185
|
+
case 104:
|
|
1151
1186
|
if (!(params.bancontact && payMethods.bancontact)) {
|
|
1152
|
-
_context13.next =
|
|
1187
|
+
_context13.next = 119;
|
|
1153
1188
|
break;
|
|
1154
1189
|
}
|
|
1155
1190
|
|
|
1156
1191
|
if (!(payMethods.card && payMethods.card.gateway === 'stripe')) {
|
|
1157
|
-
_context13.next =
|
|
1192
|
+
_context13.next = 117;
|
|
1158
1193
|
break;
|
|
1159
1194
|
}
|
|
1160
1195
|
|
|
1161
1196
|
if (window.Stripe) {
|
|
1162
|
-
_context13.next =
|
|
1197
|
+
_context13.next = 109;
|
|
1163
1198
|
break;
|
|
1164
1199
|
}
|
|
1165
1200
|
|
|
1166
|
-
_context13.next =
|
|
1201
|
+
_context13.next = 109;
|
|
1167
1202
|
return loadScript('stripe-js', 'https://js.stripe.com/v3/');
|
|
1168
1203
|
|
|
1169
|
-
case
|
|
1204
|
+
case 109:
|
|
1170
1205
|
_publishable_key = payMethods.card.publishable_key;
|
|
1171
1206
|
_stripe2 = window.Stripe(_publishable_key);
|
|
1172
|
-
_context13.next =
|
|
1207
|
+
_context13.next = 113;
|
|
1173
1208
|
return createBancontactSource(_stripe2, cart);
|
|
1174
1209
|
|
|
1175
|
-
case
|
|
1210
|
+
case 113:
|
|
1176
1211
|
_yield$createBanconta = _context13.sent;
|
|
1177
1212
|
_error3 = _yield$createBanconta.error;
|
|
1178
1213
|
_source = _yield$createBanconta.source;
|
|
@@ -1186,31 +1221,31 @@ function _paymentTokenize() {
|
|
|
1186
1221
|
return onError(err);
|
|
1187
1222
|
}));
|
|
1188
1223
|
|
|
1189
|
-
case
|
|
1190
|
-
_context13.next =
|
|
1224
|
+
case 117:
|
|
1225
|
+
_context13.next = 128;
|
|
1191
1226
|
break;
|
|
1192
1227
|
|
|
1193
|
-
case
|
|
1228
|
+
case 119:
|
|
1194
1229
|
if (!(params.paysafecard && payMethods.paysafecard)) {
|
|
1195
|
-
_context13.next =
|
|
1230
|
+
_context13.next = 128;
|
|
1196
1231
|
break;
|
|
1197
1232
|
}
|
|
1198
1233
|
|
|
1199
|
-
_context13.next =
|
|
1234
|
+
_context13.next = 122;
|
|
1200
1235
|
return createPaysafecardPayment(cart, methods(request).createIntent)["catch"](onError);
|
|
1201
1236
|
|
|
1202
|
-
case
|
|
1237
|
+
case 122:
|
|
1203
1238
|
_intent3 = _context13.sent;
|
|
1204
1239
|
|
|
1205
1240
|
if (_intent3) {
|
|
1206
|
-
_context13.next =
|
|
1241
|
+
_context13.next = 125;
|
|
1207
1242
|
break;
|
|
1208
1243
|
}
|
|
1209
1244
|
|
|
1210
1245
|
return _context13.abrupt("return");
|
|
1211
1246
|
|
|
1212
|
-
case
|
|
1213
|
-
_context13.next =
|
|
1247
|
+
case 125:
|
|
1248
|
+
_context13.next = 127;
|
|
1214
1249
|
return cartApi.methods(request, options).update({
|
|
1215
1250
|
billing: {
|
|
1216
1251
|
method: 'paysafecard',
|
|
@@ -1222,10 +1257,10 @@ function _paymentTokenize() {
|
|
|
1222
1257
|
}
|
|
1223
1258
|
});
|
|
1224
1259
|
|
|
1225
|
-
case
|
|
1260
|
+
case 127:
|
|
1226
1261
|
return _context13.abrupt("return", window.location.replace(_intent3.redirect.auth_url));
|
|
1227
1262
|
|
|
1228
|
-
case
|
|
1263
|
+
case 128:
|
|
1229
1264
|
case "end":
|
|
1230
1265
|
return _context13.stop();
|
|
1231
1266
|
}
|
|
@@ -1247,7 +1282,7 @@ function _handleRedirect3() {
|
|
|
1247
1282
|
switch (_context14.prev = _context14.next) {
|
|
1248
1283
|
case 0:
|
|
1249
1284
|
onError = function onError(error) {
|
|
1250
|
-
var errorHandler = get(params, 'card.onError') || get(params, 'paysafecard.onError');
|
|
1285
|
+
var errorHandler = get(params, 'card.onError') || get(params, 'paysafecard.onError') || get(params, 'klarna.onError');
|
|
1251
1286
|
|
|
1252
1287
|
if (isFunction(errorHandler)) {
|
|
1253
1288
|
return errorHandler(error);
|
|
@@ -1257,7 +1292,7 @@ function _handleRedirect3() {
|
|
|
1257
1292
|
};
|
|
1258
1293
|
|
|
1259
1294
|
onSuccess = function onSuccess(result) {
|
|
1260
|
-
var successHandler = get(params, 'card.onSuccess') || get(params, 'paysafecard.onSuccess');
|
|
1295
|
+
var successHandler = get(params, 'card.onSuccess') || get(params, 'paysafecard.onSuccess') || get(params, 'klarna.onSuccess');
|
|
1261
1296
|
|
|
1262
1297
|
if (isFunction(successHandler)) {
|
|
1263
1298
|
return successHandler(result);
|
|
@@ -1280,12 +1315,12 @@ function _handleRedirect3() {
|
|
|
1280
1315
|
|
|
1281
1316
|
case 8:
|
|
1282
1317
|
result = _context14.sent;
|
|
1283
|
-
_context14.next =
|
|
1318
|
+
_context14.next = 21;
|
|
1284
1319
|
break;
|
|
1285
1320
|
|
|
1286
1321
|
case 11:
|
|
1287
1322
|
if (!(gateway === 'paysafecard')) {
|
|
1288
|
-
_context14.next =
|
|
1323
|
+
_context14.next = 17;
|
|
1289
1324
|
break;
|
|
1290
1325
|
}
|
|
1291
1326
|
|
|
@@ -1294,27 +1329,41 @@ function _handleRedirect3() {
|
|
|
1294
1329
|
|
|
1295
1330
|
case 14:
|
|
1296
1331
|
result = _context14.sent;
|
|
1332
|
+
_context14.next = 21;
|
|
1333
|
+
break;
|
|
1297
1334
|
|
|
1298
|
-
case
|
|
1335
|
+
case 17:
|
|
1336
|
+
if (!(gateway === 'klarna_direct')) {
|
|
1337
|
+
_context14.next = 21;
|
|
1338
|
+
break;
|
|
1339
|
+
}
|
|
1340
|
+
|
|
1341
|
+
_context14.next = 20;
|
|
1342
|
+
return handleDirectKlarnaRedirectAction(request, cart, params, queryParams);
|
|
1343
|
+
|
|
1344
|
+
case 20:
|
|
1345
|
+
result = _context14.sent;
|
|
1346
|
+
|
|
1347
|
+
case 21:
|
|
1299
1348
|
if (result) {
|
|
1300
|
-
_context14.next =
|
|
1349
|
+
_context14.next = 25;
|
|
1301
1350
|
break;
|
|
1302
1351
|
}
|
|
1303
1352
|
|
|
1304
1353
|
return _context14.abrupt("return");
|
|
1305
1354
|
|
|
1306
|
-
case
|
|
1355
|
+
case 25:
|
|
1307
1356
|
if (!result.error) {
|
|
1308
|
-
_context14.next =
|
|
1357
|
+
_context14.next = 29;
|
|
1309
1358
|
break;
|
|
1310
1359
|
}
|
|
1311
1360
|
|
|
1312
1361
|
return _context14.abrupt("return", onError(result.error));
|
|
1313
1362
|
|
|
1314
|
-
case
|
|
1363
|
+
case 29:
|
|
1315
1364
|
return _context14.abrupt("return", onSuccess(result));
|
|
1316
1365
|
|
|
1317
|
-
case
|
|
1366
|
+
case 30:
|
|
1318
1367
|
case "end":
|
|
1319
1368
|
return _context14.stop();
|
|
1320
1369
|
}
|
|
@@ -1477,6 +1526,109 @@ function _handlePaysafecardRedirectAction() {
|
|
|
1477
1526
|
return _handlePaysafecardRedirectAction.apply(this, arguments);
|
|
1478
1527
|
}
|
|
1479
1528
|
|
|
1529
|
+
function handleDirectKlarnaRedirectAction(_x37, _x38, _x39, _x40) {
|
|
1530
|
+
return _handleDirectKlarnaRedirectAction.apply(this, arguments);
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
function _handleDirectKlarnaRedirectAction() {
|
|
1534
|
+
_handleDirectKlarnaRedirectAction = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee17(request, cart, params, queryParams) {
|
|
1535
|
+
var authorization_token;
|
|
1536
|
+
return _regenerator["default"].wrap(function _callee17$(_context17) {
|
|
1537
|
+
while (1) {
|
|
1538
|
+
switch (_context17.prev = _context17.next) {
|
|
1539
|
+
case 0:
|
|
1540
|
+
authorization_token = queryParams.authorization_token;
|
|
1541
|
+
|
|
1542
|
+
if (authorization_token) {
|
|
1543
|
+
_context17.next = 3;
|
|
1544
|
+
break;
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
return _context17.abrupt("return", {
|
|
1548
|
+
error: {
|
|
1549
|
+
message: 'We are unable to authenticate your payment method. Please choose a different payment method and try again.'
|
|
1550
|
+
}
|
|
1551
|
+
});
|
|
1552
|
+
|
|
1553
|
+
case 3:
|
|
1554
|
+
_context17.next = 5;
|
|
1555
|
+
return cartApi.methods(request, options).update({
|
|
1556
|
+
billing: {
|
|
1557
|
+
method: 'klarna',
|
|
1558
|
+
klarna: {
|
|
1559
|
+
token: authorization_token
|
|
1560
|
+
}
|
|
1561
|
+
}
|
|
1562
|
+
});
|
|
1563
|
+
|
|
1564
|
+
case 5:
|
|
1565
|
+
return _context17.abrupt("return", {
|
|
1566
|
+
success: true
|
|
1567
|
+
});
|
|
1568
|
+
|
|
1569
|
+
case 6:
|
|
1570
|
+
case "end":
|
|
1571
|
+
return _context17.stop();
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
}, _callee17);
|
|
1575
|
+
}));
|
|
1576
|
+
return _handleDirectKlarnaRedirectAction.apply(this, arguments);
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
function getTotalsDueRemaining(cart) {
|
|
1580
|
+
var grand_total = cart.grand_total,
|
|
1581
|
+
account = cart.account,
|
|
1582
|
+
account_credit_amount = cart.account_credit_amount,
|
|
1583
|
+
giftcards = cart.giftcards;
|
|
1584
|
+
var totalDue = grand_total;
|
|
1585
|
+
var totalRemaining = 0;
|
|
1586
|
+
var totalRemainingGiftcard = 0;
|
|
1587
|
+
var totalRemainingAccount = 0;
|
|
1588
|
+
|
|
1589
|
+
if (giftcards && giftcards.length > 0) {
|
|
1590
|
+
var _iterator = _createForOfIteratorHelper(giftcards),
|
|
1591
|
+
_step;
|
|
1592
|
+
|
|
1593
|
+
try {
|
|
1594
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
1595
|
+
var gc = _step.value;
|
|
1596
|
+
totalDue -= gc.amount;
|
|
1597
|
+
}
|
|
1598
|
+
} catch (err) {
|
|
1599
|
+
_iterator.e(err);
|
|
1600
|
+
} finally {
|
|
1601
|
+
_iterator.f();
|
|
1602
|
+
}
|
|
1603
|
+
|
|
1604
|
+
if (totalDue < 0) {
|
|
1605
|
+
totalRemainingGiftcard = -totalDue;
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1609
|
+
var accountCreditAmount = typeof account_credit_amount === 'number' ? account_credit_amount : account && account.balance;
|
|
1610
|
+
|
|
1611
|
+
if (accountCreditAmount > 0) {
|
|
1612
|
+
totalDue -= accountCreditAmount;
|
|
1613
|
+
|
|
1614
|
+
if (totalDue < 0) {
|
|
1615
|
+
totalRemainingAccount = -totalDue - totalRemainingGiftcard;
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
if (totalDue < 0) {
|
|
1620
|
+
totalRemaining = -totalDue;
|
|
1621
|
+
totalDue = 0;
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
return {
|
|
1625
|
+
totalDue: totalDue,
|
|
1626
|
+
totalRemaining: totalRemaining,
|
|
1627
|
+
totalRemainingGiftcard: totalRemainingGiftcard,
|
|
1628
|
+
totalRemainingAccount: totalRemainingAccount
|
|
1629
|
+
};
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1480
1632
|
module.exports = {
|
|
1481
1633
|
methods: methods
|
|
1482
1634
|
};
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
|
|
5
|
+
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
|
|
6
|
+
|
|
7
|
+
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
|
|
8
|
+
|
|
9
|
+
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
|
|
10
|
+
|
|
11
|
+
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
|
|
12
|
+
|
|
13
|
+
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
|
14
|
+
|
|
15
|
+
var _require = require('lodash'),
|
|
16
|
+
map = _require.map,
|
|
17
|
+
get = _require.get,
|
|
18
|
+
reduce = _require.reduce,
|
|
19
|
+
toNumber = _require.toNumber;
|
|
20
|
+
|
|
21
|
+
var addressFieldsMap = {
|
|
22
|
+
given_name: 'first_name',
|
|
23
|
+
family_name: 'last_name',
|
|
24
|
+
city: 'city',
|
|
25
|
+
country: 'country',
|
|
26
|
+
phone: 'phone',
|
|
27
|
+
postal_code: 'zip',
|
|
28
|
+
street_address: 'address1',
|
|
29
|
+
street_address2: 'address2',
|
|
30
|
+
region: 'state'
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
var mapFields = function mapFields(fieldsMap, data) {
|
|
34
|
+
return reduce(fieldsMap, function (acc, srcKey, destKey) {
|
|
35
|
+
var value = data[srcKey];
|
|
36
|
+
|
|
37
|
+
if (value) {
|
|
38
|
+
acc[destKey] = value;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return acc;
|
|
42
|
+
}, {});
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
var mapAddressFields = function mapAddressFields(cart, addressField) {
|
|
46
|
+
return _objectSpread(_objectSpread({}, mapFields(addressFieldsMap, cart[addressField])), {}, {
|
|
47
|
+
email: get(cart, 'account.email')
|
|
48
|
+
});
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
function getOrderLines(cart) {
|
|
52
|
+
var items = map(cart.items, function (item) {
|
|
53
|
+
return {
|
|
54
|
+
type: 'physical',
|
|
55
|
+
name: get(item, 'product.name'),
|
|
56
|
+
reference: get(item, 'product.sku') || get(item, 'product.slug'),
|
|
57
|
+
quantity: item.quantity,
|
|
58
|
+
unit_price: Math.round(toNumber(item.price - item.discount_each) * 100),
|
|
59
|
+
total_amount: Math.round(toNumber(item.price_total - item.discount_total) * 100),
|
|
60
|
+
tax_rate: 0,
|
|
61
|
+
total_tax_amount: 0
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
var tax = get(cart, 'tax_included_total');
|
|
65
|
+
var taxAmount = toNumber(tax) * 100;
|
|
66
|
+
|
|
67
|
+
if (tax) {
|
|
68
|
+
items.push({
|
|
69
|
+
type: 'sales_tax',
|
|
70
|
+
name: 'Taxes',
|
|
71
|
+
quantity: 1,
|
|
72
|
+
unit_price: taxAmount,
|
|
73
|
+
total_amount: taxAmount,
|
|
74
|
+
tax_rate: 0,
|
|
75
|
+
total_tax_amount: 0
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
var shipping = get(cart, 'shipping', {});
|
|
80
|
+
var shippingTotal = get(cart, 'shipment_total', {});
|
|
81
|
+
var shippingAmount = toNumber(shippingTotal) * 100;
|
|
82
|
+
|
|
83
|
+
if (shipping.price) {
|
|
84
|
+
items.push({
|
|
85
|
+
type: 'shipping_fee',
|
|
86
|
+
name: shipping.service_name,
|
|
87
|
+
quantity: 1,
|
|
88
|
+
unit_price: shippingAmount,
|
|
89
|
+
total_amount: shippingAmount,
|
|
90
|
+
tax_rate: 0,
|
|
91
|
+
total_tax_amount: 0
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return items;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function createKlarnaSession(_x, _x2) {
|
|
99
|
+
return _createKlarnaSession.apply(this, arguments);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function _createKlarnaSession() {
|
|
103
|
+
_createKlarnaSession = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee(cart, createIntent) {
|
|
104
|
+
var returnUrl, successUrl;
|
|
105
|
+
return _regenerator["default"].wrap(function _callee$(_context) {
|
|
106
|
+
while (1) {
|
|
107
|
+
switch (_context.prev = _context.next) {
|
|
108
|
+
case 0:
|
|
109
|
+
returnUrl = "".concat(window.location.origin).concat(window.location.pathname, "?gateway=klarna_direct&sid={{session_id}}");
|
|
110
|
+
successUrl = "".concat(returnUrl, "&authorization_token={{authorization_token}}");
|
|
111
|
+
return _context.abrupt("return", createIntent({
|
|
112
|
+
gateway: 'klarna',
|
|
113
|
+
intent: {
|
|
114
|
+
locale: get(cart, 'settings.locale') || 'en-US',
|
|
115
|
+
purchase_country: get(cart, 'billing.country') || get(cart, 'shipping.country'),
|
|
116
|
+
purchase_currency: cart.currency,
|
|
117
|
+
billing_address: mapAddressFields(cart, 'billing'),
|
|
118
|
+
shipping_address: mapAddressFields(cart, 'shipping'),
|
|
119
|
+
order_amount: Math.round(get(cart, 'grand_total', 0) * 100),
|
|
120
|
+
order_lines: JSON.stringify(getOrderLines(cart)),
|
|
121
|
+
merchant_urls: {
|
|
122
|
+
success: successUrl,
|
|
123
|
+
back: returnUrl,
|
|
124
|
+
cancel: returnUrl,
|
|
125
|
+
error: returnUrl,
|
|
126
|
+
failure: returnUrl
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}));
|
|
130
|
+
|
|
131
|
+
case 3:
|
|
132
|
+
case "end":
|
|
133
|
+
return _context.stop();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}, _callee);
|
|
137
|
+
}));
|
|
138
|
+
return _createKlarnaSession.apply(this, arguments);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
module.exports = {
|
|
142
|
+
createKlarnaSession: createKlarnaSession
|
|
143
|
+
};
|
package/package.json
CHANGED
package/src/currency.js
CHANGED
|
@@ -62,9 +62,11 @@ function methods(request, opt) {
|
|
|
62
62
|
const formatRate = params.rate || rate;
|
|
63
63
|
const formatLocale = params.locale || this.locale;
|
|
64
64
|
const formatDecimals = typeof params.decimals === 'number' ? params.decimals : decimals;
|
|
65
|
+
const { convert = true } = params;
|
|
65
66
|
|
|
66
67
|
let formatAmount = amount;
|
|
67
68
|
if (
|
|
69
|
+
convert &&
|
|
68
70
|
(type === 'display' || params.rate) &&
|
|
69
71
|
typeof formatAmount === 'number' &&
|
|
70
72
|
typeof formatRate === 'number'
|
package/src/currency.test.js
CHANGED
|
@@ -158,6 +158,13 @@ describe('currency', () => {
|
|
|
158
158
|
expect(formatted).toEqual('$0.77');
|
|
159
159
|
});
|
|
160
160
|
|
|
161
|
+
it('should not convert amount by selected display currency when convert flag is false', async () => {
|
|
162
|
+
await api.currency.select('USD');
|
|
163
|
+
const formatted = api.currency.format(1, { convert: false });
|
|
164
|
+
|
|
165
|
+
expect(formatted).toEqual('$1.00');
|
|
166
|
+
});
|
|
167
|
+
|
|
161
168
|
it('should convert amount by selected display currency with rounding (nearest whole)', async () => {
|
|
162
169
|
const config = api.currency.list().find((curr) => curr.code === 'CNY');
|
|
163
170
|
config.round = 'nearest';
|
package/src/payment.js
CHANGED
|
@@ -22,6 +22,7 @@ const {
|
|
|
22
22
|
getQuickpayCardDetais,
|
|
23
23
|
} = require('./utils/quickpay');
|
|
24
24
|
const { createPaysafecardPayment } = require('./utils/paysafecard');
|
|
25
|
+
const { createKlarnaSession } = require('./utils/klarna');
|
|
25
26
|
|
|
26
27
|
const LOADING_SCRIPTS = {};
|
|
27
28
|
const CARD_ELEMENTS = {};
|
|
@@ -223,7 +224,7 @@ const loadScript = async (id, src) => {
|
|
|
223
224
|
async function stripeElements(request, payMethods, params) {
|
|
224
225
|
const { publishable_key } = payMethods.card;
|
|
225
226
|
const stripe = window.Stripe(publishable_key);
|
|
226
|
-
const elements = stripe.elements();
|
|
227
|
+
const elements = stripe.elements(params.config);
|
|
227
228
|
const createElement = (type) => {
|
|
228
229
|
const elementParams = get(params, `card[${type}]`) || params.card || params.ideal;
|
|
229
230
|
const elementOptions = elementParams.options || {};
|
|
@@ -269,6 +270,12 @@ async function payPalButton(request, cart, payMethods, params) {
|
|
|
269
270
|
return isFunction(successHandler) && successHandler();
|
|
270
271
|
};
|
|
271
272
|
|
|
273
|
+
const { totalDue } = getTotalsDueRemaining(cart);
|
|
274
|
+
|
|
275
|
+
if (!(totalDue > 0)) {
|
|
276
|
+
throw new Error('Invalid PayPal button amount. Value should be greater than zero.');
|
|
277
|
+
}
|
|
278
|
+
|
|
272
279
|
paypal
|
|
273
280
|
.Buttons(
|
|
274
281
|
{
|
|
@@ -287,7 +294,7 @@ async function payPalButton(request, cart, payMethods, params) {
|
|
|
287
294
|
purchase_units: [
|
|
288
295
|
{
|
|
289
296
|
amount: {
|
|
290
|
-
value:
|
|
297
|
+
value: +totalDue.toFixed(2),
|
|
291
298
|
currency_code: cart.currency,
|
|
292
299
|
},
|
|
293
300
|
},
|
|
@@ -304,9 +311,11 @@ async function payPalButton(request, cart, payMethods, params) {
|
|
|
304
311
|
'purchase_units[0].payments.authorizations[0].id',
|
|
305
312
|
);
|
|
306
313
|
return cartApi.methods(request).update({
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
314
|
+
...(!cart.account_logged_in && {
|
|
315
|
+
account: {
|
|
316
|
+
email: payer.email_address,
|
|
317
|
+
},
|
|
318
|
+
}),
|
|
310
319
|
billing: { method: 'paypal', paypal: { authorization_id: authorizationID } },
|
|
311
320
|
shipping: {
|
|
312
321
|
name: shipping.name.full_name,
|
|
@@ -526,7 +535,12 @@ async function paymentTokenize(request, params, payMethods, cart) {
|
|
|
526
535
|
}
|
|
527
536
|
}
|
|
528
537
|
} else if (params.klarna && payMethods.klarna) {
|
|
529
|
-
if (payMethods.
|
|
538
|
+
if (payMethods.klarna.gateway === 'klarna') {
|
|
539
|
+
const session = await createKlarnaSession(cart, methods(request).createIntent).catch((err) =>
|
|
540
|
+
onError(err),
|
|
541
|
+
);
|
|
542
|
+
return session && window.location.replace(session.redirect_url);
|
|
543
|
+
} else if (payMethods.card && payMethods.card.gateway === 'stripe') {
|
|
530
544
|
if (!window.Stripe) {
|
|
531
545
|
await loadScript('stripe-js', 'https://js.stripe.com/v3/');
|
|
532
546
|
}
|
|
@@ -598,14 +612,20 @@ async function paymentTokenize(request, params, payMethods, cart) {
|
|
|
598
612
|
|
|
599
613
|
async function handleRedirect(request, params, cart) {
|
|
600
614
|
const onError = (error) => {
|
|
601
|
-
const errorHandler =
|
|
615
|
+
const errorHandler =
|
|
616
|
+
get(params, 'card.onError') ||
|
|
617
|
+
get(params, 'paysafecard.onError') ||
|
|
618
|
+
get(params, 'klarna.onError');
|
|
602
619
|
if (isFunction(errorHandler)) {
|
|
603
620
|
return errorHandler(error);
|
|
604
621
|
}
|
|
605
622
|
throw new Error(error.message);
|
|
606
623
|
};
|
|
607
624
|
const onSuccess = (result) => {
|
|
608
|
-
const successHandler =
|
|
625
|
+
const successHandler =
|
|
626
|
+
get(params, 'card.onSuccess') ||
|
|
627
|
+
get(params, 'paysafecard.onSuccess') ||
|
|
628
|
+
get(params, 'klarna.onSuccess');
|
|
609
629
|
if (isFunction(successHandler)) {
|
|
610
630
|
return successHandler(result);
|
|
611
631
|
}
|
|
@@ -620,6 +640,8 @@ async function handleRedirect(request, params, cart) {
|
|
|
620
640
|
result = await handleQuickpayRedirectAction(request, cart, params, queryParams);
|
|
621
641
|
} else if (gateway === 'paysafecard') {
|
|
622
642
|
result = await handlePaysafecardRedirectAction(request, cart, params, queryParams);
|
|
643
|
+
} else if (gateway === 'klarna_direct') {
|
|
644
|
+
result = await handleDirectKlarnaRedirectAction(request, cart, params, queryParams);
|
|
623
645
|
}
|
|
624
646
|
|
|
625
647
|
if (!result) {
|
|
@@ -695,6 +717,63 @@ async function handlePaysafecardRedirectAction(request, cart) {
|
|
|
695
717
|
}
|
|
696
718
|
}
|
|
697
719
|
|
|
720
|
+
async function handleDirectKlarnaRedirectAction(request, cart, params, queryParams) {
|
|
721
|
+
const { authorization_token } = queryParams;
|
|
722
|
+
|
|
723
|
+
if (!authorization_token) {
|
|
724
|
+
return {
|
|
725
|
+
error: {
|
|
726
|
+
message:
|
|
727
|
+
'We are unable to authenticate your payment method. Please choose a different payment method and try again.',
|
|
728
|
+
},
|
|
729
|
+
};
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
await cartApi.methods(request, options).update({
|
|
733
|
+
billing: {
|
|
734
|
+
method: 'klarna',
|
|
735
|
+
klarna: {
|
|
736
|
+
token: authorization_token,
|
|
737
|
+
},
|
|
738
|
+
},
|
|
739
|
+
});
|
|
740
|
+
return { success: true };
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
function getTotalsDueRemaining(cart) {
|
|
744
|
+
const { grand_total, account, account_credit_amount, giftcards } = cart;
|
|
745
|
+
|
|
746
|
+
let totalDue = grand_total;
|
|
747
|
+
let totalRemaining = 0;
|
|
748
|
+
let totalRemainingGiftcard = 0;
|
|
749
|
+
let totalRemainingAccount = 0;
|
|
750
|
+
|
|
751
|
+
if (giftcards && giftcards.length > 0) {
|
|
752
|
+
for (let gc of giftcards) {
|
|
753
|
+
totalDue -= gc.amount;
|
|
754
|
+
}
|
|
755
|
+
if (totalDue < 0) {
|
|
756
|
+
totalRemainingGiftcard = -totalDue;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
const accountCreditAmount =
|
|
761
|
+
typeof account_credit_amount === 'number' ? account_credit_amount : account && account.balance;
|
|
762
|
+
if (accountCreditAmount > 0) {
|
|
763
|
+
totalDue -= accountCreditAmount;
|
|
764
|
+
if (totalDue < 0) {
|
|
765
|
+
totalRemainingAccount = -totalDue - totalRemainingGiftcard;
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
if (totalDue < 0) {
|
|
770
|
+
totalRemaining = -totalDue;
|
|
771
|
+
totalDue = 0;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
return { totalDue, totalRemaining, totalRemainingGiftcard, totalRemainingAccount };
|
|
775
|
+
}
|
|
776
|
+
|
|
698
777
|
module.exports = {
|
|
699
778
|
methods,
|
|
700
779
|
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
const { map, get, reduce, toNumber } = require('lodash');
|
|
2
|
+
|
|
3
|
+
const addressFieldsMap = {
|
|
4
|
+
given_name: 'first_name',
|
|
5
|
+
family_name: 'last_name',
|
|
6
|
+
city: 'city',
|
|
7
|
+
country: 'country',
|
|
8
|
+
phone: 'phone',
|
|
9
|
+
postal_code: 'zip',
|
|
10
|
+
street_address: 'address1',
|
|
11
|
+
street_address2: 'address2',
|
|
12
|
+
region: 'state',
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const mapFields = (fieldsMap, data) =>
|
|
16
|
+
reduce(
|
|
17
|
+
fieldsMap,
|
|
18
|
+
(acc, srcKey, destKey) => {
|
|
19
|
+
const value = data[srcKey];
|
|
20
|
+
if (value) {
|
|
21
|
+
acc[destKey] = value;
|
|
22
|
+
}
|
|
23
|
+
return acc;
|
|
24
|
+
},
|
|
25
|
+
{},
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
const mapAddressFields = (cart, addressField) => ({
|
|
29
|
+
...mapFields(addressFieldsMap, cart[addressField]),
|
|
30
|
+
email: get(cart, 'account.email'),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
function getOrderLines(cart) {
|
|
34
|
+
const items = map(cart.items, (item) => ({
|
|
35
|
+
type: 'physical',
|
|
36
|
+
name: get(item, 'product.name'),
|
|
37
|
+
reference: get(item, 'product.sku') || get(item, 'product.slug'),
|
|
38
|
+
quantity: item.quantity,
|
|
39
|
+
unit_price: Math.round(toNumber(item.price - item.discount_each) * 100),
|
|
40
|
+
total_amount: Math.round(toNumber(item.price_total - item.discount_total) * 100),
|
|
41
|
+
tax_rate: 0,
|
|
42
|
+
total_tax_amount: 0,
|
|
43
|
+
}));
|
|
44
|
+
|
|
45
|
+
const tax = get(cart, 'tax_included_total');
|
|
46
|
+
const taxAmount = toNumber(tax) * 100;
|
|
47
|
+
if (tax) {
|
|
48
|
+
items.push({
|
|
49
|
+
type: 'sales_tax',
|
|
50
|
+
name: 'Taxes',
|
|
51
|
+
quantity: 1,
|
|
52
|
+
unit_price: taxAmount,
|
|
53
|
+
total_amount: taxAmount,
|
|
54
|
+
tax_rate: 0,
|
|
55
|
+
total_tax_amount: 0,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const shipping = get(cart, 'shipping', {});
|
|
60
|
+
const shippingTotal = get(cart, 'shipment_total', {});
|
|
61
|
+
const shippingAmount = toNumber(shippingTotal) * 100;
|
|
62
|
+
if (shipping.price) {
|
|
63
|
+
items.push({
|
|
64
|
+
type: 'shipping_fee',
|
|
65
|
+
name: shipping.service_name,
|
|
66
|
+
quantity: 1,
|
|
67
|
+
unit_price: shippingAmount,
|
|
68
|
+
total_amount: shippingAmount,
|
|
69
|
+
tax_rate: 0,
|
|
70
|
+
total_tax_amount: 0,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return items;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function createKlarnaSession(cart, createIntent) {
|
|
78
|
+
const returnUrl = `${window.location.origin}${window.location.pathname}?gateway=klarna_direct&sid={{session_id}}`;
|
|
79
|
+
const successUrl = `${returnUrl}&authorization_token={{authorization_token}}`;
|
|
80
|
+
|
|
81
|
+
return createIntent({
|
|
82
|
+
gateway: 'klarna',
|
|
83
|
+
intent: {
|
|
84
|
+
locale: get(cart, 'settings.locale') || 'en-US',
|
|
85
|
+
purchase_country: get(cart, 'billing.country') || get(cart, 'shipping.country'),
|
|
86
|
+
purchase_currency: cart.currency,
|
|
87
|
+
billing_address: mapAddressFields(cart, 'billing'),
|
|
88
|
+
shipping_address: mapAddressFields(cart, 'shipping'),
|
|
89
|
+
order_amount: Math.round(get(cart, 'grand_total', 0) * 100),
|
|
90
|
+
order_lines: JSON.stringify(getOrderLines(cart)),
|
|
91
|
+
merchant_urls: {
|
|
92
|
+
success: successUrl,
|
|
93
|
+
back: returnUrl,
|
|
94
|
+
cancel: returnUrl,
|
|
95
|
+
error: returnUrl,
|
|
96
|
+
failure: returnUrl,
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
module.exports = {
|
|
103
|
+
createKlarnaSession,
|
|
104
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { connect } from 'react-redux';
|
|
3
|
+
import { compose } from 'recompose';
|
|
4
|
+
import { withStyles } from '@material-ui/core/styles';
|
|
5
|
+
import { Card, CardContent, Button } from '@material-ui/core';
|
|
6
|
+
import Info from '../../components/info';
|
|
7
|
+
|
|
8
|
+
const styles = {
|
|
9
|
+
root: {
|
|
10
|
+
display: 'flex',
|
|
11
|
+
flexDirection: 'column',
|
|
12
|
+
},
|
|
13
|
+
input: {
|
|
14
|
+
margin: 20,
|
|
15
|
+
},
|
|
16
|
+
card: {
|
|
17
|
+
marginBottom: 20,
|
|
18
|
+
overflow: 'visible',
|
|
19
|
+
},
|
|
20
|
+
submitContainer: {
|
|
21
|
+
display: 'flex',
|
|
22
|
+
justifyContent: 'space-around',
|
|
23
|
+
},
|
|
24
|
+
button: {
|
|
25
|
+
width: '30%',
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
class Klarna extends React.Component {
|
|
30
|
+
constructor(props) {
|
|
31
|
+
super(props);
|
|
32
|
+
this.state = {
|
|
33
|
+
tokenized: false,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
componentDidMount() {
|
|
38
|
+
const { api, onError } = this.props;
|
|
39
|
+
api.payment.handleRedirect({
|
|
40
|
+
klarna: { onError, onSuccess: () => this.setState({ tokenized: true }) },
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
onClickTokenize(event) {
|
|
45
|
+
const { api, onError } = this.props;
|
|
46
|
+
|
|
47
|
+
event.preventDefault();
|
|
48
|
+
api.payment.tokenize({
|
|
49
|
+
klarna: {
|
|
50
|
+
onError,
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
render() {
|
|
56
|
+
const {
|
|
57
|
+
classes,
|
|
58
|
+
onOrderSubmit,
|
|
59
|
+
cart: { billing: { method, klarna } = {} },
|
|
60
|
+
} = this.props;
|
|
61
|
+
const { tokenized } = this.state;
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<div className={classes.root}>
|
|
65
|
+
<Card classes={{ root: classes.card }}>
|
|
66
|
+
<CardContent>
|
|
67
|
+
{tokenized && <Info title="Billing" source={{ method, klarna }} />}
|
|
68
|
+
<div className={classes.submitContainer}>
|
|
69
|
+
<Button
|
|
70
|
+
id="stripe-submit-button"
|
|
71
|
+
variant="contained"
|
|
72
|
+
color="primary"
|
|
73
|
+
size="small"
|
|
74
|
+
classes={{ root: classes.button }}
|
|
75
|
+
onClick={this.onClickTokenize.bind(this)}
|
|
76
|
+
>
|
|
77
|
+
Tokenize
|
|
78
|
+
</Button>
|
|
79
|
+
<Button
|
|
80
|
+
variant="contained"
|
|
81
|
+
color="secondary"
|
|
82
|
+
size="small"
|
|
83
|
+
disabled={!tokenized}
|
|
84
|
+
classes={{ root: classes.button }}
|
|
85
|
+
onClick={onOrderSubmit}
|
|
86
|
+
>
|
|
87
|
+
Submit
|
|
88
|
+
</Button>
|
|
89
|
+
</div>
|
|
90
|
+
</CardContent>
|
|
91
|
+
</Card>
|
|
92
|
+
</div>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const mapStateToProps = ({ api }) => ({
|
|
98
|
+
api,
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
export default compose(connect(mapStateToProps), withStyles(styles))(Klarna);
|
|
@@ -24,6 +24,7 @@ import StripeKlarna from './stripe-klarna';
|
|
|
24
24
|
import StripeBancontact from './stripe-bancontact';
|
|
25
25
|
import Quickpay from './quickpay';
|
|
26
26
|
import Paysafecard from './paysafecard';
|
|
27
|
+
import Klarna from './klarna';
|
|
27
28
|
import Info from '../../components/info';
|
|
28
29
|
|
|
29
30
|
const styles = {
|
|
@@ -186,6 +187,15 @@ class Payment extends React.Component {
|
|
|
186
187
|
onError={onError}
|
|
187
188
|
/>
|
|
188
189
|
);
|
|
190
|
+
case 'klarna':
|
|
191
|
+
return (
|
|
192
|
+
<Klarna
|
|
193
|
+
cart={cart}
|
|
194
|
+
onCartUpdate={onCartUpdate}
|
|
195
|
+
onOrderSubmit={onOrderSubmit}
|
|
196
|
+
onError={onError}
|
|
197
|
+
/>
|
|
198
|
+
);
|
|
189
199
|
case 'square':
|
|
190
200
|
return <Typography variant="h4">Coming soon</Typography>;
|
|
191
201
|
case 'braintree':
|
|
@@ -1,8 +1,17 @@
|
|
|
1
|
-
import React from 'react';
|
|
1
|
+
import React, { Fragment } from 'react';
|
|
2
2
|
import { connect } from 'react-redux';
|
|
3
3
|
import { compose } from 'recompose';
|
|
4
4
|
import { withStyles } from '@material-ui/core/styles';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
Card,
|
|
7
|
+
CardContent,
|
|
8
|
+
Button,
|
|
9
|
+
FormControl,
|
|
10
|
+
FormLabel,
|
|
11
|
+
RadioGroup,
|
|
12
|
+
FormControlLabel,
|
|
13
|
+
Radio,
|
|
14
|
+
} from '@material-ui/core';
|
|
6
15
|
|
|
7
16
|
const styles = {
|
|
8
17
|
root: {
|
|
@@ -29,29 +38,84 @@ class Stripe extends React.Component {
|
|
|
29
38
|
super(props);
|
|
30
39
|
this.state = {
|
|
31
40
|
tokenized: false,
|
|
41
|
+
type: 'card',
|
|
42
|
+
font: 'default',
|
|
32
43
|
};
|
|
44
|
+
|
|
45
|
+
this.onTokenize = this.onTokenize.bind(this);
|
|
46
|
+
this.onError = this.onError.bind(this);
|
|
47
|
+
this.onClickTokenize = this.onClickTokenize.bind(this);
|
|
48
|
+
this.onChangeType = this.onChangeType.bind(this);
|
|
49
|
+
this.onChangeFont = this.onChangeFont.bind(this);
|
|
33
50
|
}
|
|
34
51
|
|
|
35
52
|
componentDidMount() {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
53
|
+
this.renderStripeElements();
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
componentDidUpdate() {
|
|
57
|
+
this.renderStripeElements();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
renderStripeElements() {
|
|
61
|
+
const { type, font } = this.state;
|
|
62
|
+
const options = {
|
|
63
|
+
showIcon: true,
|
|
64
|
+
style: {
|
|
65
|
+
base: {
|
|
66
|
+
fontWeight: 500,
|
|
67
|
+
fontSize: '16px',
|
|
49
68
|
},
|
|
50
|
-
|
|
69
|
+
},
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
switch (font) {
|
|
73
|
+
case 'audiowide':
|
|
74
|
+
options.style.base.fontFamily = 'Audiowide';
|
|
75
|
+
break;
|
|
76
|
+
case 'festive':
|
|
77
|
+
options.style.base.fontFamily = 'Festive';
|
|
78
|
+
break;
|
|
79
|
+
default:
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
this.props.api.payment.createElements({
|
|
84
|
+
config: {
|
|
85
|
+
fonts: [
|
|
86
|
+
{
|
|
87
|
+
cssSrc: 'https://fonts.googleapis.com/css?family=Audiowide',
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
cssSrc: 'https://fonts.googleapis.com/css?family=Festive',
|
|
91
|
+
},
|
|
92
|
+
],
|
|
93
|
+
},
|
|
94
|
+
card: {
|
|
95
|
+
...(type === 'card'
|
|
96
|
+
? {
|
|
97
|
+
options,
|
|
98
|
+
}
|
|
99
|
+
: {
|
|
100
|
+
separateElements: true,
|
|
101
|
+
cardNumber: { options },
|
|
102
|
+
cardExpiry: { options },
|
|
103
|
+
cardCvc: { options },
|
|
104
|
+
}),
|
|
105
|
+
onSuccess: this.onTokenize,
|
|
106
|
+
onError: this.onError,
|
|
51
107
|
},
|
|
52
108
|
});
|
|
53
109
|
}
|
|
54
110
|
|
|
111
|
+
onTokenize() {
|
|
112
|
+
this.setState({ tokenized: true });
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
onError(err) {
|
|
116
|
+
this.props.onError(err.message);
|
|
117
|
+
}
|
|
118
|
+
|
|
55
119
|
onClickTokenize(event) {
|
|
56
120
|
const { api } = this.props;
|
|
57
121
|
|
|
@@ -59,15 +123,46 @@ class Stripe extends React.Component {
|
|
|
59
123
|
api.payment.tokenize();
|
|
60
124
|
}
|
|
61
125
|
|
|
126
|
+
onChangeType(event, type) {
|
|
127
|
+
this.setState({ type });
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
onChangeFont(event, font) {
|
|
131
|
+
this.setState({ font });
|
|
132
|
+
}
|
|
133
|
+
|
|
62
134
|
render() {
|
|
63
135
|
const { classes, onOrderSubmit } = this.props;
|
|
64
|
-
const { tokenized } = this.state;
|
|
136
|
+
const { tokenized, type } = this.state;
|
|
65
137
|
|
|
66
138
|
return (
|
|
67
139
|
<div className={classes.root}>
|
|
68
140
|
<Card classes={{ root: classes.card }}>
|
|
69
141
|
<CardContent>
|
|
70
|
-
<
|
|
142
|
+
<FormControl>
|
|
143
|
+
<FormLabel>Type</FormLabel>
|
|
144
|
+
<RadioGroup defaultValue="card" row onChange={this.onChangeType}>
|
|
145
|
+
<FormControlLabel value="card" control={<Radio />} label="Card" />
|
|
146
|
+
<FormControlLabel value="separate" control={<Radio />} label="Separate elements" />
|
|
147
|
+
</RadioGroup>
|
|
148
|
+
</FormControl>
|
|
149
|
+
<FormControl>
|
|
150
|
+
<FormLabel>Font</FormLabel>
|
|
151
|
+
<RadioGroup defaultValue="default" row onChange={this.onChangeFont}>
|
|
152
|
+
<FormControlLabel value="default" control={<Radio />} label="Default" />
|
|
153
|
+
<FormControlLabel value="audiowide" control={<Radio />} label="Audiowide" />
|
|
154
|
+
<FormControlLabel value="festive" control={<Radio />} label="Festive" />
|
|
155
|
+
</RadioGroup>
|
|
156
|
+
</FormControl>
|
|
157
|
+
{type === 'card' ? (
|
|
158
|
+
<div id="card-element" className={classes.cardInput} />
|
|
159
|
+
) : (
|
|
160
|
+
<Fragment>
|
|
161
|
+
<div id="cardNumber-element" className={classes.cardInput} />
|
|
162
|
+
<div id="cardExpiry-element" className={classes.cardInput} />
|
|
163
|
+
<div id="cardCvc-element" className={classes.cardInput} />
|
|
164
|
+
</Fragment>
|
|
165
|
+
)}
|
|
71
166
|
<div className={classes.submitContainer}>
|
|
72
167
|
<Button
|
|
73
168
|
id="stripe-submit-button"
|
|
@@ -75,7 +170,7 @@ class Stripe extends React.Component {
|
|
|
75
170
|
color="primary"
|
|
76
171
|
size="small"
|
|
77
172
|
classes={{ root: classes.button }}
|
|
78
|
-
onClick={this.onClickTokenize
|
|
173
|
+
onClick={this.onClickTokenize}
|
|
79
174
|
>
|
|
80
175
|
Tokenize
|
|
81
176
|
</Button>
|