feat: update and cancel swaps, claims, and returns (#310)

This commit is contained in:
Sebastian Mateos Nicolajsen
2021-09-10 13:57:34 +02:00
committed by GitHub
parent fab155c246
commit cf66f97758
55 changed files with 3962 additions and 1007 deletions
@@ -0,0 +1,64 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { ClaimServiceMock } from "../../../../../services/__mocks__/claim"
describe("POST /admin/orders/:id/claims/:claim_id/cancel", () => {
describe("successfully cancels a claim", () => {
let subject
beforeAll(async () => {
subject = await request(
"POST",
`/admin/orders/${IdMap.getId("test-order")}/claims/${IdMap.getId(
"test-claim"
)}/cancel`,
{
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
}
)
})
afterAll(() => {
jest.clearAllMocks()
})
it("calls ClaimService cancel", () => {
expect(ClaimServiceMock.cancel).toHaveBeenCalledTimes(1)
expect(ClaimServiceMock.cancel).toHaveBeenCalledWith(
IdMap.getId("test-claim")
)
})
})
describe("Trying to cancel a claim unrelated to the order fails", () => {
let subject
beforeAll(async () => {
subject = await request(
"POST",
`/admin/orders/${IdMap.getId("test-order2")}/claims/${IdMap.getId(
"test-claim"
)}/cancel`,
{
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
}
)
})
afterAll(() => {
jest.clearAllMocks()
})
it("returns error", () => {
expect(subject.status).toEqual(404)
})
})
})
@@ -0,0 +1,92 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { ClaimServiceMock } from "../../../../../services/__mocks__/claim"
describe("POST /admin/orders/:id/claims/:claim_id/fulfillments/:fulfillment_id/cancel", () => {
describe("successfully cancels a fulfillment", () => {
let subject
beforeAll(async () => {
subject = await request(
"POST",
`/admin/orders/${IdMap.getId("test-order")}/claims/${IdMap.getId(
"test-claim"
)}/fulfillments/${IdMap.getId("claim-fulfillment")}/cancel`,
{
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
}
)
})
afterAll(() => {
jest.clearAllMocks()
})
it("calls claimService cancelFulfillment", () => {
expect(ClaimServiceMock.cancelFulfillment).toHaveBeenCalledTimes(1)
expect(ClaimServiceMock.cancelFulfillment).toHaveBeenCalledWith(
IdMap.getId("claim-fulfillment")
)
})
})
describe("Trying to cancel a fulfillment unrelated to the claim fails", () => {
let subject
beforeAll(async () => {
subject = await request(
"POST",
`/admin/orders/${IdMap.getId("test-order")}/claims/${IdMap.getId(
"claim-fulfillment2"
)}/fulfillments/${IdMap.getId("claim-fulfillment")}/cancel`,
{
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
}
)
})
afterAll(() => {
jest.clearAllMocks()
})
it("returns error", () => {
expect(subject.status).toEqual(404)
})
})
describe("Trying to cancel a fulfillment, where claim and order are unrelated", () => {
let subject
beforeAll(async () => {
subject = await request(
"POST",
`/admin/orders/${IdMap.getId("test-order2")}/claims/${IdMap.getId(
"test-claim"
)}/fulfillments/${IdMap.getId("claim-fulfillment")}/cancel`,
{
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
}
)
})
afterAll(() => {
jest.clearAllMocks()
})
it("returns error", () => {
expect(subject.status).toEqual(404)
})
})
})
@@ -0,0 +1,92 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { SwapServiceMock } from "../../../../../services/__mocks__/swap"
describe("POST /admin/orders/:id/swaps/:swap_id/fulfillments/:fulfillment_id/cancel", () => {
describe("successfully cancels a fulfillment", () => {
let subject
beforeAll(async () => {
subject = await request(
"POST",
`/admin/orders/${IdMap.getId("test-order")}/swaps/${IdMap.getId(
"test-swap"
)}/fulfillments/${IdMap.getId("swap-fulfillment")}/cancel`,
{
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
}
)
})
afterAll(() => {
jest.clearAllMocks()
})
it("calls SwapService cancelFulfillment", () => {
expect(SwapServiceMock.cancelFulfillment).toHaveBeenCalledTimes(1)
expect(SwapServiceMock.cancelFulfillment).toHaveBeenCalledWith(
IdMap.getId("swap-fulfillment")
)
})
})
describe("Trying to cancel a fulfillment unrelated to the swap fails", () => {
let subject
beforeAll(async () => {
subject = await request(
"POST",
`/admin/orders/${IdMap.getId("test-order")}/swaps/${IdMap.getId(
"swap-fulfillment2"
)}/fulfillments/${IdMap.getId("swap-fulfillment")}/cancel`,
{
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
}
)
})
afterAll(() => {
jest.clearAllMocks()
})
it("returns error", () => {
expect(subject.status).toEqual(404)
})
})
describe("Trying to cancel a fulfillment, where swap and order are unrelated", () => {
let subject
beforeAll(async () => {
subject = await request(
"POST",
`/admin/orders/${IdMap.getId("test-order2")}/swaps/${IdMap.getId(
"test-swap"
)}/fulfillments/${IdMap.getId("swap-fulfillment")}/cancel`,
{
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
}
)
})
afterAll(() => {
jest.clearAllMocks()
})
it("returns error", () => {
expect(subject.status).toEqual(404)
})
})
})
@@ -0,0 +1,64 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { OrderServiceMock } from "../../../../../services/__mocks__/order"
describe("POST /admin/orders/:id/fulfillments/:fulfillment_id/cancel", () => {
describe("successfully cancels a fulfillment", () => {
let subject
beforeAll(async () => {
subject = await request(
"POST",
`/admin/orders/${IdMap.getId("test-order")}/fulfillments/${IdMap.getId(
"order-fulfillment"
)}/cancel`,
{
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
}
)
})
afterAll(() => {
jest.clearAllMocks()
})
it("calls OrderService cancelFulfillment", () => {
expect(OrderServiceMock.cancelFulfillment).toHaveBeenCalledTimes(1)
expect(OrderServiceMock.cancelFulfillment).toHaveBeenCalledWith(
IdMap.getId("order-fulfillment")
)
})
})
describe("Trying to cancel a fulfillment unrelated to the order fails", () => {
let subject
beforeAll(async () => {
subject = await request(
"POST",
`/admin/orders/${IdMap.getId("test-order2")}/fulfillments/${IdMap.getId(
"order-fulfillment"
)}/cancel`,
{
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
}
)
})
afterAll(() => {
jest.clearAllMocks()
})
it("returns error", () => {
expect(subject.status).toEqual(404)
})
})
})
@@ -0,0 +1,64 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { SwapServiceMock } from "../../../../../services/__mocks__/swap"
describe("POST /admin/orders/:id/swaps/:swap_id/cancel", () => {
describe("successfully cancels a claim", () => {
let subject
beforeAll(async () => {
subject = await request(
"POST",
`/admin/orders/${IdMap.getId("test-order")}/swaps/${IdMap.getId(
"test-swap"
)}/cancel`,
{
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
}
)
})
afterAll(() => {
jest.clearAllMocks()
})
it("calls SwapService cancel", () => {
expect(SwapServiceMock.cancel).toHaveBeenCalledTimes(1)
expect(SwapServiceMock.cancel).toHaveBeenCalledWith(
IdMap.getId("test-swap")
)
})
})
describe("Trying to cancel a claim unrelated to the order fails", () => {
let subject
beforeAll(async () => {
subject = await request(
"POST",
`/admin/orders/${IdMap.getId("test-order2")}/swaps/${IdMap.getId(
"test-swap"
)}/cancel`,
{
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
}
)
})
afterAll(() => {
jest.clearAllMocks()
})
it("returns error", () => {
expect(subject.status).toEqual(404)
})
})
})
@@ -19,6 +19,7 @@ const defaultRelations = [
"gift_card_transactions",
"claims",
"claims.return_order",
"claims.return_order.shipping_method",
"claims.shipping_methods",
"claims.shipping_address",
"claims.additional_items",
@@ -0,0 +1,51 @@
import { MedusaError } from "medusa-core-utils"
import { defaultRelations, defaultFields } from "."
/**
* @oas [post] /orders/{id}/claims/{claim_id}/cancel
* operationId: "PostOrdersClaimCancel"
* summary: "Cancels a Claim"
* description: "Cancels a Claim"
* parameters:
* - (path) id=* {string} The id of the Order.
* . (path) claim_id=* {string} The id of the Claim.
* tags:
* - Claim
* responses:
* 200:
* description: OK
* content:
* application/json:
* schema:
* properties:
* order:
* $ref: "#/components/schemas/claim"
*/
export default async (req, res) => {
const { id, claim_id } = req.params
try {
const claimService = req.scope.resolve("claimService")
const orderService = req.scope.resolve("orderService")
const claim = await claimService.retrieve(claim_id)
if (claim.order_id !== id) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`no claim was found with the id: ${claim_id} related to order: ${id}`
)
}
await claimService.cancel(claim_id)
const order = await orderService.retrieve(id, {
select: defaultFields,
relations: defaultRelations,
})
res.json({ order })
} catch (error) {
throw error
}
}
@@ -0,0 +1,61 @@
import { MedusaError } from "medusa-core-utils"
import { defaultRelations, defaultFields } from "."
/**
* @oas [post] orders//{id}/claims/{claim_id}/fulfillments/{fulfillment_id}/cancel
* operationId: "PostOrdersClaimFulfillmentsCancel"
* summary: "Cancels a fulfilmment related to a Claim"
* description: "Registers a Fulfillment as canceled."
* parameters:
* - (path) id=* {string} The id of the Order which the Claim relates to.
* - (path) claim_id=* {string} The id of the Claim which the Fulfillment relates to.
* - (path) fulfillment_id=* {string} The id of the Fulfillment.
* tags:
* - Fulfillment
* responses:
* 200:
* description: OK
* content:
* application/json:
* schema:
* properties:
* fulfillment:
* $ref: "#/components/schemas/fulfillment"
*/
export default async (req, res) => {
const { id, claim_id, fulfillment_id } = req.params
try {
const fulfillmentService = req.scope.resolve("fulfillmentService")
const claimService = req.scope.resolve("claimService")
const orderService = req.scope.resolve("orderService")
const fulfillment = await fulfillmentService.retrieve(fulfillment_id)
if (fulfillment.claim_order_id !== claim_id) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`no fulfillment was found with the id: ${fulfillment_id} related to claim: ${claim_id}`
)
}
const claim = await claimService.retrieve(claim_id)
if (claim.order_id !== id) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`no claim was found with the id: ${claim_id} related to order: ${id}`
)
}
await claimService.cancelFulfillment(fulfillment_id)
const order = await orderService.retrieve(id, {
select: defaultFields,
relations: defaultRelations,
})
res.json({ order })
} catch (error) {
throw error
}
}
@@ -0,0 +1,62 @@
import { MedusaError } from "medusa-core-utils"
import { defaultRelations, defaultFields } from "."
/**
* @oas [post] /orders/{id}/swaps/{swap_id}/fulfillments/{fulfillment_id}/cancel
* operationId: "PostOrdersSwapFulfillmentsCancel"
* summary: "Cancels a fulfilmment related to a Swap"
* description: "Registers a Fulfillment as canceled."
* parameters:
* - (path) id=* {string} The id of the Order which the Swap relates to.
* - (path) swap_id=* {string} The id of the Swap which the Fulfillment relates to.
* - (path) fulfillment_id=* {string} The id of the Fulfillment.
* tags:
* - Fulfillment
* responses:
* 200:
* description: OK
* content:
* application/json:
* schema:
* properties:
* fulfillment:
* $ref: "#/components/schemas/fulfillment"
*/
export default async (req, res) => {
const { id, swap_id, fulfillment_id } = req.params
try {
const fulfillmentService = req.scope.resolve("fulfillmentService")
const swapService = req.scope.resolve("swapService")
const orderService = req.scope.resolve("orderService")
const fulfillment = await fulfillmentService.retrieve(fulfillment_id)
if (fulfillment.swap_id !== swap_id) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`no fulfillment was found with the id: ${fulfillment_id} related to swap: ${id}`
)
}
const swap = await swapService.retrieve(swap_id)
if (swap.order_id !== id) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`no swap was found with the id: ${swap_id} related to order: ${id}`
)
}
await swapService.cancelFulfillment(fulfillment_id)
const order = await orderService.retrieve(id, {
select: defaultFields,
relations: defaultRelations,
})
res.json({ order })
} catch (error) {
throw error
}
}
@@ -0,0 +1,51 @@
import { MedusaError } from "medusa-core-utils"
import { defaultRelations, defaultFields } from "."
/**
* @oas [post] /orders/{id}/fulfillments/{fulfillment_id}/cancel
* operationId: "PostOrdersOrderFulfillmentsCancel"
* summary: "Cancels a fulfilmment"
* description: "Registers a Fulfillment as canceled."
* parameters:
* - (path) id=* {string} The id of the Order which the Fulfillment relates to.
* - (path) fulfillment_id=* {string} The id of the Fulfillment
* tags:
* - Fulfillment
* responses:
* 200:
* description: OK
* content:
* application/json:
* schema:
* properties:
* fulfillment:
* $ref: "#/components/schemas/fulfillment"
*/
export default async (req, res) => {
const { id, fulfillment_id } = req.params
try {
const fulfillmentService = req.scope.resolve("fulfillmentService")
const orderService = req.scope.resolve("orderService")
const fulfillment = await fulfillmentService.retrieve(fulfillment_id)
if (fulfillment.order_id !== id) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`no fulfillment was found with the id: ${fulfillment_id} related to order: ${id}`
)
}
await orderService.cancelFulfillment(fulfillment_id)
const order = await orderService.retrieve(id, {
select: defaultFields,
relations: defaultRelations,
})
res.json({ order })
} catch (error) {
throw error
}
}
@@ -1,3 +1,5 @@
import { defaultFields, defaultRelations } from "."
/**
* @oas [post] /orders/{id}/cancel
* operationId: "PostOrdersOrderCancel"
@@ -22,11 +24,11 @@ export default async (req, res) => {
try {
const orderService = req.scope.resolve("orderService")
await orderService.cancel(id)
const order = await orderService.retrieve(id, {
relations: ["region", "customer", "swaps"],
select: defaultFields,
relations: defaultRelations,
})
res.json({ order })
@@ -0,0 +1,51 @@
import { MedusaError } from "medusa-core-utils"
import { defaultRelations, defaultFields } from "."
/**
* @oas [post] /orders/{id}/swaps/{swap_id}/cancel
* operationId: "PostOrdersSwapCancel"
* summary: "Cancels a Swap"
* description: "Cancels a Swap"
* parameters:
* - (path) id=* {string} The id of the Order.
* . (path) swap_id=* {string} The id of the Swap.
* tags:
* - Swap
* responses:
* 200:
* description: OK
* content:
* application/json:
* schema:
* properties:
* order:
* $ref: "#/components/schemas/swap"
*/
export default async (req, res) => {
const { id, swap_id } = req.params
try {
const swapService = req.scope.resolve("swapService")
const orderService = req.scope.resolve("orderService")
const swap = await swapService.retrieve(swap_id)
if (swap.order_id !== id) {
throw new MedusaError(
MedusaError.Types.NOT_FOUND,
`no swap was found with the id: ${swap_id} related to order: ${id}`
)
}
await swapService.cancel(swap_id)
const order = await orderService.retrieve(id, {
select: defaultFields,
relations: defaultRelations,
})
res.json({ order })
} catch (error) {
throw error
}
}
@@ -62,6 +62,30 @@ export default app => {
middlewares.wrap(require("./create-fulfillment").default)
)
/**
* Cancel a fulfillment related to an order.
*/
route.post(
"/:id/fulfillments/:fulfillment_id/cancel",
middlewares.wrap(require("./cancel-fulfillment").default)
)
/**
* Cancel a fulfillment related to a swap.
*/
route.post(
"/:id/swaps/:swap_id/fulfillments/:fulfillment_id/cancel",
middlewares.wrap(require("./cancel-fulfillment-swap").default)
)
/**
* Cancel a fulfillment related to a claim.
*/
route.post(
"/:id/claims/:claim_id/fulfillments/:fulfillment_id/cancel",
middlewares.wrap(require("./cancel-fulfillment-claim").default)
)
/**
* Create a shipment.
*/
@@ -104,6 +128,14 @@ export default app => {
*/
route.post("/:id/swaps", middlewares.wrap(require("./create-swap").default))
/**
* Cancels a swap.
*/
route.post(
"/:id/swaps/:swap_id/cancel",
middlewares.wrap(require("./cancel-swap").default)
)
/**
* Receives the inventory to return from a swap
*/
@@ -141,6 +173,14 @@ export default app => {
*/
route.post("/:id/claims", middlewares.wrap(require("./create-claim").default))
/**
* Cancels a claim
*/
route.post(
"/:id/claims/:claim_id/cancel",
middlewares.wrap(require("./cancel-claim").default)
)
/**
* Updates a claim
*/
@@ -193,6 +233,7 @@ export const defaultRelations = [
"gift_card_transactions",
"claims",
"claims.return_order",
"claims.return_order.shipping_method",
"claims.shipping_methods",
"claims.shipping_address",
"claims.additional_items",
@@ -140,7 +140,7 @@ export default async (req, res) => {
if (typeof value.refund !== "undefined" && value.refund < 0) {
returnObj.refund_amount = 0
} else {
if (value.refund) {
if (value.refund >= 0) {
returnObj.refund_amount = value.refund
}
}
@@ -149,7 +149,10 @@ export default async (req, res) => {
.withTransaction(manager)
.retrieve(id)
const evaluatedNoNotification = value.no_notification !== undefined ? value.no_notification : order.no_notification
const evaluatedNoNotification =
value.no_notification !== undefined
? value.no_notification
: order.no_notification
returnObj.no_notification = evaluatedNoNotification
const createdReturn = await returnService
@@ -161,13 +164,13 @@ export default async (req, res) => {
.withTransaction(manager)
.fulfill(createdReturn.id)
}
await eventBus
.withTransaction(manager)
.emit("order.return_requested", {
id,
return_id: createdReturn.id,
no_notification: evaluatedNoNotification
no_notification: evaluatedNoNotification,
})
return {
@@ -0,0 +1,50 @@
import { result } from "lodash"
import { MedusaError, Validator } from "medusa-core-utils"
import { defaultFields, defaultRelations } from "../orders"
/**
* @oas [post] /returns/{id}/cancel
* operationId: "PostReturnsReturnCancel"
* summary: "Cancel a Return"
* description: "Registers a Return as canceled."
* parameters:
* - (path) id=* {string} The id of the Return.
* tags:
* - Return
* responses:
* 200:
* description: OK
* content:
* application/json:
* schema:
* properties:
* return:
* $ref: "#/components/schemas/order"
*/
export default async (req, res) => {
const { id } = req.params
try {
const returnService = req.scope.resolve("returnService")
const orderService = req.scope.resolve("orderService")
let result = await returnService.cancel(id)
if (result.swap_id) {
const swapService = req.scope.resolve("swapService")
result = await swapService.retrieve(result.swap_id)
} else if (result.claim_order_id) {
const claimService = req.scope.resolve("claimService")
result = await claimService.retrieve(result.claim_order_id)
}
const order = await orderService.retrieve(result.order_id, {
select: defaultFields,
relations: defaultRelations,
})
res.status(200).json({ order })
} catch (err) {
throw err
}
}
@@ -16,5 +16,10 @@ export default app => {
middlewares.wrap(require("./receive-return").default)
)
route.post(
"/:id/cancel",
middlewares.wrap(require("./cancel-return").default)
)
return app
}
@@ -1,7 +1,7 @@
import { MedusaError, Validator } from "medusa-core-utils"
/**
* @oas [post] /returns/{id}receive
* @oas [post] /returns/{id}/receive
* operationId: "PostReturnsReturnReceive"
* summary: "Receive a Return"
* description: "Registers a Return as received. Updates statuses on Orders and Swaps accordingly."
@@ -72,7 +72,7 @@ describe("GET /admin/swaps/:id", () => {
it("returns swap", () => {
expect(subject.status).toEqual(200)
expect(subject.body.swap.id).toEqual(IdMap.getId("test-swap"))
expect(subject.body.swap.id).toEqual("test-swap")
})
})
})
@@ -78,7 +78,7 @@ describe("POST /store/carts/:id", () => {
})
it("returns the created order", () => {
expect(subject.body.data.id).toEqual(IdMap.getId("test-swap"))
expect(subject.body.data.id).toEqual("test-swap")
})
})
@@ -3,7 +3,7 @@ import middlewares from "../../../middlewares"
const route = Router()
export default (app) => {
export default app => {
app.use("/swaps", route)
route.get(
@@ -19,6 +19,7 @@ export const defaultRelations = [
"order",
"additional_items",
"return_order",
"return_order.shipping_method",
"fulfillments",
"payment",
"shipping_address",