mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-26 18:42:49 +00:00
fix(cbe): update response for settled transactions to indicate Already paid
This commit is contained in:
@@ -184,24 +184,12 @@ export class CbeBillService {
|
|||||||
);
|
);
|
||||||
if (prior) {
|
if (prior) {
|
||||||
if (prior.tradeStatus === "SUCCESS") {
|
if (prior.tradeStatus === "SUCCESS") {
|
||||||
// A replay must be the SAME attempt. A reused id with different money details is
|
// Per CBE integration request: a settled End_To_End_Txn_Id never replays the stored
|
||||||
// not a retry — echoing the stored success would fake a settlement that never ran.
|
// success — every repeat answers "Already paid". Money moved exactly once (the first
|
||||||
const orig = prior.requestPayload as unknown as
|
// call); this only changes what a duplicate hears back. NOTE this diverges from the
|
||||||
| CbePaymentRequestDto
|
// original §6.5 replay design: if CBE retries because our SUCCESS response was lost
|
||||||
| undefined;
|
// in transit, it now sees FAILED for a debit we kept — reconcile such cases manually.
|
||||||
if (
|
return mapPaymentFailure(dto, "Already paid");
|
||||||
orig &&
|
|
||||||
(orig.Bill_Id !== dto.Bill_Id ||
|
|
||||||
orig.Cbe_Txn_Ref !== dto.Cbe_Txn_Ref ||
|
|
||||||
Number(orig.Amount) !== Number(dto.Amount))
|
|
||||||
) {
|
|
||||||
return mapPaymentFailure(
|
|
||||||
dto,
|
|
||||||
"Duplicate End_To_End_Txn_Id",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// Replay the stored body verbatim. Never re-settle.
|
|
||||||
return prior.responsePayload as unknown as CbePaymentResponseDto;
|
|
||||||
}
|
}
|
||||||
if (prior.tradeStatus === "PENDING") {
|
if (prior.tradeStatus === "PENDING") {
|
||||||
return mapPaymentFailure(dto, "Payment in progress");
|
return mapPaymentFailure(dto, "Payment in progress");
|
||||||
|
|||||||
@@ -129,7 +129,6 @@ describe("CBE Unified Bill (payment service as biller)", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let settleBody: Record<string, string>;
|
let settleBody: Record<string, string>;
|
||||||
let settledTxnRef: string;
|
|
||||||
|
|
||||||
it("settles the freight invoice when CBE reports the debit", async () => {
|
it("settles the freight invoice when CBE reports the debit", async () => {
|
||||||
const invoice = await currentInvoice(invoiceId);
|
const invoice = await currentInvoice(invoiceId);
|
||||||
@@ -147,7 +146,6 @@ describe("CBE Unified Bill (payment service as biller)", () => {
|
|||||||
const res = await cbe(token, "/cbe/payment", settleBody);
|
const res = await cbe(token, "/cbe/payment", settleBody);
|
||||||
expect(res.status).toBe(200);
|
expect(res.status).toBe(200);
|
||||||
expect(res.body.Response_Code).toBe("0");
|
expect(res.body.Response_Code).toBe("0");
|
||||||
settledTxnRef = res.body.Destination_Txn_Ref;
|
|
||||||
|
|
||||||
const paid = await poll<{ status: string }>(
|
const paid = await poll<{ status: string }>(
|
||||||
"invoice PAID via CBE bill",
|
"invoice PAID via CBE bill",
|
||||||
@@ -159,22 +157,22 @@ describe("CBE Unified Bill (payment service as biller)", () => {
|
|||||||
expect(paid.status).toBe("PAID");
|
expect(paid.status).toBe("PAID");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("replays the stored success when CBE retries the same attempt verbatim", async () => {
|
it("answers 'Already paid' when the settled attempt is sent again verbatim", async () => {
|
||||||
const res = await cbe(token, "/cbe/payment", settleBody);
|
const res = await cbe(token, "/cbe/payment", settleBody);
|
||||||
expect(res.status).toBe(200);
|
expect(res.status).toBe(200);
|
||||||
expect(res.body.Response_Code).toBe("0");
|
expect(res.body.Status).toBe("FAILED");
|
||||||
// The stored body, not a re-settlement — same order id as the first answer.
|
expect(res.body.Response_Code).toBe("2");
|
||||||
expect(res.body.Destination_Txn_Ref).toBe(settledTxnRef);
|
expect(res.body.Response_Description).toBe("Already paid");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("rejects a settled End_To_End_Txn_Id reused with a different amount", async () => {
|
it("answers 'Already paid' when the settled End_To_End_Txn_Id is reused with a different amount", async () => {
|
||||||
const res = await cbe(token, "/cbe/payment", {
|
const res = await cbe(token, "/cbe/payment", {
|
||||||
...settleBody,
|
...settleBody,
|
||||||
Amount: "1.00",
|
Amount: "1.00",
|
||||||
});
|
});
|
||||||
expect(res.status).toBe(200);
|
expect(res.status).toBe(200);
|
||||||
expect(res.body.Response_Code).toBe("2");
|
expect(res.body.Response_Code).toBe("2");
|
||||||
expect(res.body.Response_Description).toBe("Duplicate End_To_End_Txn_Id");
|
expect(res.body.Response_Description).toBe("Already paid");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("rejects a second debit on the same bill", async () => {
|
it("rejects a second debit on the same bill", async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user