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.
@@ -12110,13 +12110,18 @@
12110
12110
 
12111
12111
  async function loadPaypal(params) {
12112
12112
  if (!window.paypal) {
12113
- const { currency, client_id, merchant_id } = params;
12113
+ const { vault, currency, client_id, merchant_id } = params;
12114
+
12114
12115
  const paypalParams = {
12115
12116
  currency,
12116
12117
  'client-id': client_id,
12117
12118
  commit: false,
12118
12119
  };
12119
12120
 
12121
+ if (vault) {
12122
+ paypalParams.vault = vault;
12123
+ }
12124
+
12120
12125
  if (merchant_id) {
12121
12126
  // paypal express and ppcp onboarded
12122
12127
  paypalParams['merchant-id'] = merchant_id;
@@ -12655,7 +12660,7 @@
12655
12660
  THB: 10,
12656
12661
  };
12657
12662
 
12658
- const addressFieldsMap$1 = {
12663
+ const addressFieldsMap = {
12659
12664
  city: 'city',
12660
12665
  country: 'country',
12661
12666
  line1: 'address1',
@@ -12693,7 +12698,7 @@
12693
12698
  details.email = cart.account.email;
12694
12699
  }
12695
12700
 
12696
- const address = mapValues(addressFieldsMap$1, cart.billing);
12701
+ const address = mapValues(addressFieldsMap, cart.billing);
12697
12702
  if (!isEmpty(address)) {
12698
12703
  details.address = address;
12699
12704
  }
@@ -14243,7 +14248,7 @@
14243
14248
 
14244
14249
  // Update cart with new shipping address and force tax recalculation
14245
14250
  let cart = await this.updateCart({
14246
- shipping: convertToSwellAddress$2(
14251
+ shipping: convertToSwellAddress$3(
14247
14252
  intermediatePaymentData.shippingAddress,
14248
14253
  ),
14249
14254
  });
@@ -14509,7 +14514,7 @@
14509
14514
  * @param {google.payments.api.Address} address
14510
14515
  * @returns {Address}
14511
14516
  */
14512
- function convertToSwellAddress$2(address) {
14517
+ function convertToSwellAddress$3(address) {
14513
14518
  return {
14514
14519
  name: address.name,
14515
14520
  address1: address.address1,
@@ -14773,11 +14778,11 @@
14773
14778
  nonce,
14774
14779
  gateway: 'braintree',
14775
14780
  },
14776
- ...convertToSwellAddress$2(billingAddress),
14781
+ ...convertToSwellAddress$3(billingAddress),
14777
14782
  },
14778
14783
  ...(shippingAddress && {
14779
14784
  shipping: {
14780
- ...convertToSwellAddress$2(shippingAddress),
14785
+ ...convertToSwellAddress$3(shippingAddress),
14781
14786
  service: shippingOptionData?.id || undefined,
14782
14787
  },
14783
14788
  }),
@@ -14814,6 +14819,7 @@
14814
14819
  /** @typedef {import('./payment').default} Payment */
14815
14820
  /** @typedef {import('../../types').Cart} Cart */
14816
14821
  /** @typedef {import('../../types').Address} Address */
14822
+ /** @typedef {import('../../types').CartItemBillingSchedule} CartItemBillingSchedule */
14817
14823
 
14818
14824
  /**
14819
14825
  * @this {Payment}
@@ -14825,7 +14831,7 @@
14825
14831
  // Update cart with Apple Pay shipping address to get shipping options and tax
14826
14832
  // This happens immediately when the sheet opens with the default address
14827
14833
  const cart = await this.updateCart({
14828
- shipping: convertToSwellAddress$1(shippingContact),
14834
+ shipping: convertToSwellAddress$2(shippingContact),
14829
14835
  });
14830
14836
 
14831
14837
  if (!cart.shipment_rating?.services?.length) {
@@ -15114,7 +15120,7 @@
15114
15120
  * @param {ApplePayJS.ApplePayPaymentContact} [address]
15115
15121
  * @returns {Address}
15116
15122
  */
15117
- function convertToSwellAddress$1(address = {}) {
15123
+ function convertToSwellAddress$2(address = {}) {
15118
15124
  return {
15119
15125
  first_name: address.givenName,
15120
15126
  last_name: address.familyName,
@@ -15157,6 +15163,99 @@
15157
15163
  return { requiredBillingContactFields, requiredShippingContactFields };
15158
15164
  }
15159
15165
 
15166
+ /**
15167
+ * @param {CartItemBillingSchedule} schedule
15168
+ * @returns {{ intervalUnit: ApplePayJS.ApplePayRecurringPaymentDateUnit, intervalCount: number }}
15169
+ */
15170
+ function convertSwellScheduleToAppleRecurringInterval(schedule) {
15171
+ let intervalCount = schedule.interval_count || 1;
15172
+ let intervalUnit = 'day';
15173
+
15174
+ switch (schedule.interval) {
15175
+ case 'daily':
15176
+ intervalUnit = 'day';
15177
+ break;
15178
+
15179
+ case 'weekly':
15180
+ intervalUnit = 'day';
15181
+ intervalCount *= 7;
15182
+ break;
15183
+
15184
+ case 'monthly':
15185
+ intervalUnit = 'month';
15186
+ break;
15187
+
15188
+ case 'yearly':
15189
+ intervalUnit = 'year';
15190
+ break;
15191
+ }
15192
+
15193
+ return { intervalUnit, intervalCount };
15194
+ }
15195
+
15196
+ /**
15197
+ * @param {Cart} cart
15198
+ * @param {string} managementUrl
15199
+ * @returns {ApplePayJS.ApplePayRecurringPaymentRequest | undefined}
15200
+ */
15201
+ function getRecurringPaymentRequest(cart, managementUrl) {
15202
+ if (!cart.subscription_delivery) {
15203
+ return undefined;
15204
+ }
15205
+
15206
+ const item = cart.items.find(
15207
+ (item) =>
15208
+ item.purchase_option?.type === 'subscription' &&
15209
+ item.purchase_option.billing_schedule,
15210
+ );
15211
+
15212
+ if (item === undefined) {
15213
+ return undefined;
15214
+ }
15215
+
15216
+ const { intervalUnit, intervalCount } =
15217
+ convertSwellScheduleToAppleRecurringInterval(
15218
+ item.purchase_option.billing_schedule,
15219
+ );
15220
+
15221
+ /** @type {ApplePayJS.ApplePayRecurringPaymentRequest} */
15222
+ const recurringPaymentRequest = {
15223
+ paymentDescription:
15224
+ item.purchase_option.plan_description ||
15225
+ item.purchase_option.plan_name ||
15226
+ item.product_name ||
15227
+ item.product?.name,
15228
+ regularBilling: {
15229
+ type: 'final',
15230
+ label: item.purchase_option.plan_name || 'Subscription',
15231
+ // Calculate the subscription price manually if a trial period is specified.
15232
+ // However, discounts are not included in the calculation due to the difficulty of taking into account all scenarios.
15233
+ amount: (item.purchase_option.billing_schedule.trial_days
15234
+ ? (item.price || 0) * (item.quantity || 1)
15235
+ : item.price_total
15236
+ ).toFixed(2),
15237
+ paymentTiming: 'recurring',
15238
+ recurringPaymentIntervalUnit: intervalUnit,
15239
+ recurringPaymentIntervalCount: intervalCount,
15240
+ },
15241
+ trialBilling: item.purchase_option.billing_schedule.trial_days
15242
+ ? {
15243
+ type: 'final',
15244
+ label: 'Trial',
15245
+ // When a trial period is set, price_total is 0 (usually)
15246
+ amount: Number(item.price_total || 0).toFixed(2),
15247
+ paymentTiming: 'recurring',
15248
+ recurringPaymentIntervalUnit: 'day',
15249
+ recurringPaymentIntervalCount:
15250
+ item.purchase_option.billing_schedule.trial_days,
15251
+ }
15252
+ : undefined,
15253
+ managementURL: managementUrl,
15254
+ };
15255
+
15256
+ return recurringPaymentRequest;
15257
+ }
15258
+
15160
15259
  /** @typedef {import('../../../types').Cart} Cart */
15161
15260
 
15162
15261
  const VERSION$1 = 14;
@@ -15359,10 +15458,10 @@
15359
15458
  nonce: payload.nonce,
15360
15459
  gateway: 'braintree',
15361
15460
  },
15362
- ...convertToSwellAddress$1(billingContact),
15461
+ ...convertToSwellAddress$2(billingContact),
15363
15462
  },
15364
15463
  ...(shippingContact && {
15365
- shipping: convertToSwellAddress$1(shippingContact),
15464
+ shipping: convertToSwellAddress$2(shippingContact),
15366
15465
  }),
15367
15466
  });
15368
15467
 
@@ -15568,7 +15667,7 @@
15568
15667
  * @returns {Promise<object>}
15569
15668
  */
15570
15669
  // eslint-disable-next-line no-unused-vars
15571
- async preparePaymentDataForCartUpdate(paymentData) {
15670
+ async processPaymentData(paymentData) {
15572
15671
  throw new Error('Implement this!');
15573
15672
  }
15574
15673
 
@@ -15590,9 +15689,7 @@
15590
15689
  throw new Error('Google Pay token is missing');
15591
15690
  }
15592
15691
 
15593
- await this.preparePaymentDataForCartUpdate(paymentData).then((data) =>
15594
- this.updateCart(data),
15595
- );
15692
+ await this.processPaymentData(paymentData);
15596
15693
 
15597
15694
  this.onSuccess();
15598
15695
  }
@@ -15715,7 +15812,7 @@
15715
15812
  * @param {google.payments.api.PaymentData} paymentData
15716
15813
  * @returns {Promise<object>}
15717
15814
  */
15718
- async preparePaymentDataForCartUpdate(paymentData) {
15815
+ async processPaymentData(paymentData) {
15719
15816
  const { email, shippingAddress, shippingOptionData, paymentMethodData } =
15720
15817
  paymentData;
15721
15818
 
@@ -15724,7 +15821,7 @@
15724
15821
  tokenizationData: { token },
15725
15822
  } = paymentMethodData;
15726
15823
 
15727
- return {
15824
+ await this.updateCart({
15728
15825
  account: { email },
15729
15826
  billing: {
15730
15827
  method: 'google',
@@ -15734,15 +15831,15 @@
15734
15831
  gateway: 'authorizenet',
15735
15832
  token: base64Encode(token),
15736
15833
  },
15737
- ...convertToSwellAddress$2(billingAddress),
15834
+ ...convertToSwellAddress$3(billingAddress),
15738
15835
  },
15739
15836
  ...(shippingAddress && {
15740
15837
  shipping: {
15741
- ...convertToSwellAddress$2(shippingAddress),
15838
+ ...convertToSwellAddress$3(shippingAddress),
15742
15839
  service: shippingOptionData?.id || undefined,
15743
15840
  },
15744
15841
  }),
15745
- };
15842
+ });
15746
15843
  }
15747
15844
  }
