swell-js 5.6.1 → 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.
@@ -12741,6 +12741,7 @@
12741
12741
  return error
12742
12742
  ? { error }
12743
12743
  : {
12744
+ gateway: 'stripe',
12744
12745
  token: paymentMethod.id,
12745
12746
  last4: paymentMethod.card.last4,
12746
12747
  exp_month: paymentMethod.card.exp_month,
@@ -12844,13 +12845,13 @@
12844
12845
  tax_included_total,
12845
12846
  settings,
12846
12847
  } = cart;
12847
- const { price: shippingPrice, service_name } = shipping || {};
12848
+ const { price: shippingPrice, service, service_name } = shipping || {};
12848
12849
  const { country, name } = settings || {};
12849
12850
  const { require: { shipping: requireShipping } = {} } = params;
12850
12851
 
12851
12852
  const stripeCurrency = currency.toLowerCase();
12852
12853
  const displayItems = items.map((item) => ({
12853
- label: get(item, 'product.name', 'Unknown product'),
12854
+ label: item.product_name || item.product?.name || 'Unknown product',
12854
12855
  amount: stripeAmountByCurrency(
12855
12856
  currency,
12856
12857
  item.price_total - item.discount_total,
@@ -12872,14 +12873,21 @@
12872
12873
  }
12873
12874
 
12874
12875
  let shippingOptions;
12875
- const services = get(shipment_rating, 'services');
12876
- if (Array.isArray(services) && services.length > 0) {
12876
+ const services = shipment_rating?.services;
12877
+ if (requireShipping && Array.isArray(services) && services.length > 0) {
12877
12878
  shippingOptions = services.map((service) => ({
12878
12879
  id: service.id,
12879
12880
  label: service.name,
12880
12881
  detail: service.description,
12881
12882
  amount: stripeAmountByCurrency(currency, service.price),
12882
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
+ }
12883
12891
  }
12884
12892
 
12885
12893
  return {
@@ -12891,7 +12899,7 @@
12891
12899
  pending: true,
12892
12900
  },
12893
12901
  displayItems,
12894
- ...(requireShipping && { shippingOptions }),
12902
+ ...(shippingOptions && { shippingOptions }),
12895
12903
  };
12896
12904
  }
12897
12905
 
@@ -13011,6 +13019,10 @@
13011
13019
  throw new Error(paymentMethod.error.message);
13012
13020
  }
13013
13021
 
13022
+ if (!isLiveMode(this.method.mode)) {
13023
+ paymentMethod.test = true;
13024
+ }
13025
+
13014
13026
  // should save payment method data when payment amount is not chargeable
13015
13027
  if (!isStripeChargeableAmount(cart.capture_total, cart.currency)) {
13016
13028
  await this.updateCart({
@@ -13435,6 +13447,7 @@
13435
13447
 
13436
13448
  /** @typedef {import('@stripe/stripe-js').Stripe} Stripe */
13437
13449
  /** @typedef {import('@stripe/stripe-js').PaymentRequestPaymentMethodEvent} PaymentRequestPaymentMethodEvent */
13450
+ /** @typedef {import('../../../types').Cart} Cart */
13438
13451
 
13439
13452
  class StripeGooglePayment extends Payment {
13440
13453
  constructor(api, options, params, methods) {
@@ -13502,6 +13515,7 @@
13502
13515
  this.element.mount(`#${this.elementContainer.id}`);
13503
13516
  }
13504
13517
 
13518
+ /** @param {Cart} cart */
13505
13519
  _createPaymentRequest(cart) {
13506
13520
  const { require: { name, email, shipping, phone } = {} } = this.params;
13507
13521
 
@@ -13514,15 +13528,10 @@
13514
13528
  ...getPaymentRequestData(cart, this.params),
13515
13529
  });
13516
13530
 
13517
- paymentRequest.on(
13518
- 'shippingaddresschange',
13519
- this._onShippingAddressChange.bind(this),
13520
- );
13521
- paymentRequest.on(
13522
- 'shippingoptionchange',
13523
- this._onShippingOptionChange.bind(this),
13524
- );
13525
- 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));
13526
13535
 
13527
13536
  return paymentRequest;
13528
13537
  }
@@ -13530,9 +13539,9 @@
13530
13539
  /** @param {import('@stripe/stripe-js').PaymentRequestShippingAddressEvent} event */
13531
13540
  async _onShippingAddressChange(event) {
13532
13541
  const { shippingAddress, updateWith } = event;
13533
- const shipping = this._mapShippingAddress(shippingAddress);
13542
+
13534
13543
  const cart = await this.updateCart({
13535
- shipping: { ...shipping, service: null },
13544
+ shipping: this._mapShippingAddress(shippingAddress),
13536
13545
  shipment_rating: null,
13537
13546
  });
13538
13547
 
@@ -13572,16 +13581,15 @@
13572
13581
  shippingOption,
13573
13582
  complete,
13574
13583
  } = event;
13575
- const { require: { shipping: requireShipping } = {} } = this.params;
13576
13584
 
13577
13585
  await this.updateCart({
13578
13586
  account: {
13579
- email: payerEmail,
13587
+ email: payerEmail || billing_details?.email,
13580
13588
  },
13581
- ...(requireShipping && {
13589
+ ...(shippingAddress && {
13582
13590
  shipping: {
13583
13591
  ...this._mapShippingAddress(shippingAddress),
13584
- service: shippingOption.id,
13592
+ service: shippingOption?.id || undefined,
13585
13593
  },
13586
13594
  }),
13587
13595
  billing: {
@@ -13595,9 +13603,9 @@
13595
13603
  exp_month: card.exp_month,
13596
13604
  exp_year: card.exp_year,
13597
13605
  last4: card.last4,
13598
- address_check: card.checks.address_line1_check,
13599
- zip_check: card.checks.address_postal_code_check,
13600
- 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,
13601
13609
  },
13602
13610
  },
13603
13611
  });
@@ -13645,8 +13653,8 @@
13645
13653
  _mapShippingAddress(address = {}) {
13646
13654
  return {
13647
13655
  name: address.recipient,
13648
- address1: address.addressLine[0],
13649
- address2: address.addressLine[1],
13656
+ address1: address.addressLine?.[0],
13657
+ address2: address.addressLine?.[1],
13650
13658
  city: address.city,
13651
13659
  state: address.region,
13652
13660
  zip: address.postalCode,
@@ -13660,18 +13668,19 @@
13660
13668
  return {
13661
13669
  name: address.name,
13662
13670
  phone: address.phone,
13663
- address1: address.address.line1,
13664
- address2: address.address.line2,
13665
- city: address.address.city,
13666
- state: address.address.state,
13667
- zip: address.address.postal_code,
13668
- 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,
13669
13677
  };
13670
13678
  }
13671
13679
  }
13672
13680
 
13673
13681
  /** @typedef {import('@stripe/stripe-js').Stripe} Stripe */
13674
13682
  /** @typedef {import('@stripe/stripe-js').PaymentRequestPaymentMethodEvent} PaymentRequestPaymentMethodEvent */
13683
+ /** @typedef {import('../../../types').Cart} Cart */
13675
13684
 
13676
13685
  class StripeApplePayment extends Payment {
13677
13686
  constructor(api, options, params, methods) {
@@ -13725,7 +13734,7 @@
13725
13734
  const paymentRequest = this._createPaymentRequest(cart);
13726
13735
  const canMakePayment = await paymentRequest.canMakePayment();
13727
13736
 
13728
- if (!canMakePayment || !canMakePayment.applePay) {
13737
+ if (!canMakePayment?.applePay) {
13729
13738
  throw new Error(
13730
13739
  'This device is not capable of making Apple Pay payments',
13731
13740
  );
@@ -13762,6 +13771,7 @@
13762
13771
  }
13763
13772
  }
13764
13773
 
13774
+ /** @param {Cart} cart */
13765
13775
  _createPaymentRequest(cart) {
13766
13776
  const { require: { name, email, shipping, phone } = {} } = this.params;
13767
13777
 
@@ -13774,15 +13784,10 @@
13774
13784
  ...getPaymentRequestData(cart, this.params),
13775
13785
  });
13776
13786
 
13777
- paymentRequest.on(
13778
- 'shippingaddresschange',
13779
- this._onShippingAddressChange.bind(this),
13780
- );
13781
- paymentRequest.on(
13782
- 'shippingoptionchange',
13783
- this._onShippingOptionChange.bind(this),
13784
- );
13785
- 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));
13786
13791
 
13787
13792
  return paymentRequest;
13788
13793
  }
@@ -13790,9 +13795,9 @@
13790
13795
  /** @param {import('@stripe/stripe-js').PaymentRequestShippingAddressEvent} event */
13791
13796
  async _onShippingAddressChange(event) {
13792
13797
  const { shippingAddress, updateWith } = event;
13793
- const shipping = this._mapShippingAddress(shippingAddress);
13798
+
13794
13799
  const cart = await this.updateCart({
13795
- shipping: { ...shipping, service: null },
13800
+ shipping: this._mapShippingAddress(shippingAddress),
13796
13801
  shipment_rating: null,
13797
13802
  });
13798
13803
 
@@ -13832,16 +13837,15 @@
13832
13837
  shippingOption,
13833
13838
  complete,
13834
13839
  } = event;
13835
- const { require: { shipping: requireShipping } = {} } = this.params;
13836
13840
 
13837
13841
  await this.updateCart({
13838
13842
  account: {
13839
- email: payerEmail,
13843
+ email: payerEmail || billing_details?.email,
13840
13844
  },
13841
- ...(requireShipping && {
13845
+ ...(shippingAddress && {
13842
13846
  shipping: {
13843
13847
  ...this._mapShippingAddress(shippingAddress),
13844
- service: shippingOption.id,
13848
+ service: shippingOption?.id || undefined,
13845
13849
  },
13846
13850
  }),
13847
13851
  billing: {
@@ -13855,9 +13859,9 @@
13855
13859
  exp_month: card.exp_month,
13856
13860
  exp_year: card.exp_year,
13857
13861
  last4: card.last4,
13858
- address_check: card.checks.address_line1_check,
13859
- zip_check: card.checks.address_postal_code_check,
13860
- 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,
13861
13865
  },
13862
13866
  },
13863
13867
  });
@@ -13871,8 +13875,8 @@
13871
13875
  _mapShippingAddress(address = {}) {
13872
13876
  return {
13873
13877
  name: address.recipient,
13874
- address1: address.addressLine[0],
13875
- address2: address.addressLine[1],
13878
+ address1: address.addressLine?.[0],
13879
+ address2: address.addressLine?.[1],
13876
13880
  city: address.city,
13877
13881
  state: address.region,
13878
13882
  zip: address.postalCode,
@@ -13886,12 +13890,12 @@
13886
13890
  return {
13887
13891
  name: address.name,
13888
13892
  phone: address.phone,
13889
- address1: address.address.line1,
13890
- address2: address.address.line2,
13891
- city: address.address.city,
13892
- state: address.address.state,
13893
- zip: address.address.postal_code,
13894
- 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,
13895
13899
  };
13896
13900
  }
13897
13901
  }
@@ -14159,6 +14163,44 @@
14159
14163
  return discount.id;
14160
14164
  }
14161
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
+
14162
14204
  /** @typedef {import('./payment').default} Payment */
14163
14205
  /** @typedef {import('../../types').Cart} Cart */
14164
14206
  /** @typedef {import('../../types').Address} Address */
@@ -14246,7 +14288,7 @@
14246
14288
  this,
14247
14289
  cart,
14248
14290
  ),
14249
- newTransactionInfo: getTransactionInfo(cart),
14291
+ newTransactionInfo: getTransactionInfo.call(this, cart),
14250
14292
  };
