fix(medusa): RMA on items from swaps and claims (#1182)
This commit is contained in:
@@ -4,6 +4,7 @@ const {
|
|||||||
Order,
|
Order,
|
||||||
LineItem,
|
LineItem,
|
||||||
CustomShippingOption,
|
CustomShippingOption,
|
||||||
|
ShippingMethod,
|
||||||
} = require("@medusajs/medusa")
|
} = require("@medusajs/medusa")
|
||||||
|
|
||||||
const setupServer = require("../../../helpers/setup-server")
|
const setupServer = require("../../../helpers/setup-server")
|
||||||
@@ -914,6 +915,215 @@ describe("/admin/orders", () => {
|
|||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("creates a claim on a claim additional item", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
const response = await api
|
||||||
|
.post(
|
||||||
|
"/admin/orders/test-order/claims",
|
||||||
|
{
|
||||||
|
type: "replace",
|
||||||
|
shipping_methods: [
|
||||||
|
{
|
||||||
|
id: "test-method",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
claim_items: [
|
||||||
|
{
|
||||||
|
item_id: "test-item",
|
||||||
|
quantity: 1,
|
||||||
|
reason: "production_failure",
|
||||||
|
tags: ["fluff"],
|
||||||
|
images: ["https://test.image.com"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
additional_items: [
|
||||||
|
{
|
||||||
|
variant_id: "test-variant",
|
||||||
|
quantity: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
const cid = response.data.order.claims[0].id
|
||||||
|
const fulRes = await api.post(
|
||||||
|
`/admin/orders/test-order/claims/${cid}/fulfillments`,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const claimItemIdToClaim =
|
||||||
|
fulRes.data.order.claims[0].additional_items[0].id
|
||||||
|
|
||||||
|
const claimRes = await api
|
||||||
|
.post(
|
||||||
|
"/admin/orders/test-order/claims",
|
||||||
|
{
|
||||||
|
type: "replace",
|
||||||
|
shipping_methods: [
|
||||||
|
{
|
||||||
|
id: "test-method",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
claim_items: [
|
||||||
|
{
|
||||||
|
item_id: claimItemIdToClaim,
|
||||||
|
quantity: 1,
|
||||||
|
reason: "production_failure",
|
||||||
|
tags: ["fluff"],
|
||||||
|
images: ["https://test.image2.com"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
additional_items: [
|
||||||
|
{
|
||||||
|
variant_id: "test-variant-2",
|
||||||
|
quantity: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(claimRes.status).toEqual(200)
|
||||||
|
expect(claimRes.data.order.claims.length).toEqual(2)
|
||||||
|
|
||||||
|
const newClaim = claimRes.data.order.claims.find(
|
||||||
|
(c) => c.fulfillment_status === "not_fulfilled"
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(newClaim.claim_items[0].item.id).toEqual(claimItemIdToClaim)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("creates a claim on a swap additional item", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
// create a swap
|
||||||
|
const response = await api
|
||||||
|
.post(
|
||||||
|
"/admin/orders/test-order/swaps",
|
||||||
|
{
|
||||||
|
custom_shipping_options: [{ option_id: "test-option", price: 0 }],
|
||||||
|
return_items: [
|
||||||
|
{
|
||||||
|
item_id: "test-item",
|
||||||
|
quantity: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
additional_items: [{ variant_id: "test-variant-2", quantity: 1 }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((e) => console.log(e))
|
||||||
|
|
||||||
|
const sid = response.data.order.swaps[0].id
|
||||||
|
const manager = dbConnection.manager
|
||||||
|
|
||||||
|
// add a shipping method so we can fulfill the swap
|
||||||
|
const sm = await manager.create(ShippingMethod, {
|
||||||
|
id: "test-method-swap-cart",
|
||||||
|
swap_id: sid,
|
||||||
|
shipping_option_id: "test-option",
|
||||||
|
price: 0,
|
||||||
|
data: {},
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(sm)
|
||||||
|
|
||||||
|
// fulfill the swap
|
||||||
|
const fulRes = await api
|
||||||
|
.post(
|
||||||
|
`/admin/orders/test-order/swaps/${sid}/fulfillments`,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((e) => console.log(e))
|
||||||
|
|
||||||
|
// ship the swap
|
||||||
|
await api
|
||||||
|
.post(
|
||||||
|
`/admin/orders/test-order/swaps/${sid}/shipments`,
|
||||||
|
{
|
||||||
|
fulfillment_id: fulRes.data.order.swaps[0].fulfillments[0].id,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((e) => console.log(e))
|
||||||
|
|
||||||
|
const claimItemIdToClaim =
|
||||||
|
fulRes.data.order.swaps[0].additional_items[0].id
|
||||||
|
|
||||||
|
// create a claim on the exchange
|
||||||
|
const claimRes = await api
|
||||||
|
.post(
|
||||||
|
"/admin/orders/test-order/claims",
|
||||||
|
{
|
||||||
|
type: "replace",
|
||||||
|
claim_items: [
|
||||||
|
{
|
||||||
|
item_id: claimItemIdToClaim,
|
||||||
|
quantity: 1,
|
||||||
|
reason: "production_failure",
|
||||||
|
tags: ["fluff"],
|
||||||
|
images: ["https://test.image2.com"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
additional_items: [
|
||||||
|
{
|
||||||
|
variant_id: "test-variant-2",
|
||||||
|
quantity: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(claimRes.status).toEqual(200)
|
||||||
|
expect(claimRes.data.order.claims.length).toEqual(1)
|
||||||
|
|
||||||
|
const newClaim = claimRes.data.order.claims[0]
|
||||||
|
|
||||||
|
expect(newClaim.claim_items[0].item.id).toEqual(claimItemIdToClaim)
|
||||||
|
})
|
||||||
|
|
||||||
it("Only allow canceling claim after canceling fulfillments", async () => {
|
it("Only allow canceling claim after canceling fulfillments", async () => {
|
||||||
const order_id = "order-with-claim"
|
const order_id = "order-with-claim"
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,270 @@
|
|||||||
|
const path = require("path")
|
||||||
|
import { ReturnReason, ShippingMethod } from "@medusajs/medusa"
|
||||||
|
|
||||||
|
const setupServer = require("../../../helpers/setup-server")
|
||||||
|
const { useApi } = require("../../../helpers/use-api")
|
||||||
|
const { initDb, useDb } = require("../../../helpers/use-db")
|
||||||
|
|
||||||
|
const orderSeeder = require("../../helpers/order-seeder")
|
||||||
|
const adminSeeder = require("../../helpers/admin-seeder")
|
||||||
|
|
||||||
|
jest.setTimeout(30000)
|
||||||
|
|
||||||
|
describe("/admin/returns", () => {
|
||||||
|
let medusaProcess
|
||||||
|
let dbConnection
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
const cwd = path.resolve(path.join(__dirname, "..", ".."))
|
||||||
|
dbConnection = await initDb({ cwd })
|
||||||
|
medusaProcess = await setupServer({ cwd })
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
const db = useDb()
|
||||||
|
await db.shutdown()
|
||||||
|
|
||||||
|
medusaProcess.kill()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("POST /admin/returns/:id", () => {
|
||||||
|
let rrId
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
try {
|
||||||
|
await adminSeeder(dbConnection)
|
||||||
|
await orderSeeder(dbConnection)
|
||||||
|
|
||||||
|
const created = dbConnection.manager.create(ReturnReason, {
|
||||||
|
value: "too_big",
|
||||||
|
label: "Too Big",
|
||||||
|
})
|
||||||
|
const resultRR = await dbConnection.manager.save(created)
|
||||||
|
rrId = resultRR.id
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
const db = useDb()
|
||||||
|
await db.teardown()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should receive a return on an item added through swap additional items", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
// create a swap
|
||||||
|
const response = await api
|
||||||
|
.post(
|
||||||
|
"/admin/orders/test-order/swaps",
|
||||||
|
{
|
||||||
|
custom_shipping_options: [{ option_id: "test-option", price: 0 }],
|
||||||
|
return_items: [
|
||||||
|
{
|
||||||
|
item_id: "test-item",
|
||||||
|
quantity: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
additional_items: [{ variant_id: "test-variant-2", quantity: 1 }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((e) => console.log(e))
|
||||||
|
|
||||||
|
const sid = response.data.order.swaps[0].id
|
||||||
|
const manager = dbConnection.manager
|
||||||
|
|
||||||
|
// add a shipping method so we can fulfill the swap
|
||||||
|
const sm = await manager.create(ShippingMethod, {
|
||||||
|
id: "test-method-swap-cart",
|
||||||
|
swap_id: sid,
|
||||||
|
shipping_option_id: "test-option",
|
||||||
|
price: 0,
|
||||||
|
data: {},
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(sm)
|
||||||
|
|
||||||
|
// fulfill the swap
|
||||||
|
const fulRes = await api
|
||||||
|
.post(
|
||||||
|
`/admin/orders/test-order/swaps/${sid}/fulfillments`,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((e) => console.log(e))
|
||||||
|
|
||||||
|
// ship the swap
|
||||||
|
await api
|
||||||
|
.post(
|
||||||
|
`/admin/orders/test-order/swaps/${sid}/shipments`,
|
||||||
|
{
|
||||||
|
fulfillment_id: fulRes.data.order.swaps[0].fulfillments[0].id,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((e) => console.log(e))
|
||||||
|
|
||||||
|
const swapItemId = fulRes.data.order.swaps[0].additional_items[0].id
|
||||||
|
|
||||||
|
// request a return
|
||||||
|
const returnRes = await api
|
||||||
|
.post(
|
||||||
|
`/admin/orders/test-order/return`,
|
||||||
|
{
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
item_id: swapItemId,
|
||||||
|
quantity: 1,
|
||||||
|
reason_id: rrId,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((e) => console.log(e.response))
|
||||||
|
|
||||||
|
const returnId = returnRes.data.order.returns[0].id
|
||||||
|
|
||||||
|
const receiveRes = await api
|
||||||
|
.post(
|
||||||
|
`/admin/returns/${returnId}/receive`,
|
||||||
|
{
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
item_id: swapItemId,
|
||||||
|
quantity: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((e) => console.log(e.response))
|
||||||
|
|
||||||
|
expect(receiveRes.status).toEqual(200)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should receive a return on an item added through claim additional items", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
const response = await api
|
||||||
|
.post(
|
||||||
|
"/admin/orders/test-order/claims",
|
||||||
|
{
|
||||||
|
type: "replace",
|
||||||
|
shipping_methods: [
|
||||||
|
{
|
||||||
|
id: "test-method",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
claim_items: [
|
||||||
|
{
|
||||||
|
item_id: "test-item",
|
||||||
|
quantity: 1,
|
||||||
|
reason: "production_failure",
|
||||||
|
tags: ["fluff"],
|
||||||
|
images: ["https://test.image.com"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
additional_items: [
|
||||||
|
{
|
||||||
|
variant_id: "test-variant",
|
||||||
|
quantity: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
const cid = response.data.order.claims[0].id
|
||||||
|
const fulRes = await api.post(
|
||||||
|
`/admin/orders/test-order/claims/${cid}/fulfillments`,
|
||||||
|
{},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const claimItemId = fulRes.data.order.claims[0].additional_items[0].id
|
||||||
|
|
||||||
|
// request a return
|
||||||
|
const returnRes = await api
|
||||||
|
.post(
|
||||||
|
`/admin/orders/test-order/return`,
|
||||||
|
{
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
item_id: claimItemId,
|
||||||
|
quantity: 1,
|
||||||
|
reason_id: rrId,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
return_shipping: {
|
||||||
|
option_id: "test-option",
|
||||||
|
price: 0,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((e) => console.log(e.response))
|
||||||
|
|
||||||
|
const returnId = returnRes.data.order.returns[0].id
|
||||||
|
|
||||||
|
const receiveRes = await api
|
||||||
|
.post(
|
||||||
|
`/admin/returns/${returnId}/receive`,
|
||||||
|
{
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
item_id: claimItemId,
|
||||||
|
quantity: 1,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((e) => console.log(e.response))
|
||||||
|
|
||||||
|
expect(receiveRes.status).toEqual(200)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -153,6 +153,7 @@ module.exports = async (connection, data = {}) => {
|
|||||||
currency_code: "usd",
|
currency_code: "usd",
|
||||||
amount_refunded: 0,
|
amount_refunded: 0,
|
||||||
provider_id: "test-pay",
|
provider_id: "test-pay",
|
||||||
|
captured_at: new Date(),
|
||||||
data: {},
|
data: {},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
import { Type } from "class-transformer"
|
import { Type } from "class-transformer"
|
||||||
import {
|
import {
|
||||||
IsArray,
|
IsArray,
|
||||||
IsOptional,
|
|
||||||
ValidateNested,
|
|
||||||
IsBoolean,
|
IsBoolean,
|
||||||
IsObject,
|
IsEnum,
|
||||||
IsString,
|
|
||||||
IsInt,
|
IsInt,
|
||||||
IsNotEmpty,
|
IsNotEmpty,
|
||||||
IsEnum,
|
IsObject,
|
||||||
|
IsOptional,
|
||||||
|
IsString,
|
||||||
|
ValidateNested,
|
||||||
} from "class-validator"
|
} from "class-validator"
|
||||||
import { MedusaError } from "medusa-core-utils"
|
import { MedusaError } from "medusa-core-utils"
|
||||||
import { defaultAdminOrdersRelations, defaultAdminOrdersFields } from "."
|
import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "."
|
||||||
import { AddressPayload } from "../../../../types/common"
|
import { AddressPayload } from "../../../../types/common"
|
||||||
import { validator } from "../../../../utils/validator"
|
import { validator } from "../../../../utils/validator"
|
||||||
|
|
||||||
@@ -177,6 +177,12 @@ export default async (req, res) => {
|
|||||||
"items.tax_lines",
|
"items.tax_lines",
|
||||||
"discounts",
|
"discounts",
|
||||||
"discounts.rule",
|
"discounts.rule",
|
||||||
|
"claims",
|
||||||
|
"claims.additional_items",
|
||||||
|
"claims.additional_items.tax_lines",
|
||||||
|
"swaps",
|
||||||
|
"swaps.additional_items",
|
||||||
|
"swaps.additional_items.tax_lines",
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -230,7 +230,35 @@ class ClaimService extends BaseService {
|
|||||||
let toRefund = refund_amount
|
let toRefund = refund_amount
|
||||||
if (type === "refund" && typeof refund_amount === "undefined") {
|
if (type === "refund" && typeof refund_amount === "undefined") {
|
||||||
const lines = claim_items.map((ci) => {
|
const lines = claim_items.map((ci) => {
|
||||||
const orderItem = order.items.find((oi) => oi.id === ci.item_id)
|
const allOrderItems = order.items
|
||||||
|
|
||||||
|
if (order.swaps?.length) {
|
||||||
|
for (const swap of order.swaps) {
|
||||||
|
swap.additional_items.forEach((it) => {
|
||||||
|
if (
|
||||||
|
it.shipped_quantity ||
|
||||||
|
it.shipped_quantity === it.fulfilled_quantity
|
||||||
|
) {
|
||||||
|
allOrderItems.push(it)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (order.claims?.length) {
|
||||||
|
for (const claim of order.claims) {
|
||||||
|
claim.additional_items.forEach((it) => {
|
||||||
|
if (
|
||||||
|
it.shipped_quantity ||
|
||||||
|
it.shipped_quantity === it.fulfilled_quantity
|
||||||
|
) {
|
||||||
|
allOrderItems.push(it)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const orderItem = allOrderItems.find((oi) => oi.id === ci.item_id)
|
||||||
return {
|
return {
|
||||||
...orderItem,
|
...orderItem,
|
||||||
quantity: ci.quantity,
|
quantity: ci.quantity,
|
||||||
|
|||||||
@@ -563,6 +563,8 @@ class ReturnService extends BaseService {
|
|||||||
"region",
|
"region",
|
||||||
"swaps",
|
"swaps",
|
||||||
"swaps.additional_items",
|
"swaps.additional_items",
|
||||||
|
"claims",
|
||||||
|
"claims.additional_items",
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user