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.
@@ -12845,13 +12845,13 @@
12845
12845
  tax_included_total,
12846
12846
  settings,
12847
12847
  } = cart;
12848
- const { price: shippingPrice, service_name } = shipping || {};
12848
+ const { price: shippingPrice, service, service_name } = shipping || {};
12849
12849
  const { country, name } = settings || {};
12850
12850
  const { require: { shipping: requireShipping } = {} } = params;
12851
12851
 
12852
12852
  const stripeCurrency = currency.toLowerCase();
12853
12853
  const displayItems = items.map((item) => ({
12854
- label: get(item, 'product.name', 'Unknown product'),
12854
+ label: item.product_name || item.product?.name || 'Unknown product',
12855
12855
  amount: stripeAmountByCurrency(
12856
12856
  currency,
12857
12857
  item.price_total - item.discount_total,
@@ -12873,14 +12873,21 @@
12873
12873
  }
12874
12874
 
12875
12875
  let shippingOptions;
12876
- const services = get(shipment_rating, 'services');
12877
- if (Array.isArray(services) && services.length > 0) {
12876
+ const services = shipment_rating?.services;
12877
+ if (requireShipping && Array.isArray(services) && services.length > 0) {
12878
12878
  shippingOptions = services.map((service) => ({
12879
12879
  id: service.id,
12880
12880
  label: service.name,
12881
12881
  detail: service.description,
12882
12882
  amount: stripeAmountByCurrency(currency, service.price),
12883
12883
  }));
12884
+
12885
+ const index = shippingOptions.findIndex((item) => item.id === service);
12886
+
12887
+ if (index > 0) {
12888
+ // Move selected shipping option to the top
12889
+ shippingOptions.unshift(...shippingOptions.splice(index, 1));
12890
+ }
12884
12891
  }
12885
12892
 
12886
12893
  return {
@@ -12892,7 +12899,7 @@
12892
12899
  pending: true,
12893
12900
  },
12894
12901
  displayItems,
12895
- ...(requireShipping && { shippingOptions }),
12902
+ ...(shippingOptions && { shippingOptions }),
12896
12903
  };
12897
12904
  }
12898
12905
 
@@ -13440,6 +13447,7 @@
13440
13447
 
13441
13448
  /** @typedef {import('@stripe/stripe-js').Stripe} Stripe */
13442
13449
  /** @typedef {import('@stripe/stripe-js').PaymentRequestPaymentMethodEvent} PaymentRequestPaymentMethodEvent */
13450
+ /** @typedef {import('../../../types').Cart} Cart */
13443
13451
 
13444
13452
  class StripeGooglePayment extends Payment {
13445
13453
  constructor(api, options, params, methods) {
@@ -13507,6 +13515,7 @@
13507
13515
  this.element.mount(`#${this.elementContainer.id}`);
13508
13516
  }
13509
13517
 
13518
+ /** @param {Cart} cart */
13510
13519
  _createPaymentRequest(cart) {
13511
13520
  const { require: { name, email, shipping, phone } = {} } = this.params;
13512
13521
 
@@ -13519,15 +13528,10 @@
13519
13528
  ...getPaymentRequestData(cart, this.params),
13520
13529
  });
13521
13530
 
13522
- paymentRequest.on(
13523
- 'shippingaddresschange',
13524
- this._onShippingAddressChange.bind(this),
13525
- );
13526
- paymentRequest.on(
13527
- 'shippingoptionchange',
13528
- this._onShippingOptionChange.bind(this),
13529
- );
13530
- paymentRequest.on('paymentmethod', this._onPaymentMethod.bind(this));
13531
+ paymentRequest
13532
+ .on('shippingaddresschange', this._onShippingAddressChange.bind(this))
13533
+ .on('shippingoptionchange', this._onShippingOptionChange.bind(this))
13534
+ .on('paymentmethod', this._onPaymentMethod.bind(this));
13531
13535
 
13532
13536
  return paymentRequest;
13533
13537
  }
@@ -13535,9 +13539,9 @@
13535
13539
  /** @param {import('@stripe/stripe-js').PaymentRequestShippingAddressEvent} event */
13536
13540
  async _onShippingAddressChange(event) {
13537
13541
  const { shippingAddress, updateWith } = event;
13538
- const shipping = this._mapShippingAddress(shippingAddress);
13542
+
13539
13543
  const cart = await this.updateCart({
13540
- shipping: { ...shipping, service: null },
13544
+ shipping: this._mapShippingAddress(shippingAddress),
13541
13545
  shipment_rating: null,
13542
13546
  });
13543
13547
 
@@ -13577,16 +13581,15 @@
13577
13581
  shippingOption,
13578
13582
  complete,
13579
13583
  } = event;
13580
- const { require: { shipping: requireShipping } = {} } = this.params;
13581
13584
 
13582
13585
  await this.updateCart({
13583
13586
  account: {
13584
- email: payerEmail,
13587
+ email: payerEmail || billing_details?.email,
13585
13588
  },
13586
- ...(requireShipping && {
13589
+ ...(shippingAddress && {
13587
13590
  shipping: {
13588
13591
  ...this._mapShippingAddress(shippingAddress),
13589
- service: shippingOption.id,
13592
+ service: shippingOption?.id || undefined,
13590
13593
  },
13591
13594
  }),
13592
13595
  billing: {
@@ -13600,9 +13603,9 @@
13600
13603
  exp_month: card.exp_month,
13601
13604
  exp_year: card.exp_year,
13602
13605
  last4: card.last4,
13603
- address_check: card.checks.address_line1_check,
13604
- zip_check: card.checks.address_postal_code_check,
13605
- cvc_check: card.checks.cvc_check,
13606
+ address_check: card.checks?.address_line1_check,
13607
+ zip_check: card.checks?.address_postal_code_check,
13608
+ cvc_check: card.checks?.cvc_check,
13606
13609
  },
13607
13610
  },
13608
13611
  });
@@ -13650,8 +13653,8 @@
13650
13653
  _mapShippingAddress(address = {}) {
13651
13654
  return {
13652
13655
  name: address.recipient,
13653
- address1: address.addressLine[0],
13654
- address2: address.addressLine[1],
13656
+ address1: address.addressLine?.[0],
13657
+ address2: address.addressLine?.[1],
13655
13658
  city: address.city,
13656
13659
  state: address.region,
13657
13660
  zip: address.postalCode,
@@ -13665,18 +13668,19 @@
13665
13668
  return {
13666
13669
  name: address.name,
13667
13670
  phone: address.phone,
13668
- address1: address.address.line1,
13669
- address2: address.address.line2,
13670
- city: address.address.city,
13671
- state: address.address.state,
13672
- zip: address.address.postal_code,
13673
- country: address.address.country,
13671
+ address1: address.address?.line1,
13672
+ address2: address.address?.line2,
13673
+ city: address.address?.city,
13674
+ state: address.address?.state,
13675
+ zip: address.address?.postal_code,
13676
+ country: address.address?.country,
13674
13677
  };
13675
13678
  }
13676
13679
  }
13677
13680
 
13678
13681
  /** @typedef {import('@stripe/stripe-js').Stripe} Stripe */
13679
13682
  /** @typedef {import('@stripe/stripe-js').PaymentRequestPaymentMethodEvent} PaymentRequestPaymentMethodEvent */
13683
+ /** @typedef {import('../../../types').Cart} Cart */
13680
13684
 
13681
13685
  class StripeApplePayment extends Payment {
13682
13686
  constructor(api, options, params, methods) {
@@ -13730,7 +13734,7 @@
13730
13734
  const paymentRequest = this._createPaymentRequest(cart);
13731
13735
  const canMakePayment = await paymentRequest.canMakePayment();
13732
13736
 
13733
- if (!canMakePayment || !canMakePayment.applePay) {
13737
+ if (!canMakePayment?.applePay) {
13734
13738
  throw new Error(
13735
13739
  'This device is not capable of making Apple Pay payments',
13736
13740
  );
@@ -13767,6 +13771,7 @@
13767
13771
  }
13768
13772
  }
13769
13773
 
13774
+ /** @param {Cart} cart */
13770
13775
  _createPaymentRequest(cart) {
13771
13776
  const { require: { name, email, shipping, phone } = {} } = this.params;
13772
13777
 
@@ -13779,15 +13784,10 @@
13779
13784
  ...getPaymentRequestData(cart, this.params),
13780
13785
  });
13781
13786
 
13782
- paymentRequest.on(
13783
- 'shippingaddresschange',
13784
- this._onShippingAddressChange.bind(this),
13785
- );
13786
- paymentRequest.on(
13787
- 'shippingoptionchange',
13788
- this._onShippingOptionChange.bind(this),
13789
- );
13790
- paymentRequest.on('paymentmethod', this._onPaymentMethod.bind(this));
13787
+ paymentRequest
13788
+ .on('shippingaddresschange', this._onShippingAddressChange.bind(this))
13789
+ .on('shippingoptionchange', this._onShippingOptionChange.bind(this))
13790
+ .on('paymentmethod', this._onPaymentMethod.bind(this));
13791
13791
 
13792
13792
  return paymentRequest;
13793
13793
  }
@@ -13795,9 +13795,9 @@
13795
13795
  /** @param {import('@stripe/stripe-js').PaymentRequestShippingAddressEvent} event */
13796
13796
  async _onShippingAddressChange(event) {
13797
13797
  const { shippingAddress, updateWith } = event;
13798
- const shipping = this._mapShippingAddress(shippingAddress);
13798
+
13799
13799
  const cart = await this.updateCart({
13800
- shipping: { ...shipping, service: null },
13800
+ shipping: this._mapShippingAddress(shippingAddress),
13801
13801
  shipment_rating: null,
13802
13802
  });
13803
13803
 
@@ -13837,16 +13837,15 @@
13837
13837
  shippingOption,
13838
13838
  complete,
13839
13839
  } = event;
13840
- const { require: { shipping: requireShipping } = {} } = this.params;
13841
13840
 
13842
13841
  await this.updateCart({
13843
13842
  account: {
13844
- email: payerEmail,
13843
+ email: payerEmail || billing_details?.email,
13845
13844
  },
13846
- ...(requireShipping && {
13845
+ ...(shippingAddress && {
13847
13846
  shipping: {
13848
13847
  ...this._mapShippingAddress(shippingAddress),
13849
- service: shippingOption.id,
13848
+ service: shippingOption?.id || undefined,
13850
13849
  },
13851
13850
  }),
13852
13851
  billing: {
@@ -13860,9 +13859,9 @@
13860
13859
  exp_month: card.exp_month,
13861
13860
  exp_year: card.exp_year,
13862
13861
  last4: card.last4,
13863
- address_check: card.checks.address_line1_check,
13864
- zip_check: card.checks.address_postal_code_check,
13865
- cvc_check: card.checks.cvc_check,
13862
+ address_check: card.checks?.address_line1_check,
13863
+ zip_check: card.checks?.address_postal_code_check,
13864
+ cvc_check: card.checks?.cvc_check,
13866
13865
  },
13867
13866
  },
13868
13867
  });
@@ -13876,8 +13875,8 @@
13876
13875
  _mapShippingAddress(address = {}) {
13877
13876
  return {
13878
13877
  name: address.recipient,
13879
- address1: address.addressLine[0],
13880
- address2: address.addressLine[1],
13878
+ address1: address.addressLine?.[0],
13879
+ address2: address.addressLine?.[1],
13881
13880
  city: address.city,
13882
13881
  state: address.region,
13883
13882
  zip: address.postalCode,
@@ -13891,12 +13890,12 @@
13891
13890
  return {
13892
13891
  name: address.name,
13893
13892
  phone: address.phone,
13894
- address1: address.address.line1,
13895
- address2: address.address.line2,
13896
- city: address.address.city,
13897
- state: address.address.state,
13898
- zip: address.address.postal_code,
13899
- country: address.address.country,
13893
+ address1: address.address?.line1,
13894
+ address2: address.address?.line2,
13895
+ city: address.address?.city,
13896
+ state: address.address?.state,
13897
+ zip: address.address?.postal_code,
13898
+ country: address.address?.country,
13900
13899
  };
13901
13900
  }
13902
13901
  }
@@ -14164,6 +14163,44 @@
14164
14163
  return discount.id;
14165
14164
  }
14166
14165
 
14166
+ /** @type {Map<string, number>} */
14167
+ const CURRENCIES_CENTS = new Map();
14168
+
14169
+ /**
14170
+ * @param {string} currency
14171
+ * @returns {number}
14172
+ */
14173
+ function getCurrencyCents(currency) {
14174
+ let cents = CURRENCIES_CENTS.get(currency);
14175
+
14176
+ if (cents !== undefined) {
14177
+ return cents;
14178
+ }
14179
+
14180
+ const formatter = new Intl.NumberFormat('en-US', {
14181
+ style: 'currency',
14182
+ currency,
14183
+ });
14184
+
14185
+ const options = formatter.resolvedOptions();
14186
+ const decimals = options.maximumFractionDigits ?? 2;
14187
+
14188
+ cents = 10 ** decimals;
14189
+
14190
+ CURRENCIES_CENTS.set(currency, cents);
14191
+
14192
+ return cents;
14193
+ }
14194
+
14195
+ /**
14196
+ * @param {string} currency
14197
+ * @param {number} amount
14198
+ * @returns {number}
14199
+ */
14200
+ function amountInCents(currency, amount) {
14201
+ return Math.round(amount * getCurrencyCents(currency));
14202
+ }
14203
+
14167
14204
  /** @typedef {import('./payment').default} Payment */
14168
14205
  /** @typedef {import('../../types').Cart} Cart */
14169
14206
  /** @typedef {import('../../types').Address} Address */
@@ -14251,7 +14288,7 @@
14251
14288
  this,
14252
14289
  cart,
14253
14290
  ),
14254
- newTransactionInfo: getTransactionInfo(cart),
14291
+ newTransactionInfo: getTransactionInfo.call(this, cart),
14255
14292
  };
