swell-js 5.8.1 → 5.9.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.
Files changed (82) hide show
  1. package/dist/api.mjs +51 -39
  2. package/dist/attributes.mjs +2 -3
  3. package/dist/cache.mjs +139 -137
  4. package/dist/card.mjs +147 -145
  5. package/dist/cart.mjs +1 -2
  6. package/dist/categories.mjs +2 -3
  7. package/dist/content.mjs +1 -9
  8. package/dist/cookie.mjs +1 -1
  9. package/dist/{index.a8d5c125.mjs → index.777df7a8.mjs} +2 -14
  10. package/dist/index.mjs +1 -1
  11. package/dist/payment.mjs +296 -118
  12. package/dist/products.mjs +8 -12
  13. package/dist/settings.mjs +1 -1
  14. package/dist/subscriptions.mjs +2 -3
  15. package/dist/swell.cjs +605 -424
  16. package/dist/swell.cjs.map +1 -1
  17. package/dist/swell.umd.min.js +604 -423
  18. package/dist/swell.umd.min.js.map +1 -1
  19. package/dist/utils/index.mjs +1 -1
  20. package/package.json +14 -6
  21. package/types/account/camel.ts +10 -7
  22. package/types/account/index.ts +3 -3
  23. package/types/account/snake.ts +5 -5
  24. package/types/attribute/camel.ts +7 -4
  25. package/types/attribute/index.ts +3 -3
  26. package/types/attribute/snake.ts +2 -2
  27. package/types/billing/camel.ts +4 -4
  28. package/types/billing/index.ts +2 -2
  29. package/types/billing/snake.ts +1 -1
  30. package/types/card/camel.ts +5 -5
  31. package/types/card/index.ts +3 -3
  32. package/types/card/snake.ts +3 -3
  33. package/types/cart/camel.ts +17 -14
  34. package/types/cart/index.ts +3 -3
  35. package/types/cart/snake.ts +12 -12
  36. package/types/category/camel.ts +4 -4
  37. package/types/category/index.ts +3 -3
  38. package/types/category/snake.ts +2 -2
  39. package/types/content/camel.ts +5 -5
  40. package/types/content/index.ts +3 -3
  41. package/types/content/snake.ts +3 -3
  42. package/types/coupon/camel.ts +4 -4
  43. package/types/coupon/index.ts +2 -2
  44. package/types/coupon/snake.ts +2 -2
  45. package/types/currency/camel.ts +2 -2
  46. package/types/currency/index.ts +3 -3
  47. package/types/discount/camel.ts +3 -3
  48. package/types/discount/index.ts +2 -2
  49. package/types/giftcard/camel.ts +10 -7
  50. package/types/giftcard/index.ts +2 -2
  51. package/types/giftcard/snake.ts +5 -5
  52. package/types/index.d.cts +207 -0
  53. package/types/index.d.ts +83 -56
  54. package/types/invoice/camel.ts +10 -10
  55. package/types/invoice/index.ts +3 -3
  56. package/types/invoice/snake.ts +8 -8
  57. package/types/order/camel.ts +18 -15
  58. package/types/order/index.ts +3 -3
  59. package/types/order/snake.ts +18 -13
  60. package/types/payment/camel.ts +13 -10
  61. package/types/payment/index.ts +9 -3
  62. package/types/payment/snake.ts +8 -8
  63. package/types/product/camel.ts +5 -5
  64. package/types/product/index.ts +4 -4
  65. package/types/product/snake.ts +3 -3
  66. package/types/promotion/camel.ts +6 -6
  67. package/types/promotion/index.ts +2 -2
  68. package/types/promotion/snake.ts +4 -4
  69. package/types/purchase_link/camel.ts +10 -7
  70. package/types/purchase_link/index.ts +2 -2
  71. package/types/purchase_link/snake.ts +5 -5
  72. package/types/refund/camel.ts +6 -6
  73. package/types/refund/index.ts +2 -2
  74. package/types/refund/snake.ts +4 -4
  75. package/types/shipment_rating/camel.ts +3 -3
  76. package/types/shipment_rating/index.ts +2 -2
  77. package/types/subscription/camel.ts +16 -13
  78. package/types/subscription/index.ts +3 -3
  79. package/types/subscription/snake.ts +16 -11
  80. package/types/user/camel.ts +2 -2
  81. package/types/user/index.ts +3 -3
  82. package/types/user/snake.ts +1 -1
package/dist/payment.mjs CHANGED
@@ -1,15 +1,13 @@
1
1
  import methods from './cart.mjs';
2
2
  import methods$1 from './settings.mjs';
3
- import { b as isObject, k as isFunction, l as loadScript, c as cloneDeep, v as vaultRequest, t as toSnake, p as pick, n as isEmpty, o as isLiveMode, q as base64Encode, w as getLocationParams, x as removeUrlParams, a as toCamel } from './index.a8d5c125.mjs';
3
+ import { e as isObject, j as isFunction, l as loadScript, c as cloneDeep, v as vaultRequest, b as toSnake, p as pick, k as isEmpty, n as isLiveMode, o as base64Encode, q as getLocationParams, w as removeUrlParams, t as toCamel } from './index.777df7a8.mjs';
4
4
  import { g as get } from './find.18f1ac6d.mjs';
