chore(order): item update quantity (#8513)
This commit is contained in:
1 parent
6efdfbc9a6
commit
91f07e1a59
6 files changed
+239
No files matched your search
@@ -15,6 +15,7 @@ export type ChangeActionType =
|
|||||||
| "CANCEL_ITEM_FULFILLMENT"
|
| "CANCEL_ITEM_FULFILLMENT"
|
||||||
| "ITEM_ADD"
|
| "ITEM_ADD"
|
||||||
| "ITEM_REMOVE"
|
| "ITEM_REMOVE"
|
||||||
|
| "ITEM_UPDATE"
|
||||||
| "RECEIVE_DAMAGED_RETURN_ITEM"
|
| "RECEIVE_DAMAGED_RETURN_ITEM"
|
||||||
| "RECEIVE_RETURN_ITEM"
|
| "RECEIVE_RETURN_ITEM"
|
||||||
| "RETURN_ITEM"
|
| "RETURN_ITEM"
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ export enum ChangeActionType {
|
|||||||
CANCEL_ITEM_FULFILLMENT = "CANCEL_ITEM_FULFILLMENT",
|
CANCEL_ITEM_FULFILLMENT = "CANCEL_ITEM_FULFILLMENT",
|
||||||
ITEM_ADD = "ITEM_ADD",
|
ITEM_ADD = "ITEM_ADD",
|
||||||
ITEM_REMOVE = "ITEM_REMOVE",
|
ITEM_REMOVE = "ITEM_REMOVE",
|
||||||
|
ITEM_UPDATE = "ITEM_UPDATE",
|
||||||
RECEIVE_DAMAGED_RETURN_ITEM = "RECEIVE_DAMAGED_RETURN_ITEM",
|
RECEIVE_DAMAGED_RETURN_ITEM = "RECEIVE_DAMAGED_RETURN_ITEM",
|
||||||
RECEIVE_RETURN_ITEM = "RECEIVE_RETURN_ITEM",
|
RECEIVE_RETURN_ITEM = "RECEIVE_RETURN_ITEM",
|
||||||
RETURN_ITEM = "RETURN_ITEM",
|
RETURN_ITEM = "RETURN_ITEM",
|
||||||
|
|||||||
@@ -121,4 +121,12 @@ export class BigNumber implements IBigNumber {
|
|||||||
valueOf(): number {
|
valueOf(): number {
|
||||||
return this.numeric_
|
return this.numeric_
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Symbol.toPrimitive](hint) {
|
||||||
|
if (hint === "string") {
|
||||||
|
return this.raw?.value
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.numeric_
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -342,6 +342,165 @@ moduleIntegrationTestRunner<IOrderModuleService>({
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should create an order change, add actions to it and confirm the changes.", async function () {
|
||||||
|
const createdOrder = await service.createOrders(input)
|
||||||
|
createdOrder.items = createdOrder.items!.sort((a, b) =>
|
||||||
|
a.title.localeCompare(b.title)
|
||||||
|
)
|
||||||
|
|
||||||
|
const orderChange = await service.createOrderChange({
|
||||||
|
order_id: createdOrder.id,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
action: ChangeActionType.FULFILL_ITEM,
|
||||||
|
details: {
|
||||||
|
reference_id: createdOrder.items![1].id,
|
||||||
|
quantity: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: ChangeActionType.ITEM_UPDATE,
|
||||||
|
details: {
|
||||||
|
reference_id: createdOrder.items![1].id,
|
||||||
|
quantity: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
service.confirmOrderChange({
|
||||||
|
id: orderChange.id,
|
||||||
|
})
|
||||||
|
).rejects.toThrow(
|
||||||
|
`Item ${
|
||||||
|
createdOrder.items![1].id
|
||||||
|
} has already been fulfilled and quantity cannot be lower than 2.`
|
||||||
|
)
|
||||||
|
await service.deleteOrderChanges([orderChange.id])
|
||||||
|
|
||||||
|
// Create Order Change
|
||||||
|
const orderChange2 = await service.createOrderChange({
|
||||||
|
order_id: createdOrder.id,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
action: ChangeActionType.FULFILL_ITEM,
|
||||||
|
details: {
|
||||||
|
reference_id: createdOrder.items![1].id,
|
||||||
|
quantity: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: ChangeActionType.ITEM_UPDATE,
|
||||||
|
details: {
|
||||||
|
reference_id: createdOrder.items![1].id,
|
||||||
|
quantity: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
await service.confirmOrderChange({
|
||||||
|
id: orderChange2.id,
|
||||||
|
})
|
||||||
|
|
||||||
|
const changedOrder = await service.retrieveOrder(createdOrder.id, {
|
||||||
|
select: ["total", "items.detail", "summary"],
|
||||||
|
relations: ["items"],
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(
|
||||||
|
JSON.parse(
|
||||||
|
JSON.stringify(
|
||||||
|
changedOrder.items?.find(
|
||||||
|
(i) => i.id === createdOrder.items![1].id
|
||||||
|
)?.detail
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
quantity: 4,
|
||||||
|
fulfilled_quantity: 1,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
// Create Order Change
|
||||||
|
const orderChange3 = await service.createOrderChange({
|
||||||
|
order_id: createdOrder.id,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
action: ChangeActionType.FULFILL_ITEM,
|
||||||
|
details: {
|
||||||
|
reference_id: createdOrder.items![1].id,
|
||||||
|
quantity: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: ChangeActionType.ITEM_UPDATE,
|
||||||
|
details: {
|
||||||
|
reference_id: createdOrder.items![1].id,
|
||||||
|
quantity: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
service.confirmOrderChange({
|
||||||
|
id: orderChange3.id,
|
||||||
|
})
|
||||||
|
).rejects.toThrow(
|
||||||
|
`Item ${
|
||||||
|
createdOrder.items![1].id
|
||||||
|
} has already been fulfilled and quantity cannot be lower than 4.`
|
||||||
|
)
|
||||||
|
await service.deleteOrderChanges([orderChange3.id])
|
||||||
|
|
||||||
|
// Create Order Change
|
||||||
|
const orderChange4 = await service.createOrderChange({
|
||||||
|
order_id: createdOrder.id,
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
action: ChangeActionType.FULFILL_ITEM,
|
||||||
|
details: {
|
||||||
|
reference_id: createdOrder.items![1].id,
|
||||||
|
quantity: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
action: ChangeActionType.ITEM_UPDATE,
|
||||||
|
details: {
|
||||||
|
reference_id: createdOrder.items![1].id,
|
||||||
|
quantity: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
await service.confirmOrderChange({
|
||||||
|
id: orderChange4.id,
|
||||||
|
})
|
||||||
|
|
||||||
|
const modified = await service.retrieveOrder(createdOrder.id, {
|
||||||
|
select: ["total", "items.detail", "summary"],
|
||||||
|
relations: ["items"],
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(
|
||||||
|
JSON.parse(
|
||||||
|
JSON.stringify(
|
||||||
|
modified.items?.find((i) => i.id === createdOrder.items![1].id)
|
||||||
|
?.detail
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
quantity: 3,
|
||||||
|
fulfilled_quantity: 2,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
it("should create an order change, add actions to it, confirm the changes, revert all the changes and restore the changes again.", async function () {
|
it("should create an order change, add actions to it, confirm the changes, revert all the changes and restore the changes again.", async function () {
|
||||||
const createdOrder = await service.createOrders(input)
|
const createdOrder = await service.createOrders(input)
|
||||||
createdOrder.items = createdOrder.items!.sort((a, b) =>
|
createdOrder.items = createdOrder.items!.sort((a, b) =>
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ export * from "./cancel-return"
|
|||||||
export * from "./fulfill-item"
|
export * from "./fulfill-item"
|
||||||
export * from "./item-add"
|
export * from "./item-add"
|
||||||
export * from "./item-remove"
|
export * from "./item-remove"
|
||||||
|
export * from "./item-update"
|
||||||
export * from "./receive-damaged-return-item"
|
export * from "./receive-damaged-return-item"
|
||||||
export * from "./receive-return-item"
|
export * from "./receive-return-item"
|
||||||
export * from "./reinstate-item"
|
export * from "./reinstate-item"
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
import { ChangeActionType, MathBN, MedusaError } from "@medusajs/utils"
|
||||||
|
import { OrderChangeProcessing } from "../calculate-order-change"
|
||||||
|
import { setActionReference } from "../set-action-reference"
|
||||||
|
|
||||||
|
OrderChangeProcessing.registerActionType(ChangeActionType.ITEM_UPDATE, {
|
||||||
|
operation({ action, currentOrder, options }) {
|
||||||
|
const existingIndex = currentOrder.items.findIndex(
|
||||||
|
(item) => item.id === action.details.reference_id
|
||||||
|
)
|
||||||
|
|
||||||
|
const existing = currentOrder.items[existingIndex]
|
||||||
|
|
||||||
|
existing.detail.quantity ??= 0
|
||||||
|
|
||||||
|
const quantityDiff = MathBN.sub(
|
||||||
|
action.details.quantity,
|
||||||
|
existing.detail.quantity
|
||||||
|
)
|
||||||
|
|
||||||
|
existing.quantity = action.details.quantity
|
||||||
|
existing.detail.quantity = action.details.quantity
|
||||||
|
|
||||||
|
setActionReference(existing, action, options)
|
||||||
|
|
||||||
|
if (MathBN.lte(existing.quantity, 0)) {
|
||||||
|
currentOrder.items.splice(existingIndex, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return MathBN.mult(existing.unit_price, quantityDiff)
|
||||||
|
},
|
||||||
|
validate({ action, currentOrder }) {
|
||||||
|
const refId = action.details?.reference_id
|
||||||
|
if (refId == null) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
"Reference ID is required."
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const existing = currentOrder.items.find((item) => item.id === refId)
|
||||||
|
if (!existing) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
`Item ID "${refId}" not found.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action.details?.quantity == null) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
`Quantity of item ${refId} is required.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
action.details.quantity ??= 0
|
||||||
|
|
||||||
|
const lower = MathBN.lt(
|
||||||
|
action.details.quantity,
|
||||||
|
existing.detail?.fulfilled_quantity
|
||||||
|
)
|
||||||
|
|
||||||
|
if (lower) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
`Item ${refId} has already been fulfilled and quantity cannot be lower than ${existing.detail?.fulfilled_quantity}.`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
Reference in new issue
Block a user