14256
14293
  }
14257
14294
 
@@ -14264,7 +14301,7 @@
14264
14301
  },
14265
14302
  });
14266
14303
 
14267
- return { newTransactionInfo: getTransactionInfo(cart) };
14304
+ return { newTransactionInfo: getTransactionInfo.call(this, cart) };
14268
14305
  } catch (err) {
14269
14306
  return createError(
14270
14307
  intermediatePaymentData.callbackTrigger,
@@ -14286,7 +14323,7 @@
14286
14323
 
14287
14324
  return {
14288
14325
  newOfferInfo: getOfferInfo(cart),
14289
- newTransactionInfo: getTransactionInfo(cart),
14326
+ newTransactionInfo: getTransactionInfo.call(this, cart),
14290
14327
  };
14291
14328
  } catch (err) {
14292
14329
  return createError(
@@ -14386,12 +14423,13 @@
14386
14423
 
14387
14424
  /**
14388
14425
  * Converts cart data to Google Pay transaction information.
14426
+ * @this {Payment}
14389
14427
  * @param {Cart} cart - The current cart data
14390
14428
  * @returns {google.payments.api.TransactionInfo} Transaction info for Google Pay
14391
14429
  */
14392
14430
  function getTransactionInfo(cart) {
14393
- const { settings, capture_total, currency, shipment_delivery, shipping } =
14394
- cart;
14431
+ const { require: { shipping: shipmentDelivery = false } = {} } = this.params;
14432
+ const { settings, capture_total, currency, shipping } = cart;
14395
14433
 
14396
14434
  return {
14397
14435
  countryCode: settings?.country || 'US',
@@ -14399,7 +14437,7 @@
14399
14437
  totalPrice: String(capture_total ?? 0),
14400
14438
  // Set status to FINAL if shipping has been selected, otherwise ESTIMATED
14401
14439
  totalPriceStatus:
14402
- !shipment_delivery || shipping?.service ? 'FINAL' : 'ESTIMATED',
14440
+ !shipmentDelivery || shipping?.service ? 'FINAL' : 'ESTIMATED',
14403
14441
  totalPriceLabel: 'Total',
14404
14442
  displayItems: getDisplayItems(cart),
14405
14443
  };
@@ -14412,12 +14450,14 @@
14412
14450
  * @returns {google.payments.api.ShippingOptionParameters | undefined} Shipping options for Google Pay
14413
14451
  */
14414
14452
  function getShippingOptionParameters(cart) {
14415
- const { shipment_delivery, shipment_rating, shipping } = cart;
14453
+ const { require: { shipping: shipmentDelivery = false } = {} } = this.params;
14416
14454
 
14417
- if (!shipment_delivery) {
14455
+ if (!shipmentDelivery) {
14418
14456
  return undefined;
14419
14457
  }
14420
14458
 
14459
+ const { shipment_rating, shipping } = cart;
14460
+
14421
14461
  if (!shipment_rating?.services?.length) {
14422
14462
  // Return placeholder when no shipping services are available
14423
14463
  return {
@@ -14498,20 +14538,11 @@
14498
14538
  };
14499
14539
  }
14500
14540
 
14541
+ /** @typedef {import('../../../types').Cart} Cart */
14542
+
14501
14543
  const API_VERSION$1 = 2;
14502
14544
  const API_MINOR_VERSION$1 = 0;
14503
14545
 
14504
- const ALLOWED_CARD_AUTH_METHODS = ['PAN_ONLY', 'CRYPTOGRAM_3DS'];
14505
-
14506
- const ALLOWED_CARD_NETWORKS = [
14507
- 'AMEX',
14508
- 'DISCOVER',
14509
- 'INTERAC',
14510
- 'JCB',
14511
- 'MASTERCARD',
14512
- 'VISA',
14513
- ];
14514
-
14515
14546
  class BraintreeGooglePayment extends Payment {
14516
14547
  constructor(api, options, params, methods) {
14517
14548
  if (!methods.card) {
@@ -14547,6 +14578,9 @@
14547
14578
  if (this.google) {
14548
14579
  this.googleClient = new this.google.payments.api.PaymentsClient({
14549
14580
  environment: isLiveMode(this.method.mode) ? 'PRODUCTION' : 'TEST',
14581
+ paymentDataCallbacks: {
14582
+ onPaymentDataChanged: onPaymentDataChanged.bind(this),
14583
+ },
14550
14584
  });
14551
14585
  }
14552
14586
 
@@ -14562,31 +14596,12 @@
14562
14596
  BraintreeGooglePayment.googleClient = googleClient;
14563
14597
  }
14564
14598
 
14565
- /** @returns {google.payments.api.PaymentMethodSpecification} */
14566
- get cardPaymentMethod() {
14567
- return {
14568
- type: 'CARD',
14569
- parameters: {
14570
- allowedAuthMethods: ALLOWED_CARD_AUTH_METHODS,
14571
- allowedCardNetworks: ALLOWED_CARD_NETWORKS,
14572
- billingAddressRequired: true,
14573
- billingAddressParameters: {
14574
- format: 'FULL',
14575
- phoneNumberRequired: true,
14576
- },
14577
- },
14578
- };
14579
- }
14580
-
14581
- /** @returns {google.payments.api.PaymentMethodSpecification[]} */
14582
- get allowedPaymentMethods() {
14583
- return [this.cardPaymentMethod];
14584
- }
14585
-
14599
+ /** @param {Cart} cart */
14586
14600
  async createElements(cart) {
14587
14601
  const {
14588
14602
  elementId = 'googlepay-button',
14589
14603
  locale = 'en',
14604
+ require: { phone } = {},
14590
14605
  style: { color = 'black', type = 'plain', sizeMode = 'fill' } = {},
14591
14606
  } = this.params;
14592
14607
 
@@ -14597,10 +14612,35 @@
14597
14612
  this.setElementContainer(elementId);
14598
14613
  await this.loadScripts(this.scripts);
14599
14614
 
14615
+ const braintreeClient = await this._createBraintreeClient();
14616
+
14617
+ const googlePayment = await this.braintree.googlePayment.create({
14618
+ client: braintreeClient,
14619
+ googleMerchantId: this.method.merchant_id,
14620
+ googlePayVersion: API_VERSION$1,
14621
+ });
14622
+
14623
+ const paymentDataRequest = googlePayment.createPaymentDataRequest(
14624
+ this._createPaymentRequestData(cart),
14625
+ );
14626
+
14627
+ const cardPaymentMethod = paymentDataRequest.allowedPaymentMethods.find(
14628
+ (method) => method.type === 'CARD',
14629
+ );
14630
+
14631
+ if (cardPaymentMethod !== undefined) {
14632
+ cardPaymentMethod.parameters.billingAddressRequired = true;
14633
+
14634
+ cardPaymentMethod.parameters.billingAddressParameters = {
14635
+ format: 'FULL',
14636
+ phoneNumberRequired: Boolean(phone),
14637
+ };
14638
+ }
14639
+
14600
14640
  const isReadyToPay = await this.googleClient.isReadyToPay({
14601
14641
  apiVersion: API_VERSION$1,
14602
14642
  apiVersionMinor: API_MINOR_VERSION$1,
14603
- allowedPaymentMethods: this.allowedPaymentMethods,
14643
+ allowedPaymentMethods: paymentDataRequest.allowedPaymentMethods,
14604
14644
  existingPaymentMethodRequired: true,
14605
14645
  });
14606
14646
 
@@ -14610,16 +14650,6 @@
14610
14650
  );
14611
14651
  }
14612
14652
 
14613
- const braintreeClient = await this._createBraintreeClient();
14614
- const googlePayment = await this.braintree.googlePayment.create({
14615
- client: braintreeClient,
14616
- googleMerchantId: this.method.merchant_id,
14617
- googlePayVersion: API_VERSION$1,
14618
- });
14619
- const paymentRequestData = this._createPaymentRequestData(cart);
14620
- const paymentDataRequest =
14621
- googlePayment.createPaymentDataRequest(paymentRequestData);
14622
-
14623
14653
  this.element = this.googleClient.createButton({
14624
14654
  buttonColor: color,
14625
14655
  buttonType: type,
@@ -14646,6 +14676,7 @@
14646
14676
  }
14647
14677
  }
14648
14678
 
14679
+ /** @returns {Promise<braintree.Client>} */
14649
14680
  async _createBraintreeClient() {
14650
14681
  const authorization = await this.authorizeGateway({
14651
14682
  gateway: 'braintree',
@@ -14660,39 +14691,51 @@
14660
14691
  });
14661
14692
  }
14662
14693
 
14663
- /** @returns {google.payments.api.PaymentDataRequest} */
14694
+ /**
14695
+ * @param {Cart} cart
14696
+ * @returns {google.payments.api.PaymentDataRequest}
14697
+ */
14664
14698
  _createPaymentRequestData(cart) {
14665
14699
  const {
14666
- settings: { name, country },
14667
- capture_total,
14668
- currency,
14700
+ settings: { name },
14669
14701
  } = cart;
14702
+
14670
14703
  const { require: { email, shipping, phone } = {} } = this.params;
14671
14704
 
14705
+ /** @type {google.payments.api.CallbackIntent[]} */
14706
+ const callbackIntents = ['OFFER'];
14707
+
14708
+ if (shipping) {
14709
+ callbackIntents.push('SHIPPING_ADDRESS', 'SHIPPING_OPTION');
14710
+ }
14711
+
14672
14712
  return {
14673
14713
  apiVersion: API_VERSION$1,
14674
14714
  apiVersionMinor: API_MINOR_VERSION$1,
14675
- transactionInfo: {
14676
- countryCode: country,
14677
- currencyCode: currency,
14678
- totalPrice: capture_total.toString(),
14679
- totalPriceStatus: 'ESTIMATED',
14680
- },
14681
- allowedPaymentMethods: this.allowedPaymentMethods,
14715
+ transactionInfo: getTransactionInfo.call(this, cart),
14716
+ /**
14717
+ * @see {@link https://developer.paypal.com/braintree/docs/guides/google-pay/client-side/javascript/v3/#requesting-a-payment}
14718
+ *
14719
+ * Braintree automatically populates the `allowedPaymentMethods` property.
14720
+ */
14682
14721
  emailRequired: Boolean(email),
14683
14722
  shippingAddressRequired: Boolean(shipping),
14684
14723
  shippingAddressParameters: {
14685
14724
  phoneNumberRequired: Boolean(phone),
14686
14725
  },
14726
+ shippingOptionRequired: Boolean(shipping),
14727
+ shippingOptionParameters: getShippingOptionParameters.call(this, cart),
14728
+ offerInfo: getOfferInfo(cart),
14687
14729
  merchantInfo: {
14688
14730
  merchantName: name,
14689
14731
  merchantId: this.method.merchant_id,
14690
14732
  },
14733
+ callbackIntents,
14691
14734
  };
14692
14735
  }
14693
14736
 
14694
14737
  /**
14695
- * @param {object} googlePayment
14738
+ * @param {braintree.GooglePayment} googlePayment
14696
14739
  * @param {google.payments.api.PaymentDataRequest} paymentDataRequest
14697
14740
  */
14698
14741
  async _onClick(googlePayment, paymentDataRequest) {
@@ -14709,34 +14752,59 @@
14709
14752
  }
14710
14753
 
14711
14754
  /**
14712
- * @param {object} googlePayment
14755
+ * @param {braintree.GooglePayment} googlePayment
14713
14756
  * @param {google.payments.api.PaymentData} paymentData
14714
14757
  */
14715
14758
  async _submitPayment(googlePayment, paymentData) {
14716
- const { require: { shipping: requireShipping } = {} } = this.params;
14717
14759
  const { nonce } = await googlePayment.parseResponse(paymentData);
14718
- const { email, shippingAddress, paymentMethodData } = paymentData;
14719
- const {
14720
- info: { billingAddress },
14721
- } = paymentMethodData;
14760
+ const { email, shippingAddress, shippingOptionData, paymentMethodData } =
14761
+ paymentData;
14762
+ const { info: { billingAddress } = {} } = paymentMethodData;
14722
14763
 
14723
- await this.updateCart({
14764
+ const cart = await this.updateCart({
14724
14765
  account: {
14725
14766
  email,
14726
14767
  },
14727
14768
  billing: {
14728
14769
  method: 'google',
14770
+ account_card_id: null,
14771
+ card: null,
14729
14772
  google: {
14730
14773
  nonce,
14731
14774
  gateway: 'braintree',
14732
14775
  },
14733
14776
  ...convertToSwellAddress$2(billingAddress),
14734
14777
  },
14735
- ...(requireShipping && {
14736
- shipping: convertToSwellAddress$2(shippingAddress),
14778
+ ...(shippingAddress && {
14779
+ shipping: {
14780
+ ...convertToSwellAddress$2(shippingAddress),
14781
+ service: shippingOptionData?.id || undefined,
14782
+ },
14737
14783
  }),
14738
14784
  });
14739
14785
 
14786
+ if (cart.subscription_delivery) {
14787
+ try {
14788
+ const card = await cardApi.createToken({
14789
+ gateway: 'braintree',
14790
+ account_id: cart.account_id,
14791
+ nonce,
14792
+ });
14793
+
14794
+ delete card.nonce;
14795
+
14796
+ await this.updateCart({
14797
+ billing: {
14798
+ method: 'card',
14799
+ card,
14800
+ google: null,
14801
+ },
14802
+ });
14803
+ } catch (error) {
14804
+ console.warn('Failed to extract card data from google token', error);
14805
+ }
14806
+ }
14807
+
14740
14808
  this.onSuccess();
14741
14809
  }
14742
14810
  }
@@ -14766,7 +14834,7 @@
14766
14834
  'Shipping is not available for the provided address.';
14767
14835
 
14768
14836
  return {
14769
- newTotal: getTotal(cart, this.merchantInfo),
14837
+ newTotal: getTotal.call(this, cart, this.merchantInfo),
14770
14838
  newLineItems: getLineItems(cart),
14771
14839
  newShippingMethods: [], // REQUIRED: Must always provide this, even as empty array
14772
14840
  errors: [
@@ -14777,15 +14845,15 @@
14777
14845
 
14778
14846
  // Success: Return updated totals and shipping methods
14779
14847
  return {
14780
- newTotal: getTotal(cart, this.merchantInfo),
14848
+ newTotal: getTotal.call(this, cart, this.merchantInfo),
14781
14849
  newLineItems: getLineItems(cart),
14782
- newShippingMethods: getShippingMethods(cart),
14850
+ newShippingMethods: getShippingMethods.call(this, cart),
14783
14851
  };
14784
14852
  } catch (err) {
14785
14853
  const cartData = await this.getCart();
14786
14854
 
14787
14855
  return {
14788
- newTotal: getTotal(cartData, this.merchantInfo),
14856
+ newTotal: getTotal.call(this, cartData, this.merchantInfo),
14789
14857
  newLineItems: getLineItems(cartData),
14790
14858
  newShippingMethods: [], // REQUIRED: Must always provide this, even as empty array
14791
14859
  errors: [new ApplePayError('unknown', undefined, err.message)],
@@ -14831,12 +14899,12 @@
14831
14899
  });
14832
14900
 
14833
14901
  return {
14834
- newTotal: getTotal(cart, this.merchantInfo),
14902
+ newTotal: getTotal.call(this, cart, this.merchantInfo),
14835
14903
  newLineItems: getLineItems(cart),
14836
14904
  };
14837
14905
  } catch (err) {
14838
14906
  return {
14839
- newTotal: getTotal(await this.getCart(), this.merchantInfo),
14907
+ newTotal: getTotal.call(this, await this.getCart(), this.merchantInfo),
14840
14908
  errors: [new ApplePayError('unknown', undefined, err.message)],
14841
14909
  };
14842
14910
  }
@@ -14876,7 +14944,7 @@
14876
14944
 
14877
14945
  // Valid coupon applied successfully
14878
14946
  return {
14879
- newTotal: getTotal(cart, this.merchantInfo),
14947
+ newTotal: getTotal.call(this, cart, this.merchantInfo),
14880
14948
  newLineItems: getLineItems(cart),
14881
14949
  };
14882
14950
  } catch (err) {
@@ -14884,7 +14952,7 @@
14884
14952
  const currentCart = await this.getCart();
14885
14953
 
14886
14954
  return {
14887
- newTotal: getTotal(currentCart, this.merchantInfo),
14955
+ newTotal: getTotal.call(this, currentCart, this.merchantInfo),
14888
14956
  newLineItems: getLineItems(currentCart),
14889
14957
  errors: [new ApplePayError('couponCodeInvalid', undefined, err.message)],
14890
14958
  };
@@ -14918,15 +14986,17 @@
14918
14986
  * This ensures the user sees "pending" until they've selected shipping,
14919
14987
  * then sees the final amount once everything is calculated.
14920
14988
  *
14989
+ * @this {Payment}
14921
14990
  * @param {Cart} cart
14922
14991
  * @param {object} [merchantInfo]
14923
14992
  * @returns {ApplePayJS.ApplePayLineItem}
14924
14993
  */
14925
14994
  function getTotal(cart, merchantInfo) {
14926
- const { capture_total, shipment_delivery, shipping } = cart;
14995
+ const { require: { shipping: shipmentDelivery = false } = {} } = this.params;
14996
+ const { capture_total, shipping } = cart;
14927
14997
 
14928
14998
  // Use 'final' only after shipping method is selected or not needed, otherwise 'pending'
14929
- const isFinalPrice = !shipment_delivery || shipping?.service;
14999
+ const isFinalPrice = !shipmentDelivery || shipping?.service;
14930
15000
  const type = isFinalPrice ? 'final' : 'pending';
14931
15001
 
14932
15002
  return {
@@ -14995,16 +15065,19 @@
14995
15065
  *
14996
15066
  * IMPORTANT: Amounts must be formatted as strings with 2 decimals.
14997
15067
  *
15068
+ * @this {Payment}
14998
15069
  * @param {Cart} cart
14999
15070
  * @returns {ApplePayJS.ApplePayShippingMethod[]}
15000
15071
  */
15001
15072
  function getShippingMethods(cart) {
15002
- const { shipment_delivery, shipment_rating } = cart;
15073
+ const { require: { shipping: shipmentDelivery = false } = {} } = this.params;
15003
15074
 
15004
- if (!shipment_delivery) {
15075
+ if (!shipmentDelivery) {
15005
15076
  return [];
15006
15077
  }
15007
15078
 
15079
+ const { shipment_rating } = cart;
15080
+
15008
15081
  if (!shipment_rating?.services?.length) {
15009
15082
  return [];
15010
15083
  }
@@ -15055,13 +15128,38 @@
15055
15128
  };
15056
15129
  }
15057
15130
 
15058
- const VERSION$1 = 3;
15131
+ /** @param {object} params */
15132
+ function getRequiredContactFields(params) {
15133
+ const { require = {} } = params;
15134
+ /** @type {ApplePayJS.ApplePayContactField[]} */
15135
+ const requiredFields = [];
15136
+
15137
+ if (require.email) {
15138
+ requiredFields.push('email');
15139
+ }
15140
+
15141
+ if (require.name) {
15142
+ requiredFields.push('name');
15143
+ }
15144
+
15145
+ if (require.phone) {
15146
+ requiredFields.push('phone');
15147
+ }
15148
+
15149
+ /** @type {ApplePayJS.ApplePayContactField[]} */
15150
+ const requiredShippingContactFields = require.shipping
15151
+ ? [...requiredFields, 'postalAddress']
15152
+ : [];
15153
+
15154
+ /** @type {ApplePayJS.ApplePayContactField[]} */
15155
+ const requiredBillingContactFields = [...requiredFields, 'postalAddress'];
15156
+
15157
+ return { requiredBillingContactFields, requiredShippingContactFields };
15158
+ }
15159
+
15160
+ /** @typedef {import('../../../types').Cart} Cart */
15059
15161
 
15060
- const MERCHANT_CAPABILITIES = [
15061
- 'supports3DS',
15062
- 'supportsDebit',
15063
- 'supportsCredit',
15064
- ];
15162
+ const VERSION$1 = 14;
15065
15163
 
15066
15164
  class BraintreeApplePayment extends Payment {
15067
15165
  constructor(api, options, params, methods) {
@@ -15093,6 +15191,7 @@
15093
15191
  return window.ApplePaySession;
15094
15192
  }
15095
15193
 
15194
+ /** @param {Cart} cart */
15096
15195
  async createElements(cart) {
15097
15196
  const { elementId = 'applepay-button' } = this.params;
15098
15197
 
@@ -15106,10 +15205,12 @@
15106
15205
  }
15107
15206
 
15108
15207
  const braintreeClient = await this._createBraintreeClient();
15208
+
15109
15209
  const applePayment = await this.braintree.applePay.create({
15110
15210
  client: braintreeClient,
15111
15211
  });
15112
- const paymentRequest = await this._createPaymentRequest(cart, applePayment);
15212
+
15213
+ const paymentRequest = this._createPaymentRequest(cart, applePayment);
15113
15214
 
15114
15215
  this.element = this._createButton(applePayment, paymentRequest);
15115
15216
  }
@@ -15126,8 +15227,9 @@
15126
15227
  }
15127
15228
 
15128
15229
  /**
15129
- * @param {object} applePayment
15230
+ * @param {braintree.ApplePay} applePayment
15130
15231
  * @param {ApplePayJS.ApplePayPaymentRequest} paymentRequest
15232
+ * @returns {HTMLDivElement}
15131
15233
  */
15132
15234
  _createButton(applePayment, paymentRequest) {
15133
15235
  const { style: { type = 'plain', theme = 'black', height = '40px' } = {} } =
@@ -15148,6 +15250,7 @@
15148
15250
  return button;
15149
15251
  }
15150
15252
 
15253
+ /** @returns {Promise<braintree.Client>} */
15151
15254
  async _createBraintreeClient() {
15152
15255
  const authorization = await this.authorizeGateway({
15153
15256
  gateway: 'braintree',
@@ -15162,47 +15265,43 @@
15162
15265
  });
15163
15266
  }
15164
15267
 
15165
- /** @returns {ApplePayJS.ApplePayPaymentRequest} */
15268
+ /**
15269
+ * @param {Cart} cart
15270
+ * @param {braintree.ApplePay} applePayment
15271
+ * @returns {ApplePayJS.ApplePayPaymentRequest}
15272
+ */
15166
15273
  _createPaymentRequest(cart, applePayment) {
15167
- const { require = {} } = this.params;
15168
15274
  const {
15169
15275
  settings: { name, country },
15170
15276
  capture_total,
15171
15277
  currency,
15172
15278
  } = cart;
15173
15279
 
15174
- const requiredShippingContactFields = [];
15175
- const requiredBillingContactFields = ['postalAddress'];
15176
-
15177
- if (require.name) {
15178
- requiredShippingContactFields.push('name');
15179
- }
15180
- if (require.email) {
15181
- requiredShippingContactFields.push('email');
15182
- }
15183
- if (require.phone) {
15184
- requiredShippingContactFields.push('phone');
15185
- }
15186
- if (require.shipping) {
15187
- requiredShippingContactFields.push('postalAddress');
15188
- }
15280
+ const { requiredBillingContactFields, requiredShippingContactFields } =
15281
+ getRequiredContactFields(this.params);
15189
15282
 
15190
15283
  return applePayment.createPaymentRequest({
15191
15284
  total: {
15192
15285
  label: name,
15193
15286
  type: 'pending',
15194
- amount: capture_total.toString(),
15287
+ amount: (capture_total || 0).toFixed(2),
15195
15288
  },
15196
15289
  countryCode: country,
15197
15290
  currencyCode: currency,
15198
- merchantCapabilities: MERCHANT_CAPABILITIES,
15291
+ /**
15292
+ * @see {@link https://developer.paypal.com/braintree/docs/guides/apple-pay/client-side/javascript/v3/#create-anapplepaysession}
15293
+ *
15294
+ * Braintree automatically fills in `supportedNetworks` and `merchantCapabilities`.
15295
+ */
15199
15296
  requiredShippingContactFields,
15200
15297
  requiredBillingContactFields,
15298
+ supportsCouponCode: true,
15299
+ lineItems: getLineItems(cart),
15201
15300
  });
15202
15301
  }
15203
15302
 
15204
15303
  /**
15205
- * @param {object} applePayment
15304
+ * @param {braintree.ApplePay} applePayment
15206
15305
  * @param {ApplePayJS.ApplePayPaymentRequest} paymentRequest
15207
15306
  */
15208
15307
  _createPaymentSession(applePayment, paymentRequest) {
@@ -15223,11 +15322,23 @@
15223
15322
  }
15224
15323
  };
15225
15324
 
15325
+ session.onshippingcontactselected = onShippingContactSelected.bind(
15326
+ this,
15327
+ session,
15328
+ );
15329
+
15330
+ session.onshippingmethodselected = onShippingMethodSelected.bind(
15331
+ this,
15332
+ session,
15333
+ );
15334
+
15335
+ session.oncouponcodechanged = onCouponCodeChanged.bind(this, session);
15336
+
15226
15337
  session.onpaymentauthorized = async (event) => {
15227
15338
  const {
15228
15339
  payment: { token, shippingContact, billingContact },
15229
15340
  } = event;
15230
- const { require: { shipping: requireShipping } = {} } = this.params;
15341
+
15231
15342
  const payload = await applePayment
15232
15343
  .tokenize({ token })
15233
15344
  .catch(this.onError.bind(this));
@@ -15236,23 +15347,47 @@
15236
15347
  return session.completePayment(this.ApplePaySession.STATUS_FAILURE);
15237
15348
  }
15238
15349
 
15239
- await this.updateCart({
15350
+ const cart = await this.updateCart({
15240
15351
  account: {
15241
- email: shippingContact.emailAddress,
15352
+ email: shippingContact?.emailAddress || billingContact?.emailAddress,
15242
15353
  },
15243
15354
  billing: {
15244
15355
  method: 'apple',
15356
+ account_card_id: null,
15357
+ card: null,
15245
15358
  apple: {
15246
15359
  nonce: payload.nonce,
15247
15360
  gateway: 'braintree',
15248
15361
  },
15249
15362
  ...convertToSwellAddress$1(billingContact),
15250
15363
  },
15251
- ...(requireShipping && {
15364
+ ...(shippingContact && {
15252
15365
  shipping: convertToSwellAddress$1(shippingContact),
15253
15366
  }),
15254
15367
  });
15255
15368
 
15369
+ if (cart.subscription_delivery) {
15370
+ try {
15371
+ const card = await cardApi.createToken({
15372
+ gateway: 'braintree',
15373
+ account_id: cart.account_id,
15374
+ nonce: payload.nonce,
15375
+ });
15376
+
15377
+ delete card.nonce;
15378
+
15379
+ await this.updateCart({
15380
+ billing: {
15381
+ method: 'card',
15382
+ card,
15383
+ apple: null,
15384
+ },
15385
+ });
15386
+ } catch (error) {
15387
+ console.warn('Failed to extract card data from apple token', error);
15388
+ }
15389
+ }
15390
+
15256
15391
  this.onSuccess();
15257
15392
 
15258
15393
  return session.completePayment(this.ApplePaySession.STATUS_SUCCESS);
@@ -15358,6 +15493,8 @@
15358
15493
  * @returns {google.payments.api.PaymentMethodSpecification}
15359
15494
  */
15360
15495
  _getCardPaymentMethod(submit = false) {
15496
+ const { require: { phone } = {} } = this.params;
15497
+
15361
15498
  return {
15362
15499
  type: 'CARD',
15363
15500
  parameters: {
@@ -15366,7 +15503,7 @@
15366
15503
  billingAddressRequired: true,
15367
15504
  billingAddressParameters: {
15368
15505
  format: 'FULL',
15369
- phoneNumberRequired: true,
15506
+ phoneNumberRequired: Boolean(phone),
15370
15507
  },
15371
15508
  },
15372
15509
  ...(submit && {
@@ -15399,29 +15536,30 @@
15399
15536
  cart.shipment_price = 0;
15400
15537
  cart.shipping = {};
15401
15538
 
15402
- const { shipment_delivery } = cart;
15403
15539
  const { require: { email, shipping, phone } = {} } = this.params;
15404
15540
 
15541
+ /** @type {google.payments.api.CallbackIntent[]} */
15542
+ const callbackIntents = ['OFFER', 'PAYMENT_AUTHORIZATION'];
15543
+
15544
+ if (shipping) {
15545
+ callbackIntents.push('SHIPPING_ADDRESS', 'SHIPPING_OPTION');
15546
+ }
15547
+
15405
15548
  return {
15406
15549
  apiVersion: API_VERSION,
15407
15550
  apiVersionMinor: API_MINOR_VERSION,
15408
- transactionInfo: getTransactionInfo(cart),
15551
+ transactionInfo: getTransactionInfo.call(this, cart),
15409
15552
  allowedPaymentMethods: this._getAllowedPaymentMethods(true),
15410
15553
  emailRequired: Boolean(email),
15411
15554
  shippingAddressRequired: Boolean(shipping),
15412
15555
  shippingAddressParameters: {
15413
15556
  phoneNumberRequired: Boolean(phone),
15414
15557
  },
15415
- shippingOptionRequired: Boolean(shipment_delivery),
15558
+ shippingOptionRequired: Boolean(shipping),
15416
15559
  shippingOptionParameters: getShippingOptionParameters.call(this, cart),
15417
15560
  offerInfo: getOfferInfo(cart),
15418
15561
  merchantInfo,
15419
- callbackIntents: [
15420
- 'OFFER',
15421
- 'SHIPPING_ADDRESS',
15422
- 'SHIPPING_OPTION',
15423
- 'PAYMENT_AUTHORIZATION',
15424
- ],
15562
+ callbackIntents,
15425
15563
  };
15426
15564
  }
15427
15565
 
@@ -15545,6 +15683,22 @@
15545
15683
  /** @typedef {import('../../../types').Cart} Cart */
15546
15684
 
15547
15685
  class AuthorizeNetGooglePayment extends AbstractGooglePayment {
15686
+ /**
15687
+ * @override
15688
+ * @returns {google.payments.api.CardNetwork[]}
15689
+ */
15690
+ getAllowedCardNetworks() {
15691
+ return ['AMEX', 'DISCOVER', 'JCB', 'MASTERCARD', 'VISA'];
15692
+ }
15693
+
15694
+ /**
15695
+ * @override
15696
+ * @returns {google.payments.api.CardAuthMethod[]}
15697
+ */
15698
+ getAllowedCardAuthMethods() {
15699
+ return ['PAN_ONLY', 'CRYPTOGRAM_3DS'];
15700
+ }
15701
+
15548
15702
  /**
15549
15703
  * @override
15550
15704
  * @returns {google.payments.api.PaymentGatewayTokenizationParameters}
@@ -15562,7 +15716,6 @@
15562
15716
  * @returns {Promise<object>}
15563
15717
  */
15564
15718
  async preparePaymentDataForCartUpdate(paymentData) {
15565
- const { require: { shipping: requireShipping } = {} } = this.params;
15566
15719
  const { email, shippingAddress, shippingOptionData, paymentMethodData } =
15567
15720
  paymentData;
15568
15721
 
@@ -15583,7 +15736,7 @@
15583
15736
  },
15584
15737
  ...convertToSwellAddress$2(billingAddress),
15585
15738
  },
15586
- ...(requireShipping && {
15739
+ ...(shippingAddress && {
15587
15740
  shipping: {
15588
15741
  ...convertToSwellAddress$2(shippingAddress),
15589
15742
  service: shippingOptionData?.id || undefined,
@@ -15650,9 +15803,15 @@
15650
15803
  return window.ApplePaySession;
15651
15804
  }
15652
15805
 
15653
- /** @returns {string[]} */
15806
+ /**
15807
+ * We should specify the payment methods in the order preferred by the gateway.
15808
+ *
15809
+ * @see {@link https://developer.apple.com/documentation/applepayontheweb/applepaypaymentrequest/supportednetworks}
15810
+ *
15811
+ * @returns {string[]}
15812
+ */
15654
15813
  getSupportedCardNetworks() {
15655
- return ['amex', 'discover', 'interac', 'jcb', 'masterCard', 'visa'];
15814
+ return ['visa', 'masterCard', 'amex', 'discover', 'interac', 'jcb'];
15656
15815
  }
15657
15816
 
15658
15817
  /** @returns {ApplePayJS.ApplePayMerchantCapability[]} */
@@ -15663,12 +15822,12 @@
15663
15822
  /**
15664
15823
  * Creates the Apple Pay payment request object
15665
15824
  *
15666
- * IMPORTANT: countryCode here is the MERCHANT's country (where your business is located),
15667
- * NOT the customer's country. Customer country comes from shippingContact.countryCode.
15825
+ * IMPORTANT: `countryCode` here is the MERCHANT's country (where your business is located),
15826
+ * NOT the customer's country. Customer country comes from `shippingContact.countryCode`.
15668
15827
  *
15669
- * NOTE: We do NOT pass shippingMethods in the initial request. Shipping methods
15828
+ * NOTE: We do NOT pass `shippingMethods` in the initial request. Shipping methods
15670
15829
  * are provided dynamically after the user selects/confirms their address in the
15671
- * 'shippingcontactselected' event handler.
15830
+ * `'shippingcontactselected'` event handler.
15672
15831
  *
15673
15832
  * @param {Cart} cart
15674
15833
  * @returns {ApplePayJS.ApplePayPaymentRequest}
@@ -15676,38 +15835,21 @@
15676
15835
  _createPaymentRequest(cart) {
15677
15836
  cart = { ...cart };
15678
15837
 
15679
- const { require = {} } = this.params;
15680
15838
  const {
15681
15839
  settings: { country },
15682
15840
  currency,
15683
15841
  } = cart;
15684
15842
 
15685
- const requiredShippingContactFields = [];
15686
- const requiredBillingContactFields = ['postalAddress'];
15687
-
15688
- if (require.name) {
15689
- requiredShippingContactFields.push('name');
15690
- }
15691
-
15692
- if (require.email) {
15693
- requiredShippingContactFields.push('email');
15694
- }
15695
-
15696
- if (require.phone) {
15697
- requiredShippingContactFields.push('phone');
15698
- }
15699
-
15700
- if (require.shipping) {
15701
- requiredShippingContactFields.push('postalAddress');
15702
- }
15703
-
15704
15843
  // When initiating a payment request,
15705
15844
  // we should not display the shipping cost, as it will be calculated later.
15706
15845
  cart.shipment_price = 0;
15707
15846
  cart.shipping = {};
15708
15847
 
15848
+ const { requiredBillingContactFields, requiredShippingContactFields } =
15849
+ getRequiredContactFields(this.params);
15850
+
15709
15851
  return {
15710
- total: getTotal(cart, this.merchantInfo),
15852
+ total: getTotal.call(this, cart, this.merchantInfo),
15711
15853
  countryCode: country, // Merchant's country
15712
15854
  currencyCode: currency,
15713
15855
  supportedNetworks: this.getSupportedCardNetworks(),
@@ -15889,6 +16031,22 @@
15889
16031
  }
15890
16032
 
15891
16033
  class AuthorizeNetApplePayment extends AbstractApplePayment {
16034
+ /**
16035
+ * @override
16036
+ * @returns {string[]}
16037
+ */
16038
+ getSupportedCardNetworks() {
16039
+ return ['visa', 'masterCard', 'amex', 'discover'];
16040
+ }
16041
+
16042
+ /**
16043
+ * @override
16044
+ * @returns {ApplePayJS.ApplePayMerchantCapability[]}
16045
+ */
16046
+ getMerchantCapabilities() {
16047
+ return ['supports3DS', 'supportsDebit', 'supportsCredit'];
16048
+ }
16049
+
15892
16050
  /**
15893
16051
  * @override
15894
16052
  * @param {ApplePayJS.ApplePayValidateMerchantEvent} event
@@ -15922,11 +16080,9 @@
15922
16080
  payment: { token, shippingContact, billingContact },
15923
16081
  } = event;
15924
16082
 
15925
- const { require: { shipping: requireShipping } = {} } = this.params;
15926
-
15927
16083
  return {
15928
16084
  account: {
15929
- email: shippingContact.emailAddress,
16085
+ email: shippingContact?.emailAddress || billingContact?.emailAddress,
15930
16086
  },
15931
16087
  billing: {
15932
16088
  method: 'apple',
@@ -15938,7 +16094,7 @@
15938
16094
  },
15939
16095
  ...convertToSwellAddress$1(billingContact),
15940
16096
  },
15941
- ...(requireShipping && {
16097
+ ...(shippingContact && {
15942
16098
  shipping: convertToSwellAddress$1(shippingContact),
15943
16099
  }),
15944
16100
  };
@@ -16058,7 +16214,7 @@
16058
16214
  merchantAccount: false,
16059
16215
  countryCode: country || 'US',
16060
16216
  shopperLocale: 'en-US',
16061
- // shopperReference: email ? md5(email) : undefined,
16217
+ // shopperReference: email ? md5(email.toLowerCase()) : undefined,
16062
16218
  }),
16063
16219
  },
16064
16220
  ).then((res) => res.json());
@@ -16186,15 +16342,20 @@
16186
16342
  }
16187
16343
  }
16188
16344
 
16345
+ function getBaseConvesioVaultUrl(mode) {
16346
+ return isLiveMode(mode)
16347
+ ? 'https://vault.convesiopay.com'
16348
+ : 'https://qa-vault.convesiopay.com';
16349
+ }
16350
+
16189
16351
  function createConvesioCardPaymentToken(settings, data) {
16190
- const baseUrl = getBaseConvesioApiUrl(settings.mode);
16352
+ const baseUrl = getBaseConvesioVaultUrl(settings.mode);
16191
16353
 
16192
16354
  return fetch(`${baseUrl}/v1/create-token`, {
16193
16355
  method: 'POST',
16194
16356
  headers: {
16195
16357
  Accept: 'application/json',
16196
16358
  'Content-Type': 'application/json',
16197
- 'X-Requested-With': 'convesio-pay-dashboard',
16198
16359
  'X-Api-Key': settings.public_key,
16199
16360
  },
16200
16361
  body: JSON.stringify(data),
@@ -16309,8 +16470,6 @@
16309
16470
  payment: { token, shippingContact, billingContact },
16310
16471
  } = event;
16311
16472
 
16312
- const { require: { shipping: requireShipping } = {} } = this.params;
16313
-
16314
16473
  const payment = await createConvesioApplePaymentToken(
16315
16474
  this.method.mode,
16316
16475
  this.convesiopay,
@@ -16332,7 +16491,7 @@
16332
16491
 
16333
16492
  return {
16334
16493
  account: {
16335
- email: shippingContact.emailAddress,
16494
+ email: shippingContact?.emailAddress || billingContact?.emailAddress,
16336
16495
  },
16337
16496
  billing: {
16338
16497
  method: 'apple',
@@ -16347,7 +16506,7 @@
16347
16506
  },
16348
16507
  ...convertToSwellAddress$1(billingContact),
16349
16508
  },
16350
- ...(requireShipping && {
16509
+ ...(shippingContact && {
16351
16510
  shipping: convertToSwellAddress$1(shippingContact),
16352
16511
  }),
16353
16512
  };
@@ -16477,7 +16636,6 @@
16477
16636
  * @returns {Promise<object>}
16478
16637
  */
16479
16638
  async preparePaymentDataForCartUpdate(paymentData) {
16480
- const { require: { shipping: requireShipping } = {} } = this.params;
16481
16639
  const { email, shippingAddress, shippingOptionData, paymentMethodData } =
16482
16640
  paymentData;
16483
16641
 
@@ -16520,7 +16678,7 @@
16520
16678
  },
16521
16679
  ...convertToSwellAddress$2(billingAddress),
16522
16680
  },
16523
- ...(requireShipping && {
16681
+ ...(shippingAddress && {
16524
16682
  shipping: {
16525
16683
  ...convertToSwellAddress$2(shippingAddress),
16526
16684
  service: shippingOptionData?.id || undefined,
@@ -17416,20 +17574,29 @@
17416
17574
  settings: { name },
17417
17575
  } = cart;
17418
17576
 
17419
- const shipmentDelivery = Boolean(cart.shipment_delivery);
17577
+ const { require: { shipping } = {} } = this.params;
17420
17578
  const cartCurrency = getCartCurrency(cart);
17421
17579
 
17422
17580
  return {
17423
17581
  checkout_payload: {
17424
- express_checkout_type: shipmentDelivery ? 'multi-step' : 'no-shipping',
17582
+ express_checkout_type: shipping ? 'multi-step' : 'no-shipping',
17583
+ customer: {
17584
+ email: cart.account?.email,
17585
+ first_name: cart.account?.first_name,
17586
+ last_name: cart.account?.last_name,
17587
+ phone: cart.account?.phone,
17588
+ // TODO: recurring payments https://docs.sezzle.com/docs/api/tokenization/intro
17589
+ // tokenize: cart.subscription_delivery,
17590
+ // recurring: cart.subscription_delivery,
17591
+ },
17425
17592
  order: {
17426
17593
  intent: 'AUTH',
17427
17594
  reference_id: cart.checkout_id,
17428
17595
  description: `${name} #${cart.number}`,
17429
- requires_shipping_info: shipmentDelivery,
17596
+ requires_shipping_info: shipping,
17430
17597
  items: getItems(cart),
17431
17598
  discounts: getDiscounts(cart),
17432
- tax_amount: shipmentDelivery
17599
+ tax_amount: shipping
17433
17600
  ? undefined
17434
17601
  : getAmountInCents(cartCurrency, cart.tax_total),
17435
17602
  order_amount: getAmountInCents(cartCurrency, cart.capture_total),
@@ -17689,15 +17856,6 @@
17689
17856
  };
17690
17857
  }
17691
17858
 
17692
- /**
17693
- * @param {string} currency
17694
- * @param {number} amount
17695
- * @returns {number}
17696
- */
17697
- function amountInCents(currency, amount) {
17698
- return Math.round(amount * 100);
17699
- }
17700
-
17701
17859
  class PaymentController {
17702
17860
  constructor(api, options) {
17703
17861
  this.api = api;
@@ -18400,7 +18558,7 @@
18400
18558
  const api = {};
18401
18559
 
18402
18560
  Object.assign(api, {
18403
- version: '5.7.0',
18561
+ version: '5.8.0',
18404
18562
  options,
18405
18563
  request,
18406
18564