Merge branch 'main' into feat/installment-currency-config

This commit is contained in:
Ayush Anand
2026-03-12 17:46:33 +05:30
committed by GitHub
11 changed files with 652 additions and 1 deletions

View File

@@ -0,0 +1,108 @@
import * as fixtures from "../../../fixtures/imports";
import State from "../../../utils/State";
import { payment_methods_enabled } from "../../configs/Payment/Commons";
let globalState;
describe("Core flows", () => {
context("Modular Payment Method core flows", () => {
before("seed global state", () => {
cy.task("getGlobalState").then((state) => {
globalState = new State(state);
});
});
after("flush global state", () => {
cy.task("setGlobalState", globalState.data);
});
it("merchant create call", () => {
cy.merchantCreateCallTest(fixtures.merchantCreateBody, globalState);
});
it("API key create call", () => {
cy.apiKeyCreateTest(fixtures.apiKeyCreateBody, globalState);
});
it("Connector create call", () => {
cy.createConnectorCallTest(
"payment_processor",
fixtures.createConnectorBody,
payment_methods_enabled,
globalState
);
});
it("Modular PM Service - Customer create call", () => {
cy.customerCreateCall(globalState, fixtures.customerCreate);
});
it("Modular PM Service - Merchant Config create call", () => {
const key = `should_return_raw_payment_method_details_${globalState.get("merchantId")}`;
cy.setConfigs(globalState, key, "true", "CREATE");
});
it("Modular PM Service - Organization Config create call", () => {
const key = `should_call_pm_modular_service_${globalState.get("organizationId")}`;
cy.setConfigs(globalState, key, "true", "CREATE");
});
it("Modular PM Service - Payment Method Create call", () => {
cy.paymentMethodCreateCall(globalState, fixtures.paymentMethodCreate);
});
it("Modular PM Service - Payments call with pm_id", () => {
cy.paymentWithSavedPMCall(
globalState,
fixtures.modularPmServicePaymentsCall
);
});
it("Modular PM Service - Update Payment Method call", () => {
cy.updateSavedPMCall(globalState, fixtures.paymentMethodUpdate);
});
it("Modular PM Service - Payment Method List call", () => {
cy.listSavedPMCall(globalState);
});
it("Modular PM Service - Payment Method Session Create call", () => {
cy.pmSessionCreateCall(globalState, fixtures.paymentMethodSessionCreate);
});
it("Modular PM Service - Payment Method Session Retrieve call", () => {
cy.pmSessionRetrieveCall(globalState);
});
it("Modular PM Service - Payment Method Session List call", () => {
cy.pmSessionListPMCall(globalState);
});
it("Modular PM Service - Payment Method Session Update call", () => {
cy.pmSessionUpdatePMCall(
globalState,
fixtures.paymentMethodSessionUpdate
);
});
it("Modular PM Service - Payment Method Session Confirm call", () => {
cy.pmSessionConfirmCall(
globalState,
fixtures.paymentMethodSessionConfirm
);
});
it("Modular PM Service - Get Payment Method from session token call", () => {
cy.getPMFromTokenCall(globalState);
});
it("Modular PM Service - Payments call with pm_token", () => {
cy.paymentWithSavedPMCall(
globalState,
fixtures.modularPmServicePaymentsCall,
true
);
});
});
});

View File

