Skip to content

Commit

Permalink
Add support for 3DS Session exception (#365)
Browse files Browse the repository at this point in the history
Our 3DS Session API supports an `exception` field to specify the
exception used to opt out of authenticating the payment with the card
issuer. This PR adds support for that field when the session is
initialised by the Card Component.
  • Loading branch information
stevedomin authored Jan 8, 2025
1 parent 3121942 commit 276e54d
Show file tree
Hide file tree
Showing 4 changed files with 19 additions and 1 deletion.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@duffel/components",
"version": "3.7.26",
"version": "3.7.27",
"description": "Component library to build your travel product with Duffel.",
"keywords": [
"Duffel",
Expand Down
1 change: 1 addition & 0 deletions src/functions/createThreeDSecureSession/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ interface create3DSSessionPayload {
resource_id: string;
services?: Array<Service>;
cardholder_present: boolean;
exception: string;
}

export const createClient = (duffelUrl: string, clientKey: string) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@ const DEFAULT_ENVIRONMENT_CONFIGURATION = {
* @param resourceId - The resource (offer, order, order change) ID that the 3DS session is for.
* @param services - Include all services that are being added, empty if no services are being added. This is required when services are also being purchased to ensure an accurate total amount to be authorised. If no services, it should be an empty array.
* @param cardholderPresent - Whether the cardholder was present when the 3DS session was created. If you are collecting card details offline, for example an agent interface for entering card details received from the traveller over the phone, then you must specify the cardholder as not present
* @param exception - The name of the exception used to opt out of authenticating the payment with the card issuer
*/
type CreateThreeDSecureSessionFn = (
clientKey: string,
cardId: string,
resourceId: string,
services: Array<{ id: string; quantity: number }>,
cardholderPresent: boolean,
exception?: string,
environmentConfiguration?: Partial<typeof DEFAULT_ENVIRONMENT_CONFIGURATION>,
) => Promise<ThreeDSecureSession>;

Expand All @@ -40,6 +42,7 @@ export const createThreeDSecureSession: CreateThreeDSecureSessionFn = async (
resourceId,
services,
cardholderPresent,
exception = "",
environmentConfiguration = {},
) => {
const env: typeof DEFAULT_ENVIRONMENT_CONFIGURATION = {
Expand All @@ -60,6 +63,7 @@ export const createThreeDSecureSession: CreateThreeDSecureSessionFn = async (
resource_id: resourceId,
services: services,
cardholder_present: cardholderPresent,
exception: exception,
})
.then((threeDSSession) => {
if (!threeDSSession) {
Expand Down
13 changes: 13 additions & 0 deletions src/tests/functions/createThreeDSecureSession.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,19 @@ describe("createThreeDSecureSession", () => {
expect(result.status).toEqual("ready_for_payment");
});

it("successfully returns 3DS session without challenge when passing exception", async () => {
const result = await createThreeDSecureSession(
clientKey,
tokenisedCardId,
"off_readyforpayment",
services,
cardholderPresent,
"secure_corporate_payment",
);

expect(result.status).toEqual("ready_for_payment");
});

it("successfully returns 3DS session with challenge", async () => {
setTimeout(() => {
const callback = mockOn.mock.calls.find(
Expand Down

0 comments on commit 276e54d

Please sign in to comment.