@rebilly/instruments 3.25.0-beta.0 → 3.26.0-beta.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rebilly/instruments",
3
- "version": "3.25.0-beta.0",
3
+ "version": "3.26.0-beta.0",
4
4
  "author": "Rebilly",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",
@@ -106,7 +106,7 @@ export class DataInstance {
106
106
  }
107
107
 
108
108
  toPostmatesModel() {
109
- return {
109
+ return JSON.parse(JSON.stringify({
110
110
  ...this,
111
111
  amountAndCurrency: this.amountAndCurrency,
112
112
  isPayment: this.isPayment,
@@ -115,7 +115,7 @@ export class DataInstance {
115
115
  summaryItems: this.summaryItems,
116
116
  summaryLineItems: this.summaryLineItems,
117
117
  isShippingRequired: this.isShippingRequired
118
- }
118
+ }))
119
119
  }
120
120
  }
121
121
 
@@ -60,24 +60,23 @@ export function sanitizeOptions(options) {
60
60
  export function validateOptions(options) {
61
61
  // TODO: validate more options
62
62
  const purchaseData = [
63
- options.jwt,
64
63
  options.items,
65
64
  options.invoiceId,
66
65
  options.money,
67
66
  options.transactionId,
68
67
  ].filter(v => v);
69
68
 
70
- if (purchaseData.length === 0) {
69
+ if (!options.jwt && purchaseData.length === 0) {
71
70
  throw new Error('Must provide purchase data');
72
71
  }
73
72
 
74
73
  if (purchaseData.length > 1) {
75
- // JWT can be alone or with specific invoiceId or transactionId
76
- if (options.jwt && (options.invoiceId || options.transactionId)) {
77
- return
78
- }
79
74
  throw new Error('Must provide only one purchase data type');
80
75
  }
76
+
77
+ if (!options.jwt && (options.invoiceId || options.transactionId)) {
78
+ throw new Error('Must provide a jwt');
79
+ }
81
80
  }
82
81
 
83
82
  export default ({
@@ -121,6 +120,7 @@ export default ({
121
120
  claims: {
122
121
  transactionId,
123
122
  invoiceId,
123
+ websiteId,
124
124
  }
125
125
  } = decodeJwt(combinedOptions.jwt);
126
126
 
@@ -133,6 +133,10 @@ export default ({
133
133
  if (invoiceId) {
134
134
  combinedOptions.invoiceId = invoiceId;
135
135
  }
136
+
137
+ if (websiteId) {
138
+ combinedOptions.websiteId = websiteId;
139
+ }
136
140
  }
137
141
 
138
142
  if (options.items) {
@@ -39,9 +39,16 @@ export default ({state = {}}) => {
39
39
 
40
40
  if (state.options.features.autoResult) {
41
41
  on({
42
- eventName: state.options.transactionType === 'setup' ?
43
- 'setup-completed' : 'purchase-completed',
42
+ eventName: 'purchase-completed',
44
43
  callback: (payload) => {
44
+ payload = JSON.parse(JSON.stringify(payload));
45
+ showResult({state, payload});
46
+ }
47
+ });
48
+ on({
49
+ eventName: 'setup-completed',
50
+ callback: (payload) => {
51
+ payload = JSON.parse(JSON.stringify(payload));
45
52
  showResult({state, payload});
46
53
  }
47
54
  });
@@ -99,12 +99,13 @@ export async function makePurchase({ payload }) {
99
99
  export function handleApprovalUrl({fields, payload}) {
100
100
  if (payload.redirectUrl || !fields.transaction?.approvalUrl) {
101
101
  const { paymentMethodsUrl } = state.options._computed;
102
+ const modelSafeFields = JSON.parse(JSON.stringify(fields));
102
103
 
103
104
  const model = {};
104
105
  if (state.data.isPayment) {
105
- model.payment = fields;
106
+ model.payment = modelSafeFields;
106
107
  } else {
107
- model.purchase = fields;
108
+ model.purchase = modelSafeFields;
108
109
  }
109
110
 
110
111
  state.data = new DataInstance({...fields});
@@ -16,6 +16,7 @@ export class ReadyToPayFeatureModel {
16
16
  // Paypal fields
17
17
  paypalMerchantId = '',
18
18
  billingAgreementToken = '',
19
+ paypalClientId = '',
19
20
 
20
21
  // Plaid fields
21
22
  linkToken = '',
@@ -31,6 +32,7 @@ export class ReadyToPayFeatureModel {
31
32
 
32
33
  this.paypalMerchantId = paypalMerchantId;
33
34
  this.billingAgreementToken = billingAgreementToken;
35
+ this.paypalClientId = paypalClientId;
34
36
 
35
37
  this.linkToken = linkToken;
36
38
  }
@@ -5,6 +5,57 @@ import { Endpoint } from './index';
5
5
  import state from '../state';
6
6
  import { mapItemsQuantities } from '../utils/quantity';
7
7
 
8
+ export function filterReadyToPay(readyToPay) {
9
+ const paymentMethodsMetadata = [...paymentMethodsFile];
10
+ const EXPRESS_METHODS = [
11
+ 'Google Pay',
12
+ 'Apple Pay',
13
+ 'paypal',
14
+ ];
15
+ const BLOCKED_METHODS = [
16
+ // account number, routing number, and account type required
17
+ 'echeck',
18
+
19
+ // payment instrument is required
20
+ // card number is required
21
+ // card cvv is required
22
+ // expiration month is required
23
+ // expiration year is required
24
+ 'Khelocard',
25
+
26
+ // Klarna authorization token is required
27
+ // Klarna session ID is required
28
+ 'Klarna',
29
+ ];
30
+ const isExpressMethod = ({ method, feature }) => (
31
+ EXPRESS_METHODS.includes(method) ||
32
+ EXPRESS_METHODS.includes(feature?.name)
33
+ );
34
+ return readyToPay
35
+ .filter(readyData => {
36
+ // Remove result for "old" paypal method
37
+ const isOldPayPal = readyData.method === 'paypal' && !readyData.feature;
38
+ // Remove result for plaid method
39
+ const isPlaid = readyData.method === 'ach' && readyData.feature;
40
+ // Remove result for blocked method
41
+ const isBlocked = BLOCKED_METHODS.includes(readyData.method)
42
+
43
+ return !isOldPayPal && !isPlaid && !isBlocked
44
+ })
45
+ .map((fields, index) => {
46
+ const metadata = paymentMethodsMetadata
47
+ .find(methodMetadata => methodMetadata.apiName === fields.method) || {};
48
+ metadata.isExpressMethod = isExpressMethod(fields);
49
+
50
+ return new ReadyToPayModel({
51
+ index,
52
+ metadata,
53
+ ...fields
54
+ });
55
+ })
56
+ .filter(({metadata}) => metadata.storefrontEnabled);
57
+ }
58
+
8
59
  export async function fetchReadyToPay({
9
60
  riskMetadata = null,
10
61
  }) {
@@ -36,22 +87,7 @@ export async function fetchReadyToPay({
36
87
 
37
88
  const { fields: readyToPayFields } = await state.storefront.purchase.readyToPay({ data });
38
89
  const readyToPay = Object.values(readyToPayFields);
39
- const paymentMethodsMetadata = [...paymentMethodsFile];
40
-
41
- return readyToPay
42
- // Remove result for "old" paypal method
43
- .filter((fields) => !(fields.method === 'paypal' && !fields.feature))
44
- // Remove Plaid payment method
45
- .filter((fields) => !(fields.method === 'ach' && fields.feature))
46
- .map((fields, index) => {
47
- const metadata = paymentMethodsMetadata
48
- .find(methodMetadata => methodMetadata.apiName === fields.method);
49
-
50
- return new ReadyToPayModel({
51
- index,
52
- metadata,
53
- ...fields
54
- });
55
- });
90
+
91
+ return filterReadyToPay(readyToPay);
56
92
  });
57
93
  }
@@ -437,8 +437,8 @@ export const vars = (theme) => `
437
437
 
438
438
  /* Methods */
439
439
  .rebilly-instruments-methods-loader-card-icon {
440
- width: 32px;
441
- height: 22px;
440
+ width: calc(var(--rebilly-fontLineHeightBase) + 10px);
441
+ height: var(--rebilly-fontLineHeightBase);
442
442
  margin-left: var(--rebilly-spacing2xs);
443
443
  margin-bottom: var(--rebilly-spacing2xs);
444
444
  }
@@ -1,6 +1,4 @@
1
1
  import Postmate from 'popostmate';
2
- import { SUPPORTED_METHODS } from '../../method-selector/get-payment-methods';
3
- import { basicLoaderHTML } from '../../../loader';
4
2
 
5
3
  export default class BaseIframe {
6
4
  constructor({
@@ -48,10 +46,6 @@ export default class BaseIframe {
48
46
  },
49
47
  };
50
48
 
51
- if (SUPPORTED_METHODS.includes(this.name)) {
52
- this.container.insertAdjacentHTML('beforeend', basicLoaderHTML);
53
- }
54
-
55
49
  const component = await new Postmate({
56
50
  name: this.name,
57
51
  url: this.url,
@@ -60,6 +60,7 @@ export function clearError() {
60
60
  }
61
61
 
62
62
  export function showError(error) {
63
+ if (!error) return;
63
64
  const errorContainer = document.querySelector('#rebilly-instruments-error');
64
65
  if (!errorContainer) return ;
65
66
 
@@ -1,28 +1,5 @@
1
1
  import state from '../../state';
2
2
 
3
- // TODO: Express methods should be filtered from RTP some how
4
- export const SUPPORTED_EXPRESS_METHODS = [
5
- 'Google Pay',
6
- 'Apple Pay',
7
- 'paypal',
8
- ];
9
-
10
- // TODO: Supported methods should be aimed to be not needed
11
- // eventually moving to a BLOCKED_METHODS
12
- export const SUPPORTED_METHODS = [
13
- 'payment-card',
14
- 'ach',
15
- 'cryptocurrency',
16
- 'bitcoin'
17
- ];
18
-
19
- const isExpressMethod = ({ method, feature }) => (
20
- SUPPORTED_EXPRESS_METHODS.includes(method) ||
21
- SUPPORTED_EXPRESS_METHODS.includes(feature?.name)
22
- );
23
-
24
- const isSupportedMethod = ({ method }) => SUPPORTED_METHODS.includes(method);
25
-
26
3
  export function getPaymentMethods() {
27
4
  const result = {
28
5
  EXPRESS_METHODS: [],
@@ -30,9 +7,9 @@ export function getPaymentMethods() {
30
7
  };
31
8
 
32
9
  state.data.readyToPay?.forEach((method) => {
33
- if (isExpressMethod(method)) {
10
+ if (method.metadata.isExpressMethod) {
34
11
  result.EXPRESS_METHODS.push(method);
35
- } else if (isSupportedMethod(method)) {
12
+ } else {
36
13
  result.METHODS.push(method);
37
14
  }
38
15
  });
@@ -1,31 +1,35 @@
1
+ import { StorefontTestingInstance } from 'tests/mocks/storefront-mock';
1
2
  import { getPaymentMethods } from './get-payment-methods';
2
- import ReadyToPayModel from '@/storefront/models/ready-to-pay-model';
3
+ import { ok, post } from 'msw-when-then';
4
+ import { when } from 'tests/msw/server';
5
+ import { storefrontURL } from 'tests/mocks/storefront-api-mock';
6
+ import { fetchReadyToPay } from '../../storefront/ready-to-pay';
3
7
  import state from 'src/state';
4
8
 
5
- it('should only return the allowed methods', () => {
6
- state.data = {
7
- readyToPay: [
8
- new ReadyToPayModel({
9
- method: 'payment-card',
10
- feature: {
11
- name: 'Google Pay',
12
- merchantName: 'google-pay-merchant-name',
13
- merchantOrigin: 'google-pay-merchant-origin'
14
- },
15
- brands: ['Visa'],
16
- filters: []
17
- }),
18
- new ReadyToPayModel({
19
- method: 'fake-method',
20
- filters: []
21
- }),
22
- new ReadyToPayModel({
23
- method: 'payment-card',
24
- brands: ['Visa'],
25
- filters: []
26
- })
27
- ]
28
- }
9
+ it('should only return the allowed methods', async () => {
10
+ StorefontTestingInstance();
11
+ when(
12
+ post(`${storefrontURL}/ready-to-pay`)
13
+ ).thenReturn(
14
+ ok([{
15
+ method: 'payment-card',
16
+ feature: {
17
+ name: 'Google Pay',
18
+ merchantName: 'google-pay-merchant-name',
19
+ merchantOrigin: 'google-pay-merchant-origin'
20
+ },
21
+ brands: ['Visa'],
22
+ filters: []
23
+ }, {
24
+ method: 'fake-method',
25
+ filters: []
26
+ }, {
27
+ method: 'payment-card',
28
+ brands: ['Visa'],
29
+ filters: []
30
+ }])
31
+ );
32
+ state.data.readyToPay = await fetchReadyToPay({});
29
33
 
30
34
  const results = getPaymentMethods();
31
35
  expect(results.hasOwnProperty('EXPRESS_METHODS')).toEqual(true);