swell-js 5.7.0 → 5.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/swell.cjs CHANGED
@@ -7210,7 +7210,7 @@ const MINIMUM_CHARGE_AMOUNT = {
7210
7210
  THB: 10,
7211
7211
  };
7212
7212
 
7213
- const addressFieldsMap$1 = {
7213
+ const addressFieldsMap = {
7214
7214
  city: 'city',
7215
7215
  country: 'country',
7216
7216
  line1: 'address1',
@@ -7248,7 +7248,7 @@ function getBillingDetails(cart) {
7248
7248
  details.email = cart.account.email;
7249
7249
  }
7250
7250
 
7251
- const address = mapValues(addressFieldsMap$1, cart.billing);
7251
+ const address = mapValues(addressFieldsMap, cart.billing);
7252
7252
  if (!isEmpty(address)) {
7253
7253
  details.address = address;
7254
7254
  }
@@ -7400,13 +7400,13 @@ function getPaymentRequestData(cart, params) {
7400
7400
  tax_included_total,
7401
7401
  settings,
7402
7402
  } = cart;
7403
- const { price: shippingPrice, service_name } = shipping || {};
7403
+ const { price: shippingPrice, service, service_name } = shipping || {};
7404
7404
  const { country, name } = settings || {};
7405
7405
  const { require: { shipping: requireShipping } = {} } = params;
7406
7406
 
7407
7407
  const stripeCurrency = currency.toLowerCase();
7408
7408
  const displayItems = items.map((item) => ({
7409
- label: get(item, 'product.name', 'Unknown product'),
7409
+ label: item.product_name || item.product?.name || 'Unknown product',
7410
7410
  amount: stripeAmountByCurrency(
7411
7411
  currency,
7412
7412
  item.price_total - item.discount_total,
@@ -7428,14 +7428,21 @@ function getPaymentRequestData(cart, params) {
7428
7428
  }
7429
7429
 
7430
7430
  let shippingOptions;
7431
- const services = get(shipment_rating, 'services');
7432
- if (Array.isArray(services) && services.length > 0) {
7431
+ const services = shipment_rating?.services;
7432
+ if (requireShipping && Array.isArray(services) && services.length > 0) {
7433
7433
  shippingOptions = services.map((service) => ({
7434
7434
  id: service.id,
7435
7435
  label: service.name,
7436
7436
  detail: service.description,
7437
7437
  amount: stripeAmountByCurrency(currency, service.price),
7438
7438
  }));
7439
+
7440
+ const index = shippingOptions.findIndex((item) => item.id === service);
7441
+
7442
+ if (index > 0) {
7443
+ // Move selected shipping option to the top
7444
+ shippingOptions.unshift(...shippingOptions.splice(index, 1));
7445
+ }
7439
7446
  }
7440
7447
 
7441
7448
  return {
@@ -7447,7 +7454,7 @@ function getPaymentRequestData(cart, params) {
7447
7454
  pending: true,
7448
7455
  },
7449
7456
  displayItems,
7450
- ...(requireShipping && { shippingOptions }),
7457
+ ...(shippingOptions && { shippingOptions }),
7451
7458
  };
7452
7459
  }
7453
7460
 
@@ -7995,6 +8002,7 @@ class StripeKlarnaPayment extends Payment {
7995
8002
 
7996
8003
  /** @typedef {import('@stripe/stripe-js').Stripe} Stripe */
7997
8004
  /** @typedef {import('@stripe/stripe-js').PaymentRequestPaymentMethodEvent} PaymentRequestPaymentMethodEvent */
8005
+ /** @typedef {import('../../../types').Cart} Cart */
7998
8006
 
7999
8007
  class StripeGooglePayment extends Payment {
8000
8008
  constructor(api, options, params, methods) {
@@ -8062,6 +8070,7 @@ class StripeGooglePayment extends Payment {
8062
8070
  this.element.mount(`#${this.elementContainer.id}`);
8063
8071
  }
8064
8072
 
8073
+ /** @param {Cart} cart */
8065
8074
  _createPaymentRequest(cart) {
8066
8075
  const { require: { name, email, shipping, phone } = {} } = this.params;
8067
8076
 
@@ -8074,15 +8083,10 @@ class StripeGooglePayment extends Payment {
8074
8083
  ...getPaymentRequestData(cart, this.params),
8075
8084
  });
8076
8085
 
8077
- paymentRequest.on(
8078
- 'shippingaddresschange',
8079
- this._onShippingAddressChange.bind(this),
8080
- );
8081
- paymentRequest.on(
8082
- 'shippingoptionchange',
8083
- this._onShippingOptionChange.bind(this),
8084
- );
8085
- paymentRequest.on('paymentmethod', this._onPaymentMethod.bind(this));
8086
+ paymentRequest
8087
+ .on('shippingaddresschange', this._onShippingAddressChange.bind(this))
8088
+ .on('shippingoptionchange', this._onShippingOptionChange.bind(this))
8089
+ .on('paymentmethod', this._onPaymentMethod.bind(this));
8086
8090
 
8087
8091
  return paymentRequest;
8088
8092
  }
@@ -8090,9 +8094,9 @@ class StripeGooglePayment extends Payment {
8090
8094
  /** @param {import('@stripe/stripe-js').PaymentRequestShippingAddressEvent} event */
8091
8095
  async _onShippingAddressChange(event) {
8092
8096
  const { shippingAddress, updateWith } = event;
8093
- const shipping = this._mapShippingAddress(shippingAddress);
8097
+
8094
8098
  const cart = await this.updateCart({
8095
- shipping: { ...shipping, service: null },
8099
+ shipping: this._mapShippingAddress(shippingAddress),
8096
8100
  shipment_rating: null,
8097
8101
  });
8098
8102
 
@@ -8132,16 +8136,15 @@ class StripeGooglePayment extends Payment {
8132
8136
  shippingOption,
8133
8137
  complete,
8134
8138
  } = event;
8135
- const { require: { shipping: requireShipping } = {} } = this.params;
8136
8139
 
8137
8140
  await this.updateCart({
8138
8141
  account: {
8139
- email: payerEmail,
8142
+ email: payerEmail || billing_details?.email,
8140
8143
  },
8141
- ...(requireShipping && {
8144
+ ...(shippingAddress && {
8142
8145
  shipping: {
8143
8146
  ...this._mapShippingAddress(shippingAddress),
8144
- service: shippingOption.id,
8147
+ service: shippingOption?.id || undefined,
8145
8148
  },
8146
8149
  }),
8147
8150
  billing: {
@@ -8155,9 +8158,9 @@ class StripeGooglePayment extends Payment {
8155
8158
  exp_month: card.exp_month,
8156
8159
  exp_year: card.exp_year,
8157
8160
  last4: card.last4,
8158
- address_check: card.checks.address_line1_check,
8159
- zip_check: card.checks.address_postal_code_check,
8160
- cvc_check: card.checks.cvc_check,
8161
+ address_check: card.checks?.address_line1_check,
8162
+ zip_check: card.checks?.address_postal_code_check,
8163
+ cvc_check: card.checks?.cvc_check,
8161
8164
  },
8162
8165
  },
8163
8166
  });
@@ -8205,8 +8208,8 @@ class StripeGooglePayment extends Payment {
8205
8208
  _mapShippingAddress(address = {}) {
8206
8209
  return {
8207
8210
  name: address.recipient,
8208
- address1: address.addressLine[0],
8209
- address2: address.addressLine[1],
8211
+ address1: address.addressLine?.[0],
8212
+ address2: address.addressLine?.[1],
8210
8213
  city: address.city,
8211
8214
  state: address.region,
8212
8215
  zip: address.postalCode,
@@ -8220,18 +8223,19 @@ class StripeGooglePayment extends Payment {
8220
8223
  return {
8221
8224
  name: address.name,
8222
8225
  phone: address.phone,
8223
- address1: address.address.line1,
8224
- address2: address.address.line2,
8225
- city: address.address.city,
8226
- state: address.address.state,
8227
- zip: address.address.postal_code,
8228
- country: address.address.country,
8226
+ address1: address.address?.line1,
8227
+ address2: address.address?.line2,
8228
+ city: address.address?.city,
8229
+ state: address.address?.state,
8230
+ zip: address.address?.postal_code,
8231
+ country: address.address?.country,
8229
8232
  };
8230
8233
  }
8231
8234
  }
8232
8235
 
8233
8236
  /** @typedef {import('@stripe/stripe-js').Stripe} Stripe */
8234
8237
  /** @typedef {import('@stripe/stripe-js').PaymentRequestPaymentMethodEvent} PaymentRequestPaymentMethodEvent */
8238
+ /** @typedef {import('../../../types').Cart} Cart */
8235
8239
 
8236
8240
  class StripeApplePayment extends Payment {
8237
8241
  constructor(api, options, params, methods) {
@@ -8285,7 +8289,7 @@ class StripeApplePayment extends Payment {
8285
8289
  const paymentRequest = this._createPaymentRequest(cart);
8286
8290
  const canMakePayment = await paymentRequest.canMakePayment();
8287
8291
 
8288
- if (!canMakePayment || !canMakePayment.applePay) {
8292
+ if (!canMakePayment?.applePay) {
8289
8293
  throw new Error(
8290
8294
  'This device is not capable of making Apple Pay payments',
8291
8295
  );
@@ -8322,6 +8326,7 @@ class StripeApplePayment extends Payment {
8322
8326
  }
8323
8327
  }
8324
8328
 
8329
+ /** @param {Cart} cart */
8325
8330
  _createPaymentRequest(cart) {
8326
8331
  const { require: { name, email, shipping, phone } = {} } = this.params;
8327
8332
 
@@ -8334,15 +8339,10 @@ class StripeApplePayment extends Payment {
8334
8339
  ...getPaymentRequestData(cart, this.params),
8335
8340
  });
8336
8341
 
8337
- paymentRequest.on(
8338
- 'shippingaddresschange',
8339
- this._onShippingAddressChange.bind(this),
8340
- );
8341
- paymentRequest.on(
8342
- 'shippingoptionchange',
8343
- this._onShippingOptionChange.bind(this),
8344
- );
8345
- paymentRequest.on('paymentmethod', this._onPaymentMethod.bind(this));
8342
+ paymentRequest
8343
+ .on('shippingaddresschange', this._onShippingAddressChange.bind(this))
8344
+ .on('shippingoptionchange', this._onShippingOptionChange.bind(this))
8345
+ .on('paymentmethod', this._onPaymentMethod.bind(this));
8346
8346
 
8347
8347
  return paymentRequest;
8348
8348
  }
@@ -8350,9 +8350,9 @@ class StripeApplePayment extends Payment {
8350
8350
  /** @param {import('@stripe/stripe-js').PaymentRequestShippingAddressEvent} event */
8351
8351
  async _onShippingAddressChange(event) {
8352
8352
  const { shippingAddress, updateWith } = event;
8353
- const shipping = this._mapShippingAddress(shippingAddress);
8353
+
8354
8354
  const cart = await this.updateCart({
8355
- shipping: { ...shipping, service: null },
8355
+ shipping: this._mapShippingAddress(shippingAddress),
8356
8356
  shipment_rating: null,
8357
8357
  });
8358
8358
 
@@ -8392,16 +8392,15 @@ class StripeApplePayment extends Payment {
8392
8392
  shippingOption,
8393
8393
  complete,
8394
8394
  } = event;
8395
- const { require: { shipping: requireShipping } = {} } = this.params;
8396
8395
 
8397
8396
  await this.updateCart({
8398
8397
  account: {
8399
- email: payerEmail,
8398
+ email: payerEmail || billing_details?.email,
8400
8399
  },
8401
- ...(requireShipping && {
8400
+ ...(shippingAddress && {
8402
8401
  shipping: {
8403
8402
  ...this._mapShippingAddress(shippingAddress),
8404
- service: shippingOption.id,
8403
+ service: shippingOption?.id || undefined,
8405
8404
  },
8406
8405
  }),
8407
8406
  billing: {
@@ -8415,9 +8414,9 @@ class StripeApplePayment extends Payment {
8415
8414
  exp_month: card.exp_month,
8416
8415
  exp_year: card.exp_year,
8417
8416
  last4: card.last4,
8418
- address_check: card.checks.address_line1_check,
8419
- zip_check: card.checks.address_postal_code_check,
8420
- cvc_check: card.checks.cvc_check,
8417
+ address_check: card.checks?.address_line1_check,
8418
+ zip_check: card.checks?.address_postal_code_check,
8419
+ cvc_check: card.checks?.cvc_check,
8421
8420
  },
8422
8421
  },
8423
8422
  });
@@ -8431,8 +8430,8 @@ class StripeApplePayment extends Payment {
8431
8430
  _mapShippingAddress(address = {}) {
8432
8431
  return {
8433
8432
  name: address.recipient,
8434
- address1: address.addressLine[0],
8435
- address2: address.addressLine[1],
8433
+ address1: address.addressLine?.[0],
8434
+ address2: address.addressLine?.[1],
8436
8435
  city: address.city,
8437
8436
  state: address.region,
8438
8437
  zip: address.postalCode,
@@ -8446,12 +8445,12 @@ class StripeApplePayment extends Payment {
8446
8445
  return {
8447
8446
  name: address.name,
8448
8447
  phone: address.phone,
8449
- address1: address.address.line1,
8450
- address2: address.address.line2,
8451
- city: address.address.city,
8452
- state: address.address.state,
8453
- zip: address.address.postal_code,
8454
- country: address.address.country,
8448
+ address1: address.address?.line1,
8449
+ address2: address.address?.line2,
8450
+ city: address.address?.city,
8451
+ state: address.address?.state,
8452
+ zip: address.address?.postal_code,
8453
+ country: address.address?.country,
8455
8454
  };
8456
8455
  }
8457
8456
  }
@@ -8719,6 +8718,44 @@ function getDiscountLabel(discount, cart) {
8719
8718
  return discount.id;
8720
8719
  }
8721
8720
 
8721
+ /** @type {Map<string, number>} */
8722
+ const CURRENCIES_CENTS = new Map();
8723
+
8724
+ /**
8725
+ * @param {string} currency
8726
+ * @returns {number}
8727
+ */
8728
+ function getCurrencyCents(currency) {
8729
+ let cents = CURRENCIES_CENTS.get(currency);
8730
+
8731
+ if (cents !== undefined) {
8732
+ return cents;
8733
+ }
8734
+
8735
+ const formatter = new Intl.NumberFormat('en-US', {
8736
+ style: 'currency',
8737
+ currency,
8738
+ });
8739
+
8740
+ const options = formatter.resolvedOptions();
8741
+ const decimals = options.maximumFractionDigits ?? 2;
8742
+
8743
+ cents = 10 ** decimals;
8744
+
8745
+ CURRENCIES_CENTS.set(currency, cents);
8746
+
8747
+ return cents;
8748
+ }
8749
+
8750
+ /**
8751
+ * @param {string} currency
8752
+ * @param {number} amount
8753
+ * @returns {number}
8754
+ */
8755
+ function amountInCents(currency, amount) {
8756
+ return Math.round(amount * getCurrencyCents(currency));
8757
+ }
8758
+
8722
8759
  /** @typedef {import('./payment').default} Payment */
8723
8760
  /** @typedef {import('../../types').Cart} Cart */
8724
8761
  /** @typedef {import('../../types').Address} Address */
@@ -8806,7 +8843,7 @@ async function onPaymentDataChanged(intermediatePaymentData) {
8806
8843
  this,
8807
8844
  cart,
8808
8845
  ),
8809
- newTransactionInfo: getTransactionInfo(cart),
8846
+ newTransactionInfo: getTransactionInfo.call(this, cart),
8810
8847
  };
8811
8848
  }
8812
8849
 
@@ -8819,7 +8856,7 @@ async function onPaymentDataChanged(intermediatePaymentData) {
8819
8856
  },
8820
8857
  });
8821
8858
 
8822
- return { newTransactionInfo: getTransactionInfo(cart) };
8859
+ return { newTransactionInfo: getTransactionInfo.call(this, cart) };
8823
8860
  } catch (err) {
8824
8861
  return createError(
8825
8862
  intermediatePaymentData.callbackTrigger,
@@ -8841,7 +8878,7 @@ async function onPaymentDataChanged(intermediatePaymentData) {
8841
8878
 
8842
8879
  return {
8843
8880
  newOfferInfo: getOfferInfo(cart),
8844
- newTransactionInfo: getTransactionInfo(cart),
8881
+ newTransactionInfo: getTransactionInfo.call(this, cart),
8845
8882
  };
8846
8883
  } catch (err) {
8847
8884
  return createError(
@@ -8941,12 +8978,13 @@ function getDisplayItems(cart) {
8941
8978
 
8942
8979
  /**
8943
8980
  * Converts cart data to Google Pay transaction information.
8981
+ * @this {Payment}
8944
8982
  * @param {Cart} cart - The current cart data
8945
8983
  * @returns {google.payments.api.TransactionInfo} Transaction info for Google Pay
8946
8984
  */
8947
8985
  function getTransactionInfo(cart) {
8948
- const { settings, capture_total, currency, shipment_delivery, shipping } =
8949
- cart;
8986
+ const { require: { shipping: shipmentDelivery = false } = {} } = this.params;
8987
+ const { settings, capture_total, currency, shipping } = cart;
8950
8988
 
8951
8989
  return {
8952
8990
  countryCode: settings?.country || 'US',
@@ -8954,7 +8992,7 @@ function getTransactionInfo(cart) {
8954
8992
  totalPrice: String(capture_total ?? 0),
8955
8993
  // Set status to FINAL if shipping has been selected, otherwise ESTIMATED
8956
8994
  totalPriceStatus:
8957
- !shipment_delivery || shipping?.service ? 'FINAL' : 'ESTIMATED',
8995
+ !shipmentDelivery || shipping?.service ? 'FINAL' : 'ESTIMATED',
8958
8996
  totalPriceLabel: 'Total',
8959
8997
  displayItems: getDisplayItems(cart),
8960
8998
  };
@@ -8967,12 +9005,14 @@ function getTransactionInfo(cart) {
8967
9005
  * @returns {google.payments.api.ShippingOptionParameters | undefined} Shipping options for Google Pay
8968
9006
  */
8969
9007
  function getShippingOptionParameters(cart) {
8970
- const { shipment_delivery, shipment_rating, shipping } = cart;
9008
+ const { require: { shipping: shipmentDelivery = false } = {} } = this.params;
8971
9009
 
8972
- if (!shipment_delivery) {
9010
+ if (!shipmentDelivery) {
8973
9011
  return undefined;
8974
9012
  }
8975
9013
 
9014
+ const { shipment_rating, shipping } = cart;
9015
+
8976
9016
  if (!shipment_rating?.services?.length) {
8977
9017
  // Return placeholder when no shipping services are available
8978
9018
  return {
@@ -9053,20 +9093,11 @@ function createError(intent, reason, message) {
9053
9093
  };
9054
9094
  }
9055
9095
 
9096
+ /** @typedef {import('../../../types').Cart} Cart */
9097
+
9056
9098
  const API_VERSION$1 = 2;
9057
9099
  const API_MINOR_VERSION$1 = 0;
9058
9100
 
9059
- const ALLOWED_CARD_AUTH_METHODS = ['PAN_ONLY', 'CRYPTOGRAM_3DS'];
9060
-
9061
- const ALLOWED_CARD_NETWORKS = [
9062
- 'AMEX',
9063
- 'DISCOVER',
9064
- 'INTERAC',
9065
- 'JCB',
9066
- 'MASTERCARD',
9067
- 'VISA',
9068
- ];
9069
-
9070
9101
  class BraintreeGooglePayment extends Payment {
9071
9102
  constructor(api, options, params, methods) {
9072
9103
  if (!methods.card) {
@@ -9102,6 +9133,9 @@ class BraintreeGooglePayment extends Payment {
9102
9133
  if (this.google) {
9103
9134
  this.googleClient = new this.google.payments.api.PaymentsClient({
9104
9135
  environment: isLiveMode(this.method.mode) ? 'PRODUCTION' : 'TEST',
9136
+ paymentDataCallbacks: {
9137
+ onPaymentDataChanged: onPaymentDataChanged.bind(this),
9138
+ },
9105
9139
  });
9106
9140
  }
9107
9141
 
@@ -9117,31 +9151,12 @@ class BraintreeGooglePayment extends Payment {
9117
9151
  BraintreeGooglePayment.googleClient = googleClient;
9118
9152
  }
9119
9153
 
9120
- /** @returns {google.payments.api.PaymentMethodSpecification} */
9121
- get cardPaymentMethod() {
9122
- return {
9123
- type: 'CARD',
9124
- parameters: {
9125
- allowedAuthMethods: ALLOWED_CARD_AUTH_METHODS,
9126
- allowedCardNetworks: ALLOWED_CARD_NETWORKS,
9127
- billingAddressRequired: true,
9128
- billingAddressParameters: {
9129
- format: 'FULL',
9130
- phoneNumberRequired: true,
9131
- },
9132
- },
9133
- };
9134
- }
9135
-
9136
- /** @returns {google.payments.api.PaymentMethodSpecification[]} */
9137
- get allowedPaymentMethods() {
9138
- return [this.cardPaymentMethod];
9139
- }
9140
-
9154
+ /** @param {Cart} cart */
9141
9155
  async createElements(cart) {
9142
9156
  const {
9143
9157
  elementId = 'googlepay-button',
9144
9158
  locale = 'en',
9159
+ require: { phone } = {},
9145
9160
  style: { color = 'black', type = 'plain', sizeMode = 'fill' } = {},
9146
9161
  } = this.params;
9147
9162
 
@@ -9152,10 +9167,35 @@ class BraintreeGooglePayment extends Payment {
9152
9167
  this.setElementContainer(elementId);
9153
9168
  await this.loadScripts(this.scripts);
9154
9169
 
9170
+ const braintreeClient = await this._createBraintreeClient();
9171
+
9172
+ const googlePayment = await this.braintree.googlePayment.create({
9173
+ client: braintreeClient,
9174
+ googleMerchantId: this.method.merchant_id,
9175
+ googlePayVersion: API_VERSION$1,
9176
+ });
9177
+
9178
+ const paymentDataRequest = googlePayment.createPaymentDataRequest(
9179
+ this._createPaymentRequestData(cart),
9180
+ );
9181
+
9182
+ const cardPaymentMethod = paymentDataRequest.allowedPaymentMethods.find(
9183
+ (method) => method.type === 'CARD',
9184
+ );
9185
+
9186
+ if (cardPaymentMethod !== undefined) {
9187
+ cardPaymentMethod.parameters.billingAddressRequired = true;
9188
+
9189
+ cardPaymentMethod.parameters.billingAddressParameters = {
9190
+ format: 'FULL',
9191
+ phoneNumberRequired: Boolean(phone),
9192
+ };
9193
+ }
9194
+
9155
9195
  const isReadyToPay = await this.googleClient.isReadyToPay({
9156
9196
  apiVersion: API_VERSION$1,
9157
9197
  apiVersionMinor: API_MINOR_VERSION$1,
9158
- allowedPaymentMethods: this.allowedPaymentMethods,
9198
+ allowedPaymentMethods: paymentDataRequest.allowedPaymentMethods,
9159
9199
  existingPaymentMethodRequired: true,
9160
9200
  });
9161
9201
 
@@ -9165,16 +9205,6 @@ class BraintreeGooglePayment extends Payment {
9165
9205
  );
9166
9206
  }
9167
9207
 
9168
- const braintreeClient = await this._createBraintreeClient();
9169
- const googlePayment = await this.braintree.googlePayment.create({
9170
- client: braintreeClient,
9171
- googleMerchantId: this.method.merchant_id,
9172
- googlePayVersion: API_VERSION$1,
9173
- });
9174
- const paymentRequestData = this._createPaymentRequestData(cart);
9175
- const paymentDataRequest =
9176
- googlePayment.createPaymentDataRequest(paymentRequestData);
9177
-
9178
9208
  this.element = this.googleClient.createButton({
9179
9209
  buttonColor: color,
9180
9210
  buttonType: type,
@@ -9201,6 +9231,7 @@ class BraintreeGooglePayment extends Payment {
9201
9231
  }
9202
9232
  }
9203
9233
 
9234
+ /** @returns {Promise<braintree.Client>} */
9204
9235
  async _createBraintreeClient() {
9205
9236
  const authorization = await this.authorizeGateway({
9206
9237
  gateway: 'braintree',
@@ -9215,39 +9246,51 @@ class BraintreeGooglePayment extends Payment {
9215
9246
  });
9216
9247
  }
9217
9248
 
9218
- /** @returns {google.payments.api.PaymentDataRequest} */
9249
+ /**
9250
+ * @param {Cart} cart
9251
+ * @returns {google.payments.api.PaymentDataRequest}
9252
+ */
9219
9253
  _createPaymentRequestData(cart) {
9220
9254
  const {
9221
- settings: { name, country },
9222
- capture_total,
9223
- currency,
9255
+ settings: { name },
9224
9256
  } = cart;
9257
+
9225
9258
  const { require: { email, shipping, phone } = {} } = this.params;
9226
9259
 
9260
+ /** @type {google.payments.api.CallbackIntent[]} */
9261
+ const callbackIntents = ['OFFER'];
9262
+
9263
+ if (shipping) {
9264
+ callbackIntents.push('SHIPPING_ADDRESS', 'SHIPPING_OPTION');
9265
+ }
9266
+
9227
9267
  return {
9228
9268
  apiVersion: API_VERSION$1,
9229
9269
  apiVersionMinor: API_MINOR_VERSION$1,
9230
- transactionInfo: {
9231
- countryCode: country,
9232
- currencyCode: currency,
9233
- totalPrice: capture_total.toString(),
9234
- totalPriceStatus: 'ESTIMATED',
9235
- },
9236
- allowedPaymentMethods: this.allowedPaymentMethods,
9270
+ transactionInfo: getTransactionInfo.call(this, cart),
9271
+ /**
9272
+ * @see {@link https://developer.paypal.com/braintree/docs/guides/google-pay/client-side/javascript/v3/#requesting-a-payment}
9273
+ *
9274
+ * Braintree automatically populates the `allowedPaymentMethods` property.
9275
+ */
9237
9276
  emailRequired: Boolean(email),
9238
9277
  shippingAddressRequired: Boolean(shipping),
9239
9278
  shippingAddressParameters: {
9240
9279
  phoneNumberRequired: Boolean(phone),
9241
9280
  },
9281
+ shippingOptionRequired: Boolean(shipping),
9282
+ shippingOptionParameters: getShippingOptionParameters.call(this, cart),
9283
+ offerInfo: getOfferInfo(cart),
9242
9284
  merchantInfo: {
9243
9285
  merchantName: name,
9244
9286
  merchantId: this.method.merchant_id,
9245
9287
  },
9288
+ callbackIntents,
9246
9289
  };
9247
9290
  }
9248
9291
 
9249
9292
  /**
9250
- * @param {object} googlePayment
9293
+ * @param {braintree.GooglePayment} googlePayment
9251
9294
  * @param {google.payments.api.PaymentDataRequest} paymentDataRequest
9252
9295
  */
9253
9296
  async _onClick(googlePayment, paymentDataRequest) {
@@ -9264,34 +9307,59 @@ class BraintreeGooglePayment extends Payment {
9264
9307
  }
9265
9308
 
9266
9309
  /**
9267
- * @param {object} googlePayment
9310
+ * @param {braintree.GooglePayment} googlePayment
9268
9311
  * @param {google.payments.api.PaymentData} paymentData
9269
9312
  */
9270
9313
  async _submitPayment(googlePayment, paymentData) {
9271
- const { require: { shipping: requireShipping } = {} } = this.params;
9272
9314
  const { nonce } = await googlePayment.parseResponse(paymentData);
9273
- const { email, shippingAddress, paymentMethodData } = paymentData;
9274
- const {
9275
- info: { billingAddress },
9276
- } = paymentMethodData;
9315
+ const { email, shippingAddress, shippingOptionData, paymentMethodData } =
9316
+ paymentData;
9317
+ const { info: { billingAddress } = {} } = paymentMethodData;
9277
9318
 
9278
- await this.updateCart({
9319
+ const cart = await this.updateCart({
9279
9320
  account: {
9280
9321
  email,
9281
9322
  },
9282
9323
  billing: {
9283
9324
  method: 'google',
9325
+ account_card_id: null,
9326
+ card: null,
9284
9327
  google: {
9285
9328
  nonce,
9286
9329
  gateway: 'braintree',
9287
9330
  },
9288
9331
  ...convertToSwellAddress$2(billingAddress),
9289
9332
  },
9290
- ...(requireShipping && {
9291
- shipping: convertToSwellAddress$2(shippingAddress),
9333
+ ...(shippingAddress && {
9334
+ shipping: {
9335
+ ...convertToSwellAddress$2(shippingAddress),
9336
+ service: shippingOptionData?.id || undefined,
9337
+ },
9292
9338
  }),
9293
9339
  });
9294
9340
 
9341
+ if (cart.subscription_delivery) {
9342
+ try {
9343
+ const card = await cardApi.createToken({
9344
+ gateway: 'braintree',
9345
+ account_id: cart.account_id,
9346
+ nonce,
9347
+ });
9348
+
9349
+ delete card.nonce;
9350
+
9351
+ await this.updateCart({
9352
+ billing: {
9353
+ method: 'card',
9354
+ card,
9355
+ google: null,
9356
+ },
9357
+ });
9358
+ } catch (error) {
9359
+ console.warn('Failed to extract card data from google token', error);
9360
+ }
9361
+ }
9362
+
9295
9363
  this.onSuccess();
9296
9364
  }
9297
9365
  }
@@ -9321,7 +9389,7 @@ async function onShippingAddressChange(shippingContact) {
9321
9389
  'Shipping is not available for the provided address.';
9322
9390
 
9323
9391
  return {
9324
- newTotal: getTotal(cart, this.merchantInfo),
9392
+ newTotal: getTotal.call(this, cart, this.merchantInfo),
9325
9393
  newLineItems: getLineItems(cart),
9326
9394
  newShippingMethods: [], // REQUIRED: Must always provide this, even as empty array
9327
9395
  errors: [
@@ -9332,15 +9400,15 @@ async function onShippingAddressChange(shippingContact) {
9332
9400
 
9333
9401
  // Success: Return updated totals and shipping methods
9334
9402
  return {
9335
- newTotal: getTotal(cart, this.merchantInfo),
9403
+ newTotal: getTotal.call(this, cart, this.merchantInfo),
9336
9404
  newLineItems: getLineItems(cart),
9337
- newShippingMethods: getShippingMethods(cart),
9405
+ newShippingMethods: getShippingMethods.call(this, cart),
9338
9406
  };
9339
9407
  } catch (err) {
9340
9408
  const cartData = await this.getCart();
9341
9409
 
9342
9410
  return {
9343
- newTotal: getTotal(cartData, this.merchantInfo),
9411
+ newTotal: getTotal.call(this, cartData, this.merchantInfo),
9344
9412
  newLineItems: getLineItems(cartData),
9345
9413
  newShippingMethods: [], // REQUIRED: Must always provide this, even as empty array
9346
9414
  errors: [new ApplePayError('unknown', undefined, err.message)],
@@ -9386,12 +9454,12 @@ async function onShippingMethodChange(shippingMethod) {
9386
9454
  });
9387
9455
 
9388
9456
  return {
9389
- newTotal: getTotal(cart, this.merchantInfo),
9457
+ newTotal: getTotal.call(this, cart, this.merchantInfo),
9390
9458
  newLineItems: getLineItems(cart),
9391
9459
  };
9392
9460
  } catch (err) {
9393
9461
  return {
9394
- newTotal: getTotal(await this.getCart(), this.merchantInfo),
9462
+ newTotal: getTotal.call(this, await this.getCart(), this.merchantInfo),
9395
9463
  errors: [new ApplePayError('unknown', undefined, err.message)],
9396
9464
  };
9397
9465
  }
@@ -9431,7 +9499,7 @@ async function onCouponCodeUpdated(couponCode) {
9431
9499
 
9432
9500
  // Valid coupon applied successfully
9433
9501
  return {
9434
- newTotal: getTotal(cart, this.merchantInfo),
9502
+ newTotal: getTotal.call(this, cart, this.merchantInfo),
9435
9503
  newLineItems: getLineItems(cart),
9436
9504
  };
9437
9505
  } catch (err) {
@@ -9439,7 +9507,7 @@ async function onCouponCodeUpdated(couponCode) {
9439
9507
  const currentCart = await this.getCart();
9440
9508
 
9441
9509
  return {
9442
- newTotal: getTotal(currentCart, this.merchantInfo),
9510
+ newTotal: getTotal.call(this, currentCart, this.merchantInfo),
9443
9511
  newLineItems: getLineItems(currentCart),
9444
9512
  errors: [new ApplePayError('couponCodeInvalid', undefined, err.message)],
9445
9513
  };
@@ -9473,15 +9541,17 @@ async function onCouponCodeChanged(session, event) {
9473
9541
  * This ensures the user sees "pending" until they've selected shipping,
9474
9542
  * then sees the final amount once everything is calculated.
9475
9543
  *
9544
+ * @this {Payment}
9476
9545
  * @param {Cart} cart
9477
9546
  * @param {object} [merchantInfo]
9478
9547
  * @returns {ApplePayJS.ApplePayLineItem}
9479
9548
  */
9480
9549
  function getTotal(cart, merchantInfo) {
9481
- const { capture_total, shipment_delivery, shipping } = cart;
9550
+ const { require: { shipping: shipmentDelivery = false } = {} } = this.params;
9551
+ const { capture_total, shipping } = cart;
9482
9552
 
9483
9553
  // Use 'final' only after shipping method is selected or not needed, otherwise 'pending'
9484
- const isFinalPrice = !shipment_delivery || shipping?.service;
9554
+ const isFinalPrice = !shipmentDelivery || shipping?.service;
9485
9555
  const type = isFinalPrice ? 'final' : 'pending';
9486
9556
 
9487
9557
  return {
@@ -9550,16 +9620,19 @@ function getLineItems(cart) {
9550
9620
  *
9551
9621
  * IMPORTANT: Amounts must be formatted as strings with 2 decimals.
9552
9622
  *
9623
+ * @this {Payment}
9553
9624
  * @param {Cart} cart
9554
9625
  * @returns {ApplePayJS.ApplePayShippingMethod[]}
9555
9626
  */
9556
9627
  function getShippingMethods(cart) {
9557
- const { shipment_delivery, shipment_rating } = cart;
9628
+ const { require: { shipping: shipmentDelivery = false } = {} } = this.params;
9558
9629
 
9559
- if (!shipment_delivery) {
9630
+ if (!shipmentDelivery) {
9560
9631
  return [];
9561
9632
  }
9562
9633
 
9634
+ const { shipment_rating } = cart;
9635
+
9563
9636
  if (!shipment_rating?.services?.length) {
9564
9637
  return [];
9565
9638
  }
@@ -9610,13 +9683,38 @@ function convertToSwellAddress$1(address = {}) {
9610
9683
  };
9611
9684
  }
9612
9685
 
9613
- const VERSION$1 = 3;
9686
+ /** @param {object} params */
9687
+ function getRequiredContactFields(params) {
9688
+ const { require = {} } = params;
9689
+ /** @type {ApplePayJS.ApplePayContactField[]} */
9690
+ const requiredFields = [];
9691
+
9692
+ if (require.email) {
9693
+ requiredFields.push('email');
9694
+ }
9695
+
9696
+ if (require.name) {
9697
+ requiredFields.push('name');
9698
+ }
9699
+
9700
+ if (require.phone) {
9701
+ requiredFields.push('phone');
9702
+ }
9614
9703
 
9615
- const MERCHANT_CAPABILITIES = [
9616
- 'supports3DS',
9617
- 'supportsDebit',
9618
- 'supportsCredit',
9619
- ];
9704
+ /** @type {ApplePayJS.ApplePayContactField[]} */
9705
+ const requiredShippingContactFields = require.shipping
9706
+ ? [...requiredFields, 'postalAddress']
9707
+ : [];
9708
+
9709
+ /** @type {ApplePayJS.ApplePayContactField[]} */
9710
+ const requiredBillingContactFields = [...requiredFields, 'postalAddress'];
9711
+
9712
+ return { requiredBillingContactFields, requiredShippingContactFields };
9713
+ }
9714
+
9715
+ /** @typedef {import('../../../types').Cart} Cart */
9716
+
9717
+ const VERSION$1 = 14;
9620
9718
 
9621
9719
  class BraintreeApplePayment extends Payment {
9622
9720
  constructor(api, options, params, methods) {
@@ -9648,6 +9746,7 @@ class BraintreeApplePayment extends Payment {
9648
9746
  return window.ApplePaySession;
9649
9747
  }
9650
9748
 
9749
+ /** @param {Cart} cart */
9651
9750
  async createElements(cart) {
9652
9751
  const { elementId = 'applepay-button' } = this.params;
9653
9752
 
@@ -9661,10 +9760,12 @@ class BraintreeApplePayment extends Payment {
9661
9760
  }
9662
9761
 
9663
9762
  const braintreeClient = await this._createBraintreeClient();
9763
+
9664
9764
  const applePayment = await this.braintree.applePay.create({
9665
9765
  client: braintreeClient,
9666
9766
  });
9667
- const paymentRequest = await this._createPaymentRequest(cart, applePayment);
9767
+
9768
+ const paymentRequest = this._createPaymentRequest(cart, applePayment);
9668
9769
 
9669
9770
  this.element = this._createButton(applePayment, paymentRequest);
9670
9771
  }
@@ -9681,8 +9782,9 @@ class BraintreeApplePayment extends Payment {
9681
9782
  }
9682
9783
 
9683
9784
  /**
9684
- * @param {object} applePayment
9785
+ * @param {braintree.ApplePay} applePayment
9685
9786
  * @param {ApplePayJS.ApplePayPaymentRequest} paymentRequest
9787
+ * @returns {HTMLDivElement}
9686
9788
  */
9687
9789
  _createButton(applePayment, paymentRequest) {
9688
9790
  const { style: { type = 'plain', theme = 'black', height = '40px' } = {} } =
@@ -9703,6 +9805,7 @@ class BraintreeApplePayment extends Payment {
9703
9805
  return button;
9704
9806
  }
9705
9807
 
9808
+ /** @returns {Promise<braintree.Client>} */
9706
9809
  async _createBraintreeClient() {
9707
9810
  const authorization = await this.authorizeGateway({
9708
9811
  gateway: 'braintree',
@@ -9717,47 +9820,43 @@ class BraintreeApplePayment extends Payment {
9717
9820
  });
9718
9821
  }
9719
9822
 
9720
- /** @returns {ApplePayJS.ApplePayPaymentRequest} */
9823
+ /**
9824
+ * @param {Cart} cart
9825
+ * @param {braintree.ApplePay} applePayment
9826
+ * @returns {ApplePayJS.ApplePayPaymentRequest}
9827
+ */
9721
9828
  _createPaymentRequest(cart, applePayment) {
9722
- const { require = {} } = this.params;
9723
9829
  const {
9724
9830
  settings: { name, country },
9725
9831
  capture_total,
9726
9832
  currency,
9727
9833
  } = cart;
9728
9834
 
9729
- const requiredShippingContactFields = [];
9730
- const requiredBillingContactFields = ['postalAddress'];
9731
-
9732
- if (require.name) {
9733
- requiredShippingContactFields.push('name');
9734
- }
9735
- if (require.email) {
9736
- requiredShippingContactFields.push('email');
9737
- }
9738
- if (require.phone) {
9739
- requiredShippingContactFields.push('phone');
9740
- }
9741
- if (require.shipping) {
9742
- requiredShippingContactFields.push('postalAddress');
9743
- }
9835
+ const { requiredBillingContactFields, requiredShippingContactFields } =
9836
+ getRequiredContactFields(this.params);
9744
9837
 
9745
9838
  return applePayment.createPaymentRequest({
9746
9839
  total: {
9747
9840
  label: name,
9748
9841
  type: 'pending',
9749
- amount: capture_total.toString(),
9842
+ amount: (capture_total || 0).toFixed(2),
9750
9843
  },
9751
9844
  countryCode: country,
9752
9845
  currencyCode: currency,
9753
- merchantCapabilities: MERCHANT_CAPABILITIES,
9846
+ /**
9847
+ * @see {@link https://developer.paypal.com/braintree/docs/guides/apple-pay/client-side/javascript/v3/#create-anapplepaysession}
9848
+ *
9849
+ * Braintree automatically fills in `supportedNetworks` and `merchantCapabilities`.
9850
+ */
9754
9851
  requiredShippingContactFields,
9755
9852
  requiredBillingContactFields,
9853
+ supportsCouponCode: true,
9854
+ lineItems: getLineItems(cart),
9756
9855
  });
9757
9856
  }
9758
9857
 
9759
9858
  /**
9760
- * @param {object} applePayment
9859
+ * @param {braintree.ApplePay} applePayment
9761
9860
  * @param {ApplePayJS.ApplePayPaymentRequest} paymentRequest
9762
9861
  */
9763
9862
  _createPaymentSession(applePayment, paymentRequest) {
@@ -9778,11 +9877,23 @@ class BraintreeApplePayment extends Payment {
9778
9877
  }
9779
9878
  };
9780
9879
 
9880
+ session.onshippingcontactselected = onShippingContactSelected.bind(
9881
+ this,
9882
+ session,
9883
+ );
9884
+
9885
+ session.onshippingmethodselected = onShippingMethodSelected.bind(
9886
+ this,
9887
+ session,
9888
+ );
9889
+
9890
+ session.oncouponcodechanged = onCouponCodeChanged.bind(this, session);
9891
+
9781
9892
  session.onpaymentauthorized = async (event) => {
9782
9893
  const {
9783
9894
  payment: { token, shippingContact, billingContact },
9784
9895
  } = event;
9785
- const { require: { shipping: requireShipping } = {} } = this.params;
9896
+
9786
9897
  const payload = await applePayment
9787
9898
  .tokenize({ token })
9788
9899
  .catch(this.onError.bind(this));
@@ -9791,23 +9902,47 @@ class BraintreeApplePayment extends Payment {
9791
9902
  return session.completePayment(this.ApplePaySession.STATUS_FAILURE);
9792
9903
  }
9793
9904
 
9794
- await this.updateCart({
9905
+ const cart = await this.updateCart({
9795
9906
  account: {
9796
- email: shippingContact.emailAddress,
9907
+ email: shippingContact?.emailAddress || billingContact?.emailAddress,
9797
9908
  },
9798
9909
  billing: {
9799
9910
  method: 'apple',
9911
+ account_card_id: null,
9912
+ card: null,
9800
9913
  apple: {
9801
9914
  nonce: payload.nonce,
9802
9915
  gateway: 'braintree',
9803
9916
  },
9804
9917
  ...convertToSwellAddress$1(billingContact),
9805
9918
  },
9806
- ...(requireShipping && {
9919
+ ...(shippingContact && {
9807
9920
  shipping: convertToSwellAddress$1(shippingContact),
9808
9921
  }),
9809
9922
  });
9810
9923
 
9924
+ if (cart.subscription_delivery) {
9925
+ try {
9926
+ const card = await cardApi.createToken({
9927
+ gateway: 'braintree',
9928
+ account_id: cart.account_id,
9929
+ nonce: payload.nonce,
9930
+ });
9931
+
9932
+ delete card.nonce;
9933
+
9934
+ await this.updateCart({
9935
+ billing: {
9936
+ method: 'card',
9937
+ card,
9938
+ apple: null,
9939
+ },
9940
+ });
9941
+ } catch (error) {
9942
+ console.warn('Failed to extract card data from apple token', error);
9943
+ }
9944
+ }
9945
+
9811
9946
  this.onSuccess();
9812
9947
 
9813
9948
  return session.completePayment(this.ApplePaySession.STATUS_SUCCESS);
@@ -9913,6 +10048,8 @@ class AbstractGooglePayment extends Payment {
9913
10048
  * @returns {google.payments.api.PaymentMethodSpecification}
9914
10049
  */
9915
10050
  _getCardPaymentMethod(submit = false) {
10051
+ const { require: { phone } = {} } = this.params;
10052
+
9916
10053
  return {
9917
10054
  type: 'CARD',
9918
10055
  parameters: {
@@ -9921,7 +10058,7 @@ class AbstractGooglePayment extends Payment {
9921
10058
  billingAddressRequired: true,
9922
10059
  billingAddressParameters: {
9923
10060
  format: 'FULL',
9924
- phoneNumberRequired: true,
10061
+ phoneNumberRequired: Boolean(phone),
9925
10062
  },
9926
10063
  },
9927
10064
  ...(submit && {
@@ -9954,29 +10091,30 @@ class AbstractGooglePayment extends Payment {
9954
10091
  cart.shipment_price = 0;
9955
10092
  cart.shipping = {};
9956
10093
 
9957
- const { shipment_delivery } = cart;
9958
10094
  const { require: { email, shipping, phone } = {} } = this.params;
9959
10095
 
10096
+ /** @type {google.payments.api.CallbackIntent[]} */
10097
+ const callbackIntents = ['OFFER', 'PAYMENT_AUTHORIZATION'];
10098
+
10099
+ if (shipping) {
10100
+ callbackIntents.push('SHIPPING_ADDRESS', 'SHIPPING_OPTION');
10101
+ }
10102
+
9960
10103
  return {
9961
10104
  apiVersion: API_VERSION,
9962
10105
  apiVersionMinor: API_MINOR_VERSION,
9963
- transactionInfo: getTransactionInfo(cart),
10106
+ transactionInfo: getTransactionInfo.call(this, cart),
9964
10107
  allowedPaymentMethods: this._getAllowedPaymentMethods(true),
9965
10108
  emailRequired: Boolean(email),
9966
10109
  shippingAddressRequired: Boolean(shipping),
9967
10110
  shippingAddressParameters: {
9968
10111
  phoneNumberRequired: Boolean(phone),
9969
10112
  },
9970
- shippingOptionRequired: Boolean(shipment_delivery),
10113
+ shippingOptionRequired: Boolean(shipping),
9971
10114
  shippingOptionParameters: getShippingOptionParameters.call(this, cart),
9972
10115
  offerInfo: getOfferInfo(cart),
9973
10116
  merchantInfo,
9974
- callbackIntents: [
9975
- 'OFFER',
9976
- 'SHIPPING_ADDRESS',
9977
- 'SHIPPING_OPTION',
9978
- 'PAYMENT_AUTHORIZATION',
9979
- ],
10117
+ callbackIntents,
9980
10118
  };
9981
10119
  }
9982
10120
 
@@ -10100,6 +10238,22 @@ class AbstractGooglePayment extends Payment {
10100
10238
  /** @typedef {import('../../../types').Cart} Cart */
10101
10239
 
10102
10240
  class AuthorizeNetGooglePayment extends AbstractGooglePayment {
10241
+ /**
10242
+ * @override
10243
+ * @returns {google.payments.api.CardNetwork[]}
10244
+ */
10245
+ getAllowedCardNetworks() {
10246
+ return ['AMEX', 'DISCOVER', 'JCB', 'MASTERCARD', 'VISA'];
10247
+ }
10248
+
10249
+ /**
10250
+ * @override
10251
+ * @returns {google.payments.api.CardAuthMethod[]}
10252
+ */
10253
+ getAllowedCardAuthMethods() {
10254
+ return ['PAN_ONLY', 'CRYPTOGRAM_3DS'];
10255
+ }
10256
+
10103
10257
  /**
10104
10258
  * @override
10105
10259
  * @returns {google.payments.api.PaymentGatewayTokenizationParameters}
@@ -10117,7 +10271,6 @@ class AuthorizeNetGooglePayment extends AbstractGooglePayment {
10117
10271
  * @returns {Promise<object>}
10118
10272
  */
10119
10273
  async preparePaymentDataForCartUpdate(paymentData) {
10120
- const { require: { shipping: requireShipping } = {} } = this.params;
10121
10274
  const { email, shippingAddress, shippingOptionData, paymentMethodData } =
10122
10275
  paymentData;
10123
10276
 
@@ -10138,7 +10291,7 @@ class AuthorizeNetGooglePayment extends AbstractGooglePayment {
10138
10291
  },
10139
10292
  ...convertToSwellAddress$2(billingAddress),
10140
10293
  },
10141
- ...(requireShipping && {
10294
+ ...(shippingAddress && {
10142
10295
  shipping: {
10143
10296
  ...convertToSwellAddress$2(shippingAddress),
10144
10297
  service: shippingOptionData?.id || undefined,
@@ -10205,9 +10358,15 @@ class AbstractApplePayment extends Payment {
10205
10358
  return window.ApplePaySession;
10206
10359
  }
10207
10360
 
10208
- /** @returns {string[]} */
10361
+ /**
10362
+ * We should specify the payment methods in the order preferred by the gateway.
10363
+ *
10364
+ * @see {@link https://developer.apple.com/documentation/applepayontheweb/applepaypaymentrequest/supportednetworks}
10365
+ *
10366
+ * @returns {string[]}
10367
+ */
10209
10368
  getSupportedCardNetworks() {
10210
- return ['amex', 'discover', 'interac', 'jcb', 'masterCard', 'visa'];
10369
+ return ['visa', 'masterCard', 'amex', 'discover', 'interac', 'jcb'];
10211
10370
  }
10212
10371
 
10213
10372
  /** @returns {ApplePayJS.ApplePayMerchantCapability[]} */
@@ -10218,12 +10377,12 @@ class AbstractApplePayment extends Payment {
10218
10377
  /**
10219
10378
  * Creates the Apple Pay payment request object
10220
10379
  *
10221
- * IMPORTANT: countryCode here is the MERCHANT's country (where your business is located),
10222
- * NOT the customer's country. Customer country comes from shippingContact.countryCode.
10380
+ * IMPORTANT: `countryCode` here is the MERCHANT's country (where your business is located),
10381
+ * NOT the customer's country. Customer country comes from `shippingContact.countryCode`.
10223
10382
  *
10224
- * NOTE: We do NOT pass shippingMethods in the initial request. Shipping methods
10383
+ * NOTE: We do NOT pass `shippingMethods` in the initial request. Shipping methods
10225
10384
  * are provided dynamically after the user selects/confirms their address in the
10226
- * 'shippingcontactselected' event handler.
10385
+ * `'shippingcontactselected'` event handler.
10227
10386
  *
10228
10387
  * @param {Cart} cart
10229
10388
  * @returns {ApplePayJS.ApplePayPaymentRequest}
@@ -10231,38 +10390,21 @@ class AbstractApplePayment extends Payment {
10231
10390
  _createPaymentRequest(cart) {
10232
10391
  cart = { ...cart };
10233
10392
 
10234
- const { require = {} } = this.params;
10235
10393
  const {
10236
10394
  settings: { country },
10237
10395
  currency,
10238
10396
  } = cart;
10239
10397
 
10240
- const requiredShippingContactFields = [];
10241
- const requiredBillingContactFields = ['postalAddress'];
10242
-
10243
- if (require.name) {
10244
- requiredShippingContactFields.push('name');
10245
- }
10246
-
10247
- if (require.email) {
10248
- requiredShippingContactFields.push('email');
10249
- }
10250
-
10251
- if (require.phone) {
10252
- requiredShippingContactFields.push('phone');
10253
- }
10254
-
10255
- if (require.shipping) {
10256
- requiredShippingContactFields.push('postalAddress');
10257
- }
10258
-
10259
10398
  // When initiating a payment request,
10260
10399
  // we should not display the shipping cost, as it will be calculated later.
10261
10400
  cart.shipment_price = 0;
10262
10401
  cart.shipping = {};
10263
10402
 
10403
+ const { requiredBillingContactFields, requiredShippingContactFields } =
10404
+ getRequiredContactFields(this.params);
10405
+
10264
10406
  return {
10265
- total: getTotal(cart, this.merchantInfo),
10407
+ total: getTotal.call(this, cart, this.merchantInfo),
10266
10408
  countryCode: country, // Merchant's country
10267
10409
  currencyCode: currency,
10268
10410
  supportedNetworks: this.getSupportedCardNetworks(),
@@ -10444,6 +10586,22 @@ class AbstractApplePayment extends Payment {
10444
10586
  }
10445
10587
 
10446
10588
  class AuthorizeNetApplePayment extends AbstractApplePayment {
10589
+ /**
10590
+ * @override
10591
+ * @returns {string[]}
10592
+ */
10593
+ getSupportedCardNetworks() {
10594
+ return ['visa', 'masterCard', 'amex', 'discover'];
10595
+ }
10596
+
10597
+ /**
10598
+ * @override
10599
+ * @returns {ApplePayJS.ApplePayMerchantCapability[]}
10600
+ */
10601
+ getMerchantCapabilities() {
10602
+ return ['supports3DS', 'supportsDebit', 'supportsCredit'];
10603
+ }
10604
+
10447
10605
  /**
10448
10606
  * @override
10449
10607
  * @param {ApplePayJS.ApplePayValidateMerchantEvent} event
@@ -10477,11 +10635,9 @@ class AuthorizeNetApplePayment extends AbstractApplePayment {
10477
10635
  payment: { token, shippingContact, billingContact },
10478
10636
  } = event;
10479
10637
 
10480
- const { require: { shipping: requireShipping } = {} } = this.params;
10481
-
10482
10638
  return {
10483
10639
  account: {
10484
- email: shippingContact.emailAddress,
10640
+ email: shippingContact?.emailAddress || billingContact?.emailAddress,
10485
10641
  },
10486
10642
  billing: {
10487
10643
  method: 'apple',
@@ -10493,7 +10649,7 @@ class AuthorizeNetApplePayment extends AbstractApplePayment {
10493
10649
  },
10494
10650
  ...convertToSwellAddress$1(billingContact),
10495
10651
  },
10496
- ...(requireShipping && {
10652
+ ...(shippingContact && {
10497
10653
  shipping: convertToSwellAddress$1(shippingContact),
10498
10654
  }),
10499
10655
  };
@@ -10613,7 +10769,7 @@ async function getConvesioPaymentSettings(mode, settings, country) {
10613
10769
  merchantAccount: false,
10614
10770
  countryCode: country || 'US',
10615
10771
  shopperLocale: 'en-US',
10616
- // shopperReference: email ? md5(email) : undefined,
10772
+ // shopperReference: email ? md5(email.toLowerCase()) : undefined,
10617
10773
  }),
10618
10774
  },
10619
10775
  ).then((res) => res.json());
@@ -10741,15 +10897,20 @@ class ConvesioCardPayment extends Payment {
10741
10897
  }
10742
10898
  }
10743
10899
 
10900
+ function getBaseConvesioVaultUrl(mode) {
10901
+ return isLiveMode(mode)
10902
+ ? 'https://vault.convesiopay.com'
10903
+ : 'https://qa-vault.convesiopay.com';
10904
+ }
10905
+
10744
10906
  function createConvesioCardPaymentToken(settings, data) {
10745
- const baseUrl = getBaseConvesioApiUrl(settings.mode);
10907
+ const baseUrl = getBaseConvesioVaultUrl(settings.mode);
10746
10908
 
10747
10909
  return fetch(`${baseUrl}/v1/create-token`, {
10748
10910
  method: 'POST',
10749
10911
  headers: {
10750
10912
  Accept: 'application/json',
10751
10913
  'Content-Type': 'application/json',
10752
- 'X-Requested-With': 'convesio-pay-dashboard',
10753
10914
  'X-Api-Key': settings.public_key,
10754
10915
  },
10755
10916
  body: JSON.stringify(data),
@@ -10864,8 +11025,6 @@ class ConvesioPayApplePayment extends AbstractApplePayment {
10864
11025
  payment: { token, shippingContact, billingContact },
10865
11026
  } = event;
10866
11027
 
10867
- const { require: { shipping: requireShipping } = {} } = this.params;
10868
-
10869
11028
  const payment = await createConvesioApplePaymentToken(
10870
11029
  this.method.mode,
10871
11030
  this.convesiopay,
@@ -10887,7 +11046,7 @@ class ConvesioPayApplePayment extends AbstractApplePayment {
10887
11046
 
10888
11047
  return {
10889
11048
  account: {
10890
- email: shippingContact.emailAddress,
11049
+ email: shippingContact?.emailAddress || billingContact?.emailAddress,
10891
11050
  },
10892
11051
  billing: {
10893
11052
  method: 'apple',
@@ -10902,7 +11061,7 @@ class ConvesioPayApplePayment extends AbstractApplePayment {
10902
11061
  },
10903
11062
  ...convertToSwellAddress$1(billingContact),
10904
11063
  },
10905
- ...(requireShipping && {
11064
+ ...(shippingContact && {
10906
11065
  shipping: convertToSwellAddress$1(shippingContact),
10907
11066
  }),
10908
11067
  };
@@ -11032,7 +11191,6 @@ class ConvesioPayGooglePayment extends AbstractGooglePayment {
11032
11191
  * @returns {Promise<object>}
11033
11192
  */
11034
11193
  async preparePaymentDataForCartUpdate(paymentData) {
11035
- const { require: { shipping: requireShipping } = {} } = this.params;
11036
11194
  const { email, shippingAddress, shippingOptionData, paymentMethodData } =
11037
11195
  paymentData;
11038
11196
 
@@ -11075,7 +11233,7 @@ class ConvesioPayGooglePayment extends AbstractGooglePayment {
11075
11233
  },
11076
11234
  ...convertToSwellAddress$2(billingAddress),
11077
11235
  },
11078
- ...(requireShipping && {
11236
+ ...(shippingAddress && {
11079
11237
  shipping: {
11080
11238
  ...convertToSwellAddress$2(shippingAddress),
11081
11239
  service: shippingOptionData?.id || undefined,
@@ -11227,105 +11385,6 @@ class PaysafecardDirectPayment extends Payment {
11227
11385
  }
11228
11386
  }
11229
11387
 
11230
- const addressFieldsMap = {
11231
- given_name: 'first_name',
11232
- family_name: 'last_name',
11233
- city: 'city',
11234
- country: 'country',
11235
- phone: 'phone',
11236
- postal_code: 'zip',
11237
- street_address: 'address1',
11238
- street_address2: 'address2',
11239
- region: 'state',
11240
- };
11241
-
11242
- const mapFields = (fieldsMap, data) =>
11243
- reduce(
11244
- fieldsMap,
11245
- (acc, srcKey, destKey) => {
11246
- const value = data[srcKey];
11247
- if (value) {
11248
- acc[destKey] = value;
11249
- }
11250
- return acc;
11251
- },
11252
- {},
11253
- );
11254
-
11255
- const mapAddressFields = (cart, addressField) => ({
11256
- ...mapFields(addressFieldsMap, cart[addressField]),
11257
- email: get(cart, 'account.email'),
11258
- });
11259
-
11260
- function getOrderLines(cart) {
11261
- const items = map(cart.items, (item) => ({
11262
- type: 'physical',
11263
- name: get(item, 'product.name'),
11264
- reference: get(item, 'product.sku') || get(item, 'product.slug'),
11265
- quantity: item.quantity,
11266
- unit_price: Math.round(toNumber(item.price - item.discount_each) * 100),
11267
- total_amount: Math.round(
11268
- toNumber(item.price_total - item.discount_total) * 100,
11269
- ),
11270
- tax_rate: 0,
11271
- total_tax_amount: 0,
11272
- }));
11273
-
11274
- const tax = get(cart, 'tax_included_total');
11275
- const taxAmount = toNumber(tax) * 100;
11276
- if (tax) {
11277
- items.push({
11278
- type: 'sales_tax',
11279
- name: 'Taxes',
11280
- quantity: 1,
11281
- unit_price: taxAmount,
11282
- total_amount: taxAmount,
11283
- tax_rate: 0,
11284
- total_tax_amount: 0,
11285
- });
11286
- }
11287
-
11288
- const shipping = get(cart, 'shipping', {});
11289
- const shippingTotal = get(cart, 'shipment_total', {});
11290
- const shippingAmount = toNumber(shippingTotal) * 100;
11291
- if (shipping.price) {
11292
- items.push({
11293
- type: 'shipping_fee',
11294
- name: shipping.service_name,
11295
- quantity: 1,
11296
- unit_price: shippingAmount,
11297
- total_amount: shippingAmount,
11298
- tax_rate: 0,
11299
- total_tax_amount: 0,
11300
- });
11301
- }
11302
-
11303
- return items;
11304
- }
11305
-
11306
- function getKlarnaSessionData(cart) {
11307
- const returnUrl = `${window.location.origin}${window.location.pathname}?gateway=klarna_direct&sid={{session_id}}`;
11308
- const successUrl = `${returnUrl}&authorization_token={{authorization_token}}`;
11309
-
11310
- return {
11311
- locale: cart.display_locale || get(cart, 'settings.locale') || 'en-US',
11312
- purchase_country:
11313
- get(cart, 'billing.country') || get(cart, 'shipping.country'),
11314
- purchase_currency: cart.currency,
11315
- billing_address: mapAddressFields(cart, 'billing'),
11316
- shipping_address: mapAddressFields(cart, 'shipping'),
11317
- order_amount: Math.round(get(cart, 'capture_total', 0) * 100),
11318
- order_lines: JSON.stringify(getOrderLines(cart)),
11319
- merchant_urls: {
11320
- success: successUrl,
11321
- back: returnUrl,
11322
- cancel: returnUrl,
11323
- error: returnUrl,
11324
- failure: returnUrl,
11325
- },
11326
- };
11327
- }
11328
-
11329
11388
  class KlarnaDirectPayment extends Payment {
11330
11389
  constructor(api, options, params, methods) {
11331
11390
  super(api, options, params, methods.klarna);
@@ -11334,6 +11393,7 @@ class KlarnaDirectPayment extends Payment {
11334
11393
  async tokenize() {
11335
11394
  const cart = await this.getCart();
11336
11395
  const sessionData = getKlarnaSessionData(cart);
11396
+
11337
11397
  const session = await this.createIntent({
11338
11398
  gateway: 'klarna',
11339
11399
  intent: sessionData,
@@ -11366,6 +11426,22 @@ class KlarnaDirectPayment extends Payment {
11366
11426
  }
11367
11427
  }
11368
11428
 
11429
+ function getKlarnaSessionData(cart) {
11430
+ const returnUrl = `${window.location.origin}${window.location.pathname}?gateway=klarna_direct&sid={{session_id}}`;
11431
+ const successUrl = `${returnUrl}&authorization_token={{authorization_token}}`;
11432
+
11433
+ return {
11434
+ cart_id: cart.id,
11435
+ merchant_urls: {
11436
+ success: successUrl,
11437
+ back: returnUrl,
11438
+ cancel: returnUrl,
11439
+ error: returnUrl,
11440
+ failure: returnUrl,
11441
+ },
11442
+ };
11443
+ }
11444
+
11369
11445
  class PaypalDirectPayment extends Payment {
11370
11446
  constructor(api, options, params, methods) {
11371
11447
  super(api, options, params, methods.paypal);
@@ -11971,20 +12047,29 @@ class SezzleDirectPayment extends Payment {
11971
12047
  settings: { name },
11972
12048
  } = cart;
11973
12049
 
11974
- const shipmentDelivery = Boolean(cart.shipment_delivery);
12050
+ const { require: { shipping } = {} } = this.params;
11975
12051
  const cartCurrency = getCartCurrency(cart);
11976
12052
 
11977
12053
  return {
11978
12054
  checkout_payload: {
11979
- express_checkout_type: shipmentDelivery ? 'multi-step' : 'no-shipping',
12055
+ express_checkout_type: shipping ? 'multi-step' : 'no-shipping',
12056
+ customer: {
12057
+ email: cart.account?.email,
12058
+ first_name: cart.account?.first_name,
12059
+ last_name: cart.account?.last_name,
12060
+ phone: cart.account?.phone,
12061
+ // TODO: recurring payments https://docs.sezzle.com/docs/api/tokenization/intro
12062
+ // tokenize: cart.subscription_delivery,
12063
+ // recurring: cart.subscription_delivery,
12064
+ },
11980
12065
  order: {
11981
12066
  intent: 'AUTH',
11982
12067
  reference_id: cart.checkout_id,
11983
12068
  description: `${name} #${cart.number}`,
11984
- requires_shipping_info: shipmentDelivery,
12069
+ requires_shipping_info: shipping,
11985
12070
  items: getItems(cart),
11986
12071
  discounts: getDiscounts(cart),
11987
- tax_amount: shipmentDelivery
12072
+ tax_amount: shipping
11988
12073
  ? undefined
11989
12074
  : getAmountInCents(cartCurrency, cart.tax_total),
11990
12075
  order_amount: getAmountInCents(cartCurrency, cart.capture_total),
@@ -12244,15 +12329,6 @@ function convertToSwellAddress(address) {
12244
12329
  };
12245
12330
  }
12246
12331
 
12247
- /**
12248
- * @param {string} currency
12249
- * @param {number} amount
12250
- * @returns {number}
12251
- */
12252
- function amountInCents(currency, amount) {
12253
- return Math.round(amount * 100);
12254
- }
12255
-
12256
12332
  class PaymentController {
12257
12333
  constructor(api, options) {
12258
12334
  this.api = api;
@@ -12955,7 +13031,7 @@ function swell(initStore = undefined, initKey, initOptions = {}) {
12955
13031
  const api = {};
12956
13032
 
12957
13033
  Object.assign(api, {
12958
- version: '5.7.0',
13034
+ version: '5.8.1',
12959
13035
  options,
12960
13036
  request,
12961
13037