14251
14293
  }
14252
14294
 
@@ -14259,7 +14301,7 @@
14259
14301
  },
14260
14302
  });
14261
14303
 
14262
- return { newTransactionInfo: getTransactionInfo(cart) };
14304
+ return { newTransactionInfo: getTransactionInfo.call(this, cart) };
14263
14305
  } catch (err) {
14264
14306
  return createError(
14265
14307
  intermediatePaymentData.callbackTrigger,
@@ -14281,7 +14323,7 @@
14281
14323
 
14282
14324
  return {
14283
14325
  newOfferInfo: getOfferInfo(cart),
14284
- newTransactionInfo: getTransactionInfo(cart),
14326
+ newTransactionInfo: getTransactionInfo.call(this, cart),
14285
14327
  };
14286
14328
  } catch (err) {
14287
14329
  return createError(
@@ -14381,12 +14423,13 @@
14381
14423
 
14382
14424
  /**
14383
14425
  * Converts cart data to Google Pay transaction information.
14426
+ * @this {Payment}
14384
14427
  * @param {Cart} cart - The current cart data
14385
14428
  * @returns {google.payments.api.TransactionInfo} Transaction info for Google Pay
14386
14429
  */
14387
14430
  function getTransactionInfo(cart) {
14388
- const { settings, capture_total, currency, shipment_delivery, shipping } =
14389
- cart;
14431
+ const { require: { shipping: shipmentDelivery = false } = {} } = this.params;
14432
+ const { settings, capture_total, currency, shipping } = cart;
14390
14433
 
14391
14434
  return {
14392
14435
  countryCode: settings?.country || 'US',
@@ -14394,7 +14437,7 @@
14394
14437
  totalPrice: String(capture_total ?? 0),
14395
14438
  // Set status to FINAL if shipping has been selected, otherwise ESTIMATED
14396
14439
  totalPriceStatus:
14397
- !shipment_delivery || shipping?.service ? 'FINAL' : 'ESTIMATED',
14440
+ !shipmentDelivery || shipping?.service ? 'FINAL' : 'ESTIMATED',
14398
14441
  totalPriceLabel: 'Total',
14399
14442
  displayItems: getDisplayItems(cart),
14400
14443
  };
@@ -14407,12 +14450,14 @@
14407
14450
  * @returns {google.payments.api.ShippingOptionParameters | undefined} Shipping options for Google Pay
14408
14451
  */
14409
14452
  function getShippingOptionParameters(cart) {
14410
- const { shipment_delivery, shipment_rating, shipping } = cart;
14453
+ const { require: { shipping: shipmentDelivery = false } = {} } = this.params;
14411
14454
 
14412
- if (!shipment_delivery) {
14455
+ if (!shipmentDelivery) {
14413
14456
  return undefined;
14414
14457
  }
14415
14458
 
14459
+ const { shipment_rating, shipping } = cart;
14460
+
14416
14461
  if (!shipment_rating?.services?.length) {
14417
14462
  // Return placeholder when no shipping services are available
14418
14463
  return {
@@ -14493,20 +14538,11 @@
14493
14538
  };
14494
14539
  }
14495
14540
 
14541
+ /** @typedef {import('../../../types').Cart} Cart */
14542
+
14496
14543
  const API_VERSION$1 = 2;
14497
14544
  const API_MINOR_VERSION$1 = 0;
14498
14545
 
14499
- const ALLOWED_CARD_AUTH_METHODS = ['PAN_ONLY', 'CRYPTOGRAM_3DS'];
14500
-
14501
- const ALLOWED_CARD_NETWORKS = [
14502
- 'AMEX',
14503
- 'DISCOVER',
14504
- 'INTERAC',
14505
- 'JCB',
14506
- 'MASTERCARD',
14507
- 'VISA',
14508
- ];
14509
-
14510
14546
  class BraintreeGooglePayment extends Payment {
14511
14547
  constructor(api, options, params, methods) {
14512
14548
  if (!methods.card) {
@@ -14542,6 +14578,9 @@
14542
14578
  if (this.google) {
14543
14579
  this.googleClient = new this.google.payments.api.PaymentsClient({
14544
14580
  environment: isLiveMode(this.method.mode) ? 'PRODUCTION' : 'TEST',
14581
+ paymentDataCallbacks: {
14582
+ onPaymentDataChanged: onPaymentDataChanged.bind(this),
14583
+ },
14545
14584
  });
14546
14585
  }
14547
14586
 
@@ -14557,31 +14596,12 @@
14557
14596
  BraintreeGooglePayment.googleClient = googleClient;
14558
14597
  }
14559
14598
 
14560
- /** @returns {google.payments.api.PaymentMethodSpecification} */
14561
- get cardPaymentMethod() {
14562
- return {
14563
- type: 'CARD',
14564
- parameters: {
14565
- allowedAuthMethods: ALLOWED_CARD_AUTH_METHODS,
14566
- allowedCardNetworks: ALLOWED_CARD_NETWORKS,
14567
- billingAddressRequired: true,
14568
- billingAddressParameters: {
14569
- format: 'FULL',
14570
- phoneNumberRequired: true,
14571
- },
14572
- },
14573
- };
14574
- }
14575
-
14576
- /** @returns {google.payments.api.PaymentMethodSpecification[]} */
14577
- get allowedPaymentMethods() {
14578
- return [this.cardPaymentMethod];
14579
- }
14580
-
14599
+ /** @param {Cart} cart */
14581
14600
  async createElements(cart) {
14582
14601
  const {
14583
14602
  elementId = 'googlepay-button',
14584
14603
  locale = 'en',
14604
+ require: { phone } = {},
14585
14605
  style: { color = 'black', type = 'plain', sizeMode = 'fill' } = {},
14586
14606
  } = this.params;
14587
14607
 
@@ -14592,10 +14612,35 @@
14592
14612
  this.setElementContainer(elementId);
14593
14613
  await this.loadScripts(this.scripts);
14594
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
+
14595
14640
  const isReadyToPay = await this.googleClient.isReadyToPay({
14596
14641
  apiVersion: API_VERSION$1,
14597
14642
  apiVersionMinor: API_MINOR_VERSION$1,
14598
- allowedPaymentMethods: this.allowedPaymentMethods,
14643
+ allowedPaymentMethods: paymentDataRequest.allowedPaymentMethods,
14599
14644
  existingPaymentMethodRequired: true,
14600
14645
  });
14601
14646
 
@@ -14605,16 +14650,6 @@
14605
14650
  );
14606
14651
  }
14607
14652
 
14608
- const braintreeClient = await this._createBraintreeClient();
14609
- const googlePayment = await this.braintree.googlePayment.create({
14610
- client: braintreeClient,
14611
- googleMerchantId: this.method.merchant_id,
14612
- googlePayVersion: API_VERSION$1,
14613
- });
14614
- const paymentRequestData = this._createPaymentRequestData(cart);
14615
- const paymentDataRequest =
14616
- googlePayment.createPaymentDataRequest(paymentRequestData);
14617
-
14618
14653
  this.element = this.googleClient.createButton({
14619
14654
  buttonColor: color,
14620
14655
  buttonType: type,
@@ -14641,6 +14676,7 @@
14641
14676
  }
14642
14677
  }
14643
14678
 
14679
+ /** @returns {Promise<braintree.Client>} */
14644
14680
  async _createBraintreeClient() {
14645
14681
  const authorization = await this.authorizeGateway({
14646
14682
  gateway: 'braintree',
@@ -14655,39 +14691,51 @@
14655
14691
  });
14656
14692
  }
14657
14693
 
14658
- /** @returns {google.payments.api.PaymentDataRequest} */
14694
+ /**
14695
+ * @param {Cart} cart
14696
+ * @returns {google.payments.api.PaymentDataRequest}
14697
+ */
14659
14698
  _createPaymentRequestData(cart) {
14660
14699
  const {
14661
- settings: { name, country },
14662
- capture_total,
14663
- currency,
14700
+ settings: { name },
14664
14701
  } = cart;
14702
+
14665
14703
  const { require: { email, shipping, phone } = {} } = this.params;
14666
14704
 
14705
+ /** @type {google.payments.api.CallbackIntent[]} */
14706
+ const callbackIntents = ['OFFER'];
14707
+
14708
+ if (shipping) {
14709
+ callbackIntents.push('SHIPPING_ADDRESS', 'SHIPPING_OPTION');
14710
+ }
14711
+
14667
14712
  return {
14668
14713
  apiVersion: API_VERSION$1,
14669
14714
  apiVersionMinor: API_MINOR_VERSION$1,
14670
- transactionInfo: {
14671
- countryCode: country,
14672
- currencyCode: currency,
14673
- totalPrice: capture_total.toString(),
14674
- totalPriceStatus: 'ESTIMATED',
14675
- },
14676
- 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
+ */
14677
14721
  emailRequired: Boolean(email),
14678
14722
  shippingAddressRequired: Boolean(shipping),
14679
14723
  shippingAddressParameters: {
14680
14724
  phoneNumberRequired: Boolean(phone),
14681
14725
  },
14726
+ shippingOptionRequired: Boolean(shipping),
14727
+ shippingOptionParameters: getShippingOptionParameters.call(this, cart),
14728
+ offerInfo: getOfferInfo(cart),
14682
14729
  merchantInfo: {
14683
14730
  merchantName: name,
14684
14731
  merchantId: this.method.merchant_id,
14685
14732
  },
14733
+ callbackIntents,
14686
14734
  };
14687
14735
  }
14688
14736
 
14689
14737
  /**
14690
- * @param {object} googlePayment
14738
+ * @param {braintree.GooglePayment} googlePayment
14691
14739
  * @param {google.payments.api.PaymentDataRequest} paymentDataRequest
14692
14740
  */
14693
14741
  async _onClick(googlePayment, paymentDataRequest) {
@@ -14704,34 +14752,59 @@
14704
14752
  }
14705
14753
 
14706
14754
  /**
14707
- * @param {object} googlePayment
14755
+ * @param {braintree.GooglePayment} googlePayment
14708
14756
  * @param {google.payments.api.PaymentData} paymentData
14709
14757
  */
14710
14758
  async _submitPayment(googlePayment, paymentData) {
14711
- const { require: { shipping: requireShipping } = {} } = this.params;
14712
14759
  const { nonce } = await googlePayment.parseResponse(paymentData);
14713
- const { email, shippingAddress, paymentMethodData } = paymentData;
14714
- const {
14715
- info: { billingAddress },
14716
- } = paymentMethodData;
14760
+ const { email, shippingAddress, shippingOptionData, paymentMethodData } =
14761
+ paymentData;
14762
+ const { info: { billingAddress } = {} } = paymentMethodData;
14717
14763
 
14718
- await this.updateCart({
14764
+ const cart = await this.updateCart({
14719
14765
  account: {
14720
14766
  email,
14721
14767
  },
14722
14768
  billing: {
14723
14769
  method: 'google',
14770
+ account_card_id: null,
14771
+ card: null,
14724
14772
  google: {
14725
14773
  nonce,
14726
14774
  gateway: 'braintree',
14727
14775
  },
14728
14776
  ...convertToSwellAddress$2(billingAddress),
14729
14777
  },
14730
- ...(requireShipping && {
14731
- shipping: convertToSwellAddress$2(shippingAddress),
14778
+ ...(shippingAddress && {
14779
+ shipping: {
14780
+ ...convertToSwellAddress$2(shippingAddress),
14781
+ service: shippingOptionData?.id || undefined,
14782
+ },
14732
14783
  }),
14733
14784
  });
14734
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
+
14735
14808
  this.onSuccess();
14736
14809
  }
14737
14810
  }
@@ -14761,7 +14834,7 @@
14761
14834
  'Shipping is not available for the provided address.';
14762
14835
 
14763
14836
  return {
14764
- newTotal: getTotal(cart, this.merchantInfo),
14837
+ newTotal: getTotal.call(this, cart, this.merchantInfo),
14765
14838
  newLineItems: getLineItems(cart),
14766
14839
  newShippingMethods: [], // REQUIRED: Must always provide this, even as empty array
14767
14840
  errors: [
@@ -14772,15 +14845,15 @@
14772
14845
 
14773
14846
  // Success: Return updated totals and shipping methods
14774
14847
  return {
14775
- newTotal: getTotal(cart, this.merchantInfo),
14848
+ newTotal: getTotal.call(this, cart, this.merchantInfo),
14776
14849
  newLineItems: getLineItems(cart),
14777
- newShippingMethods: getShippingMethods(cart),
14850
+ newShippingMethods: getShippingMethods.call(this, cart),
14778
14851
  };
14779
14852
  } catch (err) {
14780
14853
  const cartData = await this.getCart();
14781
14854
 
14782
14855
  return {
14783
- newTotal: getTotal(cartData, this.merchantInfo),
14856
+ newTotal: getTotal.call(this, cartData, this.merchantInfo),
14784
14857
  newLineItems: getLineItems(cartData),
14785
14858
  newShippingMethods: [], // REQUIRED: Must always provide this, even as empty array
14786
14859
  errors: [new ApplePayError('unknown', undefined, err.message)],
@@ -14826,12 +14899,12 @@
14826
14899
  });
14827
14900
 
14828
14901
  return {
14829
- newTotal: getTotal(cart, this.merchantInfo),
14902
+ newTotal: getTotal.call(this, cart, this.merchantInfo),
14830
14903
  newLineItems: getLineItems(cart),
14831
14904
  };
14832
14905
  } catch (err) {
14833
14906
  return {
14834
- newTotal: getTotal(await this.getCart(), this.merchantInfo),
14907
+ newTotal: getTotal.call(this, await this.getCart(), this.merchantInfo),
14835
14908
  errors: [new ApplePayError('unknown', undefined, err.message)],
14836
14909
  };
14837
14910
  }
@@ -14871,7 +14944,7 @@
14871
14944
 
14872
14945
  // Valid coupon applied successfully
14873
14946
  return {
14874
- newTotal: getTotal(cart, this.merchantInfo),
14947
+ newTotal: getTotal.call(this, cart, this.merchantInfo),
14875
14948
  newLineItems: getLineItems(cart),
14876
14949
  };
14877
14950
  } catch (err) {
@@ -14879,7 +14952,7 @@
14879
14952
  const currentCart = await this.getCart();
14880
14953
 
14881
14954
  return {
14882
- newTotal: getTotal(currentCart, this.merchantInfo),
14955
+ newTotal: getTotal.call(this, currentCart, this.merchantInfo),
14883
14956
  newLineItems: getLineItems(currentCart),
14884
14957
  errors: [new ApplePayError('couponCodeInvalid', undefined, err.message)],
14885
14958
  };
@@ -14913,15 +14986,17 @@
14913
14986
  * This ensures the user sees "pending" until they've selected shipping,
14914
14987
  * then sees the final amount once everything is calculated.
14915
14988
  *
14989
+ * @this {Payment}
14916
14990
  * @param {Cart} cart
14917
14991
  * @param {object} [merchantInfo]
14918
14992
  * @returns {ApplePayJS.ApplePayLineItem}
14919
14993
  */
14920
14994
  function getTotal(cart, merchantInfo) {
14921
- const { capture_total, shipment_delivery, shipping } = cart;
14995
+ const { require: { shipping: shipmentDelivery = false } = {} } = this.params;
14996
+ const { capture_total, shipping } = cart;
14922
14997
 
14923
14998
  // Use 'final' only after shipping method is selected or not needed, otherwise 'pending'
14924
- const isFinalPrice = !shipment_delivery || shipping?.service;
14999
+ const isFinalPrice = !shipmentDelivery || shipping?.service;
14925
15000
  const type = isFinalPrice ? 'final' : 'pending';
14926
15001
 
14927
15002
  return {
@@ -14990,16 +15065,19 @@
14990
15065
  *
14991
15066
  * IMPORTANT: Amounts must be formatted as strings with 2 decimals.
14992
15067
  *
15068
+ * @this {Payment}
14993
15069
  * @param {Cart} cart
14994
15070
  * @returns {ApplePayJS.ApplePayShippingMethod[]}
14995
15071
  */
14996
15072
  function getShippingMethods(cart) {
14997
- const { shipment_delivery, shipment_rating } = cart;
15073
+ const { require: { shipping: shipmentDelivery = false } = {} } = this.params;
14998
15074
 
14999
- if (!shipment_delivery) {
15075
+ if (!shipmentDelivery) {
15000
15076
  return [];
15001
15077
  }
15002
15078
 
15079
+ const { shipment_rating } = cart;
15080
+
15003
15081
  if (!shipment_rating?.services?.length) {
15004
15082
  return [];
15005
15083
  }
@@ -15050,13 +15128,38 @@
15050
15128
  };
15051
15129
  }
15052
15130
 
15053
- 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 */
15054
15161
 
15055
- const MERCHANT_CAPABILITIES = [
15056
- 'supports3DS',
15057
- 'supportsDebit',
15058
- 'supportsCredit',
15059
- ];
15162
+ const VERSION$1 = 14;
15060
15163
 
15061
15164
  class BraintreeApplePayment extends Payment {
15062
15165
  constructor(api, options, params, methods) {
@@ -15088,6 +15191,7 @@
15088
15191
  return window.ApplePaySession;
15089
15192
  }
15090
15193
 
15194
+ /** @param {Cart} cart */
15091
15195
  async createElements(cart) {
15092
15196
  const { elementId = 'applepay-button' } = this.params;
15093
15197
 
@@ -15101,10 +15205,12 @@
15101
15205
  }
15102
15206
 
15103
15207
  const braintreeClient = await this._createBraintreeClient();
15208
+
15104
15209
  const applePayment = await this.braintree.applePay.create({
15105
15210
  client: braintreeClient,
15106
15211
  });
15107
- const paymentRequest = await this._createPaymentRequest(cart, applePayment);
15212
+
15213
+ const paymentRequest = this._createPaymentRequest(cart, applePayment);
15108
15214
 
15109
15215
  this.element = this._createButton(applePayment, paymentRequest);
15110
15216
  }
@@ -15121,8 +15227,9 @@
15121
15227
  }
15122
15228
 
15123
15229
  /**
15124
- * @param {object} applePayment
15230
+ * @param {braintree.ApplePay} applePayment
15125
15231
  * @param {ApplePayJS.ApplePayPaymentRequest} paymentRequest
15232
+ * @returns {HTMLDivElement}
15126
15233
  */
15127
15234
  _createButton(applePayment, paymentRequest) {
15128
15235
  const { style: { type = 'plain', theme = 'black', height = '40px' } = {} } =
@@ -15143,6 +15250,7 @@
15143
15250
  return button;
15144
15251
  }
15145
15252
 
15253
+ /** @returns {Promise<braintree.Client>} */
15146
15254
  async _createBraintreeClient() {
15147
15255
  const authorization = await this.authorizeGateway({
15148
15256
  gateway: 'braintree',
@@ -15157,47 +15265,43 @@
15157
15265
  });
15158
15266
  }
15159
15267
 
15160
- /** @returns {ApplePayJS.ApplePayPaymentRequest} */
15268
+ /**
15269
+ * @param {Cart} cart
15270
+ * @param {braintree.ApplePay} applePayment
15271
+ * @returns {ApplePayJS.ApplePayPaymentRequest}
15272
+ */
15161
15273
  _createPaymentRequest(cart, applePayment) {
15162
- const { require = {} } = this.params;
15163
15274
  const {
15164
15275
  settings: { name, country },
15165
15276
  capture_total,
15166
15277
  currency,
15167
15278
  } = cart;
15168
15279
 
15169
- const requiredShippingContactFields = [];
15170
- const requiredBillingContactFields = ['postalAddress'];
15171
-
15172
- if (require.name) {
15173
- requiredShippingContactFields.push('name');
15174
- }
15175
- if (require.email) {
15176
- requiredShippingContactFields.push('email');
15177
- }
15178
- if (require.phone) {
15179
- requiredShippingContactFields.push('phone');
15180
- }
15181
- if (require.shipping) {
15182
- requiredShippingContactFields.push('postalAddress');
15183
- }
15280
+ const { requiredBillingContactFields, requiredShippingContactFields } =
15281
+ getRequiredContactFields(this.params);
15184
15282
 
15185
15283
  return applePayment.createPaymentRequest({
15186
15284
  total: {
15187
15285
  label: name,
15188
15286
  type: 'pending',
15189
- amount: capture_total.toString(),
15287
+ amount: (capture_total || 0).toFixed(2),
15190
15288
  },
15191
15289
  countryCode: country,
15192
15290
  currencyCode: currency,
15193
- 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
+ */
15194
15296
  requiredShippingContactFields,
15195
15297
  requiredBillingContactFields,
15298
+ supportsCouponCode: true,
15299
+ lineItems: getLineItems(cart),
15196
15300
  });
15197
15301
  }
15198
15302
 
15199
15303
  /**
15200
- * @param {object} applePayment
15304
+ * @param {braintree.ApplePay} applePayment
15201
15305
  * @param {ApplePayJS.ApplePayPaymentRequest} paymentRequest
15202
15306
  */
15203
15307
  _createPaymentSession(applePayment, paymentRequest) {
@@ -15218,11 +15322,23 @@
15218
15322
  }
15219
15323
  };
15220
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
+
15221
15337
  session.onpaymentauthorized = async (event) => {
15222
15338
  const {
15223
15339
  payment: { token, shippingContact, billingContact },
15224
15340
  } = event;
15225
- const { require: { shipping: requireShipping } = {} } = this.params;
15341
+
15226
15342
  const payload = await applePayment
15227
15343
  .tokenize({ token })
15228
15344
  .catch(this.onError.bind(this));
@@ -15231,23 +15347,47 @@
15231
15347
  return session.completePayment(this.ApplePaySession.STATUS_FAILURE);
15232
15348
  }
15233
15349
 
15234
- await this.updateCart({
15350
+ const cart = await this.updateCart({
15235
15351
  account: {
15236
- email: shippingContact.emailAddress,
15352
+ email: shippingContact?.emailAddress || billingContact?.emailAddress,
15237
15353
  },
15238
15354
  billing: {
15239
15355
  method: 'apple',
15356
+ account_card_id: null,
15357
+ card: null,
15240
15358
  apple: {
15241
15359
  nonce: payload.nonce,
15242
15360
  gateway: 'braintree',
15243
15361
  },
15244
15362
  ...convertToSwellAddress$1(billingContact),
15245
15363
  },
15246
- ...(requireShipping && {
15364
+ ...(shippingContact && {
15247
15365
  shipping: convertToSwellAddress$1(shippingContact),
15248
15366
  }),
15249
15367
  });
15250
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
+
15251
15391
  this.onSuccess();
15252
15392
 
15253
15393
  return session.completePayment(this.ApplePaySession.STATUS_SUCCESS);
@@ -15353,6 +15493,8 @@
15353
15493
  * @returns {google.payments.api.PaymentMethodSpecification}
15354
15494
  */
15355
15495
  _getCardPaymentMethod(submit = false) {
15496
+ const { require: { phone } = {} } = this.params;
15497
+
15356
15498
  return {
15357
15499
  type: 'CARD',
15358
15500
  parameters: {
@@ -15361,7 +15503,7 @@
15361
15503
  billingAddressRequired: true,
15362
15504
  billingAddressParameters: {
15363
15505
  format: 'FULL',
15364
- phoneNumberRequired: true,
15506
+ phoneNumberRequired: Boolean(phone),
15365
15507
  },
15366
15508
  },
15367
15509
  ...(submit && {
@@ -15394,29 +15536,30 @@
15394
15536
  cart.shipment_price = 0;
15395
15537
  cart.shipping = {};
15396
15538
 
15397
- const { shipment_delivery } = cart;
15398
15539
  const { require: { email, shipping, phone } = {} } = this.params;
15399
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
+
15400
15548
  return {
15401
15549
  apiVersion: API_VERSION,
15402
15550
  apiVersionMinor: API_MINOR_VERSION,
15403
- transactionInfo: getTransactionInfo(cart),
15551
+ transactionInfo: getTransactionInfo.call(this, cart),
15404
15552
  allowedPaymentMethods: this._getAllowedPaymentMethods(true),
15405
15553
  emailRequired: Boolean(email),
15406
15554
  shippingAddressRequired: Boolean(shipping),
15407
15555
  shippingAddressParameters: {
15408
15556
  phoneNumberRequired: Boolean(phone),
15409
15557
  },
15410
- shippingOptionRequired: Boolean(shipment_delivery),
15558
+ shippingOptionRequired: Boolean(shipping),
15411
15559
  shippingOptionParameters: getShippingOptionParameters.call(this, cart),
15412
15560
  offerInfo: getOfferInfo(cart),
15413
15561
  merchantInfo,
15414
- callbackIntents: [
15415
- 'OFFER',
15416
- 'SHIPPING_ADDRESS',
15417
- 'SHIPPING_OPTION',
15418
- 'PAYMENT_AUTHORIZATION',
15419
- ],
15562
+ callbackIntents,
15420
15563
  };
15421
15564
  }
15422
15565
 
@@ -15540,6 +15683,22 @@
15540
15683
  /** @typedef {import('../../../types').Cart} Cart */
15541
15684
 
15542
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
+
15543
15702
  /**
15544
15703
  * @override
15545
15704
  * @returns {google.payments.api.PaymentGatewayTokenizationParameters}
@@ -15557,7 +15716,6 @@
15557
15716
  * @returns {Promise<object>}
15558
15717
  */
15559
15718
  async preparePaymentDataForCartUpdate(paymentData) {
15560
- const { require: { shipping: requireShipping } = {} } = this.params;
15561
15719
  const { email, shippingAddress, shippingOptionData, paymentMethodData } =
15562
15720
  paymentData;
15563
15721
 
@@ -15578,7 +15736,7 @@
15578
15736
  },
15579
15737
  ...convertToSwellAddress$2(billingAddress),
15580
15738
  },
15581
- ...(requireShipping && {
15739
+ ...(shippingAddress && {
15582
15740
  shipping: {
15583
15741
  ...convertToSwellAddress$2(shippingAddress),
15584
15742
  service: shippingOptionData?.id || undefined,
@@ -15645,9 +15803,15 @@
15645
15803
  return window.ApplePaySession;
15646
15804
  }
15647
15805
 
15648
- /** @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
+ */
15649
15813
  getSupportedCardNetworks() {
15650
- return ['amex', 'discover', 'interac', 'jcb', 'masterCard', 'visa'];
15814
+ return ['visa', 'masterCard', 'amex', 'discover', 'interac', 'jcb'];
15651
15815
  }
15652
15816
 
15653
15817
  /** @returns {ApplePayJS.ApplePayMerchantCapability[]} */
@@ -15658,12 +15822,12 @@
15658
15822
  /**
15659
15823
  * Creates the Apple Pay payment request object
15660
15824
  *
15661
- * IMPORTANT: countryCode here is the MERCHANT's country (where your business is located),
15662
- * 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`.
15663
15827
  *
15664
- * 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
15665
15829
  * are provided dynamically after the user selects/confirms their address in the
15666
- * 'shippingcontactselected' event handler.
15830
+ * `'shippingcontactselected'` event handler.
15667
15831
  *
15668
15832
  * @param {Cart} cart
15669
15833
  * @returns {ApplePayJS.ApplePayPaymentRequest}
@@ -15671,38 +15835,21 @@
15671
15835
  _createPaymentRequest(cart) {
15672
15836
  cart = { ...cart };
15673
15837
 
15674
- const { require = {} } = this.params;
15675
15838
  const {
15676
15839
  settings: { country },
15677
15840
  currency,
15678
15841
  } = cart;
15679
15842
 
15680
- const requiredShippingContactFields = [];
15681
- const requiredBillingContactFields = ['postalAddress'];
15682
-
15683
- if (require.name) {
15684
- requiredShippingContactFields.push('name');
15685
- }
15686
-
15687
- if (require.email) {
15688
- requiredShippingContactFields.push('email');
15689
- }
15690
-
15691
- if (require.phone) {
15692
- requiredShippingContactFields.push('phone');
15693
- }
15694
-
15695
- if (require.shipping) {
15696
- requiredShippingContactFields.push('postalAddress');
15697
- }
15698
-
15699
15843
  // When initiating a payment request,
15700
15844
  // we should not display the shipping cost, as it will be calculated later.
15701
15845
  cart.shipment_price = 0;
15702
15846
  cart.shipping = {};
15703
15847
 
15848
+ const { requiredBillingContactFields, requiredShippingContactFields } =
15849
+ getRequiredContactFields(this.params);
15850
+
15704
15851
  return {
15705
- total: getTotal(cart, this.merchantInfo),
15852
+ total: getTotal.call(this, cart, this.merchantInfo),
15706
15853
  countryCode: country, // Merchant's country
15707
15854
  currencyCode: currency,
15708
15855
  supportedNetworks: this.getSupportedCardNetworks(),
@@ -15884,6 +16031,22 @@
15884
16031
  }
15885
16032
 
15886
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
+
15887
16050
  /**
15888
16051
  * @override
15889
16052
  * @param {ApplePayJS.ApplePayValidateMerchantEvent} event
@@ -15917,11 +16080,9 @@
15917
16080
  payment: { token, shippingContact, billingContact },
15918
16081
  } = event;
15919
16082
 
15920
- const { require: { shipping: requireShipping } = {} } = this.params;
15921
-
15922
16083
  return {
15923
16084
  account: {
15924
- email: shippingContact.emailAddress,
16085
+ email: shippingContact?.emailAddress || billingContact?.emailAddress,
15925
16086
  },
15926
16087
  billing: {
15927
16088
  method: 'apple',
@@ -15933,7 +16094,7 @@
15933
16094
  },
15934
16095
  ...convertToSwellAddress$1(billingContact),
15935
16096
  },
15936
- ...(requireShipping && {
16097
+ ...(shippingContact && {
15937
16098
  shipping: convertToSwellAddress$1(shippingContact),
15938
16099
  }),
15939
16100
  };
@@ -15946,7 +16107,7 @@
15946
16107
  }
15947
16108
 
15948
16109
  get orderId() {
15949
- return Math.random().toString(36).substr(2, 9);
16110
+ return Math.random().toString(36).slice(2, 11);
15950
16111
  }
15951
16112
 
15952
16113
  async tokenize() {
@@ -16008,6 +16169,12 @@
16008
16169
  throw new Error(card.error.message);
16009
16170
  }
16010
16171
 
16172
+ card.gateway = 'quickpay';
16173
+
16174
+ if (!isLiveMode(this.method.mode)) {
16175
+ card.test = true;
16176
+ }
16177
+
16011
16178
  await this.updateCart({
16012
16179
  billing: {
16013
16180
  method: 'card',
@@ -16047,7 +16214,7 @@
16047
16214
  merchantAccount: false,
16048
16215
  countryCode: country || 'US',
16049
16216
  shopperLocale: 'en-US',
16050
- // shopperReference: email ? md5(email) : undefined,
16217
+ // shopperReference: email ? md5(email.toLowerCase()) : undefined,
16051
16218
  }),
16052
16219
  },
16053
16220
  ).then((res) => res.json());
@@ -16175,15 +16342,20 @@
16175
16342
  }
16176
16343
  }
16177
16344
 
16345
+ function getBaseConvesioVaultUrl(mode) {
16346
+ return isLiveMode(mode)
16347
+ ? 'https://vault.convesiopay.com'
16348
+ : 'https://qa-vault.convesiopay.com';
16349
+ }
16350
+
16178
16351
  function createConvesioCardPaymentToken(settings, data) {
16179
- const baseUrl = getBaseConvesioApiUrl(settings.mode);
16352
+ const baseUrl = getBaseConvesioVaultUrl(settings.mode);
16180
16353
 
16181
16354
  return fetch(`${baseUrl}/v1/create-token`, {
16182
16355
  method: 'POST',
16183
16356
  headers: {
16184
16357
  Accept: 'application/json',
16185
16358
  'Content-Type': 'application/json',
16186
- 'X-Requested-With': 'convesio-pay-dashboard',
16187
16359
  'X-Api-Key': settings.public_key,
16188
16360
  },
16189
16361
  body: JSON.stringify(data),
@@ -16298,8 +16470,6 @@
16298
16470
  payment: { token, shippingContact, billingContact },
16299
16471
  } = event;
16300
16472
 
16301
- const { require: { shipping: requireShipping } = {} } = this.params;
16302
-
16303
16473
  const payment = await createConvesioApplePaymentToken(
16304
16474
  this.method.mode,
16305
16475
  this.convesiopay,
@@ -16321,7 +16491,7 @@
16321
16491
 
16322
16492
  return {
16323
16493
  account: {
16324
- email: shippingContact.emailAddress,
16494
+ email: shippingContact?.emailAddress || billingContact?.emailAddress,
16325
16495
  },
16326
16496
  billing: {
16327
16497
  method: 'apple',
@@ -16336,7 +16506,7 @@
16336
16506
  },
16337
16507
  ...convertToSwellAddress$1(billingContact),
16338
16508
  },
16339
- ...(requireShipping && {
16509
+ ...(shippingContact && {
16340
16510
  shipping: convertToSwellAddress$1(shippingContact),
16341
16511
  }),
16342
16512
  };
@@ -16466,7 +16636,6 @@
16466
16636
  * @returns {Promise<object>}
16467
16637
  */
16468
16638
  async preparePaymentDataForCartUpdate(paymentData) {
16469
- const { require: { shipping: requireShipping } = {} } = this.params;
16470
16639
  const { email, shippingAddress, shippingOptionData, paymentMethodData } =
16471
16640
  paymentData;
16472
16641
 
@@ -16509,7 +16678,7 @@
16509
16678
  },
16510
16679
  ...convertToSwellAddress$2(billingAddress),
16511
16680
  },
16512
- ...(requireShipping && {
16681
+ ...(shippingAddress && {
16513
16682
  shipping: {
16514
16683
  ...convertToSwellAddress$2(shippingAddress),
16515
16684
  service: shippingOptionData?.id || undefined,
@@ -17405,20 +17574,29 @@
17405
17574
  settings: { name },
17406
17575
  } = cart;
17407
17576
 
17408
- const shipmentDelivery = Boolean(cart.shipment_delivery);
17577
+ const { require: { shipping } = {} } = this.params;
17409
17578
  const cartCurrency = getCartCurrency(cart);
17410
17579
 
17411
17580
  return {
17412
17581
  checkout_payload: {
17413
- 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
+ },
17414
17592
  order: {
17415
17593
  intent: 'AUTH',
17416
17594
  reference_id: cart.checkout_id,
17417
17595
  description: `${name} #${cart.number}`,
17418
- requires_shipping_info: shipmentDelivery,
17596
+ requires_shipping_info: shipping,
17419
17597
  items: getItems(cart),
17420
17598
  discounts: getDiscounts(cart),
17421
- tax_amount: shipmentDelivery
17599
+ tax_amount: shipping
17422
17600
  ? undefined
17423
17601
  : getAmountInCents(cartCurrency, cart.tax_total),
17424
17602
  order_amount: getAmountInCents(cartCurrency, cart.capture_total),
@@ -17678,15 +17856,6 @@
17678
17856
  };
17679
17857
  }
17680
17858
 
17681
- /**
17682
- * @param {string} currency
17683
- * @param {number} amount
17684
- * @returns {number}
17685
- */
17686
- function amountInCents(currency, amount) {
17687
- return Math.round(amount * 100);
17688
- }
17689
-
17690
17859
  class PaymentController {
17691
17860
  constructor(api, options) {
17692
17861
  this.api = api;
@@ -18389,7 +18558,7 @@
18389
18558
  const api = {};
18390
18559
 
18391
18560
  Object.assign(api, {
18392
- version: '5.6.1',
18561
+ version: '5.8.0',
18393
18562
  options,
18394
18563
  request,
18395
18564