Skip to content

Commit d264abf

Browse files
committed
feat(payment): INT-2452 Add billing and shipping for klarna
1 parent 796f23e commit d264abf

File tree

8 files changed

+111
-8
lines changed

8 files changed

+111
-8
lines changed

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

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { getKlarna } from '../../payment-methods.mock';
2121
import KlarnaCredit from './klarna-credit';
2222
import KlarnaPaymentStrategy from './klarna-payment-strategy';
2323
import KlarnaScriptLoader from './klarna-script-loader';
24-
import { getEUBillingAddress, getEUBillingAddressWithNoPhone, getKlarnaUpdateSessionParams, getKlarnaUpdateSessionParamsPhone } from './klarna.mock';
24+
import { getEUBillingAddress, getEUBillingAddressWithNoPhone, getKlarnaUpdateSessionParams, getKlarnaUpdateSessionParamsForOC, getKlarnaUpdateSessionParamsPhone, getOCBillingAddress } from './klarna.mock';
2525

2626
describe('KlarnaPaymentStrategy', () => {
2727
let initializePaymentAction: Observable<Action>;
@@ -162,6 +162,28 @@ describe('KlarnaPaymentStrategy', () => {
162162
.toHaveBeenCalledWith(getKlarnaUpdateSessionParamsPhone(), expect.any(Function));
163163
});
164164

165+
it('loads widget in OC', async () => {
166+
store = store = createCheckoutStore({
167+
...getCheckoutStoreState(),
168+
billingAddress: { data: getOCBillingAddress(), errors: {}, statuses: {} },
169+
});
170+
strategy = new KlarnaPaymentStrategy(
171+
store,
172+
orderActionCreator,
173+
paymentMethodActionCreator,
174+
remoteCheckoutActionCreator,
175+
scriptLoader
176+
);
177+
jest.spyOn(store, 'dispatch').mockReturnValue(Promise.resolve(store.getState()));
178+
jest.spyOn(store.getState().paymentMethods, 'getPaymentMethod').mockReturnValue(paymentMethodMock);
179+
180+
await strategy.initialize({ methodId: paymentMethod.id, klarna: { container: '#container' } });
181+
strategy.execute(payload);
182+
183+
expect(klarnaCredit.authorize)
184+
.toHaveBeenCalledWith(getKlarnaUpdateSessionParamsForOC(), expect.any(Function));
185+
});
186+
165187
it('loads widget in EU with no phone', async () => {
166188
store = store = createCheckoutStore({
167189
...getCheckoutStoreState(),

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { RemoteCheckoutActionCreator } from '../../../remote-checkout';
1010
import { PaymentMethodCancelledError, PaymentMethodInvalidError } from '../../errors';
1111
import PaymentMethodActionCreator from '../../payment-method-action-creator';
1212
import { PaymentInitializeOptions, PaymentRequestOptions } from '../../payment-request-options';
13+
import { supportedCountries, supportedCountriesRequiringStates } from '../klarnav2';
1314
import PaymentStrategy from '../payment-strategy';
1415

1516
import KlarnaCredit, { KlarnaAddress, KlarnaLoadResponse, KlarnaUpdateSessionParams } from './klarna-credit';
@@ -18,7 +19,6 @@ import KlarnaScriptLoader from './klarna-script-loader';
1819
export default class KlarnaPaymentStrategy implements PaymentStrategy {
1920
private _klarnaCredit?: KlarnaCredit;
2021
private _unsubscribe?: (() => void);
21-
private _supportedEUCountries = ['AT', 'DE', 'DK', 'FI', 'GB', 'NL', 'NO', 'SE', 'CH'];
2222

2323
constructor(
2424
private _store: CheckoutStore,
@@ -115,7 +115,7 @@ export default class KlarnaPaymentStrategy implements PaymentStrategy {
115115
}
116116

117117
private _getUpdateSessionData(billingAddress: BillingAddress, shippingAddress?: Address): KlarnaUpdateSessionParams {
118-
if (!includes(this._supportedEUCountries, billingAddress.countryCode)) {
118+
if (!includes([...supportedCountries, ...supportedCountriesRequiringStates], billingAddress.countryCode)) {
119119
return {};
120120
}
121121

@@ -130,6 +130,10 @@ export default class KlarnaPaymentStrategy implements PaymentStrategy {
130130
return data;
131131
}
132132

133+
private _needsStateCode(countryCode: string) {
134+
return includes(supportedCountriesRequiringStates, countryCode);
135+
}
136+
133137
private _mapToKlarnaAddress(address: Address, email?: string): KlarnaAddress {
134138
const klarnaAddress: KlarnaAddress = {
135139
street_address: address.address1,
@@ -138,7 +142,7 @@ export default class KlarnaPaymentStrategy implements PaymentStrategy {
138142
given_name: address.firstName,
139143
family_name: address.lastName,
140144
postal_code: address.postalCode,
141-
region: address.stateOrProvince,
145+
region: this._needsStateCode(address.countryCode) ? address.stateOrProvinceCode : address.stateOrProvince,
142146
email,
143147
};
144148

src/payment/strategies/klarna/klarna.mock.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ export function getEUBillingAddress(): BillingAddress {
4848
};
4949
}
5050

51+
export function getOCBillingAddress(): BillingAddress {
52+
return {
53+
...getEUBillingAddress(),
54+
countryCode: 'AU',
55+
};
56+
}
57+
5158
export function getEUBillingAddressWithNoPhone(): BillingAddress {
5259
return {
5360
id: '55c96cda6f04c',
@@ -94,3 +101,20 @@ export function getKlarnaUpdateSessionParamsPhone(): KlarnaUpdateSessionParams {
94101
},
95102
};
96103
}
104+
105+
export function getKlarnaUpdateSessionParamsForOC(): KlarnaUpdateSessionParams {
106+
return {
107+
...getKlarnaUpdateSessionParamsPhone(),
108+
billing_address: {
109+
street_address: '12345 Testing Way',
110+
city: 'Some City',
111+
country: 'AU',
112+
given_name: 'Test',
113+
family_name: 'Tester',
114+
postal_code: '95555',
115+
region: 'CA',
116+
email: 'test@bigcommerce.com',
117+
phone: '555-555-5555',
118+
},
119+
};
120+
}

src/payment/strategies/klarnav2/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ export { default as KlarnaV2PaymentStrategy } from './klarnav2-payment-strategy'
22
export { default as KlarnaV2PaymentInitializeOptions } from './klarnav2-payment-initialize-options';
33
export { default as KlarnaPayments, KlarnaLoadResponse } from './klarna-payments';
44
export { default as KlarnaV2ScriptLoader } from './klarnav2-script-loader';
5+
export { supportedCountries, supportedCountriesRequiringStates } from './klarna-supported-countries';
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export const supportedCountries = ['AT', 'DE', 'DK', 'FI', 'GB', 'NL', 'NO', 'SE', 'CH', 'NZ'];
2+
export const supportedCountriesRequiringStates = ['AU'];

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

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ import { getKlarna } from '../../payment-methods.mock';
2121
import KlarnaPayments from './klarna-payments';
2222
import KlarnaV2PaymentStrategy from './klarnav2-payment-strategy';
2323
import KlarnaV2ScriptLoader from './klarnav2-script-loader';
24-
import { getEUBillingAddress, getEUBillingAddressWithNoPhone, getEUShippingAddress, getKlarnaV2UpdateSessionParams, getKlarnaV2UpdateSessionParamsPhone } from './klarnav2.mock';
24+
import { getEUBillingAddress, getEUBillingAddressWithNoPhone, getEUShippingAddress, getKlarnaV2UpdateSessionParams, getKlarnaV2UpdateSessionParamsForOC, getKlarnaV2UpdateSessionParamsPhone, getOCBillingAddress } from './klarnav2.mock';
2525

2626
describe('KlarnaV2PaymentStrategy', () => {
2727
let initializePaymentAction: Observable<Action>;
@@ -163,6 +163,28 @@ describe('KlarnaV2PaymentStrategy', () => {
163163
.toHaveBeenCalledWith({ payment_method_category: paymentMethod.id }, getKlarnaV2UpdateSessionParamsPhone(), expect.any(Function));
164164
});
165165

166+
it('loads widget in OC', async () => {
167+
store = store = createCheckoutStore({
168+
...getCheckoutStoreState(),
169+
billingAddress: { data: getOCBillingAddress(), errors: {}, statuses: {} },
170+
});
171+
strategy = new KlarnaV2PaymentStrategy(
172+
store,
173+
orderActionCreator,
174+
paymentMethodActionCreator,
175+
remoteCheckoutActionCreator,
176+
scriptLoader
177+
);
178+
jest.spyOn(store, 'dispatch').mockReturnValue(Promise.resolve(store.getState()));
179+
jest.spyOn(store.getState().paymentMethods, 'getPaymentMethodOrThrow').mockReturnValue(paymentMethodMock);
180+
181+
await strategy.initialize({ methodId: paymentMethod.id, klarnav2: { container: '#container' } });
182+
strategy.execute(payload);
183+
184+
expect(klarnaPayments.authorize)
185+
.toHaveBeenCalledWith({ payment_method_category: paymentMethod.id }, getKlarnaV2UpdateSessionParamsForOC(), expect.any(Function));
186+
});
187+
166188
it('loads widget in EU with no phone', async () => {
167189
store = store = createCheckoutStore({
168190
...getCheckoutStoreState(),

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@ import { PaymentInitializeOptions, PaymentRequestOptions } from '../../payment-r
1313
import PaymentStrategy from '../payment-strategy';
1414

1515
import KlarnaPayments, { KlarnaAddress, KlarnaAuthorizationResponse, KlarnaLoadResponse, KlarnaUpdateSessionParams } from './klarna-payments';
16+
import { supportedCountries, supportedCountriesRequiringStates } from './klarna-supported-countries';
1617
import KlarnaV2ScriptLoader from './klarnav2-script-loader';
1718

1819
export default class KlarnaV2PaymentStrategy implements PaymentStrategy {
1920
private _klarnaPayments?: KlarnaPayments;
20-
private _supportedEUCountries = ['AT', 'DE', 'DK', 'FI', 'GB', 'NL', 'NO', 'SE', 'CH'];
2121

2222
constructor(
2323
private _store: CheckoutStore,
@@ -95,7 +95,7 @@ export default class KlarnaV2PaymentStrategy implements PaymentStrategy {
9595
}
9696

9797
private _getUpdateSessionData(billingAddress: BillingAddress, shippingAddress?: Address): KlarnaUpdateSessionParams {
98-
if (!includes(this._supportedEUCountries, billingAddress.countryCode)) {
98+
if (!includes([...supportedCountries, ...supportedCountriesRequiringStates], billingAddress.countryCode)) {
9999
return {};
100100
}
101101

@@ -110,6 +110,10 @@ export default class KlarnaV2PaymentStrategy implements PaymentStrategy {
110110
return data;
111111
}
112112

113+
private _needsStateCode(countryCode: string) {
114+
return includes(supportedCountriesRequiringStates, countryCode);
115+
}
116+
113117
private _mapToKlarnaAddress(address: Address, email?: string): KlarnaAddress {
114118
const klarnaAddress: KlarnaAddress = {
115119
street_address: address.address1,
@@ -118,7 +122,7 @@ export default class KlarnaV2PaymentStrategy implements PaymentStrategy {
118122
given_name: address.firstName,
119123
family_name: address.lastName,
120124
postal_code: address.postalCode,
121-
region: address.stateOrProvince,
125+
region: this._needsStateCode(address.countryCode) ? address.stateOrProvinceCode : address.stateOrProvince,
122126
email,
123127
};
124128

src/payment/strategies/klarnav2/klarnav2.mock.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,13 @@ export function getEUBillingAddress(): BillingAddress {
4949
};
5050
}
5151

52+
export function getOCBillingAddress(): BillingAddress {
53+
return {
54+
...getEUBillingAddress(),
55+
countryCode: 'AU',
56+
};
57+
}
58+
5259
export function getEUBillingAddressWithNoPhone(): BillingAddress {
5360
return {
5461
id: '55c96cda6f04c',
@@ -113,3 +120,20 @@ export function getKlarnaV2UpdateSessionParamsPhone(): KlarnaUpdateSessionParams
113120
},
114121
};
115122
}
123+
124+
export function getKlarnaV2UpdateSessionParamsForOC(): KlarnaUpdateSessionParams {
125+
return {
126+
...getKlarnaV2UpdateSessionParamsPhone(),
127+
billing_address: {
128+
street_address: '12345 Testing Way',
129+
city: 'Some City',
130+
country: 'AU',
131+
given_name: 'Test',
132+
family_name: 'Tester',
133+
postal_code: '95555',
134+
region: 'CA',
135+
email: 'test@bigcommerce.com',
136+
phone: '555-555-5555',
137+
},
138+
};
139+
}

0 commit comments

Comments
 (0)