* wip * chore: prepare for PR * move to end * Change order of operations in refundPaymentWorkflow Updated the order of operations in the refundPaymentWorkflow. * chore: Add validation
442 lines
12 KiB
TypeScript
442 lines
12 KiB
TypeScript
import { medusaIntegrationTestRunner } from "@medusajs/test-utils"
|
|
import { ClaimType } from "@medusajs/utils"
|
|
import {
|
|
adminHeaders,
|
|
createAdminUser,
|
|
} from "../../../../helpers/create-admin-user"
|
|
import { createOrderSeeder } from "../../fixtures/order"
|
|
|
|
jest.setTimeout(50000)
|
|
|
|
medusaIntegrationTestRunner({
|
|
testSuite: ({ dbConnection, getContainer, api }) => {
|
|
let container
|
|
let order
|
|
|
|
const createClaim = async ({ order }) => {
|
|
const claim = (
|
|
await api.post(
|
|
"/admin/claims",
|
|
{
|
|
order_id: order.id,
|
|
type: ClaimType.REPLACE,
|
|
description: "Base claim",
|
|
},
|
|
adminHeaders
|
|
)
|
|
).data.claim
|
|
|
|
await api.post(
|
|
`/admin/claims/${claim.id}/inbound/items`,
|
|
{ items: [{ id: order.items[0].id, quantity: 1 }] },
|
|
adminHeaders
|
|
)
|
|
|
|
const createdClaim = await api.post(
|
|
`/admin/claims/${claim.id}/request`,
|
|
{},
|
|
adminHeaders
|
|
)
|
|
|
|
const returnOrder = createdClaim.data.return
|
|
const returnId = returnOrder.id
|
|
await api.post(`/admin/returns/${returnId}/receive`, {}, adminHeaders)
|
|
|
|
let lineItem = returnOrder.items[0].item
|
|
await api.post(
|
|
`/admin/returns/${returnId}/receive-items`,
|
|
{
|
|
items: [
|
|
{
|
|
id: lineItem.id,
|
|
quantity: returnOrder.items[0].quantity,
|
|
},
|
|
],
|
|
},
|
|
adminHeaders
|
|
)
|
|
|
|
await api.post(
|
|
`/admin/returns/${returnId}/receive/confirm`,
|
|
{},
|
|
adminHeaders
|
|
)
|
|
}
|
|
|
|
beforeEach(async () => {
|
|
container = getContainer()
|
|
await createAdminUser(dbConnection, adminHeaders, container)
|
|
|
|
const inventoryItemOverride = (
|
|
await api.post(
|
|
`/admin/inventory-items`,
|
|
{ sku: "test-variant", requires_shipping: false },
|
|
adminHeaders
|
|
)
|
|
).data.inventory_item
|
|
|
|
const seeders = await createOrderSeeder({
|
|
api,
|
|
container,
|
|
inventoryItemOverride,
|
|
withoutShipping: true,
|
|
})
|
|
|
|
order = seeders.order
|
|
|
|
await api.post(
|
|
`/admin/orders/${order.id}/fulfillments`,
|
|
{ items: [{ id: order.items[0].id, quantity: 1 }] },
|
|
adminHeaders
|
|
)
|
|
})
|
|
|
|
describe("with outstanding amount due to claim", () => {
|
|
it("should capture an authorized payment", async () => {
|
|
const payment = order.payment_collections[0].payments[0]
|
|
|
|
const response = await api.post(
|
|
`/admin/payments/${payment.id}/capture`,
|
|
undefined,
|
|
adminHeaders
|
|
)
|
|
|
|
expect(response.data.payment).toEqual(
|
|
expect.objectContaining({
|
|
id: payment.id,
|
|
captured_at: expect.any(String),
|
|
captures: [
|
|
expect.objectContaining({
|
|
id: expect.any(String),
|
|
amount: 100,
|
|
}),
|
|
],
|
|
refunds: [],
|
|
amount: 100,
|
|
})
|
|
)
|
|
expect(response.status).toEqual(200)
|
|
})
|
|
|
|
it("should throw if capture amount is greater than authorized amount", async () => {
|
|
const payment = order.payment_collections[0].payments[0]
|
|
|
|
const response = await api.post(
|
|
`/admin/payments/${payment.id}/capture`,
|
|
{ amount: 75 },
|
|
adminHeaders
|
|
)
|
|
|
|
expect(response.data.payment).toEqual(
|
|
expect.objectContaining({
|
|
id: payment.id,
|
|
captured_at: null, // not fully captured yet
|
|
captures: [
|
|
expect.objectContaining({
|
|
id: expect.any(String),
|
|
amount: 75,
|
|
}),
|
|
],
|
|
refunds: [],
|
|
amount: 100,
|
|
})
|
|
)
|
|
expect(response.status).toEqual(200)
|
|
|
|
const errResponse = await api
|
|
.post(
|
|
`/admin/payments/${payment.id}/capture`,
|
|
{ amount: 75 },
|
|
adminHeaders
|
|
)
|
|
.catch((e) => e)
|
|
|
|
expect(errResponse.response.data.message).toEqual(
|
|
"You cannot capture more than the authorized amount substracted by what is already captured."
|
|
)
|
|
})
|
|
|
|
it("should return payment if payment is already fully captured", async () => {
|
|
const payment = order.payment_collections[0].payments[0]
|
|
|
|
const response = await api.post(
|
|
`/admin/payments/${payment.id}/capture`,
|
|
undefined,
|
|
adminHeaders
|
|
)
|
|
|
|
expect(response.data.payment).toEqual(
|
|
expect.objectContaining({
|
|
id: payment.id,
|
|
captured_at: expect.any(String),
|
|
captures: [
|
|
expect.objectContaining({
|
|
id: expect.any(String),
|
|
amount: 100,
|
|
}),
|
|
],
|
|
refunds: [],
|
|
amount: 100,
|
|
})
|
|
)
|
|
expect(response.status).toEqual(200)
|
|
|
|
const anotherResponse = await api.post(
|
|
`/admin/payments/${payment.id}/capture`,
|
|
undefined,
|
|
adminHeaders
|
|
)
|
|
|
|
expect(anotherResponse.data.payment).toEqual(
|
|
expect.objectContaining({
|
|
id: payment.id,
|
|
captured_at: expect.any(String),
|
|
captures: [
|
|
expect.objectContaining({
|
|
id: expect.any(String),
|
|
amount: 100,
|
|
}),
|
|
],
|
|
refunds: [],
|
|
amount: 100,
|
|
})
|
|
)
|
|
expect(anotherResponse.status).toEqual(200)
|
|
})
|
|
|
|
it("should refund a captured payment", async () => {
|
|
const payment = order.payment_collections[0].payments[0]
|
|
|
|
await api.post(
|
|
`/admin/payments/${payment.id}/capture`,
|
|
undefined,
|
|
adminHeaders
|
|
)
|
|
|
|
await createClaim({ order })
|
|
|
|
const refundReason = (
|
|
await api.post(
|
|
`/admin/refund-reasons`,
|
|
{ label: "test", code: "test" },
|
|
adminHeaders
|
|
)
|
|
).data.refund_reason
|
|
|
|
// BREAKING: reason is now refund_reason_id
|
|
const response = await api.post(
|
|
`/admin/payments/${payment.id}/refund`,
|
|
{
|
|
amount: 50,
|
|
refund_reason_id: refundReason.id,
|
|
note: "Do not like it",
|
|
},
|
|
adminHeaders
|
|
)
|
|
|
|
// BREAKING: Response was `data.refund` in V1 with payment ID, reason, and amount
|
|
expect(response.status).toEqual(200)
|
|
expect(response.data.payment).toEqual(
|
|
expect.objectContaining({
|
|
id: payment.id,
|
|
captured_at: expect.any(String),
|
|
captures: [
|
|
expect.objectContaining({
|
|
id: expect.any(String),
|
|
amount: 100,
|
|
}),
|
|
],
|
|
refunds: [
|
|
expect.objectContaining({
|
|
id: expect.any(String),
|
|
amount: 50,
|
|
note: "Do not like it",
|
|
refund_reason_id: refundReason.id,
|
|
refund_reason: expect.objectContaining({
|
|
label: "test",
|
|
code: "test",
|
|
}),
|
|
}),
|
|
],
|
|
amount: 100,
|
|
})
|
|
)
|
|
})
|
|
|
|
it("should issue multiple refunds", async () => {
|
|
const payment = order.payment_collections[0].payments[0]
|
|
|
|
await api.post(
|
|
`/admin/payments/${payment.id}/capture`,
|
|
undefined,
|
|
adminHeaders
|
|
)
|
|
|
|
const refundReason = (
|
|
await api.post(
|
|
`/admin/refund-reasons`,
|
|
{ label: "test", code: "test" },
|
|
adminHeaders
|
|
)
|
|
).data.refund_reason
|
|
|
|
await createClaim({ order })
|
|
|
|
await api.post(
|
|
`/admin/payments/${payment.id}/refund`,
|
|
{
|
|
amount: 25,
|
|
refund_reason_id: refundReason.id,
|
|
note: "Do not like it",
|
|
},
|
|
adminHeaders
|
|
)
|
|
|
|
await api.post(
|
|
`/admin/payments/${payment.id}/refund`,
|
|
{
|
|
amount: 25,
|
|
refund_reason_id: refundReason.id,
|
|
note: "Do not like it",
|
|
},
|
|
adminHeaders
|
|
)
|
|
|
|
const refundedPayment = (
|
|
await api.get(`/admin/payments/${payment.id}`, adminHeaders)
|
|
).data.payment
|
|
|
|
expect(refundedPayment).toEqual(
|
|
expect.objectContaining({
|
|
id: payment.id,
|
|
currency_code: "usd",
|
|
amount: 100,
|
|
captured_at: expect.any(String),
|
|
captures: [
|
|
expect.objectContaining({
|
|
amount: 100,
|
|
}),
|
|
],
|
|
refunds: [
|
|
expect.objectContaining({
|
|
amount: 25,
|
|
note: "Do not like it",
|
|
}),
|
|
expect.objectContaining({
|
|
amount: 25,
|
|
note: "Do not like it",
|
|
}),
|
|
],
|
|
})
|
|
)
|
|
})
|
|
|
|
it("should create credit lines if issuing a refund when outstanding amount if >= 0", async () => {
|
|
const payment = order.payment_collections[0].payments[0]
|
|
|
|
const refundReason = (
|
|
await api.post(
|
|
`/admin/refund-reasons`,
|
|
{ label: "Test", code: "test" },
|
|
adminHeaders
|
|
)
|
|
).data.refund_reason
|
|
|
|
await api.post(
|
|
`/admin/payments/${payment.id}/capture`,
|
|
undefined,
|
|
adminHeaders
|
|
)
|
|
|
|
await api.post(
|
|
`/admin/payments/${payment.id}/refund`,
|
|
{
|
|
amount: 50,
|
|
refund_reason_id: refundReason.id,
|
|
},
|
|
adminHeaders
|
|
)
|
|
|
|
const updatedOrder = (
|
|
await api.get(`/admin/orders/${order.id}`, adminHeaders)
|
|
).data.order
|
|
|
|
expect(updatedOrder.credit_line_total).toEqual(50)
|
|
expect(updatedOrder.credit_lines).toEqual([
|
|
expect.objectContaining({
|
|
reference: "Test",
|
|
reference_id: "test",
|
|
}),
|
|
])
|
|
})
|
|
|
|
it("should throw if the refund amount exceeds the payment amount", async () => {
|
|
const payment = order.payment_collections[0].payments[0]
|
|
|
|
const refundReason = (
|
|
await api.post(
|
|
`/admin/refund-reasons`,
|
|
{ label: "Test", code: "test" },
|
|
adminHeaders
|
|
)
|
|
).data.refund_reason
|
|
|
|
await api.post(
|
|
`/admin/payments/${payment.id}/capture`,
|
|
undefined,
|
|
adminHeaders
|
|
)
|
|
|
|
await api.post(
|
|
`/admin/payments/${payment.id}/refund`,
|
|
{
|
|
amount: 50,
|
|
refund_reason_id: refundReason.id,
|
|
},
|
|
adminHeaders
|
|
)
|
|
|
|
const updatedOrder = (
|
|
await api.get(`/admin/orders/${order.id}`, adminHeaders)
|
|
).data.order
|
|
|
|
expect(updatedOrder.credit_line_total).toEqual(50)
|
|
expect(updatedOrder.credit_lines).toEqual([
|
|
expect.objectContaining({
|
|
reference: "Test",
|
|
reference_id: "test",
|
|
}),
|
|
])
|
|
|
|
try {
|
|
await api.post(
|
|
`/admin/payments/${payment.id}/refund`,
|
|
{
|
|
amount: 5000,
|
|
refund_reason_id: refundReason.id,
|
|
},
|
|
adminHeaders
|
|
)
|
|
} catch (error) {
|
|
expect(error.response.status).toBe(400)
|
|
expect(error.response.data.message).toBe(
|
|
"You are not allowed to refund more than the captured amount"
|
|
)
|
|
}
|
|
|
|
const updatedUpdatedOrder = (
|
|
await api.get(`/admin/orders/${order.id}`, adminHeaders)
|
|
).data.order
|
|
|
|
expect(updatedUpdatedOrder.credit_line_total).toEqual(50)
|
|
expect(updatedUpdatedOrder.credit_lines).toEqual([
|
|
expect.objectContaining({
|
|
reference: "Test",
|
|
reference_id: "test",
|
|
}),
|
|
])
|
|
})
|
|
})
|
|
},
|
|
})
|