15748
15845
 
@@ -15857,6 +15954,10 @@
15857
15954
  requiredShippingContactFields,
15858
15955
  requiredBillingContactFields,
15859
15956
  supportsCouponCode: true,
15957
+ recurringPaymentRequest: getRecurringPaymentRequest(
15958
+ cart,
15959
+ this.params.managementUrl,
15960
+ ),
15860
15961
  lineItems: getLineItems(cart),
15861
15962
  };
15862
15963
  }
@@ -15879,7 +15980,7 @@
15879
15980
  * @returns {Promise<object>}
15880
15981
  */
15881
15982
  // eslint-disable-next-line no-unused-vars
15882
- async preparePaymentDataForCartUpdate(event) {
15983
+ async processPaymentData(event) {
15883
15984
  throw new Error('Implement this!');
15884
15985
  }
15885
15986
 
@@ -15937,9 +16038,7 @@
15937
16038
  //
15938
16039
  // We store the payment token but DO NOT process the order yet.
15939
16040
  // The user must manually click "Place Order" to complete the transaction.
15940
- await this.preparePaymentDataForCartUpdate(event).then((data) =>
15941
- this.updateCart(data),
15942
- );
16041
+ await this.processPaymentData(event);
15943
16042
 
15944
16043
  // Complete Apple Pay session successfully
15945
16044
  // This closes the Apple Pay sheet and shows success to the user
@@ -16075,12 +16174,12 @@
16075
16174
  * @param {ApplePayJS.ApplePayPaymentAuthorizedEvent} event
16076
16175
  * @returns {Promise<object>}
16077
16176
  */
16078
- async preparePaymentDataForCartUpdate(event) {
16177
+ async processPaymentData(event) {
16079
16178
  const {
16080
16179
  payment: { token, shippingContact, billingContact },
16081
16180
  } = event;
16082
16181
 
16083
- return {
16182
+ return this.updateCart({
16084
16183
  account: {
16085
16184
  email: shippingContact?.emailAddress || billingContact?.emailAddress,
16086
16185
  },
@@ -16092,12 +16191,12 @@
16092
16191
  gateway: 'authorizenet',
16093
16192
  token: base64Encode(JSON.stringify(token.paymentData)),
16094
16193
  },
16095
- ...convertToSwellAddress$1(billingContact),
16194
+ ...convertToSwellAddress$2(billingContact),
16096
16195
  },
16097
16196
  ...(shippingContact && {
16098
- shipping: convertToSwellAddress$1(shippingContact),
16197
+ shipping: convertToSwellAddress$2(shippingContact),
16099
16198
  }),
16100
- };
16199
+ });
16101
16200
  }
