swell-js 5.7.0 → 5.8.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/payment.mjs CHANGED
@@ -782,13 +782,13 @@ function getPaymentRequestData(cart, params) {
782
782
  tax_included_total,
783
783
  settings,
784
784
  } = cart;
785
- const { price: shippingPrice, service_name } = shipping || {};
785
+ const { price: shippingPrice, service, service_name } = shipping || {};
786
786
  const { country, name } = settings || {};
787
787
  const { require: { shipping: requireShipping } = {} } = params;
788
788
 
789
789
  const stripeCurrency = currency.toLowerCase();
790
790
  const displayItems = items.map((item) => ({
791
- label: get(item, 'product.name', 'Unknown product'),
791
+ label: item.product_name || item.product?.name || 'Unknown product',
792
792
  amount: stripeAmountByCurrency(
793
793
  currency,
794
794
  item.price_total - item.discount_total,
@@ -810,14 +810,21 @@ function getPaymentRequestData(cart, params) {
810
810
  }
811
811
 
812
812
  let shippingOptions;
813
- const services = get(shipment_rating, 'services');
814
- if (Array.isArray(services) && services.length > 0) {
813
+ const services = shipment_rating?.services;
814
+ if (requireShipping && Array.isArray(services) && services.length > 0) {
815
815
  shippingOptions = services.map((service) => ({
816
816
  id: service.id,
817
817
  label: service.name,
818
818
  detail: service.description,
819
819
  amount: stripeAmountByCurrency(currency, service.price),
820
820
  }));
821
+
822
+ const index = shippingOptions.findIndex((item) => item.id === service);
823
+
824
+ if (index > 0) {
825
+ // Move selected shipping option to the top
826
+ shippingOptions.unshift(...shippingOptions.splice(index, 1));
827
+ }
821
828
  }
822
829
 
823
830
  return {
@@ -829,7 +836,7 @@ function getPaymentRequestData(cart, params) {
829
836
  pending: true,
830
837
  },
831
838
  displayItems,
832
- ...(requireShipping && { shippingOptions }),
839
+ ...(shippingOptions && { shippingOptions }),
833
840
  };
834
841
  }
835
842
 
@@ -1377,6 +1384,7 @@ class StripeKlarnaPayment extends Payment {
1377
1384
 
1378
1385
  /** @typedef {import('@stripe/stripe-js').Stripe} Stripe */
1379
1386
  /** @typedef {import('@stripe/stripe-js').PaymentRequestPaymentMethodEvent} PaymentRequestPaymentMethodEvent */
1387
+ /** @typedef {import('../../../types').Cart} Cart */
1380
1388
 
1381
1389
  class StripeGooglePayment extends Payment {
1382
1390
  constructor(api, options, params, methods) {
@@ -1444,6 +1452,7 @@ class StripeGooglePayment extends Payment {
1444
1452
  this.element.mount(`#${this.elementContainer.id}`);
1445
1453
  }
1446
1454
 
1455
+ /** @param {Cart} cart */
1447
1456
  _createPaymentRequest(cart) {
1448
1457
  const { require: { name, email, shipping, phone } = {} } = this.params;
1449
1458
 
@@ -1456,15 +1465,10 @@ class StripeGooglePayment extends Payment {
1456
1465
  ...getPaymentRequestData(cart, this.params),
1457
1466
  });
1458
1467
 
1459
- paymentRequest.on(
1460
- 'shippingaddresschange',
1461
- this._onShippingAddressChange.bind(this),
1462
- );
1463
- paymentRequest.on(
1464
- 'shippingoptionchange',
1465
- this._onShippingOptionChange.bind(this),
1466
- );
1467
- paymentRequest.on('paymentmethod', this._onPaymentMethod.bind(this));
1468
+ paymentRequest
1469
+ .on('shippingaddresschange', this._onShippingAddressChange.bind(this))
1470
+ .on('shippingoptionchange', this._onShippingOptionChange.bind(this))
1471
+ .on('paymentmethod', this._onPaymentMethod.bind(this));
1468
1472
 
1469
1473
  return paymentRequest;
1470
1474
  }
@@ -1472,9 +1476,9 @@ class StripeGooglePayment extends Payment {
1472
1476
  /** @param {import('@stripe/stripe-js').PaymentRequestShippingAddressEvent} event */
1473
1477
  async _onShippingAddressChange(event) {
1474
1478
  const { shippingAddress, updateWith } = event;
1475
- const shipping = this._mapShippingAddress(shippingAddress);
1479
+
1476
1480
  const cart = await this.updateCart({
1477
- shipping: { ...shipping, service: null },
1481
+ shipping: this._mapShippingAddress(shippingAddress),
1478
1482
  shipment_rating: null,
1479
1483
  });
1480
1484
 
@@ -1514,16 +1518,15 @@ class StripeGooglePayment extends Payment {
1514
1518
  shippingOption,
1515
1519
  complete,
1516
1520
  } = event;
1517
- const { require: { shipping: requireShipping } = {} } = this.params;
1518
1521
 
1519
1522
  await this.updateCart({
1520
1523
  account: {
1521
- email: payerEmail,
1524
+ email: payerEmail || billing_details?.email,
1522
1525
  },
1523
- ...(requireShipping && {
1526
+ ...(shippingAddress && {
1524
1527
  shipping: {
1525
1528
  ...this._mapShippingAddress(shippingAddress),
1526
- service: shippingOption.id,
1529
+ service: shippingOption?.id || undefined,
1527
1530
  },
1528
1531
  }),
1529
1532
  billing: {
@@ -1537,9 +1540,9 @@ class StripeGooglePayment extends Payment {
1537
1540
  exp_month: card.exp_month,
1538
1541
  exp_year: card.exp_year,
1539
1542
  last4: card.last4,
1540
- address_check: card.checks.address_line1_check,
1541
- zip_check: card.checks.address_postal_code_check,
1542
- cvc_check: card.checks.cvc_check,
1543
+ address_check: card.checks?.address_line1_check,
1544
+ zip_check: card.checks?.address_postal_code_check,
1545
+ cvc_check: card.checks?.cvc_check,
1543
1546
  },
1544
1547
  },
1545
1548
  });
@@ -1587,8 +1590,8 @@ class StripeGooglePayment extends Payment {
1587
1590
  _mapShippingAddress(address = {}) {
1588
1591
  return {
1589
1592
  name: address.recipient,
1590
- address1: address.addressLine[0],
1591
- address2: address.addressLine[1],
1593
+ address1: address.addressLine?.[0],
1594
+ address2: address.addressLine?.[1],
1592
1595
  city: address.city,
1593
1596
  state: address.region,
1594
1597
  zip: address.postalCode,
@@ -1602,18 +1605,19 @@ class StripeGooglePayment extends Payment {
1602
1605
  return {
1603
1606
  name: address.name,
1604
1607
  phone: address.phone,
1605
- address1: address.address.line1,
1606
- address2: address.address.line2,
1607
- city: address.address.city,
1608
- state: address.address.state,
1609
- zip: address.address.postal_code,
1610
- country: address.address.country,
1608
+ address1: address.address?.line1,
1609
+ address2: address.address?.line2,
1610
+ city: address.address?.city,
1611
+ state: address.address?.state,
1612
+ zip: address.address?.postal_code,
1613
+ country: address.address?.country,
1611
1614
  };
1612
1615
  }
1613
1616
  }
1614
1617
 
1615
1618
  /** @typedef {import('@stripe/stripe-js').Stripe} Stripe */
1616
1619
  /** @typedef {import('@stripe/stripe-js').PaymentRequestPaymentMethodEvent} PaymentRequestPaymentMethodEvent */
1620
+ /** @typedef {import('../../../types').Cart} Cart */
1617
1621
 
1618
1622
  class StripeApplePayment extends Payment {
1619
1623
  constructor(api, options, params, methods) {
@@ -1667,7 +1671,7 @@ class StripeApplePayment extends Payment {
1667
1671
  const paymentRequest = this._createPaymentRequest(cart);
1668
1672
  const canMakePayment = await paymentRequest.canMakePayment();
1669
1673
 
1670
- if (!canMakePayment || !canMakePayment.applePay) {
1674
+ if (!canMakePayment?.applePay) {
1671
1675
  throw new Error(
1672
1676
  'This device is not capable of making Apple Pay payments',
1673
1677
  );
@@ -1704,6 +1708,7 @@ class StripeApplePayment extends Payment {
1704
1708
  }
1705
1709
  }
1706
1710
 
1711
+ /** @param {Cart} cart */
1707
1712
  _createPaymentRequest(cart) {
1708
1713
  const { require: { name, email, shipping, phone } = {} } = this.params;
1709
1714
 
@@ -1716,15 +1721,10 @@ class StripeApplePayment extends Payment {
1716
1721
  ...getPaymentRequestData(cart, this.params),
1717
1722
  });
1718
1723
 
1719
- paymentRequest.on(
1720
- 'shippingaddresschange',
1721
- this._onShippingAddressChange.bind(this),
1722
- );
1723
- paymentRequest.on(
1724
- 'shippingoptionchange',
1725
- this._onShippingOptionChange.bind(this),
1726
- );
1727
- paymentRequest.on('paymentmethod', this._onPaymentMethod.bind(this));
1724
+ paymentRequest
1725
+ .on('shippingaddresschange', this._onShippingAddressChange.bind(this))
1726
+ .on('shippingoptionchange', this._onShippingOptionChange.bind(this))
1727
+ .on('paymentmethod', this._onPaymentMethod.bind(this));
1728
1728
 
1729
1729
  return paymentRequest;
1730
1730
  }
@@ -1732,9 +1732,9 @@ class StripeApplePayment extends Payment {
1732
1732
  /** @param {import('@stripe/stripe-js').PaymentRequestShippingAddressEvent} event */
1733
1733
  async _onShippingAddressChange(event) {
1734
1734
  const { shippingAddress, updateWith } = event;
1735
- const shipping = this._mapShippingAddress(shippingAddress);
1735
+
1736
1736
  const cart = await this.updateCart({
1737
- shipping: { ...shipping, service: null },
1737
+ shipping: this._mapShippingAddress(shippingAddress),
1738
1738
  shipment_rating: null,
1739
1739
  });
1740
1740
 
@@ -1774,16 +1774,15 @@ class StripeApplePayment extends Payment {
1774
1774
  shippingOption,
1775
1775
  complete,
1776
1776
  } = event;
1777
- const { require: { shipping: requireShipping } = {} } = this.params;
1778
1777
 
1779
1778
  await this.updateCart({
1780
1779
  account: {
1781
- email: payerEmail,
1780
+ email: payerEmail || billing_details?.email,
1782
1781
  },
1783
- ...(requireShipping && {
1782
+ ...(shippingAddress && {
1784
1783
  shipping: {
1785
1784
  ...this._mapShippingAddress(shippingAddress),
1786
- service: shippingOption.id,
1785
+ service: shippingOption?.id || undefined,
1787
1786
  },
1788
1787
  }),
1789
1788
  billing: {
@@ -1797,9 +1796,9 @@ class StripeApplePayment extends Payment {
1797
1796
  exp_month: card.exp_month,
1798
1797
  exp_year: card.exp_year,
1799
1798
  last4: card.last4,
1800
- address_check: card.checks.address_line1_check,
1801
- zip_check: card.checks.address_postal_code_check,
1802
- cvc_check: card.checks.cvc_check,
1799
+ address_check: card.checks?.address_line1_check,
1800
+ zip_check: card.checks?.address_postal_code_check,
1801
+ cvc_check: card.checks?.cvc_check,
1803
1802
  },
1804
1803
  },
1805
1804
  });
@@ -1813,8 +1812,8 @@ class StripeApplePayment extends Payment {
1813
1812
  _mapShippingAddress(address = {}) {
1814
1813
  return {
1815
1814
  name: address.recipient,
1816
- address1: address.addressLine[0],
1817
- address2: address.addressLine[1],
1815
+ address1: address.addressLine?.[0],
1816
+ address2: address.addressLine?.[1],
1818
1817
  city: address.city,
1819
1818
  state: address.region,
1820
1819
  zip: address.postalCode,
@@ -1828,12 +1827,12 @@ class StripeApplePayment extends Payment {
1828
1827
  return {
1829
1828
  name: address.name,
1830
1829
  phone: address.phone,
1831
- address1: address.address.line1,
1832
- address2: address.address.line2,
1833
- city: address.address.city,
1834
- state: address.address.state,
1835
- zip: address.address.postal_code,
1836
- country: address.address.country,
1830
+ address1: address.address?.line1,
1831
+ address2: address.address?.line2,
1832
+ city: address.address?.city,
1833
+ state: address.address?.state,
1834
+ zip: address.address?.postal_code,
1835
+ country: address.address?.country,
1837
1836
  };
1838
1837
  }
1839
1838
  }
@@ -2101,6 +2100,44 @@ function getDiscountLabel(discount, cart) {
2101
2100
  return discount.id;
2102
2101
  }
2103
2102
 
2103
+ /** @type {Map<string, number>} */
2104
+ const CURRENCIES_CENTS = new Map();
2105
+
2106
+ /**
2107
+ * @param {string} currency
2108
+ * @returns {number}
2109
+ */
2110
+ function getCurrencyCents(currency) {
2111
+ let cents = CURRENCIES_CENTS.get(currency);
2112
+
2113
+ if (cents !== undefined) {
2114
+ return cents;
2115
+ }
2116
+
2117
+ const formatter = new Intl.NumberFormat('en-US', {
2118
+ style: 'currency',
2119
+ currency,
2120
+ });
2121
+
2122
+ const options = formatter.resolvedOptions();
2123
+ const decimals = options.maximumFractionDigits ?? 2;
2124
+
2125
+ cents = 10 ** decimals;
2126
+
2127
+ CURRENCIES_CENTS.set(currency, cents);
2128
+
2129
+ return cents;
2130
+ }
2131
+
2132
+ /**
2133
+ * @param {string} currency
2134
+ * @param {number} amount
2135
+ * @returns {number}
2136
+ */
2137
+ function amountInCents(currency, amount) {
2138
+ return Math.round(amount * getCurrencyCents(currency));
2139
+ }
2140
+
2104
2141
  /** @typedef {import('./payment').default} Payment */
2105
2142
  /** @typedef {import('../../types').Cart} Cart */
2106
2143
  /** @typedef {import('../../types').Address} Address */
@@ -2188,7 +2225,7 @@ async function onPaymentDataChanged(intermediatePaymentData) {
2188
2225
  this,
2189
2226
  cart,
2190
2227
  ),
2191
- newTransactionInfo: getTransactionInfo(cart),
2228
+ newTransactionInfo: getTransactionInfo.call(this, cart),
2192
2229
  };
2193
2230
  }
2194
2231
 
@@ -2201,7 +2238,7 @@ async function onPaymentDataChanged(intermediatePaymentData) {
2201
2238
  },
2202
2239
  });
2203
2240
 
2204
- return { newTransactionInfo: getTransactionInfo(cart) };
2241
+ return { newTransactionInfo: getTransactionInfo.call(this, cart) };
2205
2242
  } catch (err) {
2206
2243
  return createError(
2207
2244
  intermediatePaymentData.callbackTrigger,
@@ -2223,7 +2260,7 @@ async function onPaymentDataChanged(intermediatePaymentData) {
2223
2260
 
2224
2261
  return {
2225
2262
  newOfferInfo: getOfferInfo(cart),
2226
- newTransactionInfo: getTransactionInfo(cart),
2263
+ newTransactionInfo: getTransactionInfo.call(this, cart),
2227
2264
  };
2228
2265
  } catch (err) {
2229
2266
  return createError(
@@ -2323,12 +2360,13 @@ function getDisplayItems(cart) {
2323
2360
 
2324
2361
  /**
2325
2362
  * Converts cart data to Google Pay transaction information.
2363
+ * @this {Payment}
2326
2364
  * @param {Cart} cart - The current cart data
2327
2365
  * @returns {google.payments.api.TransactionInfo} Transaction info for Google Pay
2328
2366
  */
2329
2367
  function getTransactionInfo(cart) {
2330
- const { settings, capture_total, currency, shipment_delivery, shipping } =
2331
- cart;
2368
+ const { require: { shipping: shipmentDelivery = false } = {} } = this.params;
2369
+ const { settings, capture_total, currency, shipping } = cart;
2332
2370
 
2333
2371
  return {
2334
2372
  countryCode: settings?.country || 'US',
@@ -2336,7 +2374,7 @@ function getTransactionInfo(cart) {
2336
2374
  totalPrice: String(capture_total ?? 0),
2337
2375
  // Set status to FINAL if shipping has been selected, otherwise ESTIMATED
2338
2376
  totalPriceStatus:
2339
- !shipment_delivery || shipping?.service ? 'FINAL' : 'ESTIMATED',
2377
+ !shipmentDelivery || shipping?.service ? 'FINAL' : 'ESTIMATED',
2340
2378
  totalPriceLabel: 'Total',
2341
2379
  displayItems: getDisplayItems(cart),
2342
2380
  };
@@ -2349,12 +2387,14 @@ function getTransactionInfo(cart) {
2349
2387
  * @returns {google.payments.api.ShippingOptionParameters | undefined} Shipping options for Google Pay
2350
2388
  */
2351
2389
  function getShippingOptionParameters(cart) {
2352
- const { shipment_delivery, shipment_rating, shipping } = cart;
2390
+ const { require: { shipping: shipmentDelivery = false } = {} } = this.params;
2353
2391
 
2354
- if (!shipment_delivery) {
2392
+ if (!shipmentDelivery) {
2355
2393
  return undefined;
2356
2394
  }
2357
2395
 
2396
+ const { shipment_rating, shipping } = cart;
2397
+
2358
2398
  if (!shipment_rating?.services?.length) {
2359
2399
  // Return placeholder when no shipping services are available
2360
2400
  return {
@@ -2435,20 +2475,11 @@ function createError(intent, reason, message) {
2435
2475
  };
2436
2476
  }
2437
2477
 
2478
+ /** @typedef {import('../../../types').Cart} Cart */
2479
+
2438
2480
  const API_VERSION$1 = 2;
2439
2481
  const API_MINOR_VERSION$1 = 0;
2440
2482
 
2441
- const ALLOWED_CARD_AUTH_METHODS = ['PAN_ONLY', 'CRYPTOGRAM_3DS'];
2442
-
2443
- const ALLOWED_CARD_NETWORKS = [
2444
- 'AMEX',
2445
- 'DISCOVER',
2446
- 'INTERAC',
2447
- 'JCB',
2448
- 'MASTERCARD',
2449
- 'VISA',
2450
- ];
2451
-
2452
2483
  class BraintreeGooglePayment extends Payment {
2453
2484
  constructor(api, options, params, methods) {
2454
2485
  if (!methods.card) {
@@ -2484,6 +2515,9 @@ class BraintreeGooglePayment extends Payment {
2484
2515
  if (this.google) {
2485
2516
  this.googleClient = new this.google.payments.api.PaymentsClient({
2486
2517
  environment: isLiveMode(this.method.mode) ? 'PRODUCTION' : 'TEST',
2518
+ paymentDataCallbacks: {
2519
+ onPaymentDataChanged: onPaymentDataChanged.bind(this),
2520
+ },
2487
2521
  });
2488
2522
  }
2489
2523
 
@@ -2499,31 +2533,12 @@ class BraintreeGooglePayment extends Payment {
2499
2533
  BraintreeGooglePayment.googleClient = googleClient;
2500
2534
  }
2501
2535
 
2502
- /** @returns {google.payments.api.PaymentMethodSpecification} */
2503
- get cardPaymentMethod() {
2504
- return {
2505
- type: 'CARD',
2506
- parameters: {
2507
- allowedAuthMethods: ALLOWED_CARD_AUTH_METHODS,
2508
- allowedCardNetworks: ALLOWED_CARD_NETWORKS,
2509
- billingAddressRequired: true,
2510
- billingAddressParameters: {
2511
- format: 'FULL',
2512
- phoneNumberRequired: true,
2513
- },
2514
- },
2515
- };
2516
- }
2517
-
2518
- /** @returns {google.payments.api.PaymentMethodSpecification[]} */
2519
- get allowedPaymentMethods() {
2520
- return [this.cardPaymentMethod];
2521
- }
2522
-
2536
+ /** @param {Cart} cart */
2523
2537
  async createElements(cart) {
2524
2538
  const {
2525
2539
  elementId = 'googlepay-button',
2526
2540
  locale = 'en',
2541
+ require: { phone } = {},
2527
2542
  style: { color = 'black', type = 'plain', sizeMode = 'fill' } = {},
2528
2543
  } = this.params;
2529
2544
 
@@ -2534,10 +2549,35 @@ class BraintreeGooglePayment extends Payment {
2534
2549
  this.setElementContainer(elementId);
2535
2550
  await this.loadScripts(this.scripts);
2536
2551
 
2552
+ const braintreeClient = await this._createBraintreeClient();
2553
+
2554
+ const googlePayment = await this.braintree.googlePayment.create({
2555
+ client: braintreeClient,
2556
+ googleMerchantId: this.method.merchant_id,
2557
+ googlePayVersion: API_VERSION$1,
2558
+ });
2559
+
2560
+ const paymentDataRequest = googlePayment.createPaymentDataRequest(
2561
+ this._createPaymentRequestData(cart),
2562
+ );
2563
+
2564
+ const cardPaymentMethod = paymentDataRequest.allowedPaymentMethods.find(
2565
+ (method) => method.type === 'CARD',
2566
+ );
2567
+
2568
+ if (cardPaymentMethod !== undefined) {
2569
+ cardPaymentMethod.parameters.billingAddressRequired = true;
2570
+
2571
+ cardPaymentMethod.parameters.billingAddressParameters = {
2572
+ format: 'FULL',
2573
+ phoneNumberRequired: Boolean(phone),
2574
+ };
2575
+ }
2576
+
2537
2577
  const isReadyToPay = await this.googleClient.isReadyToPay({
2538
2578
  apiVersion: API_VERSION$1,
2539
2579
  apiVersionMinor: API_MINOR_VERSION$1,
2540
- allowedPaymentMethods: this.allowedPaymentMethods,
2580
+ allowedPaymentMethods: paymentDataRequest.allowedPaymentMethods,
2541
2581
  existingPaymentMethodRequired: true,
2542
2582
  });
2543
2583
 
@@ -2547,16 +2587,6 @@ class BraintreeGooglePayment extends Payment {
2547
2587
  );
2548
2588
  }
2549
2589
 
2550
- const braintreeClient = await this._createBraintreeClient();
2551
- const googlePayment = await this.braintree.googlePayment.create({
2552
- client: braintreeClient,
2553
- googleMerchantId: this.method.merchant_id,
2554
- googlePayVersion: API_VERSION$1,
2555
- });
2556
- const paymentRequestData = this._createPaymentRequestData(cart);
2557
- const paymentDataRequest =
2558
- googlePayment.createPaymentDataRequest(paymentRequestData);
2559
-
2560
2590
  this.element = this.googleClient.createButton({
2561
2591
  buttonColor: color,
2562
2592
  buttonType: type,
@@ -2583,6 +2613,7 @@ class BraintreeGooglePayment extends Payment {
2583
2613
  }
2584
2614
  }
2585
2615
 
2616
+ /** @returns {Promise<braintree.Client>} */
2586
2617
  async _createBraintreeClient() {
2587
2618
  const authorization = await this.authorizeGateway({
2588
2619
  gateway: 'braintree',
@@ -2597,39 +2628,51 @@ class BraintreeGooglePayment extends Payment {
2597
2628
  });
2598
2629
  }
2599
2630
 
2600
- /** @returns {google.payments.api.PaymentDataRequest} */
2631
+ /**
2632
+ * @param {Cart} cart
2633
+ * @returns {google.payments.api.PaymentDataRequest}
2634
+ */
2601
2635
  _createPaymentRequestData(cart) {
2602
2636
  const {
2603
- settings: { name, country },
2604
- capture_total,
2605
- currency,
2637
+ settings: { name },
2606
2638
  } = cart;
2639
+
2607
2640
  const { require: { email, shipping, phone } = {} } = this.params;
2608
2641
 
2642
+ /** @type {google.payments.api.CallbackIntent[]} */
2643
+ const callbackIntents = ['OFFER'];
2644
+
2645
+ if (shipping) {
2646
+ callbackIntents.push('SHIPPING_ADDRESS', 'SHIPPING_OPTION');
2647
+ }
2648
+
2609
2649
  return {
2610
2650
  apiVersion: API_VERSION$1,
2611
2651
  apiVersionMinor: API_MINOR_VERSION$1,
2612
- transactionInfo: {
2613
- countryCode: country,
2614
- currencyCode: currency,
2615
- totalPrice: capture_total.toString(),
2616
- totalPriceStatus: 'ESTIMATED',
2617
- },
2618
- allowedPaymentMethods: this.allowedPaymentMethods,
2652
+ transactionInfo: getTransactionInfo.call(this, cart),
2653
+ /**
2654
+ * @see {@link https://developer.paypal.com/braintree/docs/guides/google-pay/client-side/javascript/v3/#requesting-a-payment}
2655
+ *
2656
+ * Braintree automatically populates the `allowedPaymentMethods` property.
2657
+ */
2619
2658
  emailRequired: Boolean(email),
2620
2659
  shippingAddressRequired: Boolean(shipping),
2621
2660
  shippingAddressParameters: {
2622
2661
  phoneNumberRequired: Boolean(phone),
2623
2662
  },
2663
+ shippingOptionRequired: Boolean(shipping),
2664
+ shippingOptionParameters: getShippingOptionParameters.call(this, cart),
2665
+ offerInfo: getOfferInfo(cart),
2624
2666
  merchantInfo: {
2625
2667
  merchantName: name,
2626
2668
  merchantId: this.method.merchant_id,
2627
2669
  },
2670
+ callbackIntents,
2628
2671
  };
2629
2672
  }
2630
2673
 
2631
2674
  /**
2632
- * @param {object} googlePayment
2675
+ * @param {braintree.GooglePayment} googlePayment
2633
2676
  * @param {google.payments.api.PaymentDataRequest} paymentDataRequest
2634
2677
  */
2635
2678
  async _onClick(googlePayment, paymentDataRequest) {
@@ -2646,34 +2689,59 @@ class BraintreeGooglePayment extends Payment {
2646
2689
  }
2647
2690
 
2648
2691
  /**
2649
- * @param {object} googlePayment
2692
+ * @param {braintree.GooglePayment} googlePayment
2650
2693
  * @param {google.payments.api.PaymentData} paymentData
2651
2694
  */
2652
2695
  async _submitPayment(googlePayment, paymentData) {
2653
- const { require: { shipping: requireShipping } = {} } = this.params;
2654
2696
  const { nonce } = await googlePayment.parseResponse(paymentData);
2655
- const { email, shippingAddress, paymentMethodData } = paymentData;
2656
- const {
2657
- info: { billingAddress },
2658
- } = paymentMethodData;
2697
+ const { email, shippingAddress, shippingOptionData, paymentMethodData } =
2698
+ paymentData;
2699
+ const { info: { billingAddress } = {} } = paymentMethodData;
2659
2700
 
2660
- await this.updateCart({
2701
+ const cart = await this.updateCart({
2661
2702
  account: {
2662
2703
  email,
2663
2704
  },
2664
2705
  billing: {
2665
2706
  method: 'google',
2707
+ account_card_id: null,
2708
+ card: null,
2666
2709
  google: {
2667
2710
  nonce,
2668
2711
  gateway: 'braintree',
2669
2712
  },
2670
2713
  ...convertToSwellAddress$2(billingAddress),
2671
2714
  },
2672
- ...(requireShipping && {
2673
- shipping: convertToSwellAddress$2(shippingAddress),
2715
+ ...(shippingAddress && {
2716
+ shipping: {
2717
+ ...convertToSwellAddress$2(shippingAddress),
2718
+ service: shippingOptionData?.id || undefined,
2719
+ },
2674
2720
  }),
2675
2721
  });
2676
2722
 
2723
+ if (cart.subscription_delivery) {
2724
+ try {
2725
+ const card = await cardApi.createToken({
2726
+ gateway: 'braintree',
2727
+ account_id: cart.account_id,
2728
+ nonce,
2729
+ });
2730
+
2731
+ delete card.nonce;
2732
+
2733
+ await this.updateCart({
2734
+ billing: {
2735
+ method: 'card',
2736
+ card,
2737
+ google: null,
2738
+ },
2739
+ });
2740
+ } catch (error) {
2741
+ console.warn('Failed to extract card data from google token', error);
2742
+ }
2743
+ }
2744
+
2677
2745
  this.onSuccess();
2678
2746
  }
2679
2747
  }
@@ -2703,7 +2771,7 @@ async function onShippingAddressChange(shippingContact) {
2703
2771
  'Shipping is not available for the provided address.';
2704
2772
 
2705
2773
  return {
2706
- newTotal: getTotal(cart, this.merchantInfo),
2774
+ newTotal: getTotal.call(this, cart, this.merchantInfo),
2707
2775
  newLineItems: getLineItems(cart),
2708
2776
  newShippingMethods: [], // REQUIRED: Must always provide this, even as empty array
2709
2777
  errors: [
@@ -2714,15 +2782,15 @@ async function onShippingAddressChange(shippingContact) {
2714
2782
 
2715
2783
  // Success: Return updated totals and shipping methods
2716
2784
  return {
2717
- newTotal: getTotal(cart, this.merchantInfo),
2785
+ newTotal: getTotal.call(this, cart, this.merchantInfo),
2718
2786
  newLineItems: getLineItems(cart),
2719
- newShippingMethods: getShippingMethods(cart),
2787
+ newShippingMethods: getShippingMethods.call(this, cart),
2720
2788
  };
2721
2789
  } catch (err) {
2722
2790
  const cartData = await this.getCart();
2723
2791
 
2724
2792
  return {
2725
- newTotal: getTotal(cartData, this.merchantInfo),
2793
+ newTotal: getTotal.call(this, cartData, this.merchantInfo),
2726
2794
  newLineItems: getLineItems(cartData),
2727
2795
  newShippingMethods: [], // REQUIRED: Must always provide this, even as empty array
2728
2796
  errors: [new ApplePayError('unknown', undefined, err.message)],
@@ -2768,12 +2836,12 @@ async function onShippingMethodChange(shippingMethod) {
2768
2836
  });
2769
2837
 
2770
2838
  return {
2771
- newTotal: getTotal(cart, this.merchantInfo),
2839
+ newTotal: getTotal.call(this, cart, this.merchantInfo),
2772
2840
  newLineItems: getLineItems(cart),
2773
2841
  };
2774
2842
  } catch (err) {
2775
2843
  return {
2776
- newTotal: getTotal(await this.getCart(), this.merchantInfo),
2844
+ newTotal: getTotal.call(this, await this.getCart(), this.merchantInfo),
2777
2845
  errors: [new ApplePayError('unknown', undefined, err.message)],
2778
2846
  };
2779
2847
  }
@@ -2813,7 +2881,7 @@ async function onCouponCodeUpdated(couponCode) {
2813
2881
 
2814
2882
  // Valid coupon applied successfully
2815
2883
  return {
2816
- newTotal: getTotal(cart, this.merchantInfo),
2884
+ newTotal: getTotal.call(this, cart, this.merchantInfo),
2817
2885
  newLineItems: getLineItems(cart),
2818
2886
  };
2819
2887
  } catch (err) {
@@ -2821,7 +2889,7 @@ async function onCouponCodeUpdated(couponCode) {
2821
2889
  const currentCart = await this.getCart();
2822
2890
 
2823
2891
  return {
2824
- newTotal: getTotal(currentCart, this.merchantInfo),
2892
+ newTotal: getTotal.call(this, currentCart, this.merchantInfo),
2825
2893
  newLineItems: getLineItems(currentCart),
2826
2894
  errors: [new ApplePayError('couponCodeInvalid', undefined, err.message)],
2827
2895
  };
@@ -2855,15 +2923,17 @@ async function onCouponCodeChanged(session, event) {
2855
2923
  * This ensures the user sees "pending" until they've selected shipping,
2856
2924
  * then sees the final amount once everything is calculated.
2857
2925
  *
2926
+ * @this {Payment}
2858
2927
  * @param {Cart} cart
2859
2928
  * @param {object} [merchantInfo]
2860
2929
  * @returns {ApplePayJS.ApplePayLineItem}
2861
2930
  */
2862
2931
  function getTotal(cart, merchantInfo) {
2863
- const { capture_total, shipment_delivery, shipping } = cart;
2932
+ const { require: { shipping: shipmentDelivery = false } = {} } = this.params;
2933
+ const { capture_total, shipping } = cart;
2864
2934
 
2865
2935
  // Use 'final' only after shipping method is selected or not needed, otherwise 'pending'
2866
- const isFinalPrice = !shipment_delivery || shipping?.service;
2936
+ const isFinalPrice = !shipmentDelivery || shipping?.service;
2867
2937
  const type = isFinalPrice ? 'final' : 'pending';
2868
2938
 
2869
2939
  return {
@@ -2932,16 +3002,19 @@ function getLineItems(cart) {
2932
3002
  *
2933
3003
  * IMPORTANT: Amounts must be formatted as strings with 2 decimals.
2934
3004
  *
3005
+ * @this {Payment}
2935
3006
  * @param {Cart} cart
2936
3007
  * @returns {ApplePayJS.ApplePayShippingMethod[]}
2937
3008
  */
2938
3009
  function getShippingMethods(cart) {
2939
- const { shipment_delivery, shipment_rating } = cart;
3010
+ const { require: { shipping: shipmentDelivery = false } = {} } = this.params;
2940
3011
 
2941
- if (!shipment_delivery) {
3012
+ if (!shipmentDelivery) {
2942
3013
  return [];
2943
3014
  }
2944
3015
 
3016
+ const { shipment_rating } = cart;
3017
+
2945
3018
  if (!shipment_rating?.services?.length) {
2946
3019
  return [];
2947
3020
  }
@@ -2992,13 +3065,38 @@ function convertToSwellAddress$1(address = {}) {
2992
3065
  };
2993
3066
  }
2994
3067
 
2995
- const VERSION$1 = 3;
3068
+ /** @param {object} params */
3069
+ function getRequiredContactFields(params) {
3070
+ const { require = {} } = params;
3071
+ /** @type {ApplePayJS.ApplePayContactField[]} */
3072
+ const requiredFields = [];
3073
+
3074
+ if (require.email) {
3075
+ requiredFields.push('email');
3076
+ }
3077
+
3078
+ if (require.name) {
3079
+ requiredFields.push('name');
3080
+ }
3081
+
3082
+ if (require.phone) {
3083
+ requiredFields.push('phone');
3084
+ }
3085
+
3086
+ /** @type {ApplePayJS.ApplePayContactField[]} */
3087
+ const requiredShippingContactFields = require.shipping
3088
+ ? [...requiredFields, 'postalAddress']
3089
+ : [];
3090
+
3091
+ /** @type {ApplePayJS.ApplePayContactField[]} */
3092
+ const requiredBillingContactFields = [...requiredFields, 'postalAddress'];
3093
+
3094
+ return { requiredBillingContactFields, requiredShippingContactFields };
3095
+ }
3096
+
3097
+ /** @typedef {import('../../../types').Cart} Cart */
2996
3098
 
2997
- const MERCHANT_CAPABILITIES = [
2998
- 'supports3DS',
2999
- 'supportsDebit',
3000
- 'supportsCredit',
3001
- ];
3099
+ const VERSION$1 = 14;
3002
3100
 
3003
3101
  class BraintreeApplePayment extends Payment {
3004
3102
  constructor(api, options, params, methods) {
@@ -3030,6 +3128,7 @@ class BraintreeApplePayment extends Payment {
3030
3128
  return window.ApplePaySession;
3031
3129
  }
3032
3130
 
3131
+ /** @param {Cart} cart */
3033
3132
  async createElements(cart) {
3034
3133
  const { elementId = 'applepay-button' } = this.params;
3035
3134
 
@@ -3043,10 +3142,12 @@ class BraintreeApplePayment extends Payment {
3043
3142
  }
3044
3143
 
3045
3144
  const braintreeClient = await this._createBraintreeClient();
3145
+
3046
3146
  const applePayment = await this.braintree.applePay.create({
3047
3147
  client: braintreeClient,
3048
3148
  });
3049
- const paymentRequest = await this._createPaymentRequest(cart, applePayment);
3149
+
3150
+ const paymentRequest = this._createPaymentRequest(cart, applePayment);
3050
3151
 
3051
3152
  this.element = this._createButton(applePayment, paymentRequest);
3052
3153
  }
@@ -3063,8 +3164,9 @@ class BraintreeApplePayment extends Payment {
3063
3164
  }
3064
3165
 
3065
3166
  /**
3066
- * @param {object} applePayment
3167
+ * @param {braintree.ApplePay} applePayment
3067
3168
  * @param {ApplePayJS.ApplePayPaymentRequest} paymentRequest
3169
+ * @returns {HTMLDivElement}
3068
3170
  */
3069
3171
  _createButton(applePayment, paymentRequest) {
3070
3172
  const { style: { type = 'plain', theme = 'black', height = '40px' } = {} } =
@@ -3085,6 +3187,7 @@ class BraintreeApplePayment extends Payment {
3085
3187
  return button;
3086
3188
  }
3087
3189
 
3190
+ /** @returns {Promise<braintree.Client>} */
3088
3191
  async _createBraintreeClient() {
3089
3192
  const authorization = await this.authorizeGateway({
3090
3193
  gateway: 'braintree',
@@ -3099,47 +3202,43 @@ class BraintreeApplePayment extends Payment {
3099
3202
  });
3100
3203
  }
3101
3204
 
3102
- /** @returns {ApplePayJS.ApplePayPaymentRequest} */
3205
+ /**
3206
+ * @param {Cart} cart
3207
+ * @param {braintree.ApplePay} applePayment
3208
+ * @returns {ApplePayJS.ApplePayPaymentRequest}
3209
+ */
3103
3210
  _createPaymentRequest(cart, applePayment) {
3104
- const { require = {} } = this.params;
3105
3211
  const {
3106
3212
  settings: { name, country },
3107
3213
  capture_total,
3108
3214
  currency,
3109
3215
  } = cart;
3110
3216
 
3111
- const requiredShippingContactFields = [];
3112
- const requiredBillingContactFields = ['postalAddress'];
3113
-
3114
- if (require.name) {
3115
- requiredShippingContactFields.push('name');
3116
- }
3117
- if (require.email) {
3118
- requiredShippingContactFields.push('email');
3119
- }
3120
- if (require.phone) {
3121
- requiredShippingContactFields.push('phone');
3122
- }
3123
- if (require.shipping) {
3124
- requiredShippingContactFields.push('postalAddress');
3125
- }
3217
+ const { requiredBillingContactFields, requiredShippingContactFields } =
3218
+ getRequiredContactFields(this.params);
3126
3219
 
3127
3220
  return applePayment.createPaymentRequest({
3128
3221
  total: {
3129
3222
  label: name,
3130
3223
  type: 'pending',
3131
- amount: capture_total.toString(),
3224
+ amount: (capture_total || 0).toFixed(2),
3132
3225
  },
3133
3226
  countryCode: country,
3134
3227
  currencyCode: currency,
3135
- merchantCapabilities: MERCHANT_CAPABILITIES,
3228
+ /**
3229
+ * @see {@link https://developer.paypal.com/braintree/docs/guides/apple-pay/client-side/javascript/v3/#create-anapplepaysession}
3230
+ *
3231
+ * Braintree automatically fills in `supportedNetworks` and `merchantCapabilities`.
3232
+ */
3136
3233
  requiredShippingContactFields,
3137
3234
  requiredBillingContactFields,
3235
+ supportsCouponCode: true,
3236
+ lineItems: getLineItems(cart),
3138
3237
  });
3139
3238
  }
3140
3239
 
3141
3240
  /**
3142
- * @param {object} applePayment
3241
+ * @param {braintree.ApplePay} applePayment
3143
3242
  * @param {ApplePayJS.ApplePayPaymentRequest} paymentRequest
3144
3243
  */
3145
3244
  _createPaymentSession(applePayment, paymentRequest) {
@@ -3160,11 +3259,23 @@ class BraintreeApplePayment extends Payment {
3160
3259
  }
3161
3260
  };
3162
3261
 
3262
+ session.onshippingcontactselected = onShippingContactSelected.bind(
3263
+ this,
3264
+ session,
3265
+ );
3266
+
3267
+ session.onshippingmethodselected = onShippingMethodSelected.bind(
3268
+ this,
3269
+ session,
3270
+ );
3271
+
3272
+ session.oncouponcodechanged = onCouponCodeChanged.bind(this, session);
3273
+
3163
3274
  session.onpaymentauthorized = async (event) => {
3164
3275
  const {
3165
3276
  payment: { token, shippingContact, billingContact },
3166
3277
  } = event;
3167
- const { require: { shipping: requireShipping } = {} } = this.params;
3278
+
3168
3279
  const payload = await applePayment
3169
3280
  .tokenize({ token })
3170
3281
  .catch(this.onError.bind(this));
@@ -3173,23 +3284,47 @@ class BraintreeApplePayment extends Payment {
3173
3284
  return session.completePayment(this.ApplePaySession.STATUS_FAILURE);
3174
3285
  }
3175
3286
 
3176
- await this.updateCart({
3287
+ const cart = await this.updateCart({
3177
3288
  account: {
3178
- email: shippingContact.emailAddress,
3289
+ email: shippingContact?.emailAddress || billingContact?.emailAddress,
3179
3290
  },
3180
3291
  billing: {
3181
3292
  method: 'apple',
3293
+ account_card_id: null,
3294
+ card: null,
3182
3295
  apple: {
3183
3296
  nonce: payload.nonce,
3184
3297
  gateway: 'braintree',
3185
3298
  },
3186
3299
  ...convertToSwellAddress$1(billingContact),
3187
3300
  },
3188
- ...(requireShipping && {
3301
+ ...(shippingContact && {
3189
3302
  shipping: convertToSwellAddress$1(shippingContact),
3190
3303
  }),
3191
3304
  });
3192
3305
 
3306
+ if (cart.subscription_delivery) {
3307
+ try {
3308
+ const card = await cardApi.createToken({
3309
+ gateway: 'braintree',
3310
+ account_id: cart.account_id,
3311
+ nonce: payload.nonce,
3312
+ });
3313
+
3314
+ delete card.nonce;
3315
+
3316
+ await this.updateCart({
3317
+ billing: {
3318
+ method: 'card',
3319
+ card,
3320
+ apple: null,
3321
+ },
3322
+ });
3323
+ } catch (error) {
3324
+ console.warn('Failed to extract card data from apple token', error);
3325
+ }
3326
+ }
3327
+
3193
3328
  this.onSuccess();
3194
3329
 
3195
3330
  return session.completePayment(this.ApplePaySession.STATUS_SUCCESS);
@@ -3295,6 +3430,8 @@ class AbstractGooglePayment extends Payment {
3295
3430
  * @returns {google.payments.api.PaymentMethodSpecification}
3296
3431
  */
3297
3432
  _getCardPaymentMethod(submit = false) {
3433
+ const { require: { phone } = {} } = this.params;
3434
+
3298
3435
  return {
3299
3436
  type: 'CARD',
3300
3437
  parameters: {
@@ -3303,7 +3440,7 @@ class AbstractGooglePayment extends Payment {
3303
3440
  billingAddressRequired: true,
3304
3441
  billingAddressParameters: {
3305
3442
  format: 'FULL',
3306
- phoneNumberRequired: true,
3443
+ phoneNumberRequired: Boolean(phone),
3307
3444
  },
3308
3445
  },
3309
3446
  ...(submit && {
@@ -3336,29 +3473,30 @@ class AbstractGooglePayment extends Payment {
3336
3473
  cart.shipment_price = 0;
3337
3474
  cart.shipping = {};
3338
3475
 
3339
- const { shipment_delivery } = cart;
3340
3476
  const { require: { email, shipping, phone } = {} } = this.params;
3341
3477
 
3478
+ /** @type {google.payments.api.CallbackIntent[]} */
3479
+ const callbackIntents = ['OFFER', 'PAYMENT_AUTHORIZATION'];
3480
+
3481
+ if (shipping) {
3482
+ callbackIntents.push('SHIPPING_ADDRESS', 'SHIPPING_OPTION');
3483
+ }
3484
+
3342
3485
  return {
3343
3486
  apiVersion: API_VERSION,
3344
3487
  apiVersionMinor: API_MINOR_VERSION,
3345
- transactionInfo: getTransactionInfo(cart),
3488
+ transactionInfo: getTransactionInfo.call(this, cart),
3346
3489
  allowedPaymentMethods: this._getAllowedPaymentMethods(true),
3347
3490
  emailRequired: Boolean(email),
3348
3491
  shippingAddressRequired: Boolean(shipping),
3349
3492
  shippingAddressParameters: {
3350
3493
  phoneNumberRequired: Boolean(phone),
3351
3494
  },
3352
- shippingOptionRequired: Boolean(shipment_delivery),
3495
+ shippingOptionRequired: Boolean(shipping),
3353
3496
  shippingOptionParameters: getShippingOptionParameters.call(this, cart),
3354
3497
  offerInfo: getOfferInfo(cart),
3355
3498
  merchantInfo,
3356
- callbackIntents: [
3357
- 'OFFER',
3358
- 'SHIPPING_ADDRESS',
3359
- 'SHIPPING_OPTION',
3360
- 'PAYMENT_AUTHORIZATION',
3361
- ],
3499
+ callbackIntents,
3362
3500
  };
3363
3501
  }
3364
3502
 
@@ -3482,6 +3620,22 @@ class AbstractGooglePayment extends Payment {
3482
3620
  /** @typedef {import('../../../types').Cart} Cart */
3483
3621
 
3484
3622
  class AuthorizeNetGooglePayment extends AbstractGooglePayment {
3623
+ /**
3624
+ * @override
3625
+ * @returns {google.payments.api.CardNetwork[]}
3626
+ */
3627
+ getAllowedCardNetworks() {
3628
+ return ['AMEX', 'DISCOVER', 'JCB', 'MASTERCARD', 'VISA'];
3629
+ }
3630
+
3631
+ /**
3632
+ * @override
3633
+ * @returns {google.payments.api.CardAuthMethod[]}
3634
+ */
3635
+ getAllowedCardAuthMethods() {
3636
+ return ['PAN_ONLY', 'CRYPTOGRAM_3DS'];
3637
+ }
3638
+
3485
3639
  /**
3486
3640
  * @override
3487
3641
  * @returns {google.payments.api.PaymentGatewayTokenizationParameters}
@@ -3499,7 +3653,6 @@ class AuthorizeNetGooglePayment extends AbstractGooglePayment {
3499
3653
  * @returns {Promise<object>}
3500
3654
  */
3501
3655
  async preparePaymentDataForCartUpdate(paymentData) {
3502
- const { require: { shipping: requireShipping } = {} } = this.params;
3503
3656
  const { email, shippingAddress, shippingOptionData, paymentMethodData } =
3504
3657
  paymentData;
3505
3658
 
@@ -3520,7 +3673,7 @@ class AuthorizeNetGooglePayment extends AbstractGooglePayment {
3520
3673
  },
3521
3674
  ...convertToSwellAddress$2(billingAddress),
3522
3675
  },
3523
- ...(requireShipping && {
3676
+ ...(shippingAddress && {
3524
3677
  shipping: {
3525
3678
  ...convertToSwellAddress$2(shippingAddress),
3526
3679
  service: shippingOptionData?.id || undefined,
@@ -3587,9 +3740,15 @@ class AbstractApplePayment extends Payment {
3587
3740
  return window.ApplePaySession;
3588
3741
  }
3589
3742
 
3590
- /** @returns {string[]} */
3743
+ /**
3744
+ * We should specify the payment methods in the order preferred by the gateway.
3745
+ *
3746
+ * @see {@link https://developer.apple.com/documentation/applepayontheweb/applepaypaymentrequest/supportednetworks}
3747
+ *
3748
+ * @returns {string[]}
3749
+ */
3591
3750
  getSupportedCardNetworks() {
3592
- return ['amex', 'discover', 'interac', 'jcb', 'masterCard', 'visa'];
3751
+ return ['visa', 'masterCard', 'amex', 'discover', 'interac', 'jcb'];
3593
3752
  }
3594
3753
 
3595
3754
  /** @returns {ApplePayJS.ApplePayMerchantCapability[]} */
@@ -3600,12 +3759,12 @@ class AbstractApplePayment extends Payment {
3600
3759
  /**
3601
3760
  * Creates the Apple Pay payment request object
3602
3761
  *
3603
- * IMPORTANT: countryCode here is the MERCHANT's country (where your business is located),
3604
- * NOT the customer's country. Customer country comes from shippingContact.countryCode.
3762
+ * IMPORTANT: `countryCode` here is the MERCHANT's country (where your business is located),
3763
+ * NOT the customer's country. Customer country comes from `shippingContact.countryCode`.
3605
3764
  *
3606
- * NOTE: We do NOT pass shippingMethods in the initial request. Shipping methods
3765
+ * NOTE: We do NOT pass `shippingMethods` in the initial request. Shipping methods
3607
3766
  * are provided dynamically after the user selects/confirms their address in the
3608
- * 'shippingcontactselected' event handler.
3767
+ * `'shippingcontactselected'` event handler.
3609
3768
  *
3610
3769
  * @param {Cart} cart
3611
3770
  * @returns {ApplePayJS.ApplePayPaymentRequest}
@@ -3613,38 +3772,21 @@ class AbstractApplePayment extends Payment {
3613
3772
  _createPaymentRequest(cart) {
3614
3773
  cart = { ...cart };
3615
3774
 
3616
- const { require = {} } = this.params;
3617
3775
  const {
3618
3776
  settings: { country },
3619
3777
  currency,
3620
3778
  } = cart;
3621
3779
 
3622
- const requiredShippingContactFields = [];
3623
- const requiredBillingContactFields = ['postalAddress'];
3624
-
3625
- if (require.name) {
3626
- requiredShippingContactFields.push('name');
3627
- }
3628
-
3629
- if (require.email) {
3630
- requiredShippingContactFields.push('email');
3631
- }
3632
-
3633
- if (require.phone) {
3634
- requiredShippingContactFields.push('phone');
3635
- }
3636
-
3637
- if (require.shipping) {
3638
- requiredShippingContactFields.push('postalAddress');
3639
- }
3640
-
3641
3780
  // When initiating a payment request,
3642
3781
  // we should not display the shipping cost, as it will be calculated later.
3643
3782
  cart.shipment_price = 0;
3644
3783
  cart.shipping = {};
3645
3784
 
3785
+ const { requiredBillingContactFields, requiredShippingContactFields } =
3786
+ getRequiredContactFields(this.params);
3787
+
3646
3788
  return {
3647
- total: getTotal(cart, this.merchantInfo),
3789
+ total: getTotal.call(this, cart, this.merchantInfo),
3648
3790
  countryCode: country, // Merchant's country
3649
3791
  currencyCode: currency,
3650
3792
  supportedNetworks: this.getSupportedCardNetworks(),
@@ -3826,6 +3968,22 @@ class AbstractApplePayment extends Payment {
3826
3968
  }
3827
3969
 
3828
3970
  class AuthorizeNetApplePayment extends AbstractApplePayment {
3971
+ /**
3972
+ * @override
3973
+ * @returns {string[]}
3974
+ */
3975
+ getSupportedCardNetworks() {
3976
+ return ['visa', 'masterCard', 'amex', 'discover'];
3977
+ }
3978
+
3979
+ /**
3980
+ * @override
3981
+ * @returns {ApplePayJS.ApplePayMerchantCapability[]}
3982
+ */
3983
+ getMerchantCapabilities() {
3984
+ return ['supports3DS', 'supportsDebit', 'supportsCredit'];
3985
+ }
3986
+
3829
3987
  /**
3830
3988
  * @override
3831
3989
  * @param {ApplePayJS.ApplePayValidateMerchantEvent} event
@@ -3859,11 +4017,9 @@ class AuthorizeNetApplePayment extends AbstractApplePayment {
3859
4017
  payment: { token, shippingContact, billingContact },
3860
4018
  } = event;
3861
4019
 
3862
- const { require: { shipping: requireShipping } = {} } = this.params;
3863
-
3864
4020
  return {
3865
4021
  account: {
3866
- email: shippingContact.emailAddress,
4022
+ email: shippingContact?.emailAddress || billingContact?.emailAddress,
3867
4023
  },
3868
4024
  billing: {
3869
4025
  method: 'apple',
@@ -3875,7 +4031,7 @@ class AuthorizeNetApplePayment extends AbstractApplePayment {
3875
4031
  },
3876
4032
  ...convertToSwellAddress$1(billingContact),
3877
4033
  },
3878
- ...(requireShipping && {
4034
+ ...(shippingContact && {
3879
4035
  shipping: convertToSwellAddress$1(shippingContact),
3880
4036
  }),
3881
4037
  };
@@ -3995,7 +4151,7 @@ async function getConvesioPaymentSettings(mode, settings, country) {
3995
4151
  merchantAccount: false,
3996
4152
  countryCode: country || 'US',
3997
4153
  shopperLocale: 'en-US',
3998
- // shopperReference: email ? md5(email) : undefined,
4154
+ // shopperReference: email ? md5(email.toLowerCase()) : undefined,
3999
4155
  }),
4000
4156
  },
4001
4157
  ).then((res) => res.json());
@@ -4123,15 +4279,20 @@ class ConvesioCardPayment extends Payment {
4123
4279
  }
4124
4280
  }
4125
4281
 
4282
+ function getBaseConvesioVaultUrl(mode) {
4283
+ return isLiveMode(mode)
4284
+ ? 'https://vault.convesiopay.com'
4285
+ : 'https://qa-vault.convesiopay.com';
4286
+ }
4287
+
4126
4288
  function createConvesioCardPaymentToken(settings, data) {
4127
- const baseUrl = getBaseConvesioApiUrl(settings.mode);
4289
+ const baseUrl = getBaseConvesioVaultUrl(settings.mode);
4128
4290
 
4129
4291
  return fetch(`${baseUrl}/v1/create-token`, {
4130
4292
  method: 'POST',
4131
4293
  headers: {
4132
4294
  Accept: 'application/json',
4133
4295
  'Content-Type': 'application/json',
4134
- 'X-Requested-With': 'convesio-pay-dashboard',
4135
4296
  'X-Api-Key': settings.public_key,
4136
4297
  },
4137
4298
  body: JSON.stringify(data),
@@ -4246,8 +4407,6 @@ class ConvesioPayApplePayment extends AbstractApplePayment {
4246
4407
  payment: { token, shippingContact, billingContact },
4247
4408
  } = event;
4248
4409
 
4249
- const { require: { shipping: requireShipping } = {} } = this.params;
4250
-
4251
4410
  const payment = await createConvesioApplePaymentToken(
4252
4411
  this.method.mode,
4253
4412
  this.convesiopay,
@@ -4269,7 +4428,7 @@ class ConvesioPayApplePayment extends AbstractApplePayment {
4269
4428
 
4270
4429
  return {
4271
4430
  account: {
4272
- email: shippingContact.emailAddress,
4431
+ email: shippingContact?.emailAddress || billingContact?.emailAddress,
4273
4432
  },
4274
4433
  billing: {
4275
4434
  method: 'apple',
@@ -4284,7 +4443,7 @@ class ConvesioPayApplePayment extends AbstractApplePayment {
4284
4443
  },
4285
4444
  ...convertToSwellAddress$1(billingContact),
4286
4445
  },
4287
- ...(requireShipping && {
4446
+ ...(shippingContact && {
4288
4447
  shipping: convertToSwellAddress$1(shippingContact),
4289
4448
  }),
4290
4449
  };
@@ -4414,7 +4573,6 @@ class ConvesioPayGooglePayment extends AbstractGooglePayment {
4414
4573
  * @returns {Promise<object>}
4415
4574
  */
4416
4575
  async preparePaymentDataForCartUpdate(paymentData) {
4417
- const { require: { shipping: requireShipping } = {} } = this.params;
4418
4576
  const { email, shippingAddress, shippingOptionData, paymentMethodData } =
4419
4577
  paymentData;
4420
4578
 
@@ -4457,7 +4615,7 @@ class ConvesioPayGooglePayment extends AbstractGooglePayment {
4457
4615
  },
4458
4616
  ...convertToSwellAddress$2(billingAddress),
4459
4617
  },
4460
- ...(requireShipping && {
4618
+ ...(shippingAddress && {
4461
4619
  shipping: {
4462
4620
  ...convertToSwellAddress$2(shippingAddress),
4463
4621
  service: shippingOptionData?.id || undefined,
@@ -5353,20 +5511,29 @@ class SezzleDirectPayment extends Payment {
5353
5511
  settings: { name },
5354
5512
  } = cart;
5355
5513
 
5356
- const shipmentDelivery = Boolean(cart.shipment_delivery);
5514
+ const { require: { shipping } = {} } = this.params;
5357
5515
  const cartCurrency = getCartCurrency(cart);
5358
5516
 
5359
5517
  return {
5360
5518
  checkout_payload: {
5361
- express_checkout_type: shipmentDelivery ? 'multi-step' : 'no-shipping',
5519
+ express_checkout_type: shipping ? 'multi-step' : 'no-shipping',
5520
+ customer: {
5521
+ email: cart.account?.email,
5522
+ first_name: cart.account?.first_name,
5523
+ last_name: cart.account?.last_name,
5524
+ phone: cart.account?.phone,
5525
+ // TODO: recurring payments https://docs.sezzle.com/docs/api/tokenization/intro
5526
+ // tokenize: cart.subscription_delivery,
5527
+ // recurring: cart.subscription_delivery,
5528
+ },
5362
5529
  order: {
5363
5530
  intent: 'AUTH',
5364
5531
  reference_id: cart.checkout_id,
5365
5532
  description: `${name} #${cart.number}`,
5366
- requires_shipping_info: shipmentDelivery,
5533
+ requires_shipping_info: shipping,
5367
5534
  items: getItems(cart),
5368
5535
  discounts: getDiscounts(cart),
5369
- tax_amount: shipmentDelivery
5536
+ tax_amount: shipping
5370
5537
  ? undefined
5371
5538
  : getAmountInCents(cartCurrency, cart.tax_total),
5372
5539
  order_amount: getAmountInCents(cartCurrency, cart.capture_total),
@@ -5626,15 +5793,6 @@ function convertToSwellAddress(address) {
5626
5793
  };
5627
5794
  }
5628
5795
 
5629
- /**
5630
- * @param {string} currency
5631
- * @param {number} amount
5632
- * @returns {number}
5633
- */
5634
- function amountInCents(currency, amount) {
5635
- return Math.round(amount * 100);
5636
- }
5637
-
5638
5796
  class PaymentController {
5639
5797
  constructor(api, options) {
5640
5798
  this.api = api;