fix(medusa-payment-paypal): Should not throw when canceling already canceled payment (#1470)

This commit is contained in:
Adrien de Peretti
2022-05-19 18:28:51 +02:00
committed by GitHub
parent f17e44d88a
commit 58387936c9
3 changed files with 74 additions and 13 deletions
@@ -27,7 +27,11 @@ export const PayPalMock = {
payments: { payments: {
AuthorizationsGetRequest: jest.fn().mockImplementation(() => {}), AuthorizationsGetRequest: jest.fn().mockImplementation(() => {}),
AuthorizationsVoidRequest: jest.fn().mockImplementation(() => {}), AuthorizationsVoidRequest: jest.fn().mockImplementation(() => {
return {
status: "VOIDED"
}
}),
AuthorizationsCaptureRequest: jest.fn().mockImplementation(() => { AuthorizationsCaptureRequest: jest.fn().mockImplementation(() => {
return { return {
result: { result: {
@@ -41,6 +45,8 @@ export const PayPalMock = {
result: { result: {
id: "test", id: "test",
}, },
status: "COMPLETED",
invoice_id: 'invoice_id',
body: null, body: null,
requestBody: function (d) { requestBody: function (d) {
this.body = d this.body = d
@@ -74,11 +80,29 @@ export const PayPalMock = {
}, },
} }
}), }),
OrdersGetRequest: jest.fn().mockImplementation(() => { OrdersGetRequest: jest.fn().mockImplementation((id) => {
return { switch (id) {
result: { case "test-refund":
id: "test", return {
}, result: {
id: "test-refund",
status: "COMPLETED",
invoice_id: "invoice_id"
}
}
case "test-voided":
return {
result: {
id: "test-voided",
status: "VOIDED"
}
}
default:
return {
result: {
id: "test",
},
}
} }
}), }),
}, },
@@ -310,7 +310,7 @@ describe("PaypalProviderService", () => {
"test_cap" "test_cap"
) )
expect(PayPalMock.orders.OrdersGetRequest).toHaveBeenCalledWith("test") expect(PayPalMock.orders.OrdersGetRequest).toHaveBeenCalledWith("test")
expect(PayPalClientMock.execute).toHaveBeenCalledTimes(2) expect(PayPalClientMock.execute).toHaveBeenCalledTimes(3)
expect(result.id).toEqual("test") expect(result.id).toEqual("test")
}) })
@@ -338,9 +338,41 @@ describe("PaypalProviderService", () => {
PayPalMock.payments.AuthorizationsVoidRequest PayPalMock.payments.AuthorizationsVoidRequest
).toHaveBeenCalledWith("test_auth") ).toHaveBeenCalledWith("test_auth")
expect(PayPalMock.orders.OrdersGetRequest).toHaveBeenCalledWith("test") expect(PayPalMock.orders.OrdersGetRequest).toHaveBeenCalledWith("test")
expect(PayPalClientMock.execute).toHaveBeenCalledTimes(2) expect(PayPalClientMock.execute).toHaveBeenCalledTimes(3)
expect(result.id).toEqual("test") expect(result.id).toEqual("test")
}) })
it("should return the order if already canceled", async () => {
result = await paypalProviderService.cancelPayment({
currency_code: "eur",
data: { id: "test-voided" },
})
expect(PayPalMock.payments.AuthorizationsVoidRequest).not.toHaveBeenCalled()
expect(PayPalMock.payments.CapturesRefundRequest).not.toHaveBeenCalled()
expect(PayPalMock.orders.OrdersGetRequest).toHaveBeenCalledWith("test-voided")
expect(PayPalClientMock.execute).toHaveBeenCalledTimes(1)
expect(result.id).toEqual("test-voided")
expect(result.status).toEqual("VOIDED")
})
it("should return the order if already fully refund", async () => {
result = await paypalProviderService.cancelPayment({
currency_code: "eur",
data: {
id: "test-refund",
},
})
expect(PayPalMock.payments.AuthorizationsVoidRequest).not.toHaveBeenCalled()
expect(PayPalMock.payments.CapturesRefundRequest).not.toHaveBeenCalled()
expect(PayPalMock.orders.OrdersGetRequest).toHaveBeenCalledWith("test-refund")
expect(PayPalClientMock.execute).toHaveBeenCalledTimes(1)
expect(result.id).toEqual("test-refund")
expect(result.status).toEqual("COMPLETED")
})
}) })
}) })
@@ -1,4 +1,3 @@
import _ from "lodash"
import { humanizeAmount, zeroDecimalCurrencies } from "medusa-core-utils" import { humanizeAmount, zeroDecimalCurrencies } from "medusa-core-utils"
import PayPal from "@paypal/checkout-server-sdk" import PayPal from "@paypal/checkout-server-sdk"
import { PaymentService } from "medusa-interfaces" import { PaymentService } from "medusa-interfaces"
@@ -72,7 +71,6 @@ class PayPalProviderService extends PaymentService {
return "requires_more" return "requires_more"
case "VOIDED": case "VOIDED":
return "canceled" return "canceled"
// return "captured"
default: default:
return status return status
} }
@@ -284,11 +282,18 @@ class PayPalProviderService extends PaymentService {
} }
/** /**
* Cancels payment for Stripe payment intent. * Cancels payment for paypal payment.
* @param {object} paymentData - payment method data from cart * @param {Payment} payment - payment object
* @returns {Promise<object>} canceled payment intent * @returns {Promise<object>} canceled payment intent
*/ */
async cancelPayment(payment) { async cancelPayment(payment) {
const order = await this.retrievePayment(payment.data)
const isAlreadyCanceled = order.status === "VOIDED"
const isCanceledAndFullyRefund = order.status === "COMPLETED" && !!order.invoice_id
if (isAlreadyCanceled || isCanceledAndFullyRefund) {
return order
}
try { try {
const { purchase_units } = payment.data const { purchase_units } = payment.data
if (payment.captured_at) { if (payment.captured_at) {
@@ -303,7 +308,7 @@ class PayPalProviderService extends PaymentService {
await this.paypal_.execute(request) await this.paypal_.execute(request)
} }
return this.retrievePayment(payment.data) return await this.retrievePayment(payment.data)
} catch (error) { } catch (error) {
throw error throw error
} }