16102
16201
  }
16103
16202
 
@@ -16465,7 +16564,7 @@
16465
16564
  * @param {ApplePayJS.ApplePayPaymentAuthorizedEvent} event
16466
16565
  * @returns {Promise<object>}
16467
16566
  */
16468
- async preparePaymentDataForCartUpdate(event) {
16567
+ async processPaymentData(event) {
16469
16568
  const {
16470
16569
  payment: { token, shippingContact, billingContact },
16471
16570
  } = event;
@@ -16489,7 +16588,7 @@
16489
16588
  },
16490
16589
  );
16491
16590
 
16492
- return {
16591
+ return this.updateCart({
16493
16592
  account: {
16494
16593
  email: shippingContact?.emailAddress || billingContact?.emailAddress,
16495
16594
  },
@@ -16504,12 +16603,12 @@
16504
16603
  convesiopay: {
16505
16604
  return_url: this.params.returnUrl,
16506
16605
  },
16507
- ...convertToSwellAddress$1(billingContact),
16606
+ ...convertToSwellAddress$2(billingContact),
16508
16607
  },
16509
16608
  ...(shippingContact && {
16510
- shipping: convertToSwellAddress$1(shippingContact),
16609
+ shipping: convertToSwellAddress$2(shippingContact),
16511
16610
  }),
16512
- };
16611
+ });
16513
16612
  }