5
5
  import 'qs';
6
6
  import 'deepmerge';
7
7
  import 'fast-case';
8
- import cardApi from './card.mjs';
9
8
  import './products.mjs';
10
- import './cache.mjs';
11
- import './round.577a8441.mjs';
12
9
  import './attributes.mjs';
10
+ import './round.577a8441.mjs';
13
11
 
14
12
  const SCRIPT_HANDLERS = {
15
13
  'stripe-js': loadStripe,
@@ -47,13 +45,18 @@ async function loadStripe() {
47
45
 
48
46
  async function loadPaypal(params) {
49
47
  if (!window.paypal) {
50
- const { currency, client_id, merchant_id } = params;
48
+ const { vault, currency, client_id, merchant_id } = params;
49
+
51
50
  const paypalParams = {
52
51
  currency,
53
52
  'client-id': client_id,
54
53
  commit: false,
55
54
  };
56
55
 
56
+ if (vault) {
57
+ paypalParams.vault = vault;
58
+ }
59
+
57
60
  if (merchant_id) {
58
61
  // paypal express and ppcp onboarded
59
62
  paypalParams['merchant-id'] = merchant_id;
@@ -418,7 +421,7 @@ class Payment {
418
421
  * @returns {Promise<object>}
419
422
  */
420
423
  async createIntent(data) {
421
- return vaultRequest('post', '/intent', data);
424
+ return vaultRequest('post', '/intent', data, this.options);
422
425
  }
423
426
 
424
427
  /**
@@ -428,7 +431,7 @@ class Payment {
428
431
  * @returns {Promise<object>}
429
432
  */
430
433
  async updateIntent(data) {
431
- return vaultRequest('put', '/intent', data);
434
+ return vaultRequest('put', '/intent', data, this.options);
432
435
  }
433
436
 
434
437
  /**
@@ -438,7 +441,7 @@ class Payment {
438
441
  * @returns {Promise<object>}
439
442
  */
440
443
  async authorizeGateway(data) {
441
- return vaultRequest('post', '/authorization', data);
444
+ return vaultRequest('post', '/authorization', data, this.options);
442
445
  }
443
446
 
444
447
  /**
@@ -2180,7 +2183,7 @@ async function onPaymentDataChanged(intermediatePaymentData) {
2180
2183
 
2181
2184
  // Update cart with new shipping address and force tax recalculation
2182
2185
  let cart = await this.updateCart({
2183
- shipping: convertToSwellAddress$2(
2186
+ shipping: convertToSwellAddress$3(
2184
2187
  intermediatePaymentData.shippingAddress,
2185
2188
  ),
2186
2189
  });
@@ -2446,7 +2449,7 @@ function getOfferInfo(cart) {
2446
2449
  * @param {google.payments.api.Address} address
2447
2450
  * @returns {Address}
2448
2451
  */
2449
- function convertToSwellAddress$2(address) {
2452
+ function convertToSwellAddress$3(address) {
2450
2453
  return {
2451
2454
  name: address.name,
2452
2455
  address1: address.address1,
@@ -2710,11 +2713,11 @@ class BraintreeGooglePayment extends Payment {
2710
2713
  nonce,
2711
2714
  gateway: 'braintree',
2712
2715
  },
2713
- ...convertToSwellAddress$2(billingAddress),
2716
+ ...convertToSwellAddress$3(billingAddress),
2714
2717
  },
2715
2718
  ...(shippingAddress && {
2716
2719
  shipping: {
2717
- ...convertToSwellAddress$2(shippingAddress),
2720
+ ...convertToSwellAddress$3(shippingAddress),
2718
2721
  service: shippingOptionData?.id || undefined,
2719
2722
  },
2720
2723
  }),
@@ -2722,7 +2725,7 @@ class BraintreeGooglePayment extends Payment {
2722
2725
 
2723
2726
  if (cart.subscription_delivery) {
2724
2727
  try {
2725
- const card = await cardApi.createToken({
2728
+ const card = await this.api.card.createToken({
2726
2729
  gateway: 'braintree',
2727
2730
  account_id: cart.account_id,
2728
2731
  nonce,
@@ -2751,6 +2754,7 @@ class BraintreeGooglePayment extends Payment {
2751
2754
  /** @typedef {import('./payment').default} Payment */
2752
2755
  /** @typedef {import('../../types').Cart} Cart */
2753
2756
  /** @typedef {import('../../types').Address} Address */
2757
+ /** @typedef {import('../../types').CartItemBillingSchedule} CartItemBillingSchedule */
2754
2758
 
2755
2759
  /**
2756
2760
  * @this {Payment}
@@ -2762,7 +2766,7 @@ async function onShippingAddressChange(shippingContact) {
2762
2766
  // Update cart with Apple Pay shipping address to get shipping options and tax
2763
2767
  // This happens immediately when the sheet opens with the default address
2764
2768
  const cart = await this.updateCart({
2765
- shipping: convertToSwellAddress$1(shippingContact),
2769
+ shipping: convertToSwellAddress$2(shippingContact),
2766
2770
  });
2767
2771
 
2768
2772
  if (!cart.shipment_rating?.services?.length) {
@@ -3051,7 +3055,7 @@ function getShippingMethods(cart) {
3051
3055
  * @param {ApplePayJS.ApplePayPaymentContact} [address]
3052
3056
  * @returns {Address}
3053
3057
  */
3054
- function convertToSwellAddress$1(address = {}) {
3058
+ function convertToSwellAddress$2(address = {}) {
3055
3059
  return {
3056
3060
  first_name: address.givenName,
3057
3061
  last_name: address.familyName,
@@ -3094,6 +3098,99 @@ function getRequiredContactFields(params) {
3094
3098
  return { requiredBillingContactFields, requiredShippingContactFields };
3095
3099
  }
3096
3100
 
3101
+ /**
3102
+ * @param {CartItemBillingSchedule} schedule
3103
+ * @returns {{ intervalUnit: ApplePayJS.ApplePayRecurringPaymentDateUnit, intervalCount: number }}
3104
+ */
3105
+ function convertSwellScheduleToAppleRecurringInterval(schedule) {
3106
+ let intervalCount = schedule.interval_count || 1;
3107
+ let intervalUnit = 'day';
3108
+
3109
+ switch (schedule.interval) {
3110
+ case 'daily':
3111
+ intervalUnit = 'day';
3112
+ break;
3113
+
3114
+ case 'weekly':
3115
+ intervalUnit = 'day';
3116
+ intervalCount *= 7;
3117
+ break;
3118
+
3119
+ case 'monthly':
3120
+ intervalUnit = 'month';
3121
+ break;
3122
+
3123
+ case 'yearly':
3124
+ intervalUnit = 'year';
3125
+ break;
3126
+ }
3127
+
3128
+ return { intervalUnit, intervalCount };
3129
+ }
3130
+
3131
+ /**
3132
+ * @param {Cart} cart
3133
+ * @param {string} managementUrl
3134
+ * @returns {ApplePayJS.ApplePayRecurringPaymentRequest | undefined}
3135
+ */
3136
+ function getRecurringPaymentRequest(cart, managementUrl) {
3137
+ if (!cart.subscription_delivery) {
3138
+ return undefined;
3139
+ }
3140
+
3141
+ const item = cart.items.find(
3142
+ (item) =>
3143
+ item.purchase_option?.type === 'subscription' &&
3144
+ item.purchase_option.billing_schedule,
3145
+ );
3146
+
3147
+ if (item === undefined) {
3148
+ return undefined;
3149
+ }
3150
+
3151
+ const { intervalUnit, intervalCount } =
3152
+ convertSwellScheduleToAppleRecurringInterval(
3153
+ item.purchase_option.billing_schedule,
3154
+ );
3155
+
3156
+ /** @type {ApplePayJS.ApplePayRecurringPaymentRequest} */
3157
+ const recurringPaymentRequest = {
3158
+ paymentDescription:
3159
+ item.purchase_option.plan_description ||
3160
+ item.purchase_option.plan_name ||
3161
+ item.product_name ||
3162
+ item.product?.name,
3163
+ regularBilling: {
3164
+ type: 'final',
3165
+ label: item.purchase_option.plan_name || 'Subscription',
3166
+ // Calculate the subscription price manually if a trial period is specified.
3167
+ // However, discounts are not included in the calculation due to the difficulty of taking into account all scenarios.
3168
+ amount: (item.purchase_option.billing_schedule.trial_days
3169
+ ? (item.price || 0) * (item.quantity || 1)
3170
+ : item.price_total
3171
+ ).toFixed(2),
3172
+ paymentTiming: 'recurring',
3173
+ recurringPaymentIntervalUnit: intervalUnit,
3174
+ recurringPaymentIntervalCount: intervalCount,
3175
+ },
3176
+ trialBilling: item.purchase_option.billing_schedule.trial_days
3177
+ ? {
3178
+ type: 'final',
3179
+ label: 'Trial',
3180
+ // When a trial period is set, price_total is 0 (usually)
3181
+ amount: Number(item.price_total || 0).toFixed(2),
3182
+ paymentTiming: 'recurring',
3183
+ recurringPaymentIntervalUnit: 'day',
3184
+ recurringPaymentIntervalCount:
3185
+ item.purchase_option.billing_schedule.trial_days,
3186
+ }
3187
+ : undefined,
3188
+ managementURL: managementUrl,
3189
+ };
3190
+
3191
+ return recurringPaymentRequest;
3192
+ }
3193
+
3097
3194
  /** @typedef {import('../../../types').Cart} Cart */
3098
3195
 
3099
3196
  const VERSION$1 = 14;
@@ -3296,16 +3393,16 @@ class BraintreeApplePayment extends Payment {
3296
3393
  nonce: payload.nonce,
3297
3394
  gateway: 'braintree',
3298
3395
  },
3299
- ...convertToSwellAddress$1(billingContact),
3396
+ ...convertToSwellAddress$2(billingContact),
3300
3397
  },
3301
3398
  ...(shippingContact && {
3302
- shipping: convertToSwellAddress$1(shippingContact),
3399
+ shipping: convertToSwellAddress$2(shippingContact),
3303
3400
  }),
3304
3401
  });
3305
3402
 
3306
3403
  if (cart.subscription_delivery) {
3307
3404
  try {
3308
- const card = await cardApi.createToken({
3405
+ const card = await this.api.card.createToken({
3309
3406
  gateway: 'braintree',
3310
3407
  account_id: cart.account_id,
3311
3408
  nonce: payload.nonce,
@@ -3505,7 +3602,7 @@ class AbstractGooglePayment extends Payment {
3505
3602
  * @returns {Promise<object>}
3506
3603
  */
3507
3604
  // eslint-disable-next-line no-unused-vars
3508
- async preparePaymentDataForCartUpdate(paymentData) {
3605
+ async processPaymentData(paymentData) {
3509
3606
  throw new Error('Implement this!');
3510
3607
  }
3511
3608
 
@@ -3527,9 +3624,7 @@ class AbstractGooglePayment extends Payment {
3527
3624
  throw new Error('Google Pay token is missing');
3528
3625
  }
3529
3626
 
3530
- await this.preparePaymentDataForCartUpdate(paymentData).then((data) =>
3531
- this.updateCart(data),
3532
- );
3627
+ await this.processPaymentData(paymentData);
3533
3628
 
3534
3629
  this.onSuccess();
3535
3630
  }
@@ -3652,7 +3747,7 @@ class AuthorizeNetGooglePayment extends AbstractGooglePayment {
3652
3747
  * @param {google.payments.api.PaymentData} paymentData
3653
3748
  * @returns {Promise<object>}
3654
3749
  */
3655
- async preparePaymentDataForCartUpdate(paymentData) {
3750
+ async processPaymentData(paymentData) {
3656
3751
  const { email, shippingAddress, shippingOptionData, paymentMethodData } =
3657
3752
  paymentData;
3658
3753
 
@@ -3661,7 +3756,7 @@ class AuthorizeNetGooglePayment extends AbstractGooglePayment {
3661
3756
  tokenizationData: { token },
3662
3757
  } = paymentMethodData;
3663
3758
 
3664
- return {
3759
+ await this.updateCart({
3665
3760
  account: { email },
3666
3761
  billing: {
3667
3762
  method: 'google',
@@ -3671,15 +3766,15 @@ class AuthorizeNetGooglePayment extends AbstractGooglePayment {
3671
3766
  gateway: 'authorizenet',
3672
3767
  token: base64Encode(token),
3673
3768
  },
3674
- ...convertToSwellAddress$2(billingAddress),
3769
+ ...convertToSwellAddress$3(billingAddress),
3675
3770
  },
3676
3771
  ...(shippingAddress && {
3677
3772
  shipping: {
3678
- ...convertToSwellAddress$2(shippingAddress),
3773
+ ...convertToSwellAddress$3(shippingAddress),
3679
3774
  service: shippingOptionData?.id || undefined,
3680
3775
  },
3681
3776
  }),
3682
- };
3777
+ });
3683
3778
  }
3684
3779
  }
3685
3780
 
@@ -3794,6 +3889,10 @@ class AbstractApplePayment extends Payment {
3794
3889
  requiredShippingContactFields,
3795
3890
  requiredBillingContactFields,
3796
3891
  supportsCouponCode: true,
3892
+ recurringPaymentRequest: getRecurringPaymentRequest(
3893
+ cart,
3894
+ this.params.managementUrl,
3895
+ ),
3797
3896
  lineItems: getLineItems(cart),
3798
3897
  };
3799
3898
  }
@@ -3816,7 +3915,7 @@ class AbstractApplePayment extends Payment {
3816
3915
  * @returns {Promise<object>}
3817
3916
  */
3818
3917
  // eslint-disable-next-line no-unused-vars
3819
- async preparePaymentDataForCartUpdate(event) {
3918
+ async processPaymentData(event) {
3820
3919
  throw new Error('Implement this!');
3821
3920
  }
3822
3921
 
@@ -3874,9 +3973,7 @@ class AbstractApplePayment extends Payment {
3874
3973
  //
3875
3974
  // We store the payment token but DO NOT process the order yet.
3876
3975
  // The user must manually click "Place Order" to complete the transaction.
3877
- await this.preparePaymentDataForCartUpdate(event).then((data) =>
3878
- this.updateCart(data),
3879
- );
3976
+ await this.processPaymentData(event);
3880
3977
 
3881
3978
  // Complete Apple Pay session successfully
3882
3979
  // This closes the Apple Pay sheet and shows success to the user
@@ -4012,12 +4109,12 @@ class AuthorizeNetApplePayment extends AbstractApplePayment {
4012
4109
  * @param {ApplePayJS.ApplePayPaymentAuthorizedEvent} event
4013
4110
  * @returns {Promise<object>}
4014
4111
  */
4015
- async preparePaymentDataForCartUpdate(event) {
4112
+ async processPaymentData(event) {
4016
4113
  const {
4017
4114
  payment: { token, shippingContact, billingContact },
4018
4115
  } = event;
4019
4116
 
4020
- return {
4117
+ return this.updateCart({
4021
4118
  account: {
4022
4119
  email: shippingContact?.emailAddress || billingContact?.emailAddress,
4023
4120
  },
@@ -4029,12 +4126,12 @@ class AuthorizeNetApplePayment extends AbstractApplePayment {
4029
4126
  gateway: 'authorizenet',
4030
4127
  token: base64Encode(JSON.stringify(token.paymentData)),
4031
4128
  },
4032
- ...convertToSwellAddress$1(billingContact),
4129
+ ...convertToSwellAddress$2(billingContact),
4033
4130
  },
4034
4131
  ...(shippingContact && {
4035
- shipping: convertToSwellAddress$1(shippingContact),
4132
+ shipping: convertToSwellAddress$2(shippingContact),
4036
4133
  }),
4037
- };
4134
+ });
4038
4135
  }
4039
4136
  }
4040
4137
 
@@ -4211,7 +4308,7 @@ class ConvesioCardPayment extends Payment {
4211
4308
  ''
4212
4309
  ).replace(/[^0-9]+/g, '');
4213
4310
 
4214
- const cardExpiry = cardApi.expiry(
4311
+ const cardExpiry = this.api.card.expiry(
4215
4312
  this.params.exp ||
4216
4313
  document.getElementById(
4217
4314
  this.params.cardExpiry?.elementId || 'cardExpiry-element',
@@ -4235,7 +4332,7 @@ class ConvesioCardPayment extends Payment {
4235
4332
  ''
4236
4333
  ).trim();
4237
4334
 
4238
- const cardBrand = cardApi.type(cardNumber).toLowerCase();
4335
+ const cardBrand = this.api.card.type(cardNumber).toLowerCase();
4239
4336
 
4240
4337
  const payment = await createConvesioCardPaymentToken(this.method, {
4241
4338
  paymentMethod: {
@@ -4402,7 +4499,7 @@ class ConvesioPayApplePayment extends AbstractApplePayment {
4402
4499
  * @param {ApplePayJS.ApplePayPaymentAuthorizedEvent} event
4403
4500
  * @returns {Promise<object>}
4404
4501
  */
4405
- async preparePaymentDataForCartUpdate(event) {
4502
+ async processPaymentData(event) {
4406
4503
  const {
4407
4504
  payment: { token, shippingContact, billingContact },
4408
4505
  } = event;
@@ -4426,7 +4523,7 @@ class ConvesioPayApplePayment extends AbstractApplePayment {
4426
4523
  },
4427
4524
  );
4428
4525
 
4429
- return {
4526
+ return this.updateCart({
4430
4527
  account: {
4431
4528
  email: shippingContact?.emailAddress || billingContact?.emailAddress,
4432
4529
  },
@@ -4441,12 +4538,12 @@ class ConvesioPayApplePayment extends AbstractApplePayment {
4441
4538
  convesiopay: {
4442
4539
  return_url: this.params.returnUrl,
4443
4540
  },
4444
- ...convertToSwellAddress$1(billingContact),
4541
+ ...convertToSwellAddress$2(billingContact),
4445
4542
  },
4446
4543
  ...(shippingContact && {
4447
- shipping: convertToSwellAddress$1(shippingContact),
4544
+ shipping: convertToSwellAddress$2(shippingContact),
4448
4545
  }),
4449
- };
4546
+ });
4450
4547
  }
4451
4548
  }
4452
4549
 
@@ -4572,7 +4669,7 @@ class ConvesioPayGooglePayment extends AbstractGooglePayment {
4572
4669
  * @param {google.payments.api.PaymentData} paymentData
4573
4670
  * @returns {Promise<object>}
4574
4671
  */
4575
- async preparePaymentDataForCartUpdate(paymentData) {
4672
+ async processPaymentData(paymentData) {
4576
4673
  const { email, shippingAddress, shippingOptionData, paymentMethodData } =
4577
4674
  paymentData;
4578
4675
 
@@ -4600,7 +4697,7 @@ class ConvesioPayGooglePayment extends AbstractGooglePayment {
4600
4697
  },
4601
4698
  );
4602
4699
 
4603
- return {
4700
+ return this.updateCart({
4604
4701
  account: { email },
4605
4702
  billing: {
4606
4703
  method: 'google',
@@ -4613,15 +4710,15 @@ class ConvesioPayGooglePayment extends AbstractGooglePayment {
4613
4710
  convesiopay: {
4614
4711
  return_url: this.params.returnUrl,
4615
4712
  },
4616
- ...convertToSwellAddress$2(billingAddress),
4713
+ ...convertToSwellAddress$3(billingAddress),
4617
4714
  },
4618
4715
  ...(shippingAddress && {
4619
4716
  shipping: {
4620
- ...convertToSwellAddress$2(shippingAddress),
4717
+ ...convertToSwellAddress$3(shippingAddress),
4621
4718
  service: shippingOptionData?.id || undefined,
4622
4719
  },
4623
4720
  }),
4624
- };
4721
+ });
4625
4722
  }
4626
4723
  }
4627
4724
 
@@ -4824,12 +4921,26 @@ function getKlarnaSessionData(cart) {
4824
4921
  };
4825
4922
  }
4826
4923
 
4924
+ /** @typedef {import('@paypal/paypal-js').PayPalNamespace} PayPal */
4925
+ /** @typedef {import('@paypal/paypal-js').ShippingAddress} ShippingAddress */
4926
+ /** @typedef {import('@paypal/paypal-js').CreateOrderData} CreateOrderData */
4927
+ /** @typedef {import('@paypal/paypal-js').CreateOrderActions} CreateOrderActions */
4928
+ /** @typedef {import('@paypal/paypal-js').OnShippingAddressChangeData} OnShippingAddressChangeData */
4929
+ /** @typedef {import('@paypal/paypal-js').OnShippingAddressChangeActions} OnShippingAddressChangeActions */
4930
+ /** @typedef {import('@paypal/paypal-js').OnShippingOptionsChangeData} OnShippingOptionsChangeData */
4931
+ /** @typedef {import('@paypal/paypal-js').OnShippingOptionsChangeActions} OnShippingOptionsChangeActions */
4932
+ /** @typedef {import('@paypal/paypal-js').OnApproveData} OnApproveData */
4933
+ /** @typedef {import('@paypal/paypal-js').OnApproveActions} OnApproveActions */
4934
+ /** @typedef {import('../../../types').Cart} Cart */
4935
+ /** @typedef {import('../../../types').Address} Address */
4936
+
4827
4937
  class PaypalDirectPayment extends Payment {
4828
4938
  constructor(api, options, params, methods) {
4829
4939
  super(api, options, params, methods.paypal);
4830
4940
  }
4831
4941
 
4832
- get scripts() {
4942
+ /** @param {Cart} cart */
4943
+ getScripts(cart) {
4833
4944
  const { client_id } = this.method;
4834
4945
 
4835
4946
  return [
@@ -4839,11 +4950,13 @@ class PaypalDirectPayment extends Payment {
4839
4950
  client_id,
4840
4951
  merchant_id: this.merchantId,
4841
4952
  cart: ['currency'],
4953
+ vault: cart.subscription_delivery,
4842
4954
  },
4843
4955
  },
4844
4956
  ];
4845
4957
  }
4846
4958
 
4959
+ /** @returns {PayPal} */
4847
4960
  get paypal() {
4848
4961
  if (!window.paypal) {
4849
4962
  throw new LibraryNotLoadedError('PayPal');
@@ -4867,7 +4980,6 @@ class PaypalDirectPayment extends Payment {
4867
4980
  async createElements(cart) {
4868
4981
  const {
4869
4982
  elementId = 'paypal-button',
4870
- locale = 'en_US',
4871
4983
  style: {
4872
4984
  layout = 'horizontal',
4873
4985
  height = 45,
@@ -4876,15 +4988,16 @@ class PaypalDirectPayment extends Payment {
4876
4988
  label = 'paypal',
4877
4989
  tagline = false,
4878
4990
  } = {},
4991
+ require: { shipping: requireShipping = true } = {},
4879
4992
  } = this.params;
4880
4993
 
4881
4994
  this.setElementContainer(elementId);
4882
4995
 
4883
4996
  this._validateCart(cart);
4884
- await this.loadScripts(this.scripts);
4997
+ await this.loadScripts(this.getScripts(cart));
4885
4998
 
4886
- this.element = this.paypal.Buttons({
4887
- locale,
4999
+ /** @type {import('@paypal/paypal-js').PayPalButtonsComponentOptions} */
5000
+ const buttonsOptions = {
4888
5001
  style: {
4889
5002
  layout,
4890
5003
  height,
@@ -4893,11 +5006,27 @@ class PaypalDirectPayment extends Payment {
4893
5006
  label,
4894
5007
  tagline,
4895
5008
  },
5009
+ fundingSource: this.paypal.FUNDING.PAYPAL,
4896
5010
  createOrder: this._onCreateOrder.bind(this, cart),
4897
- onShippingChange: this._onShippingChange.bind(this),
4898
5011
  onApprove: this._onApprove.bind(this),
4899
5012
  onError: this.onError.bind(this),
4900
- });
5013
+ };
5014
+
5015
+ if (requireShipping) {
5016
+ buttonsOptions.onShippingAddressChange =
5017
+ this._onShippingAddressChange.bind(this);
5018
+
5019
+ buttonsOptions.onShippingOptionsChange =
5020
+ this._onShippingOptionsChange.bind(this);
5021
+ }
5022
+
5023
+ const component = this.paypal.Buttons(buttonsOptions);
5024
+
5025
+ if (!component.isEligible()) {
5026
+ throw new Error('PayPal button with provided options is not eligible.');
5027
+ }
5028
+
5029
+ this.element = component;
4901
5030
  }
4902
5031
 
4903
5032
  mountElements() {
@@ -4911,6 +5040,7 @@ class PaypalDirectPayment extends Payment {
4911
5040
  }
4912
5041
  }
4913
5042
 
5043
+ /** @param {Cart} cart */
4914
5044
  _validateCart(cart) {
4915
5045
  const hasSubscriptionProduct = Boolean(cart.subscription_delivery);
4916
5046
 
@@ -4920,27 +5050,35 @@ class PaypalDirectPayment extends Payment {
4920
5050
  );
4921
5051
  }
4922
5052
 
4923
- if (!(cart.capture_total > 0)) {
5053
+ if ((cart.capture_total || 0) <= 0) {
4924
5054
  throw new Error(
4925
5055
  'Invalid PayPal button amount. Value should be greater than zero.',
4926
5056
  );
4927
5057
  }
4928
5058
  }
4929
5059
 
5060
+ /**
5061
+ * @param {Cart} cart
5062
+ * @param {CreateOrderData} _data
5063
+ * @param {CreateOrderActions} _actions
5064
+ * @returns {Promise<string>}
5065
+ */
4930
5066
  async _onCreateOrder(cart, _data, _actions) {
4931
- const { require: { shipping: requireShipping = true } = {} } = this.params;
5067
+ const {
5068
+ locale = 'en-US',
5069
+ require: { shipping: requireShipping = true } = {},
5070
+ } = this.params;
5071
+
4932
5072
  const { capture_total, currency, subscription_delivery } = cart;
4933
5073
  const hasSubscriptionProduct = Boolean(subscription_delivery);
4934
5074
  const merchantId = this.merchantId;
4935
5075
  const returnUrl = this.returnUrl;
4936
- const orderData = {
4937
- application_context: {
4938
- shipping_preference: requireShipping ? 'GET_FROM_FILE' : 'NO_SHIPPING',
4939
- },
4940
- };
5076
+ /** @type {import('@paypal/paypal-js').CreateOrderRequestBody} */
5077
+ const orderData = {};
5078
+ /** @type {import('@paypal/paypal-js').PurchaseUnit} */
4941
5079
  const purchaseUnit = {
4942
5080
  amount: {
4943
- value: Number(capture_total.toFixed(2)),
5081
+ value: Number(capture_total).toFixed(2),
4944
5082
  currency_code: currency,
4945
5083
  },
4946
5084
  };
@@ -4948,29 +5086,44 @@ class PaypalDirectPayment extends Payment {
4948
5086
  if (merchantId) {
4949
5087
  // express checkout and ppcp
4950
5088
  orderData.intent = 'AUTHORIZE';
5089
+
5090
+ orderData.payment_source = {
5091
+ paypal: {
5092
+ experience_context: {
5093
+ locale,
5094
+ shipping_preference: requireShipping
5095
+ ? 'GET_FROM_FILE'
5096
+ : 'NO_SHIPPING',
5097
+ },
5098
+ },
5099
+ };
5100
+
4951
5101
  purchaseUnit.payee = {
4952
5102
  merchant_id: merchantId,
4953
5103
  };
4954
5104
 
4955
5105
  if (hasSubscriptionProduct) {
4956
- orderData.payment_source = {
4957
- paypal: {
4958
- attributes: {
4959
- vault: {
4960
- store_in_vault: 'ON_SUCCESS',
4961
- usage_type: 'MERCHANT',
4962
- },
4963
- },
4964
- experience_context: {
4965
- return_url: `${returnUrl}&redirect_status=succeeded`,
4966
- cancel_url: `${returnUrl}&redirect_status=canceled`,
4967
- },
5106
+ orderData.payment_source.paypal.attributes = {
5107
+ vault: {
5108
+ store_in_vault: 'ON_SUCCESS',
5109
+ usage_type: 'MERCHANT',
4968
5110
  },
4969
5111
  };
5112
+
5113
+ Object.assign(orderData.payment_source.paypal.experience_context, {
5114
+ return_url: `${returnUrl}&redirect_status=succeeded`,
5115
+ cancel_url: `${returnUrl}&redirect_status=canceled`,
5116
+ });
4970
5117
  }
4971
5118
  } else {
4972
5119
  // progressive checkout
4973
5120
  orderData.intent = 'CAPTURE';
5121
+
5122
+ orderData.application_context = {
5123
+ locale,
5124
+ shipping_preference: requireShipping ? 'GET_FROM_FILE' : 'NO_SHIPPING',
5125
+ };
5126
+
4974
5127
  purchaseUnit.payee = {
4975
5128
  email_address: this.method.store_owner_email,
4976
5129
  };
@@ -4986,44 +5139,37 @@ class PaypalDirectPayment extends Payment {
4986
5139
  return order.id;
4987
5140
  }
4988
5141
 
4989
- async _onShippingChange(data, actions) {
5142
+ /**
5143
+ * @param {OnShippingAddressChangeData} data
5144
+ * @param {OnShippingAddressChangeActions} actions
5145
+ */
5146
+ async _onShippingAddressChange(data, actions) {
4990
5147
  try {
4991
- const { orderID, shipping_address, selected_shipping_option } = data;
4992
- const updateData = {
5148
+ const { orderID, shippingAddress } = data;
5149
+
5150
+ const cart = await this.updateCart({
4993
5151
  shipping: {
4994
- state: shipping_address.state,
4995
- city: shipping_address.city,
4996
- zip: shipping_address.postal_code,
4997
- country: shipping_address.country_code,
5152
+ state: shippingAddress.state,
5153
+ city: shippingAddress.city,
5154
+ zip: shippingAddress.postalCode,
5155
+ country: shippingAddress.countryCode,
4998
5156
  },
4999
5157
  shipment_rating: null,
5000
- };
5001
-
5002
- if (selected_shipping_option) {
5003
- updateData.shipping.service = selected_shipping_option.id;
5004
- updateData.$taxes = true;
5005
- }
5158
+ });
5006
5159
 
5007
- const cart = await this.updateCart(updateData);
5008
- const shippingServices = get(cart, 'shipment_rating.services');
5160
+ const shippingServices = cart.shipment_rating?.services;
5009
5161
 
5010
- // can't fulfill shipping to selected address
5162
+ // Can't fulfill shipping to selected address
5011
5163
  if (isEmpty(shippingServices)) {
5012
5164
  return actions.reject();
5013
5165
  }
5014
5166
 
5015
- let selectedShippingService;
5016
-
5017
- if (selected_shipping_option) {
5018
- selectedShippingService = shippingServices.find(
5019
- (shippingService) =>
5020
- shippingService.id === selected_shipping_option.id,
5021
- );
5022
- }
5167
+ let selectedShippingService = cart.shipping?.service;
5023
5168
 
5024
5169
  // need to set first service for cart by default
5025
5170
  if (!selectedShippingService) {
5026
5171
  const [firstShippingService] = shippingServices;
5172
+ selectedShippingService = firstShippingService.id;
5027
5173
 
5028
5174
  await this.updateCart({
5029
5175
  shipping: {
@@ -5040,8 +5186,33 @@ class PaypalDirectPayment extends Payment {
5040
5186
  paypal_order_id: orderID,
5041
5187
  },
5042
5188
  });
5189
+ } catch (error) {
5190
+ this.onError(error);
5191
+
5192
+ return actions.reject();
5193
+ }
5194
+ }
5195
+
5196
+ /**
5197
+ * @param {OnShippingOptionsChangeData} data
5198
+ * @param {OnShippingOptionsChangeActions} actions
5199
+ */
5200
+ async _onShippingOptionsChange(data, actions) {
5201
+ try {
5202
+ const { orderID, selectedShippingOption } = data;
5203
+
5204
+ const cart = await this.updateCart({
5205
+ shipping: { service: selectedShippingOption.id },
5206
+ $taxes: true,
5207
+ });
5043
5208
 
5044
- return orderID;
5209
+ await this.updateIntent({
5210
+ gateway: 'paypal',
5211
+ intent: {
5212
+ cart_id: cart.id,
5213
+ paypal_order_id: orderID,
5214
+ },
5215
+ });
5045
5216
  } catch (error) {
5046
5217
  this.onError(error);
5047
5218
 
@@ -5049,14 +5220,17 @@ class PaypalDirectPayment extends Payment {
5049
5220
  }
5050
5221
  }
5051
5222
 
5223
+ /**
5224
+ * @param {OnApproveData} data
5225
+ * @param {OnApproveActions} actions
5226
+ */
5052
5227
  async _onApprove(data, actions) {
5053
- const { require: { shipping: requireShipping = true } = {} } = this.params;
5054
5228
  const order = await actions.order.get();
5055
5229
  const orderId = order.id;
5056
- const payer = order.payer;
5230
+ const payer = order.payment_source?.paypal || order.payer;
5057
5231
  const billing = payer.address;
5058
- const shipping = get(order, 'purchase_units[0].shipping');
5059
- const name = `${payer.name.given_name} ${payer.name.surname}`;
5232
+ const shipping = order.purchase_units?.[0]?.shipping;
5233
+ const name = `${payer.name?.given_name} ${payer.name?.surname}`;
5060
5234
 
5061
5235
  await this.updateCart({
5062
5236
  account: {
@@ -5068,31 +5242,35 @@ class PaypalDirectPayment extends Payment {
5068
5242
  order_id: orderId,
5069
5243
  },
5070
5244
  name,
5071
- ...this._mapAddress(billing),
5245
+ ...convertToSwellAddress$1(billing),
5072
5246
  },
5073
- ...(requireShipping && {
5247
+ ...(shipping?.address && {
5074
5248
  shipping: {
5075
5249
  first_name: payer.name.given_name,
5076
5250
  last_name: payer.name.surname,
5077
5251
  name: shipping.name.full_name,
5078
- ...this._mapAddress(shipping.address),
5252
+ ...convertToSwellAddress$1(shipping.address),
5079
5253
  },
5080
5254
  }),
5081
5255
  });
5082
5256
 
5083
5257
  this.onSuccess();
5084
5258
  }
5259
+ }
5085
5260
 
5086
- _mapAddress(address) {
5087
- return {
5088
- address1: address.address_line_1,
5089
- address2: address.address_line_2,
5090
- state: address.admin_area_1,
5091
- city: address.admin_area_2,
5092
- zip: address.postal_code,
5093
- country: address.country_code,
5094
- };
5095
- }
5261
+ /**
5262
+ * @param {ShippingAddress} address
5263
+ * @returns {Address}
5264
+ */
5265
+ function convertToSwellAddress$1(address) {
5266
+ return {
5267
+ address1: address.address_line_1,
5268
+ address2: address.address_line_2,
5269
+ state: address.admin_area_1,
5270
+ city: address.admin_area_2,
5271
+ zip: address.postal_code,
5272
+ country: address.country_code,
5273
+ };
5096
5274
  }
5097
5275
 
5098
5276
  class AmazonDirectPayment extends Payment {
@@ -5859,7 +6037,7 @@ class PaymentController {
5859
6037
  }
5860
6038
 
5861
6039
  async _vaultRequest(method, url, data) {
5862
- const response = await vaultRequest(method, url, data);
6040
+ const response = await vaultRequest(method, url, data, this.options);
5863
6041
 
5864
6042
  if (this.options.useCamelCase) {
5865
6043
  return toCamel(response);