fix(payment): Double idempotent capture called with auto capture beha… (#14073)
* fix(payment): Double idempotent capture called with auto capture behaviour * Create sweet-peaches-dress.md * naming * feedback * naming
This commit is contained in:
+118
@@ -631,6 +631,62 @@ moduleIntegrationTestRunner<IPaymentModuleService>({
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it("should auto capture payment when provider returns captured status", async () => {
|
||||
const collection = await service.createPaymentCollections({
|
||||
amount: 200,
|
||||
currency_code: "usd",
|
||||
})
|
||||
|
||||
const session = await service.createPaymentSession(collection.id, {
|
||||
provider_id: "pp_system_default",
|
||||
amount: 100,
|
||||
currency_code: "usd",
|
||||
data: {},
|
||||
context: {
|
||||
customer: { id: "cus-id-1", email: "new@test.tsst" },
|
||||
},
|
||||
})
|
||||
|
||||
// Mock the provider to return CAPTURED status
|
||||
const authorizePaymentMock = jest
|
||||
.spyOn(
|
||||
(service as any).paymentProviderService_,
|
||||
"authorizePayment"
|
||||
)
|
||||
.mockResolvedValueOnce({
|
||||
data: { payment_id: "external_payment_id" },
|
||||
status: "captured",
|
||||
})
|
||||
|
||||
const capturePaymentMock = jest.spyOn(
|
||||
(service as any).paymentProviderService_,
|
||||
"capturePayment"
|
||||
)
|
||||
|
||||
const payment = await service.authorizePaymentSession(
|
||||
session.id,
|
||||
{}
|
||||
)
|
||||
|
||||
expect(authorizePaymentMock).toHaveBeenCalledTimes(1)
|
||||
expect(capturePaymentMock).not.toHaveBeenCalled()
|
||||
|
||||
expect(payment).toEqual(
|
||||
expect.objectContaining({
|
||||
id: expect.any(String),
|
||||
amount: 100,
|
||||
currency_code: "usd",
|
||||
provider_id: "pp_system_default",
|
||||
captured_at: expect.any(Date),
|
||||
captures: [expect.objectContaining({})],
|
||||
payment_session: expect.objectContaining({
|
||||
status: "authorized",
|
||||
authorized_at: expect.any(Date),
|
||||
}),
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -780,6 +836,68 @@ moduleIntegrationTestRunner<IPaymentModuleService>({
|
||||
"The payment: pay-id-1 has been canceled."
|
||||
)
|
||||
})
|
||||
|
||||
it("should not call provider capturePayment for auto-captured payments", async () => {
|
||||
const collection = await service.createPaymentCollections({
|
||||
amount: 200,
|
||||
currency_code: "usd",
|
||||
})
|
||||
|
||||
const session = await service.createPaymentSession(collection.id, {
|
||||
provider_id: "pp_system_default",
|
||||
amount: 100,
|
||||
currency_code: "usd",
|
||||
data: {},
|
||||
context: {
|
||||
customer: { id: "cus-id-1", email: "new@test.tsst" },
|
||||
},
|
||||
})
|
||||
|
||||
// Mock the provider to return CAPTURED status for auto-capture
|
||||
jest
|
||||
.spyOn(
|
||||
(service as any).paymentProviderService_,
|
||||
"authorizePayment"
|
||||
)
|
||||
.mockResolvedValueOnce({
|
||||
data: { payment_id: "external_payment_id" },
|
||||
status: "captured",
|
||||
})
|
||||
|
||||
const payment = await service.authorizePaymentSession(
|
||||
session.id,
|
||||
{}
|
||||
)
|
||||
|
||||
// Spy on capturePayment provider method
|
||||
const capturePaymentMock = jest.spyOn(
|
||||
(service as any).paymentProviderService_,
|
||||
"capturePayment"
|
||||
)
|
||||
|
||||
// Try to capture the already auto-captured payment
|
||||
const capturedPayment = await service.capturePayment({
|
||||
amount: 100,
|
||||
payment_id: payment.id,
|
||||
})
|
||||
|
||||
// Provider's capturePayment should NOT be called since it was auto-captured
|
||||
expect(capturePaymentMock).not.toHaveBeenCalled()
|
||||
|
||||
// Verify data consistency
|
||||
expect(capturedPayment).toEqual(
|
||||
expect.objectContaining({
|
||||
id: payment.id,
|
||||
amount: 100,
|
||||
captured_at: expect.any(Date),
|
||||
captures: [
|
||||
expect.objectContaining({
|
||||
amount: 100,
|
||||
}),
|
||||
],
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("refund", () => {
|
||||
|
||||
Reference in New Issue
Block a user