16514
16613
  }
16515
16614
 
@@ -16635,7 +16734,7 @@
16635
16734
  * @param {google.payments.api.PaymentData} paymentData
16636
16735
  * @returns {Promise<object>}
16637
16736
  */
16638
- async preparePaymentDataForCartUpdate(paymentData) {
16737
+ async processPaymentData(paymentData) {
16639
16738
  const { email, shippingAddress, shippingOptionData, paymentMethodData } =
16640
16739
  paymentData;
16641
16740
 
@@ -16663,7 +16762,7 @@
16663
16762
  },
16664
16763
  );
16665
16764
 
16666
- return {
16765
+ return this.updateCart({
16667
16766
  account: { email },
16668
16767
  billing: {
16669
16768
  method: 'google',
@@ -16676,15 +16775,15 @@
16676
16775
  convesiopay: {
16677
16776
  return_url: this.params.returnUrl,
16678
16777
  },
16679
- ...convertToSwellAddress$2(billingAddress),
16778
+ ...convertToSwellAddress$3(billingAddress),
16680
16779
  },
16681
16780
  ...(shippingAddress && {
16682
16781
  shipping: {
16683
- ...convertToSwellAddress$2(shippingAddress),
16782
+ ...convertToSwellAddress$3(shippingAddress),
16684
16783
  service: shippingOptionData?.id || undefined,
16685
16784
  },
16686
16785
  }),
16687
- };
16786
+ });
16688
16787
  }
16689
16788
  }
16690
16789
 
@@ -16830,105 +16929,6 @@
16830
16929
  }
16831
16930
  }
16832
16931
 
