swell-js 5.8.0 → 5.8.2

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
@@ -6665,13 +6665,18 @@ async function loadStripe() {
6665
6665
 
6666
6666
  async function loadPaypal(params) {
6667
6667
  if (!window.paypal) {
6668
- const { currency, client_id, merchant_id } = params;
6668
+ const { vault, currency, client_id, merchant_id } = params;
6669
+
6669
6670
  const paypalParams = {
6670
6671
  currency,
6671
6672
  'client-id': client_id,
6672
6673
  commit: false,
6673
6674
  };
6674
6675
 
6676
+ if (vault) {
6677
+ paypalParams.vault = vault;
6678
+ }
6679
+
6675
6680
  if (merchant_id) {
6676
6681
  // paypal express and ppcp onboarded
6677
6682
  paypalParams['merchant-id'] = merchant_id;
@@ -7210,7 +7215,7 @@ const MINIMUM_CHARGE_AMOUNT = {
7210
7215
  THB: 10,
7211
7216
  };
7212
7217
 
7213
- const addressFieldsMap$1 = {
7218
+ const addressFieldsMap = {
7214
7219
  city: 'city',
7215
7220
  country: 'country',
7216
7221
  line1: 'address1',
@@ -7248,7 +7253,7 @@ function getBillingDetails(cart) {
7248
7253
  details.email = cart.account.email;
7249
7254
  }
7250
7255
 
7251
- const address = mapValues(addressFieldsMap$1, cart.billing);
7256
+ const address = mapValues(addressFieldsMap, cart.billing);
7252
7257
  if (!isEmpty(address)) {
7253
7258
  details.address = address;
7254
7259
  }
@@ -8798,7 +8803,7 @@ async function onPaymentDataChanged(intermediatePaymentData) {
8798
8803
 
8799
8804
  // Update cart with new shipping address and force tax recalculation
8800
8805
  let cart = await this.updateCart({
8801
- shipping: convertToSwellAddress$2(
8806
+ shipping: convertToSwellAddress$3(
8802
8807
  intermediatePaymentData.shippingAddress,
8803
8808
  ),
8804
8809
  });
@@ -9064,7 +9069,7 @@ function getOfferInfo(cart) {
9064
9069
  * @param {google.payments.api.Address} address
9065
9070
  * @returns {Address}
9066
9071
  */
9067
- function convertToSwellAddress$2(address) {
9072
+ function convertToSwellAddress$3(address) {
9068
9073
  return {
9069
9074
  name: address.name,
9070
9075
  address1: address.address1,
@@ -9328,11 +9333,11 @@ class BraintreeGooglePayment extends Payment {
9328
9333
  nonce,
9329
9334
  gateway: 'braintree',
9330
9335
  },
9331
- ...convertToSwellAddress$2(billingAddress),
9336
+ ...convertToSwellAddress$3(billingAddress),
9332
9337
  },
9333
9338
  ...(shippingAddress && {
9334
9339
  shipping: {
9335
- ...convertToSwellAddress$2(shippingAddress),
9340
+ ...convertToSwellAddress$3(shippingAddress),
9336
9341
  service: shippingOptionData?.id || undefined,
9337
9342
  },
9338
9343
  }),
@@ -9369,6 +9374,7 @@ class BraintreeGooglePayment extends Payment {
9369
9374
  /** @typedef {import('./payment').default} Payment */
9370
9375
  /** @typedef {import('../../types').Cart} Cart */
9371
9376
  /** @typedef {import('../../types').Address} Address */
9377
+ /** @typedef {import('../../types').CartItemBillingSchedule} CartItemBillingSchedule */
9372
9378
 
9373
9379
  /**
9374
9380
  * @this {Payment}
@@ -9380,7 +9386,7 @@ async function onShippingAddressChange(shippingContact) {
9380
9386
  // Update cart with Apple Pay shipping address to get shipping options and tax
9381
9387
  // This happens immediately when the sheet opens with the default address
9382
9388
  const cart = await this.updateCart({
9383
- shipping: convertToSwellAddress$1(shippingContact),
9389
+ shipping: convertToSwellAddress$2(shippingContact),
9384
9390
  });
9385
9391
 
9386
9392
  if (!cart.shipment_rating?.services?.length) {
@@ -9669,7 +9675,7 @@ function getShippingMethods(cart) {
9669
9675
  * @param {ApplePayJS.ApplePayPaymentContact} [address]
9670
9676
  * @returns {Address}
9671
9677
  */
9672
- function convertToSwellAddress$1(address = {}) {
9678
+ function convertToSwellAddress$2(address = {}) {
9673
9679
  return {
9674
9680
  first_name: address.givenName,
9675
9681
  last_name: address.familyName,
@@ -9712,6 +9718,99 @@ function getRequiredContactFields(params) {
9712
9718
  return { requiredBillingContactFields, requiredShippingContactFields };
9713
9719
  }
9714
9720
 
9721
+ /**
9722
+ * @param {CartItemBillingSchedule} schedule
9723
+ * @returns {{ intervalUnit: ApplePayJS.ApplePayRecurringPaymentDateUnit, intervalCount: number }}
9724
+ */
9725
+ function convertSwellScheduleToAppleRecurringInterval(schedule) {
9726
+ let intervalCount = schedule.interval_count || 1;
9727
+ let intervalUnit = 'day';
9728
+
9729
+ switch (schedule.interval) {
9730
+ case 'daily':
9731
+ intervalUnit = 'day';
9732
+ break;
9733
+
9734
+ case 'weekly':
9735
+ intervalUnit = 'day';
9736
+ intervalCount *= 7;
9737
+ break;
9738
+
9739
+ case 'monthly':
9740
+ intervalUnit = 'month';
9741
+ break;
9742
+
9743
+ case 'yearly':
9744
+ intervalUnit = 'year';
9745
+ break;
9746
+ }
9747
+
9748
+ return { intervalUnit, intervalCount };
9749
+ }
9750
+
9751
+ /**
9752
+ * @param {Cart} cart
9753
+ * @param {string} managementUrl
9754
+ * @returns {ApplePayJS.ApplePayRecurringPaymentRequest | undefined}
9755
+ */
9756
+ function getRecurringPaymentRequest(cart, managementUrl) {
9757
+ if (!cart.subscription_delivery) {
9758
+ return undefined;
9759
+ }
9760
+
9761
+ const item = cart.items.find(
9762
+ (item) =>
9763
+ item.purchase_option?.type === 'subscription' &&
9764
+ item.purchase_option.billing_schedule,
9765
+ );
9766
+
9767
+ if (item === undefined) {
9768
+ return undefined;
9769
+ }
9770
+
9771
+ const { intervalUnit, intervalCount } =
9772
+ convertSwellScheduleToAppleRecurringInterval(
9773
+ item.purchase_option.billing_schedule,
9774
+ );
9775
+
9776
+ /** @type {ApplePayJS.ApplePayRecurringPaymentRequest} */
9777
+ const recurringPaymentRequest = {
9778
+ paymentDescription:
9779
+ item.purchase_option.plan_description ||
9780
+ item.purchase_option.plan_name ||
9781
+ item.product_name ||
9782
+ item.product?.name,
9783
+ regularBilling: {
9784
+ type: 'final',
9785
+ label: item.purchase_option.plan_name || 'Subscription',
9786
+ // Calculate the subscription price manually if a trial period is specified.
9787
+ // However, discounts are not included in the calculation due to the difficulty of taking into account all scenarios.
9788
+ amount: (item.purchase_option.billing_schedule.trial_days
9789
+ ? (item.price || 0) * (item.quantity || 1)
9790
+ : item.price_total
9791
+ ).toFixed(2),
9792
+ paymentTiming: 'recurring',
9793
+ recurringPaymentIntervalUnit: intervalUnit,
9794
+ recurringPaymentIntervalCount: intervalCount,
9795
+ },
9796
+ trialBilling: item.purchase_option.billing_schedule.trial_days
9797
+ ? {
9798
+ type: 'final',
9799
+ label: 'Trial',
9800
+ // When a trial period is set, price_total is 0 (usually)
9801
+ amount: Number(item.price_total || 0).toFixed(2),
9802
+ paymentTiming: 'recurring',
9803
+ recurringPaymentIntervalUnit: 'day',
9804
+ recurringPaymentIntervalCount:
9805
+ item.purchase_option.billing_schedule.trial_days,
9806
+ }
9807
+ : undefined,
9808
+ managementURL: managementUrl,
9809
+ };
9810
+
9811
+ return recurringPaymentRequest;
9812
+ }
9813
+
9715
9814
  /** @typedef {import('../../../types').Cart} Cart */
9716
9815
 
9717
9816
  const VERSION$1 = 14;
@@ -9914,10 +10013,10 @@ class BraintreeApplePayment extends Payment {
9914
10013
  nonce: payload.nonce,
9915
10014
  gateway: 'braintree',
9916
10015
  },
9917
- ...convertToSwellAddress$1(billingContact),
10016
+ ...convertToSwellAddress$2(billingContact),
9918
10017
  },
9919
10018
  ...(shippingContact && {
9920
- shipping: convertToSwellAddress$1(shippingContact),
10019
+ shipping: convertToSwellAddress$2(shippingContact),
9921
10020
  }),
9922
10021
  });
9923
10022
 
@@ -10123,7 +10222,7 @@ class AbstractGooglePayment extends Payment {
10123
10222
  * @returns {Promise<object>}
10124
10223
  */
10125
10224
  // eslint-disable-next-line no-unused-vars
10126
- async preparePaymentDataForCartUpdate(paymentData) {
10225
+ async processPaymentData(paymentData) {
10127
10226
  throw new Error('Implement this!');
10128
10227
  }
10129
10228
 
@@ -10145,9 +10244,7 @@ class AbstractGooglePayment extends Payment {
10145
10244
  throw new Error('Google Pay token is missing');
10146
10245
  }
10147
10246
 
10148
- await this.preparePaymentDataForCartUpdate(paymentData).then((data) =>
10149
- this.updateCart(data),
10150
- );
10247
+ await this.processPaymentData(paymentData);
10151
10248
 
10152
10249
  this.onSuccess();
10153
10250
  }
@@ -10270,7 +10367,7 @@ class AuthorizeNetGooglePayment extends AbstractGooglePayment {
10270
10367
  * @param {google.payments.api.PaymentData} paymentData
10271
10368
  * @returns {Promise<object>}
10272
10369
  */
10273
- async preparePaymentDataForCartUpdate(paymentData) {
10370
+ async processPaymentData(paymentData) {
10274
10371
  const { email, shippingAddress, shippingOptionData, paymentMethodData } =
10275
10372
  paymentData;
10276
10373
 
@@ -10279,7 +10376,7 @@ class AuthorizeNetGooglePayment extends AbstractGooglePayment {
10279
10376
  tokenizationData: { token },
10280
10377
  } = paymentMethodData;
10281
10378
 
10282
- return {
10379
+ await this.updateCart({
10283
10380
  account: { email },
10284
10381
  billing: {
10285
10382
  method: 'google',
@@ -10289,15 +10386,15 @@ class AuthorizeNetGooglePayment extends AbstractGooglePayment {
10289
10386
  gateway: 'authorizenet',
10290
10387
  token: base64Encode(token),
10291
10388
  },
10292
- ...convertToSwellAddress$2(billingAddress),
10389
+ ...convertToSwellAddress$3(billingAddress),
10293
10390
  },
10294
10391
  ...(shippingAddress && {
10295
10392
  shipping: {
10296
- ...convertToSwellAddress$2(shippingAddress),
10393
+ ...convertToSwellAddress$3(shippingAddress),
10297
10394
  service: shippingOptionData?.id || undefined,
10298
10395
  },
10299
10396
  }),
10300
- };
10397
+ });
10301
10398
  }
10302
10399
  }
10303
10400
 
@@ -10412,6 +10509,10 @@ class AbstractApplePayment extends Payment {
10412
10509
  requiredShippingContactFields,
10413
10510
  requiredBillingContactFields,
10414
10511
  supportsCouponCode: true,
10512
+ recurringPaymentRequest: getRecurringPaymentRequest(
10513
+ cart,
10514
+ this.params.managementUrl,
10515
+ ),
10415
10516
  lineItems: getLineItems(cart),
10416
10517
  };
10417
10518
  }
@@ -10434,7 +10535,7 @@ class AbstractApplePayment extends Payment {
10434
10535
  * @returns {Promise<object>}
10435
10536
  */
10436
10537
  // eslint-disable-next-line no-unused-vars
10437
- async preparePaymentDataForCartUpdate(event) {
10538
+ async processPaymentData(event) {
10438
10539
  throw new Error('Implement this!');
10439
10540
  }
10440
10541
 
@@ -10492,9 +10593,7 @@ class AbstractApplePayment extends Payment {
10492
10593
  //
10493
10594
  // We store the payment token but DO NOT process the order yet.
10494
10595
  // The user must manually click "Place Order" to complete the transaction.
10495
- await this.preparePaymentDataForCartUpdate(event).then((data) =>
10496
- this.updateCart(data),
10497
- );
10596
+ await this.processPaymentData(event);
10498
10597
 
10499
10598
  // Complete Apple Pay session successfully
10500
10599
  // This closes the Apple Pay sheet and shows success to the user
@@ -10630,12 +10729,12 @@ class AuthorizeNetApplePayment extends AbstractApplePayment {
10630
10729
  * @param {ApplePayJS.ApplePayPaymentAuthorizedEvent} event
10631
10730
  * @returns {Promise<object>}
10632
10731
  */
10633
- async preparePaymentDataForCartUpdate(event) {
10732
+ async processPaymentData(event) {
10634
10733
  const {
10635
10734
  payment: { token, shippingContact, billingContact },
10636
10735
  } = event;
10637
10736
 
10638
- return {
10737
+ return this.updateCart({
10639
10738
  account: {
10640
10739
  email: shippingContact?.emailAddress || billingContact?.emailAddress,
10641
10740
  },
@@ -10647,12 +10746,12 @@ class AuthorizeNetApplePayment extends AbstractApplePayment {
10647
10746
  gateway: 'authorizenet',
10648
10747
  token: base64Encode(JSON.stringify(token.paymentData)),
10649
10748
  },
10650
- ...convertToSwellAddress$1(billingContact),
10749
+ ...convertToSwellAddress$2(billingContact),
10651
10750
  },
10652
10751
  ...(shippingContact && {
10653
- shipping: convertToSwellAddress$1(shippingContact),
10752
+ shipping: convertToSwellAddress$2(shippingContact),
10654
10753
  }),
10655
- };
10754
+ });
10656
10755
  }
10657
10756
  }
10658
10757
 
@@ -11020,7 +11119,7 @@ class ConvesioPayApplePayment extends AbstractApplePayment {
11020
11119
  * @param {ApplePayJS.ApplePayPaymentAuthorizedEvent} event
11021
11120
  * @returns {Promise<object>}
11022
11121
  */
11023
- async preparePaymentDataForCartUpdate(event) {
11122
+ async processPaymentData(event) {
11024
11123
  const {
11025
11124
  payment: { token, shippingContact, billingContact },
11026
11125
  } = event;
@@ -11044,7 +11143,7 @@ class ConvesioPayApplePayment extends AbstractApplePayment {
11044
11143
  },
11045
11144
  );
11046
11145
 
11047
- return {
11146
+ return this.updateCart({
11048
11147
  account: {
11049
11148
  email: shippingContact?.emailAddress || billingContact?.emailAddress,
11050
11149
  },
@@ -11059,12 +11158,12 @@ class ConvesioPayApplePayment extends AbstractApplePayment {
11059
11158
  convesiopay: {
11060
11159
  return_url: this.params.returnUrl,
11061
11160
  },
11062
- ...convertToSwellAddress$1(billingContact),
11161
+ ...convertToSwellAddress$2(billingContact),
11063
11162
  },
11064
11163
  ...(shippingContact && {
11065
- shipping: convertToSwellAddress$1(shippingContact),
11164
+ shipping: convertToSwellAddress$2(shippingContact),
11066
11165
  }),
11067
- };
11166
+ });
11068
11167
  }
11069
11168
  }
11070
11169
 
@@ -11190,7 +11289,7 @@ class ConvesioPayGooglePayment extends AbstractGooglePayment {
11190
11289
  * @param {google.payments.api.PaymentData} paymentData
11191
11290
  * @returns {Promise<object>}
11192
11291
  */
11193
- async preparePaymentDataForCartUpdate(paymentData) {
11292
+ async processPaymentData(paymentData) {
11194
11293
  const { email, shippingAddress, shippingOptionData, paymentMethodData } =
11195
11294
  paymentData;
11196
11295
 
@@ -11218,7 +11317,7 @@ class ConvesioPayGooglePayment extends AbstractGooglePayment {
11218
11317
  },
11219
11318
  );
11220
11319
 
11221
- return {
11320
+ return this.updateCart({
11222
11321
  account: { email },
11223
11322
  billing: {
11224
11323
  method: 'google',
@@ -11231,15 +11330,15 @@ class ConvesioPayGooglePayment extends AbstractGooglePayment {
11231
11330
  convesiopay: {
11232
11331
  return_url: this.params.returnUrl,
11233
11332
  },
11234
- ...convertToSwellAddress$2(billingAddress),
11333
+ ...convertToSwellAddress$3(billingAddress),
11235
11334
  },
11236
11335
  ...(shippingAddress && {
11237
11336
  shipping: {
11238
- ...convertToSwellAddress$2(shippingAddress),
11337
+ ...convertToSwellAddress$3(shippingAddress),
11239
11338
  service: shippingOptionData?.id || undefined,
11240
11339
  },
11241
11340
  }),
11242
- };
11341
+ });
11243
11342
  }
11244
11343
  }
11245
11344
 
@@ -11385,105 +11484,6 @@ class PaysafecardDirectPayment extends Payment {
11385
11484
  }
11386
11485
  }
11387
11486
 
11388
- const addressFieldsMap = {
11389
- given_name: 'first_name',
11390
- family_name: 'last_name',
11391
- city: 'city',
11392
- country: 'country',
11393
- phone: 'phone',
11394
- postal_code: 'zip',
11395
- street_address: 'address1',
11396
- street_address2: 'address2',
11397
- region: 'state',
11398
- };
11399
-
11400
- const mapFields = (fieldsMap, data) =>
11401
- reduce(
11402
- fieldsMap,
11403
- (acc, srcKey, destKey) => {
11404
- const value = data[srcKey];
11405
- if (value) {
11406
- acc[destKey] = value;
11407
- }
11408
- return acc;
11409
- },
11410
- {},
11411
- );
11412
-
11413
- const mapAddressFields = (cart, addressField) => ({
11414
- ...mapFields(addressFieldsMap, cart[addressField]),
11415
- email: get(cart, 'account.email'),
11416
- });
11417
-
11418
- function getOrderLines(cart) {
11419
- const items = map(cart.items, (item) => ({
11420
- type: 'physical',
11421
- name: get(item, 'product.name'),
11422
- reference: get(item, 'product.sku') || get(item, 'product.slug'),
11423
- quantity: item.quantity,
11424
- unit_price: Math.round(toNumber(item.price - item.discount_each) * 100),
11425
- total_amount: Math.round(
11426
- toNumber(item.price_total - item.discount_total) * 100,
11427
- ),
11428
- tax_rate: 0,
11429
- total_tax_amount: 0,
11430
- }));
11431
-
11432
- const tax = get(cart, 'tax_included_total');
11433
- const taxAmount = toNumber(tax) * 100;
11434
- if (tax) {
11435
- items.push({
11436
- type: 'sales_tax',
11437
- name: 'Taxes',
11438
- quantity: 1,
11439
- unit_price: taxAmount,
11440
- total_amount: taxAmount,
11441
- tax_rate: 0,
11442
- total_tax_amount: 0,
11443
- });
11444
- }
11445
-
11446
- const shipping = get(cart, 'shipping', {});
11447
- const shippingTotal = get(cart, 'shipment_total', {});
11448
- const shippingAmount = toNumber(shippingTotal) * 100;
11449
- if (shipping.price) {
11450
- items.push({
11451
- type: 'shipping_fee',
11452
- name: shipping.service_name,
11453
- quantity: 1,
11454
- unit_price: shippingAmount,
11455
- total_amount: shippingAmount,
11456
- tax_rate: 0,
11457
- total_tax_amount: 0,
11458
- });
11459
- }
11460
-
11461
- return items;
11462
- }
11463
-
11464
- function getKlarnaSessionData(cart) {
11465
- const returnUrl = `${window.location.origin}${window.location.pathname}?gateway=klarna_direct&sid={{session_id}}`;
11466
- const successUrl = `${returnUrl}&authorization_token={{authorization_token}}`;
11467
-
11468
- return {
11469
- locale: cart.display_locale || get(cart, 'settings.locale') || 'en-US',
11470
- purchase_country:
11471
- get(cart, 'billing.country') || get(cart, 'shipping.country'),
11472
- purchase_currency: cart.currency,
11473
- billing_address: mapAddressFields(cart, 'billing'),
11474
- shipping_address: mapAddressFields(cart, 'shipping'),
11475
- order_amount: Math.round(get(cart, 'capture_total', 0) * 100),
11476
- order_lines: JSON.stringify(getOrderLines(cart)),
11477
- merchant_urls: {
11478
- success: successUrl,
11479
- back: returnUrl,
11480
- cancel: returnUrl,
11481
- error: returnUrl,
11482
- failure: returnUrl,
11483
- },
11484
- };
11485
- }
11486
-
11487
11487
  class KlarnaDirectPayment extends Payment {
11488
11488
  constructor(api, options, params, methods) {
11489
11489
  super(api, options, params, methods.klarna);
@@ -11492,6 +11492,7 @@ class KlarnaDirectPayment extends Payment {
11492
11492
  async tokenize() {
11493
11493
  const cart = await this.getCart();
11494
11494
  const sessionData = getKlarnaSessionData(cart);
11495
+
11495
11496
  const session = await this.createIntent({
11496
11497
  gateway: 'klarna',
11497
11498
  intent: sessionData,
@@ -11524,12 +11525,42 @@ class KlarnaDirectPayment extends Payment {
11524
11525
  }
11525
11526
  }
11526
11527
 
11528
+ function getKlarnaSessionData(cart) {
11529
+ const returnUrl = `${window.location.origin}${window.location.pathname}?gateway=klarna_direct&sid={{session_id}}`;
11530
+ const successUrl = `${returnUrl}&authorization_token={{authorization_token}}`;
11531
+
11532
+ return {
11533
+ cart_id: cart.id,
11534
+ merchant_urls: {
11535
+ success: successUrl,
11536
+ back: returnUrl,
11537
+ cancel: returnUrl,
11538
+ error: returnUrl,
11539
+ failure: returnUrl,
11540
+ },
11541
+ };
11542
+ }
11543
+
11544
+ /** @typedef {import('@paypal/paypal-js').PayPalNamespace} PayPal */
11545
+ /** @typedef {import('@paypal/paypal-js').ShippingAddress} ShippingAddress */
11546
+ /** @typedef {import('@paypal/paypal-js').CreateOrderData} CreateOrderData */
11547
+ /** @typedef {import('@paypal/paypal-js').CreateOrderActions} CreateOrderActions */
11548
+ /** @typedef {import('@paypal/paypal-js').OnShippingAddressChangeData} OnShippingAddressChangeData */
11549
+ /** @typedef {import('@paypal/paypal-js').OnShippingAddressChangeActions} OnShippingAddressChangeActions */
11550
+ /** @typedef {import('@paypal/paypal-js').OnShippingOptionsChangeData} OnShippingOptionsChangeData */
11551
+ /** @typedef {import('@paypal/paypal-js').OnShippingOptionsChangeActions} OnShippingOptionsChangeActions */
11552
+ /** @typedef {import('@paypal/paypal-js').OnApproveData} OnApproveData */
11553
+ /** @typedef {import('@paypal/paypal-js').OnApproveActions} OnApproveActions */
11554
+ /** @typedef {import('../../../types').Cart} Cart */
11555
+ /** @typedef {import('../../../types').Address} Address */
11556
+
11527
11557
  class PaypalDirectPayment extends Payment {
11528
11558
  constructor(api, options, params, methods) {
11529
11559
  super(api, options, params, methods.paypal);
11530
11560
  }
11531
11561
 
11532
- get scripts() {
11562
+ /** @param {Cart} cart */
11563
+ getScripts(cart) {
11533
11564
  const { client_id } = this.method;
11534
11565
 
11535
11566
  return [
@@ -11539,11 +11570,13 @@ class PaypalDirectPayment extends Payment {
11539
11570
  client_id,
11540
11571
  merchant_id: this.merchantId,
11541
11572
  cart: ['currency'],
11573
+ vault: cart.subscription_delivery,
11542
11574
  },
11543
11575
  },
11544
11576
  ];
11545
11577
  }
11546
11578
 
11579
+ /** @returns {PayPal} */
11547
11580
  get paypal() {
11548
11581
  if (!window.paypal) {
11549
11582
  throw new LibraryNotLoadedError('PayPal');
@@ -11567,7 +11600,6 @@ class PaypalDirectPayment extends Payment {
11567
11600
  async createElements(cart) {
11568
11601
  const {
11569
11602
  elementId = 'paypal-button',
11570
- locale = 'en_US',
11571
11603
  style: {
11572
11604
  layout = 'horizontal',
11573
11605
  height = 45,
@@ -11576,15 +11608,16 @@ class PaypalDirectPayment extends Payment {
11576
11608
  label = 'paypal',
11577
11609
  tagline = false,
11578
11610
  } = {},
11611
+ require: { shipping: requireShipping = true } = {},
11579
11612
  } = this.params;
11580
11613
 
11581
11614
  this.setElementContainer(elementId);
11582
11615
 
11583
11616
  this._validateCart(cart);
11584
- await this.loadScripts(this.scripts);
11617
+ await this.loadScripts(this.getScripts(cart));
11585
11618
 
11586
- this.element = this.paypal.Buttons({
11587
- locale,
11619
+ /** @type {import('@paypal/paypal-js').PayPalButtonsComponentOptions} */
11620
+ const buttonsOptions = {
11588
11621
  style: {
11589
11622
  layout,
11590
11623
  height,
@@ -11593,11 +11626,27 @@ class PaypalDirectPayment extends Payment {
11593
11626
  label,
11594
11627
  tagline,
11595
11628
  },
11629
+ fundingSource: this.paypal.FUNDING.PAYPAL,
11596
11630
  createOrder: this._onCreateOrder.bind(this, cart),
11597
- onShippingChange: this._onShippingChange.bind(this),
11598
11631
  onApprove: this._onApprove.bind(this),
11599
11632
  onError: this.onError.bind(this),
11600
- });
11633
+ };
11634
+
11635
+ if (requireShipping) {
11636
+ buttonsOptions.onShippingAddressChange =
11637
+ this._onShippingAddressChange.bind(this);
11638
+
11639
+ buttonsOptions.onShippingOptionsChange =
11640
+ this._onShippingOptionsChange.bind(this);
11641
+ }
11642
+
11643
+ const component = this.paypal.Buttons(buttonsOptions);
11644
+
11645
+ if (!component.isEligible()) {
11646
+ throw new Error('PayPal button with provided options is not eligible.');
11647
+ }
11648
+
11649
+ this.element = component;
11601
11650
  }
11602
11651
 
11603
11652
  mountElements() {
@@ -11611,6 +11660,7 @@ class PaypalDirectPayment extends Payment {
11611
11660
  }
11612
11661
  }
11613
11662
 
11663
+ /** @param {Cart} cart */
11614
11664
  _validateCart(cart) {
11615
11665
  const hasSubscriptionProduct = Boolean(cart.subscription_delivery);
11616
11666
 
@@ -11620,27 +11670,35 @@ class PaypalDirectPayment extends Payment {
11620
11670
  );
11621
11671
  }
11622
11672
 
11623
- if (!(cart.capture_total > 0)) {
11673
+ if ((cart.capture_total || 0) <= 0) {
11624
11674
  throw new Error(
11625
11675
  'Invalid PayPal button amount. Value should be greater than zero.',
11626
11676
  );
11627
11677
  }
11628
11678
  }
11629
11679
 
11680
+ /**
11681
+ * @param {Cart} cart
11682
+ * @param {CreateOrderData} _data
11683
+ * @param {CreateOrderActions} _actions
11684
+ * @returns {Promise<string>}
11685
+ */
11630
11686
  async _onCreateOrder(cart, _data, _actions) {
11631
- const { require: { shipping: requireShipping = true } = {} } = this.params;
11687
+ const {
11688
+ locale = 'en-US',
11689
+ require: { shipping: requireShipping = true } = {},
11690
+ } = this.params;
11691
+
11632
11692
  const { capture_total, currency, subscription_delivery } = cart;
11633
11693
  const hasSubscriptionProduct = Boolean(subscription_delivery);
11634
11694
  const merchantId = this.merchantId;
11635
11695
  const returnUrl = this.returnUrl;
11636
- const orderData = {
11637
- application_context: {
11638
- shipping_preference: requireShipping ? 'GET_FROM_FILE' : 'NO_SHIPPING',
11639
- },
11640
- };
11696
+ /** @type {import('@paypal/paypal-js').CreateOrderRequestBody} */
11697
+ const orderData = {};
11698
+ /** @type {import('@paypal/paypal-js').PurchaseUnit} */
11641
11699
  const purchaseUnit = {
11642
11700
  amount: {
11643
- value: Number(capture_total.toFixed(2)),
11701
+ value: Number(capture_total).toFixed(2),
11644
11702
  currency_code: currency,
11645
11703
  },
11646
11704
  };
@@ -11648,29 +11706,44 @@ class PaypalDirectPayment extends Payment {
11648
11706
  if (merchantId) {
11649
11707
  // express checkout and ppcp
11650
11708
  orderData.intent = 'AUTHORIZE';
11709
+
11710
+ orderData.payment_source = {
11711
+ paypal: {
11712
+ experience_context: {
11713
+ locale,
11714
+ shipping_preference: requireShipping
11715
+ ? 'GET_FROM_FILE'
11716
+ : 'NO_SHIPPING',
11717
+ },
11718
+ },
11719
+ };
11720
+
11651
11721
  purchaseUnit.payee = {
11652
11722
  merchant_id: merchantId,
11653
11723
  };
11654
11724
 
11655
11725
  if (hasSubscriptionProduct) {
11656
- orderData.payment_source = {
11657
- paypal: {
11658
- attributes: {
11659
- vault: {
11660
- store_in_vault: 'ON_SUCCESS',
11661
- usage_type: 'MERCHANT',
11662
- },
11663
- },
11664
- experience_context: {
11665
- return_url: `${returnUrl}&redirect_status=succeeded`,
11666
- cancel_url: `${returnUrl}&redirect_status=canceled`,
11667
- },
11726
+ orderData.payment_source.paypal.attributes = {
11727
+ vault: {
11728
+ store_in_vault: 'ON_SUCCESS',
11729
+ usage_type: 'MERCHANT',
11668
11730
  },
11669
11731
  };
11732
+
11733
+ Object.assign(orderData.payment_source.paypal.experience_context, {
11734
+ return_url: `${returnUrl}&redirect_status=succeeded`,
11735
+ cancel_url: `${returnUrl}&redirect_status=canceled`,
11736
+ });
11670
11737
  }
11671
11738
  } else {
11672
11739
  // progressive checkout
11673
11740
  orderData.intent = 'CAPTURE';
11741
+
11742
+ orderData.application_context = {
11743
+ locale,
11744
+ shipping_preference: requireShipping ? 'GET_FROM_FILE' : 'NO_SHIPPING',
11745
+ };
11746
+
11674
11747
  purchaseUnit.payee = {
11675
11748
  email_address: this.method.store_owner_email,
11676
11749
  };
@@ -11686,44 +11759,37 @@ class PaypalDirectPayment extends Payment {
11686
11759
  return order.id;
11687
11760
  }
11688
11761
 
11689
- async _onShippingChange(data, actions) {
11762
+ /**
11763
+ * @param {OnShippingAddressChangeData} data
11764
+ * @param {OnShippingAddressChangeActions} actions
11765
+ */
11766
+ async _onShippingAddressChange(data, actions) {
11690
11767
  try {
11691
- const { orderID, shipping_address, selected_shipping_option } = data;
11692
- const updateData = {
11768
+ const { orderID, shippingAddress } = data;
11769
+
11770
+ const cart = await this.updateCart({
11693
11771
  shipping: {
11694
- state: shipping_address.state,
11695
- city: shipping_address.city,
11696
- zip: shipping_address.postal_code,
11697
- country: shipping_address.country_code,
11772
+ state: shippingAddress.state,
11773
+ city: shippingAddress.city,
11774
+ zip: shippingAddress.postalCode,
11775
+ country: shippingAddress.countryCode,
11698
11776
  },
11699
11777
  shipment_rating: null,
11700
- };
11701
-
11702
- if (selected_shipping_option) {
11703
- updateData.shipping.service = selected_shipping_option.id;
11704
- updateData.$taxes = true;
11705
- }
11778
+ });
11706
11779
 
11707
- const cart = await this.updateCart(updateData);
11708
- const shippingServices = get(cart, 'shipment_rating.services');
11780
+ const shippingServices = cart.shipment_rating?.services;
11709
11781
 
11710
- // can't fulfill shipping to selected address
11782
+ // Can't fulfill shipping to selected address
11711
11783
  if (isEmpty(shippingServices)) {
11712
11784
  return actions.reject();
11713
11785
  }
11714
11786
 
11715
- let selectedShippingService;
11716
-
11717
- if (selected_shipping_option) {
11718
- selectedShippingService = shippingServices.find(
11719
- (shippingService) =>
11720
- shippingService.id === selected_shipping_option.id,
11721
- );
11722
- }
11787
+ let selectedShippingService = cart.shipping?.service;
11723
11788
 
11724
11789
  // need to set first service for cart by default
11725
11790
  if (!selectedShippingService) {
11726
11791
  const [firstShippingService] = shippingServices;
11792
+ selectedShippingService = firstShippingService.id;
11727
11793
 
11728
11794
  await this.updateCart({
11729
11795
  shipping: {
@@ -11740,8 +11806,33 @@ class PaypalDirectPayment extends Payment {
11740
11806
  paypal_order_id: orderID,
11741
11807
  },
11742
11808
  });
11809
+ } catch (error) {
11810
+ this.onError(error);
11811
+
11812
+ return actions.reject();
11813
+ }
11814
+ }
11815
+
11816
+ /**
11817
+ * @param {OnShippingOptionsChangeData} data
11818
+ * @param {OnShippingOptionsChangeActions} actions
11819
+ */
11820
+ async _onShippingOptionsChange(data, actions) {
11821
+ try {
11822
+ const { orderID, selectedShippingOption } = data;
11823
+
11824
+ const cart = await this.updateCart({
11825
+ shipping: { service: selectedShippingOption.id },
11826
+ $taxes: true,
11827
+ });
11743
11828
 
11744
- return orderID;
11829
+ await this.updateIntent({
11830
+ gateway: 'paypal',
11831
+ intent: {
11832
+ cart_id: cart.id,
11833
+ paypal_order_id: orderID,
11834
+ },
11835
+ });
11745
11836
  } catch (error) {
11746
11837
  this.onError(error);
11747
11838
 
@@ -11749,14 +11840,17 @@ class PaypalDirectPayment extends Payment {
11749
11840
  }
11750
11841
  }
11751
11842
 
11843
+ /**
11844
+ * @param {OnApproveData} data
11845
+ * @param {OnApproveActions} actions
11846
+ */
11752
11847
  async _onApprove(data, actions) {
11753
- const { require: { shipping: requireShipping = true } = {} } = this.params;
11754
11848
  const order = await actions.order.get();
11755
11849
  const orderId = order.id;
11756
- const payer = order.payer;
11850
+ const payer = order.payment_source?.paypal || order.payer;
11757
11851
  const billing = payer.address;
11758
- const shipping = get(order, 'purchase_units[0].shipping');
11759
- const name = `${payer.name.given_name} ${payer.name.surname}`;
11852
+ const shipping = order.purchase_units?.[0]?.shipping;
11853
+ const name = `${payer.name?.given_name} ${payer.name?.surname}`;
11760
11854
 
11761
11855
  await this.updateCart({
11762
11856
  account: {
@@ -11768,31 +11862,35 @@ class PaypalDirectPayment extends Payment {
11768
11862
  order_id: orderId,
11769
11863
  },
11770
11864
  name,
11771
- ...this._mapAddress(billing),
11865
+ ...convertToSwellAddress$1(billing),
11772
11866
  },
11773
- ...(requireShipping && {
11867
+ ...(shipping?.address && {
11774
11868
  shipping: {
11775
11869
  first_name: payer.name.given_name,
11776
11870
  last_name: payer.name.surname,
11777
11871
  name: shipping.name.full_name,
11778
- ...this._mapAddress(shipping.address),
11872
+ ...convertToSwellAddress$1(shipping.address),
11779
11873
  },
11780
11874
  }),
11781
11875
  });
11782
11876
 
11783
11877
  this.onSuccess();
11784
11878
  }
11879
+ }
11785
11880
 
11786
- _mapAddress(address) {
11787
- return {
11788
- address1: address.address_line_1,
11789
- address2: address.address_line_2,
11790
- state: address.admin_area_1,
11791
- city: address.admin_area_2,
11792
- zip: address.postal_code,
11793
- country: address.country_code,
11794
- };
11795
- }
11881
+ /**
11882
+ * @param {ShippingAddress} address
11883
+ * @returns {Address}
11884
+ */
11885
+ function convertToSwellAddress$1(address) {
11886
+ return {
11887
+ address1: address.address_line_1,
11888
+ address2: address.address_line_2,
11889
+ state: address.admin_area_1,
11890
+ city: address.admin_area_2,
11891
+ zip: address.postal_code,
11892
+ country: address.country_code,
11893
+ };
11796
11894
  }
11797
11895
 
11798
11896
  class AmazonDirectPayment extends Payment {
@@ -13113,7 +13211,7 @@ function swell(initStore = undefined, initKey, initOptions = {}) {
13113
13211
  const api = {};
13114
13212
 
13115
13213
  Object.assign(api, {
13116
- version: '5.8.0',
13214
+ version: '5.8.2',
13117
13215
  options,
13118
13216
  request,
13119
13217