Skip to content

Commit 8f134e8

Browse files
committed
feat(payment): PAYMENTS-2744 Updating Afterpay to support US and NZ customers.
1 parent e6449db commit 8f134e8

File tree

5 files changed

+95
-20
lines changed

5 files changed

+95
-20
lines changed

src/payment/strategies/afterpay-payment-strategy.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ describe('AfterpayPaymentStrategy', () => {
4646
let verifyCartAction: Observable<Action>;
4747

4848
const afterpaySdk = {
49-
init: () => {},
49+
initialize: () => {},
5050
display: () => {},
5151
};
5252

@@ -120,15 +120,15 @@ describe('AfterpayPaymentStrategy', () => {
120120
jest.spyOn(scriptLoader, 'load')
121121
.mockReturnValue(Promise.resolve(afterpaySdk));
122122

123-
jest.spyOn(afterpaySdk, 'init').mockImplementation(() => {});
123+
jest.spyOn(afterpaySdk, 'initialize').mockImplementation(() => {});
124124
jest.spyOn(afterpaySdk, 'display').mockImplementation(() => {});
125125
});
126126

127127
describe('#initialize()', () => {
128128
it('loads script when initializing strategy', async () => {
129129
await strategy.initialize({ methodId: paymentMethod.id, gatewayId: paymentMethod.gateway });
130130

131-
expect(scriptLoader.load).toHaveBeenCalledWith(paymentMethod);
131+
expect(scriptLoader.load).toHaveBeenCalledWith(paymentMethod, 'US');
132132
});
133133
});
134134

@@ -144,7 +144,7 @@ describe('AfterpayPaymentStrategy', () => {
144144
});
145145

146146
it('displays the afterpay modal', () => {
147-
expect(afterpaySdk.init).toHaveBeenCalled();
147+
expect(afterpaySdk.initialize).toHaveBeenCalledWith({ countryCode: 'US' });
148148
expect(afterpaySdk.display).toHaveBeenCalledWith({ token: paymentMethod.clientToken });
149149
});
150150

src/payment/strategies/afterpay-payment-strategy.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,14 @@ export default class AfterpayPaymentStrategy extends PaymentStrategy {
3333

3434
const state = this._store.getState();
3535
const paymentMethod = state.paymentMethods.getPaymentMethod(options.methodId, options.gatewayId);
36+
const config = state.config.getStoreConfig();
37+
const storeCountryName = config ? config.storeProfile.storeCountry : '';
3638

3739
if (!paymentMethod) {
3840
throw new MissingDataError(`Unable to initialize because "paymentMethod (${options.methodId})" data is missing.`);
3941
}
4042

41-
return this._afterpayScriptLoader.load(paymentMethod)
43+
return this._afterpayScriptLoader.load(paymentMethod, this._mapCountryToISO2(storeCountryName))
4244
.then(afterpaySdk => {
4345
this._afterpaySdk = afterpaySdk;
4446
})
@@ -66,6 +68,9 @@ export default class AfterpayPaymentStrategy extends PaymentStrategy {
6668

6769
const useStoreCredit = !!payload.useStoreCredit;
6870
const customerMessage = payload.customerMessage ? payload.customerMessage : '';
71+
const state = this._store.getState();
72+
const config = state.config.getStoreConfig();
73+
const storeCountryName = config ? config.storeProfile.storeCountry : '';
6974

7075
return this._store.dispatch(
7176
this._remoteCheckoutActionCreator.initializePayment(paymentId, { useStoreCredit, customerMessage })
@@ -76,7 +81,7 @@ export default class AfterpayPaymentStrategy extends PaymentStrategy {
7681
.then(() => this._store.dispatch(
7782
this._paymentMethodActionCreator.loadPaymentMethod(paymentId, options)
7883
))
79-
.then(state => this._displayModal(state.paymentMethods.getPaymentMethod(paymentId)))
84+
.then(state => this._displayModal(storeCountryName, state.paymentMethods.getPaymentMethod(paymentId)))
8085
// Afterpay will handle the rest of the flow so return a promise that doesn't really resolve
8186
.then(() => new Promise<never>(() => {}));
8287
}
@@ -106,12 +111,25 @@ export default class AfterpayPaymentStrategy extends PaymentStrategy {
106111
);
107112
}
108113

109-
private _displayModal(paymentMethod?: PaymentMethod): void {
114+
private _displayModal(countryName: string, paymentMethod?: PaymentMethod): void {
110115
if (!this._afterpaySdk || !paymentMethod || !paymentMethod.clientToken) {
111116
throw new NotInitializedError('Unable to display payment modal because payment method has not been initialized.');
112117
}
113118

114-
this._afterpaySdk.init();
119+
this._afterpaySdk.initialize({ countryCode: this._mapCountryToISO2(countryName)});
115120
this._afterpaySdk.display({ token: paymentMethod.clientToken });
116121
}
122+
123+
private _mapCountryToISO2(countryName: string): string {
124+
switch (countryName) {
125+
case 'Australia':
126+
return 'AU';
127+
case 'New Zealand':
128+
return 'NZ';
129+
case 'United States':
130+
return 'US';
131+
default:
132+
return 'AU';
133+
}
134+
}
117135
}

src/remote-checkout/methods/afterpay/afterpay-script-loader.spec.ts

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,55 @@ describe('AfterpayScriptLoader', () => {
1414
.mockReturnValue(Promise.resolve(new Event('load')));
1515
});
1616

17-
it('loads widget script', () => {
17+
it('loads widget script for AU & NZ', () => {
1818
const method = getAfterpay();
1919

20-
afterpayScriptLoader.load(method);
20+
afterpayScriptLoader.load(method, 'AU');
2121

2222
expect(scriptLoader.loadScript).toHaveBeenCalledWith(
23-
'//www.secure-afterpay.com.au/afterpay-async.js'
23+
'//portal.afterpay.com/afterpay-async.js'
24+
);
25+
26+
afterpayScriptLoader.load(method, 'NZ');
27+
28+
expect(scriptLoader.loadScript).toHaveBeenCalledWith(
29+
'//portal.afterpay.com/afterpay-async.js'
30+
);
31+
});
32+
33+
it('loads sandbox widget script if in test mode for AU & NZ', () => {
34+
const method = merge({}, getAfterpay(), { config: { testMode: true } });
35+
36+
afterpayScriptLoader.load(method, 'AU');
37+
38+
expect(scriptLoader.loadScript).toHaveBeenCalledWith(
39+
'//portal-sandbox.afterpay.com/afterpay-async.js'
40+
);
41+
42+
afterpayScriptLoader.load(method, 'NZ');
43+
44+
expect(scriptLoader.loadScript).toHaveBeenCalledWith(
45+
'//portal-sandbox.afterpay.com/afterpay-async.js'
46+
);
47+
});
48+
49+
it('loads widget script for US', () => {
50+
const method = getAfterpay();
51+
52+
afterpayScriptLoader.load(method, 'US');
53+
54+
expect(scriptLoader.loadScript).toHaveBeenCalledWith(
55+
'//portal.afterpay.com/afterpay-async.js'
2456
);
2557
});
2658

27-
it('loads sandbox widget script if in test mode', () => {
59+
it('loads sandbox widget script if in test mode for US', () => {
2860
const method = merge({}, getAfterpay(), { config: { testMode: true } });
2961

30-
afterpayScriptLoader.load(method);
62+
afterpayScriptLoader.load(method, 'US');
3163

3264
expect(scriptLoader.loadScript).toHaveBeenCalledWith(
33-
'//www-sandbox.secure-afterpay.com.au/afterpay-async.js'
65+
'//portal.us-sandbox.afterpay.com/afterpay-async.js'
3466
);
3567
});
3668
});

src/remote-checkout/methods/afterpay/afterpay-script-loader.ts

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,20 @@ import { PaymentMethod } from '../../../payment';
55
import AfterpaySdk from './afterpay-sdk';
66
import AfterpayWindow from './afterpay-window';
77

8-
const SCRIPT_PROD = '//www.secure-afterpay.com.au/afterpay-async.js';
9-
const SCRIPT_SANDBOX = '//www-sandbox.secure-afterpay.com.au/afterpay-async.js';
8+
interface AfterpayScripts {
9+
PROD: string;
10+
SANDBOX: string;
11+
}
12+
13+
const SCRIPTS_DEFAULT: AfterpayScripts = {
14+
PROD: '//portal.afterpay.com/afterpay-async.js',
15+
SANDBOX: '//portal-sandbox.afterpay.com/afterpay-async.js',
16+
};
17+
18+
const SCRIPTS_US: AfterpayScripts = {
19+
PROD: '//portal.afterpay.com/afterpay-async.js',
20+
SANDBOX: '//portal.us-sandbox.afterpay.com/afterpay-async.js',
21+
};
1022

1123
/** Class responsible for loading the Afterpay SDK */
1224
export default class AfterpayScriptLoader {
@@ -18,11 +30,20 @@ export default class AfterpayScriptLoader {
1830
* Loads the appropriate Afterpay SDK depending on the payment method data.
1931
* @param method the payment method data
2032
*/
21-
load(method: PaymentMethod): Promise<AfterpaySdk> {
22-
const testMode = method.config.testMode;
23-
const scriptURI = testMode ? SCRIPT_SANDBOX : SCRIPT_PROD;
33+
load(method: PaymentMethod, countryCode: string): Promise<AfterpaySdk> {
34+
const testMode = method.config.testMode || false;
35+
const scriptURI = this._getScriptURI(countryCode, testMode);
2436

2537
return this._scriptLoader.loadScript(scriptURI)
2638
.then(() => (window as AfterpayWindow).AfterPay);
2739
}
40+
41+
private _getScriptURI(countryCode: string, testMode: boolean): string {
42+
if (countryCode === 'US') {
43+
return testMode ? SCRIPTS_US.SANDBOX : SCRIPTS_US.PROD;
44+
}
45+
46+
return testMode ? SCRIPTS_DEFAULT.SANDBOX : SCRIPTS_DEFAULT.PROD;
47+
}
48+
2849
}
Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
export default interface AfterpaySdk {
2-
init(): void;
2+
initialize(options: AfterpayInitializeOptions): void;
33
display(options: AfterpayDisplayOptions): void;
44
}
55

66
export interface AfterpayDisplayOptions {
77
token: string;
88
}
9+
10+
export interface AfterpayInitializeOptions {
11+
countryCode: string;
12+
}

0 commit comments

Comments
 (0)