16833
- const addressFieldsMap = {
16834
- given_name: 'first_name',
16835
- family_name: 'last_name',
16836
- city: 'city',
16837
- country: 'country',
16838
- phone: 'phone',
16839
- postal_code: 'zip',
16840
- street_address: 'address1',
16841
- street_address2: 'address2',
16842
- region: 'state',
16843
- };
16844
-
16845
- const mapFields = (fieldsMap, data) =>
16846
- reduce(
16847
- fieldsMap,
16848
- (acc, srcKey, destKey) => {
16849
- const value = data[srcKey];
16850
- if (value) {
16851
- acc[destKey] = value;
16852
- }
16853
- return acc;
16854
- },
16855
- {},
16856
- );
16857
-
16858
- const mapAddressFields = (cart, addressField) => ({
16859
- ...mapFields(addressFieldsMap, cart[addressField]),
16860
- email: get(cart, 'account.email'),
16861
- });
16862
-
16863
- function getOrderLines(cart) {
16864
- const items = map(cart.items, (item) => ({
16865
- type: 'physical',
16866
- name: get(item, 'product.name'),
16867
- reference: get(item, 'product.sku') || get(item, 'product.slug'),
16868
- quantity: item.quantity,
16869
- unit_price: Math.round(toNumber(item.price - item.discount_each) * 100),
16870
- total_amount: Math.round(
16871
- toNumber(item.price_total - item.discount_total) * 100,
16872
- ),
16873
- tax_rate: 0,
16874
- total_tax_amount: 0,
16875
- }));
16876
-
16877
- const tax = get(cart, 'tax_included_total');
16878
- const taxAmount = toNumber(tax) * 100;
16879
- if (tax) {
16880
- items.push({
16881
- type: 'sales_tax',
16882
- name: 'Taxes',
16883
- quantity: 1,
16884
- unit_price: taxAmount,
16885
- total_amount: taxAmount,
16886
- tax_rate: 0,
16887
- total_tax_amount: 0,
16888
- });
16889
- }
16890
-
16891
- const shipping = get(cart, 'shipping', {});
16892
- const shippingTotal = get(cart, 'shipment_total', {});
16893
- const shippingAmount = toNumber(shippingTotal) * 100;
16894
- if (shipping.price) {
16895
- items.push({
16896
- type: 'shipping_fee',
16897
- name: shipping.service_name,
16898
- quantity: 1,
16899
- unit_price: shippingAmount,
16900
- total_amount: shippingAmount,
16901
- tax_rate: 0,
16902
- total_tax_amount: 0,
16903
- });
16904
- }
16905
-
16906
- return items;
16907
- }
16908
-
16909
- function getKlarnaSessionData(cart) {
16910
- const returnUrl = `${window.location.origin}${window.location.pathname}?gateway=klarna_direct&sid={{session_id}}`;
16911
- const successUrl = `${returnUrl}&authorization_token={{authorization_token}}`;
16912
-
16913
- return {
16914
- locale: cart.display_locale || get(cart, 'settings.locale') || 'en-US',
16915
- purchase_country:
16916
- get(cart, 'billing.country') || get(cart, 'shipping.country'),
16917
- purchase_currency: cart.currency,
16918
- billing_address: mapAddressFields(cart, 'billing'),
16919
- shipping_address: mapAddressFields(cart, 'shipping'),
16920
- order_amount: Math.round(get(cart, 'capture_total', 0) * 100),
16921
- order_lines: JSON.stringify(getOrderLines(cart)),
16922
- merchant_urls: {
16923
- success: successUrl,
16924
- back: returnUrl,
16925
- cancel: returnUrl,
16926
- error: returnUrl,
16927
- failure: returnUrl,
16928
- },
16929
- };
16930
- }
16931
-
16932
16932
  class KlarnaDirectPayment extends Payment {
16933
16933
  constructor(api, options, params, methods) {
16934
16934
  super(api, options, params, methods.klarna);
@@ -16937,6 +16937,7 @@
16937
16937
  async tokenize() {
16938
16938
  const cart = await this.getCart();
16939
16939
  const sessionData = getKlarnaSessionData(cart);
16940
+
16940
16941
  const session = await this.createIntent({
16941
16942
  gateway: 'klarna',
16942
16943
  intent: sessionData,
@@ -16969,12 +16970,42 @@
16969
16970
  }
16970
16971
  }
16971
16972
 
16973
+ function getKlarnaSessionData(cart) {
16974
+ const returnUrl = `${window.location.origin}${window.location.pathname}?gateway=klarna_direct&sid={{session_id}}`;
16975
+ const successUrl = `${returnUrl}&authorization_token={{authorization_token}}`;
16976
+
16977
+ return {
16978
+ cart_id: cart.id,
16979
+ merchant_urls: {
16980
+ success: successUrl,
16981
+ back: returnUrl,
16982
+ cancel: returnUrl,
16983
+ error: returnUrl,
16984
+ failure: returnUrl,
16985
+ },
16986
+ };
16987
+ }
16988
+
16989
+ /** @typedef {import('@paypal/paypal-js').PayPalNamespace} PayPal */
16990
+ /** @typedef {import('@paypal/paypal-js').ShippingAddress} ShippingAddress */
16991
+ /** @typedef {import('@paypal/paypal-js').CreateOrderData} CreateOrderData */
16992
+ /** @typedef {import('@paypal/paypal-js').CreateOrderActions} CreateOrderActions */
16993
+ /** @typedef {import('@paypal/paypal-js').OnShippingAddressChangeData} OnShippingAddressChangeData */
16994
+ /** @typedef {import('@paypal/paypal-js').OnShippingAddressChangeActions} OnShippingAddressChangeActions */
16995
+ /** @typedef {import('@paypal/paypal-js').OnShippingOptionsChangeData} OnShippingOptionsChangeData */
16996
+ /** @typedef {import('@paypal/paypal-js').OnShippingOptionsChangeActions} OnShippingOptionsChangeActions */
16997
+ /** @typedef {import('@paypal/paypal-js').OnApproveData} OnApproveData */
16998
+ /** @typedef {import('@paypal/paypal-js').OnApproveActions} OnApproveActions */
16999
+ /** @typedef {import('../../../types').Cart} Cart */
17000
+ /** @typedef {import('../../../types').Address} Address */
17001
+
16972
17002
  class PaypalDirectPayment extends Payment {
16973
17003
  constructor(api, options, params, methods) {
16974
17004
  super(api, options, params, methods.paypal);
16975
17005
  }
16976
17006
 
16977
- get scripts() {
17007
+ /** @param {Cart} cart */
17008
+ getScripts(cart) {
16978
17009
  const { client_id } = this.method;
16979
17010
 
16980
17011
  return [
@@ -16984,11 +17015,13 @@
16984
17015
  client_id,
16985
17016
  merchant_id: this.merchantId,
16986
17017
  cart: ['currency'],
17018
+ vault: cart.subscription_delivery,
16987
17019
  },
16988
17020
  },
16989
17021
  ];
16990
17022
  }
16991
17023
 
17024
+ /** @returns {PayPal} */
16992
17025
  get paypal() {
16993
17026
  if (!window.paypal) {
16994
17027
  throw new LibraryNotLoadedError('PayPal');
@@ -17012,7 +17045,6 @@
17012
17045
  async createElements(cart) {
17013
17046
  const {
17014
17047
  elementId = 'paypal-button',
17015
- locale = 'en_US',
17016
17048
  style: {
17017
17049
  layout = 'horizontal',
17018
17050
  height = 45,
@@ -17021,15 +17053,16 @@
17021
17053
  label = 'paypal',
17022
17054
  tagline = false,
17023
17055
  } = {},
17056
+ require: { shipping: requireShipping = true } = {},
17024
17057
  } = this.params;
17025
17058
 
17026
17059
  this.setElementContainer(elementId);
17027
17060
 
17028
17061
  this._validateCart(cart);
17029
- await this.loadScripts(this.scripts);
17062
+ await this.loadScripts(this.getScripts(cart));
17030
17063
 
17031
- this.element = this.paypal.Buttons({
17032
- locale,
17064
+ /** @type {import('@paypal/paypal-js').PayPalButtonsComponentOptions} */
17065
+ const buttonsOptions = {
17033
17066
  style: {
17034
17067
  layout,
17035
17068
  height,
@@ -17038,11 +17071,27 @@
17038
17071
  label,
17039
17072
  tagline,
17040
17073
  },
17074
+ fundingSource: this.paypal.FUNDING.PAYPAL,
17041
17075
  createOrder: this._onCreateOrder.bind(this, cart),
17042
- onShippingChange: this._onShippingChange.bind(this),
17043
17076
  onApprove: this._onApprove.bind(this),
17044
17077
  onError: this.onError.bind(this),
17045
- });
17078
+ };
17079
+
17080
+ if (requireShipping) {
17081
+ buttonsOptions.onShippingAddressChange =
17082
+ this._onShippingAddressChange.bind(this);
17083
+
17084
+ buttonsOptions.onShippingOptionsChange =
17085
+ this._onShippingOptionsChange.bind(this);
17086
+ }
17087
+
17088
+ const component = this.paypal.Buttons(buttonsOptions);
17089
+
17090
+ if (!component.isEligible()) {
17091
+ throw new Error('PayPal button with provided options is not eligible.');
17092
+ }
17093
+
17094
+ this.element = component;
17046
17095
  }
17047
17096
 
17048
17097
  mountElements() {
@@ -17056,6 +17105,7 @@
17056
17105
  }
17057
17106
  }
17058
17107
 
17108
+ /** @param {Cart} cart */
17059
17109
  _validateCart(cart) {
17060
17110
  const hasSubscriptionProduct = Boolean(cart.subscription_delivery);
17061
17111
 
@@ -17065,27 +17115,35 @@
17065
17115
  );
17066
17116
  }
17067
17117
 
17068
- if (!(cart.capture_total > 0)) {
17118
+ if ((cart.capture_total || 0) <= 0) {
17069
17119
  throw new Error(
17070
17120
  'Invalid PayPal button amount. Value should be greater than zero.',
17071
17121
  );
17072
17122
  }
17073
17123
  }
17074
17124
 
17125
+ /**
17126
+ * @param {Cart} cart
17127
+ * @param {CreateOrderData} _data
17128
+ * @param {CreateOrderActions} _actions
17129
+ * @returns {Promise<string>}
17130
+ */
17075
17131
  async _onCreateOrder(cart, _data, _actions) {
17076
- const { require: { shipping: requireShipping = true } = {} } = this.params;
17132
+ const {
17133
+ locale = 'en-US',
17134
+ require: { shipping: requireShipping = true } = {},
17135
+ } = this.params;
17136
+
17077
17137
  const { capture_total, currency, subscription_delivery } = cart;
17078
17138
  const hasSubscriptionProduct = Boolean(subscription_delivery);
17079
17139
  const merchantId = this.merchantId;
17080
17140
  const returnUrl = this.returnUrl;
17081
- const orderData = {
17082
- application_context: {
17083
- shipping_preference: requireShipping ? 'GET_FROM_FILE' : 'NO_SHIPPING',
17084
- },
17085
- };
17141
+ /** @type {import('@paypal/paypal-js').CreateOrderRequestBody} */
17142
+ const orderData = {};
17143
+ /** @type {import('@paypal/paypal-js').PurchaseUnit} */
17086
17144
  const purchaseUnit = {
17087
17145
  amount: {
17088
- value: Number(capture_total.toFixed(2)),
17146
+ value: Number(capture_total).toFixed(2),
17089
17147
  currency_code: currency,
17090
17148
  },
17091
17149
  };
@@ -17093,29 +17151,44 @@
17093
17151
  if (merchantId) {
17094
17152
  // express checkout and ppcp
17095
17153
  orderData.intent = 'AUTHORIZE';
17154
+
17155
+ orderData.payment_source = {
17156
+ paypal: {
17157
+ experience_context: {
17158
+ locale,
17159
+ shipping_preference: requireShipping
17160
+ ? 'GET_FROM_FILE'
17161
+ : 'NO_SHIPPING',
17162
+ },
17163
+ },
17164
+ };
17165
+
17096
17166
  purchaseUnit.payee = {
17097
17167
  merchant_id: merchantId,
17098
17168
  };
17099
17169
 
17100
17170
  if (hasSubscriptionProduct) {
17101
- orderData.payment_source = {
17102
- paypal: {
17103
- attributes: {
17104
- vault: {
17105
- store_in_vault: 'ON_SUCCESS',
17106
- usage_type: 'MERCHANT',
17107
- },
17108
- },
17109
- experience_context: {
17110
- return_url: `${returnUrl}&redirect_status=succeeded`,
17111
- cancel_url: `${returnUrl}&redirect_status=canceled`,
17112
- },
17171
+ orderData.payment_source.paypal.attributes = {
17172
+ vault: {
17173
+ store_in_vault: 'ON_SUCCESS',
17174
+ usage_type: 'MERCHANT',
17113
17175
  },
17114
17176
  };
17177
+
17178
+ Object.assign(orderData.payment_source.paypal.experience_context, {
17179
+ return_url: `${returnUrl}&redirect_status=succeeded`,
17180
+ cancel_url: `${returnUrl}&redirect_status=canceled`,
17181
+ });
17115
17182
  }
17116
17183
  } else {
17117
17184
  // progressive checkout
17118
17185
  orderData.intent = 'CAPTURE';
17186
+
17187
+ orderData.application_context = {
17188
+ locale,
17189
+ shipping_preference: requireShipping ? 'GET_FROM_FILE' : 'NO_SHIPPING',
17190
+ };
17191
+
17119
17192
  purchaseUnit.payee = {
17120
17193
  email_address: this.method.store_owner_email,
17121
17194
  };
@@ -17131,44 +17204,37 @@
17131
17204
  return order.id;
17132
17205
  }
17133
17206
 
17134
- async _onShippingChange(data, actions) {
17207
+ /**
17208
+ * @param {OnShippingAddressChangeData} data
17209
+ * @param {OnShippingAddressChangeActions} actions
17210
+ */
17211
+ async _onShippingAddressChange(data, actions) {
17135
17212
  try {
17136
- const { orderID, shipping_address, selected_shipping_option } = data;
17137
- const updateData = {
17213
+ const { orderID, shippingAddress } = data;
17214
+
17215
+ const cart = await this.updateCart({
17138
17216
  shipping: {
17139
- state: shipping_address.state,
17140
- city: shipping_address.city,
17141
- zip: shipping_address.postal_code,
17142
- country: shipping_address.country_code,
17217
+ state: shippingAddress.state,
17218
+ city: shippingAddress.city,
17219
+ zip: shippingAddress.postalCode,
17220
+ country: shippingAddress.countryCode,
17143
17221
  },
17144
17222
  shipment_rating: null,
17145
- };
17146
-
17147
- if (selected_shipping_option) {
17148
- updateData.shipping.service = selected_shipping_option.id;
17149
- updateData.$taxes = true;
17150
- }
17223
+ });
17151
17224
 
17152
- const cart = await this.updateCart(updateData);
17153
- const shippingServices = get(cart, 'shipment_rating.services');
17225
+ const shippingServices = cart.shipment_rating?.services;
17154
17226
 
17155
- // can't fulfill shipping to selected address
17227
+ // Can't fulfill shipping to selected address
17156
17228
  if (isEmpty(shippingServices)) {
17157
17229
  return actions.reject();
17158
17230
  }
17159
17231
 
17160
- let selectedShippingService;
17161
-
17162
- if (selected_shipping_option) {
17163
- selectedShippingService = shippingServices.find(
17164
- (shippingService) =>
17165
- shippingService.id === selected_shipping_option.id,
17166
- );
17167
- }
17232
+ let selectedShippingService = cart.shipping?.service;
17168
17233
 
17169
17234
  // need to set first service for cart by default
17170
17235
  if (!selectedShippingService) {
17171
17236
  const [firstShippingService] = shippingServices;
17237
+ selectedShippingService = firstShippingService.id;
17172
17238
 
17173
17239
  await this.updateCart({
17174
17240
  shipping: {
@@ -17185,8 +17251,33 @@
17185
17251
  paypal_order_id: orderID,
17186
17252
  },
17187
17253
  });
17254
+ } catch (error) {
17255
+ this.onError(error);
17256
+
17257
+ return actions.reject();
17258
+ }
17259
+ }
17260
+
17261
+ /**
17262
+ * @param {OnShippingOptionsChangeData} data
17263
+ * @param {OnShippingOptionsChangeActions} actions
17264
+ */
17265
+ async _onShippingOptionsChange(data, actions) {
17266
+ try {
17267
+ const { orderID, selectedShippingOption } = data;
17268
+
17269
+ const cart = await this.updateCart({
17270
+ shipping: { service: selectedShippingOption.id },
17271
+ $taxes: true,
17272
+ });
17188
17273
 
17189
- return orderID;
17274
+ await this.updateIntent({
17275
+ gateway: 'paypal',
17276
+ intent: {
17277
+ cart_id: cart.id,
17278
+ paypal_order_id: orderID,
17279
+ },
17280
+ });
17190
17281
  } catch (error) {
17191
17282
  this.onError(error);
17192
17283
 
@@ -17194,14 +17285,17 @@
17194
17285
  }
17195
17286
  }
17196
17287
 
17288
+ /**
17289
+ * @param {OnApproveData} data
17290
+ * @param {OnApproveActions} actions
17291
+ */
17197
17292
  async _onApprove(data, actions) {
17198
- const { require: { shipping: requireShipping = true } = {} } = this.params;
17199
17293
  const order = await actions.order.get();
17200
17294
  const orderId = order.id;
17201
- const payer = order.payer;
17295
+ const payer = order.payment_source?.paypal || order.payer;
17202
17296
  const billing = payer.address;
17203
- const shipping = get(order, 'purchase_units[0].shipping');
17204
- const name = `${payer.name.given_name} ${payer.name.surname}`;
17297
+ const shipping = order.purchase_units?.[0]?.shipping;
17298
+ const name = `${payer.name?.given_name} ${payer.name?.surname}`;
17205
17299
 
17206
17300
  await this.updateCart({
17207
17301
  account: {
@@ -17213,31 +17307,35 @@
17213
17307
  order_id: orderId,
17214
17308
  },
17215
17309
  name,
17216
- ...this._mapAddress(billing),
17310
+ ...convertToSwellAddress$1(billing),
17217
17311
  },
17218
- ...(requireShipping && {
17312
+ ...(shipping?.address && {
17219
17313
  shipping: {
17220
17314
  first_name: payer.name.given_name,
17221
17315
  last_name: payer.name.surname,
17222
17316
  name: shipping.name.full_name,
17223
- ...this._mapAddress(shipping.address),
17317
+ ...convertToSwellAddress$1(shipping.address),
17224
17318
  },
17225
17319
  }),
17226
17320
  });
17227
17321
 
17228
17322
  this.onSuccess();
17229
17323
  }
17324
+ }
17230
17325
 
17231
- _mapAddress(address) {
17232
- return {
17233
- address1: address.address_line_1,
17234
- address2: address.address_line_2,
17235
- state: address.admin_area_1,
17236
- city: address.admin_area_2,
17237
- zip: address.postal_code,
17238
- country: address.country_code,
17239
- };
17240
- }
17326
+ /**
17327
+ * @param {ShippingAddress} address
17328
+ * @returns {Address}
17329
+ */
17330
+ function convertToSwellAddress$1(address) {
17331
+ return {
17332
+ address1: address.address_line_1,
17333
+ address2: address.address_line_2,
17334
+ state: address.admin_area_1,
17335
+ city: address.admin_area_2,
17336
+ zip: address.postal_code,
17337
+ country: address.country_code,
17338
+ };
17241
17339
  }
17242
17340
 
17243
17341
  class AmazonDirectPayment extends Payment {
@@ -18558,7 +18656,7 @@
18558
18656
  const api = {};
18559
18657
 
18560
18658
  Object.assign(api, {
18561
- version: '5.8.0',
18659
+ version: '5.8.2',
18562
18660
  options,
18563
18661
  request,
18564
18662