@@ -27,7 +27,13 @@ import ntidConfirmBody from "./create-ntid-mit.json";
import blocklistCreateBody from "./blocklist-create-body.json";
import eligibilityCheckBody from "./eligibility-check-body.json";
import * as IncomingWebhookBody from "./webhooks/import";
import customerCreate from "./modularPmService/modularPmServiceCustomerCreate.json";
import paymentMethodCreate from "./modularPmService/modular-pm-service-pm-create.json";
import paymentMethodUpdate from "./modularPmService/modular-pm-service-pm-update.json";
import paymentMethodSessionCreate from "./modularPmService/modular-pm-service-pms-create.json";
import paymentMethodSessionUpdate from "./modularPmService/modular-pm-service-update-pms-saved-pm.json";
import paymentMethodSessionConfirm from "./modularPmService/modular-pm-service-pms-confim.json";
import modularPmServicePaymentsCall from "./modularPmService/modular-pm-service-payments-call.json";
export {
apiKeyCreateBody,
apiKeyUpdateBody,
@@ -58,4 +64,11 @@ export {
updateConnectorBody,
voidBody,
IncomingWebhookBody,
customerCreate,
paymentMethodCreate,
paymentMethodUpdate,
paymentMethodSessionCreate,
paymentMethodSessionUpdate,
paymentMethodSessionConfirm,
modularPmServicePaymentsCall,
};

View File

@@ -0,0 +1,68 @@
{
"amount": 200,
"currency": "USD",
"confirm": true,
"capture_method": "automatic",
"capture_on": "2022-09-10T10:11:12Z",
"email": "guest@example.com",
"name": "John Doe",
"phone": "999999999",
"phone_country_code": "+65",
"description": "Its my first payment request",
"authentication_type": "no_three_ds",
"return_url": "https://google.com",
"payment_method": "card",
"billing": {
"address": {
"line1": "1467",
"line2": "Harrison Street",
"line3": "Harrison Street",
"city": "San Fransico",
"state": "California",
"zip": "94122",
"country": "US",
"first_name": "PiX",
"last_name": "ss"
}
},
"shipping": {
"address": {
"line1": "1467",
"line2": "Harrison Street",
"line3": "Harrison Street",
"city": "San Fransico",
"state": "California",
"zip": "94122",
"country": "US",
"first_name": "John",
"last_name": "Doe"
},
"phone": {
"number": "8056594427",
"country_code": "+91"
}
},
"browser_info": {
"user_agent": "Mozilla\/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit\/537.36 (KHTML, like Gecko) Chrome\/70.0.3538.110 Safari\/537.36",
"accept_header": "text\/html,application\/xhtml+xml,application\/xml;q=0.9,image\/webp,image\/apng,*\/*;q=0.8",
"language": "nl-NL",
"color_depth": 24,
"screen_height": 723,
"screen_width": 1536,
"time_zone": 0,
"java_enabled": true,
"java_script_enabled": true,
"ip_address": "125.0.0.1"
},
"statement_descriptor_name": "joseph",
"statement_descriptor_suffix": "JS",
"metadata": {},
"order_details": [
{
"product_name": "Apple iphone 15",
"quantity": 1,
"amount": 0,
"account_name": "transaction_processing"
}
]
}

View File

@@ -0,0 +1,15 @@
{
"payment_method_type": "card",
"payment_method_subtype": "credit",
"payment_method_data": {
"card": {
"card_number": "4761360080000093",
"card_exp_month": "07",
"card_exp_year": "2030",
"card_holder_name": "Gaurav rawat",
"card_cvc": "123",
"nick_name": "abcd"
}
},
"storage_type": "persistent"
}

View File

@@ -0,0 +1,7 @@
{
"payment_method_data": {
"card": {
"card_cvc": "123"
}
}
}

View File

@@ -0,0 +1,13 @@
{
"payment_method_data": {
"card": {
"card_number": "4242424242424242",
"card_exp_month": "01",
"card_exp_year": "27",
"card_holder_name": "John Doe",
"card_cvc": "100"
}
},
"payment_method_type": "card",
"payment_method_subtype": "credit"
}

View File

@@ -0,0 +1,11 @@
{
"billing": {
"address": {
"first_name": "John",
"last_name": "Dough"
},
"email": "example@example.com"
},
"storage_type": "persistent",
"keep_alive": true
}

View File

@@ -0,0 +1,7 @@
{
"payment_method_data": {
"card": {
"card_holder_name": "Gaurav Rawat"
}
}
}

View File

@@ -0,0 +1,35 @@
{
"merchant_reference_id": "customer_1771243192",
"name": "John Doe",
"email": "guest@example.com",
"phone": "999999999",
"phone_country_code": "+65",
"description": "First customer",
"default_billing_address": {
"line1": "1467",
"line2": "Harrison Street",
"line3": "Harrison Street",
"city": "San Fransico",
"state": "California",
"zip": "94122",
"country": "US",
"first_name": "joseph",
"last_name": "Doe"
},
"default_shipping_address": {
"line1": "1467",
"line2": "Harrison Street",
"line3": "Harrison Street",
"city": "San Fransico",
"state": "California",
"zip": "94122",
"country": "US",
"first_name": "joseph",
"last_name": "Doe"
},
"metadata": {
"udf1": "value1",
"new_customer": "true",
"login_date": "2019-09-10T10:11:12Z"
}
}

View File

@@ -480,6 +480,7 @@ Cypress.Commands.add(
globalState.set("profileId", response.body.default_profile);
globalState.set("publishableKey", response.body.publishable_key);
globalState.set("merchantDetails", response.body.merchant_details);
globalState.set("organizationId", response.body.organization_id);
});
});
}
@@ -5211,6 +5212,378 @@ Cypress.Commands.add("IncomingWebhookTest", (globalState, webhookPayload) => {
});
});
Cypress.Commands.add(
"customerCreateCall",
(globalState, customerCreateBody) => {
const reqData = { ...customerCreateBody };
reqData.merchant_reference_id = `customer_${Date.now()}`;
cy.request({
method: "POST",
url: `${globalState.get("pmServiceUrl")}/v1/customers`,
headers: {
"Content-Type": "application/json",
Authorization: `api-key=${globalState.get("apiKey")}`,
"x-profile-id": globalState.get("profileId"),
},
body: reqData,
failOnStatusCode: false,
}).then((response) => {
if (response.status === 200) {
globalState.set("customerId", response.body.id);
expect(response.body.id, "customer_id").to.not.be.empty;
expect(customerCreateBody.email, "email").to.equal(response.body.email);
expect(customerCreateBody.name, "name").to.equal(response.body.name);
expect(customerCreateBody.phone, "phone").to.equal(response.body.phone);
expect(customerCreateBody.metadata, "metadata").to.deep.equal(
response.body.metadata
);
expect(customerCreateBody.address, "address").to.deep.equal(
response.body.address
);
expect(
customerCreateBody.phone_country_code,
"phone_country_code"
).to.equal(response.body.phone_country_code);
} else if (response.status === 400) {
if (response.body.error.message.includes("already exists")) {
expect(response.body.error.code).to.equal("IR_12");
expect(response.body.error.message).to.equal(
"Customer with the given `customer_id` already exists"
);
}
} else {
throw new Error(
`Customer create call failed with status: ${response.status} and message: ${response.body?.error?.message}`
);
}
});
}
);
// Payment Methods Commands (v2 code - port 8082)
Cypress.Commands.add("paymentMethodCreateCall", (globalState, pmData) => {
const apiKey = globalState.get("apiKey");
const profileId = globalState.get("profileId");
const customerId = globalState.get("customerId");
const requestBody = {
...pmData,
customer_id: customerId,
};
cy.request({
method: "POST",
url: `${globalState.get("pmServiceUrl")}/v1/payment-methods`,
headers: {
"Content-Type": "application/json",
Accept: "application/json",
"X-Profile-Id": profileId,
Authorization: `api-key=${apiKey}`,
},
body: requestBody,
failOnStatusCode: false,
}).then((response) => {
if (response.status === 200) {
globalState.set("paymentMethodId", response.body.id);
expect(requestBody.customer_id, "customer_id").to.equal(
response.body.customer_id
);
expect(requestBody.payment_method_type, "payment_method_type").to.equal(
response.body.payment_method_type
);
expect(
requestBody.payment_method_subtype,
"payment_method_subtype"
).to.equal(response.body.payment_method_subtype);
expect(requestBody.storage_type, "storage_type").to.equal(
response.body.storage_type
);
} else {
throw new Error(
`Payment method create failed with status ${response.status}: ${JSON.stringify(response.body)}`
);
}
});
});
Cypress.Commands.add("updateSavedPMCall", (globalState, updateData) => {
const apiKey = globalState.get("apiKey");
const profileId = globalState.get("profileId");
const paymentMethodId = globalState.get("paymentMethodId");
cy.request({
method: "PUT",
url: `${globalState.get("pmServiceUrl")}/v1/payment-methods/${paymentMethodId}/update-saved-payment-method`,
headers: {
"Content-Type": "application/json",
Accept: "application/json",
"X-Profile-Id": profileId,
"X-Resource-Type": "payment_method",
Authorization: `api-key=${apiKey}`,
},
body: updateData,
failOnStatusCode: false,
}).then((response) => {
if (response.status === 200) {
expect(response.body).to.have.property("id");
} else {
throw new Error(
`Update saved PM failed with status ${response.status}: ${JSON.stringify(response.body)}`
);
}
});
});
Cypress.Commands.add("listSavedPMCall", (globalState) => {
const apiKey = globalState.get("apiKey");
const profileId = globalState.get("profileId");
const customerId = globalState.get("customerId");
cy.request({
method: "GET",
url: `${globalState.get("pmServiceUrl")}/v1/customers/${customerId}/saved-payment-methods`,
headers: {
"Content-Type": "application/json",
"x-profile-id": profileId,
Authorization: `api-key=${apiKey}`,
},
failOnStatusCode: false,
}).then((response) => {
if (response.status === 200) {
expect(response.body.customer_payment_methods).to.be.an("array");
} else {
throw new Error(
`List saved PM failed with status ${response.status}: ${JSON.stringify(response.body)}`
);
}
});
});
// Payment Method Session Commands (v2 code - port 8082)
Cypress.Commands.add("pmSessionCreateCall", (globalState, sessionData) => {
const apiKey = globalState.get("apiKey");
const profileId = globalState.get("profileId");
const customerId = globalState.get("customerId");
const requestBody = {
...sessionData,
customer_id: customerId,
};
cy.request({
method: "POST",
url: `${globalState.get("pmServiceUrl")}/v1/payment-method-sessions`,
headers: {
"Content-Type": "application/json",
"x-profile-id": profileId,
Authorization: `api-key=${apiKey}`,
},
body: requestBody,
failOnStatusCode: false,
}).then((response) => {
if (response.status === 200) {
globalState.set("paymentMethodSessionId", response.body.id);
globalState.set("clientSecret", response.body.client_secret);
expect(response.body).to.have.property("id");
expect(response.body).to.have.property("client_secret");
} else {
throw new Error(
`PM session create failed with status ${response.status}: ${JSON.stringify(response.body)}`
);
}
});
});
Cypress.Commands.add("pmSessionRetrieveCall", (globalState) => {
const profileId = globalState.get("profileId");
const sessionId = globalState.get("paymentMethodSessionId");
const publishableKey = globalState.get("publishableKey");
const clientSecret = globalState.get("clientSecret");
cy.request({
method: "GET",
url: `${globalState.get("pmServiceUrl")}/v1/payment-method-sessions/${sessionId}`,
headers: {
"x-profile-id": profileId,
Authorization: `publishable-key=${publishableKey},client-secret=${clientSecret}`,
},
failOnStatusCode: false,
}).then((response) => {
if (response.status === 200) {
expect(response.body).to.have.property("id");
} else {
throw new Error(
`PM session retrieve failed with status ${response.status}: ${JSON.stringify(response.body)}`
);
}
});
});
Cypress.Commands.add("pmSessionListPMCall", (globalState) => {
const profileId = globalState.get("profileId");
const sessionId = globalState.get("paymentMethodSessionId");
const publishableKey = globalState.get("publishableKey");
const clientSecret = globalState.get("clientSecret");
cy.request({
method: "GET",
url: `${globalState.get("pmServiceUrl")}/v1/payment-method-sessions/${sessionId}/list-payment-methods`,
headers: {
"x-profile-id": profileId,
Authorization: `publishable-key=${publishableKey},client-secret=${clientSecret}`,
},
failOnStatusCode: false,
}).then((response) => {
if (response.status === 200) {
globalState.set(
"paymentMethodToken",
response.body.customer_payment_methods[0].payment_method_token
);
} else {
throw new Error(
`PM session list PM failed with status ${response.status}: ${JSON.stringify(response.body)}`
);
}
});
});
Cypress.Commands.add("pmSessionUpdatePMCall", (globalState, updateData) => {
const profileId = globalState.get("profileId");
const sessionId = globalState.get("paymentMethodSessionId");
const publishableKey = globalState.get("publishableKey");
const clientSecret = globalState.get("clientSecret");
const payment_method_token = globalState.get("paymentMethodToken");
if (!payment_method_token) {
throw new Error("Payment method token is required for PM session update");
}
const req_body = {
...updateData,
payment_method_token,
};
cy.request({
method: "PUT",
url: `${globalState.get("pmServiceUrl")}/v1/payment-method-sessions/${sessionId}/update-saved-payment-method`,
headers: {
"Content-Type": "application/json",
"x-profile-id": profileId,
Authorization: `publishable-key=${publishableKey},client-secret=${clientSecret}`,
},
body: req_body,
failOnStatusCode: false,
}).then((response) => {
if (response.status === 200) {
expect(response.body).to.have.property("id");
} else {
throw new Error(
`PM session update PM failed with status ${response.status}: ${JSON.stringify(response.body)}`
);
}
});
});
Cypress.Commands.add("pmSessionConfirmCall", (globalState, confirmData) => {
const profileId = globalState.get("profileId");
const sessionId = globalState.get("paymentMethodSessionId");
const publishableKey = globalState.get("publishableKey");
const clientSecret = globalState.get("clientSecret");
cy.request({
method: "POST",
url: `${globalState.get("pmServiceUrl")}/v1/payment-method-sessions/${sessionId}/confirm`,
headers: {
"Content-Type": "application/json",
"x-profile-id": profileId,
Authorization: `publishable-key=${publishableKey},client-secret=${clientSecret}`,
},
body: confirmData,
failOnStatusCode: false,
}).then((response) => {
if (response.status === 200) {
globalState.set(
"paymentMethodToken",
response.body.associated_payment_methods[0].payment_method_token.data
);
expect(response.body).to.have.property("id");
} else {
throw new Error(
`PM session confirm failed with status ${response.status}: ${JSON.stringify(response.body)}`
);
}
});
});
Cypress.Commands.add("getPMFromTokenCall", (globalState) => {
const apiKey = globalState.get("apiKey");
const profileId = globalState.get("profileId");
const paymentMethodToken = globalState.get("paymentMethodToken");
cy.request({
method: "GET",
url: `${globalState.get("pmServiceUrl")}/v1/payment-methods/token/${paymentMethodToken}/details`,
headers: {
"Content-Type": "application/json",
"x-profile-id": profileId,
Authorization: `api-key=${apiKey}`,
},
failOnStatusCode: false,
}).then((response) => {
if (response.status === 200) {
expect(response.body).to.have.property("id");
} else {
throw new Error(
`Get PM from token failed with status ${response.status}: ${JSON.stringify(response.body)}`
);
}
});
});
Cypress.Commands.add(
"paymentWithSavedPMCall",
(globalState, paymentData, useToken = false) => {
const baseUrl = globalState.get("baseUrl");
const apiKey = globalState.get("apiKey");
const customerId = globalState.get("customerId");
const profileId = globalState.get("profileId");
const requestBody = {
...paymentData,
customer_id: customerId,
profile_id: profileId,
payment_token: useToken
? globalState.get("paymentMethodToken")
: globalState.get("paymentMethodId"),
};
cy.request({
method: "POST",
url: `${baseUrl}/payments`,
headers: {
"Content-Type": "application/json",
"api-key": apiKey,
},
body: requestBody,
failOnStatusCode: false,
}).then((response) => {
if (response.status === 200) {
globalState.set("paymentId", response.body.payment_id);
expect(response.body).to.have.property("payment_id");
expect(response.body).to.have.property("status");
expect(response.body.amount).to.equal(paymentData.amount);
expect(response.body.currency).to.equal(paymentData.currency);
} else {
throw new Error(
`Payment with saved PM failed with status ${response.status}: ${JSON.stringify(response.body)}`
);
}
});
}
);
Cypress.Commands.add("step", (stepName, fn) => {
cy.task("cli_log", `\nSTEP: ${stepName}`);

View File

@@ -4,6 +4,7 @@ class State {
this.data = data;
this.data["connectorId"] = Cypress.env("CONNECTOR");
this.data["baseUrl"] = Cypress.env("BASEURL");
this.data["pmServiceUrl"] = Cypress.env("PM_SERVICE_URL");
this.data["adminApiKey"] = Cypress.env("ADMINAPIKEY");
this.data["email"] = Cypress.env("HS_EMAIL");
this.data["password"] = Cypress.env("HS_PASSWORD");