fix(core-flows): account for unfulfilled items while generating order status (#8698)

what:

- account for unfulfilled items while generating order status

RESOLVES CC-314
This commit is contained in:
Riqwan Thamir authored and GitHub committed 2024-08-21 14:33:43 +00:00
1 parent 0da9445d80
commit de7848f68d
3 files changed
+103 -10

No files matched your search

@@ -877,7 +877,7 @@ medusaIntegrationTestRunner({
items: [ items: [
{ {
variant_id: productExtra.variants[0].id, variant_id: productExtra.variants[0].id,
quantity: 2, quantity: 3,
}, },
], ],
}, },
@@ -917,7 +917,7 @@ medusaIntegrationTestRunner({
await api.get(`/admin/orders/${order.id}`, adminHeaders) await api.get(`/admin/orders/${order.id}`, adminHeaders)
).data.order ).data.order
const fulfillableItem = fulfillOrder.items.find( const fulfillableItem = fulfillOrder.items.filter(
(item) => item.detail.fulfilled_quantity === 0 (item) => item.detail.fulfilled_quantity === 0
) )
@@ -925,10 +925,85 @@ medusaIntegrationTestRunner({
`/admin/orders/${order.id}/fulfillments`, `/admin/orders/${order.id}/fulfillments`,
{ {
location_id: location.id, location_id: location.id,
items: [{ id: fulfillableItem.id, quantity: 1 }], items: [{ id: fulfillableItem[0].id, quantity: 1 }],
}, },
adminHeaders adminHeaders
) )
let orderResult = (
await api.get(`/admin/orders/${order.id}`, adminHeaders)
).data.order
expect(orderResult.fulfillment_status).toEqual("partially_fulfilled")
await api.post(
`/admin/orders/${order.id}/fulfillments`,
{
location_id: location.id,
items: [{ id: fulfillableItem[0].id, quantity: 2 }],
},
adminHeaders
)
orderResult = (
await api.get(
`/admin/orders/${order.id}?fields=*fulfillments,*fulfillments.items`,
adminHeaders
)
).data.order
expect(orderResult.fulfillment_status).toEqual("fulfilled")
await api.post(
`admin/orders/${order.id}/fulfillments/${orderResult.fulfillments[0].id}/shipments`,
{
items: orderResult.fulfillments[0]?.items?.map((i) => ({
id: i.line_item_id,
quantity: i.quantity,
})),
},
adminHeaders
)
orderResult = (
await api.get(
`/admin/orders/${order.id}?fields=*fulfillments,*fulfillments.items`,
adminHeaders
)
).data.order
expect(orderResult.fulfillment_status).toEqual("partially_shipped")
await api.post(
`admin/orders/${order.id}/fulfillments/${orderResult.fulfillments[1].id}/shipments`,
{
items: orderResult.fulfillments[1]?.items?.map((i) => ({
id: i.line_item_id,
quantity: i.quantity,
})),
},
adminHeaders
)
await api.post(
`admin/orders/${order.id}/fulfillments/${orderResult.fulfillments[2].id}/shipments`,
{
items: orderResult.fulfillments[2]?.items?.map((i) => ({
id: i.line_item_id,
quantity: i.quantity,
})),
},
adminHeaders
)
orderResult = (
await api.get(
`/admin/orders/${order.id}?fields=*fulfillments`,
adminHeaders
)
).data.order
expect(orderResult.fulfillment_status).toEqual("shipped")
}) })
}) })
}) })
@@ -1,5 +1,5 @@
import { OrderDetailDTO } from "@medusajs/types" import { OrderDetailDTO } from "@medusajs/types"
import { MathBN } from "@medusajs/utils" import { isDefined, MathBN } from "@medusajs/utils"
export const getLastPaymentStatus = (order: OrderDetailDTO) => { export const getLastPaymentStatus = (order: OrderDetailDTO) => {
const PaymentStatus = { const PaymentStatus = {
@@ -103,17 +103,22 @@ export const getLastFulfillmentStatus = (order: OrderDetailDTO) => {
} }
let fulfillmentStatus = {} let fulfillmentStatus = {}
for (const status in FulfillmentStatus) { for (const status in FulfillmentStatus) {
fulfillmentStatus[FulfillmentStatus[status]] = 0 fulfillmentStatus[FulfillmentStatus[status]] = 0
} }
const statusMap = { const statusMap = {
packed_at: FulfillmentStatus.FULFILLED,
shipped_at: FulfillmentStatus.SHIPPED,
delivered_at: FulfillmentStatus.DELIVERED,
canceled_at: FulfillmentStatus.CANCELED, canceled_at: FulfillmentStatus.CANCELED,
delivered_at: FulfillmentStatus.DELIVERED,
shipped_at: FulfillmentStatus.SHIPPED,
packed_at: FulfillmentStatus.FULFILLED,
} }
for (const fulfillmentCollection of order.fulfillments) { for (const fulfillmentCollection of order.fulfillments) {
// Note: The order of the statusMap keys is important as we break
// the loop when we have found a match. The match should be prioritized
// based on order of precedence of statuses
for (const key in statusMap) { for (const key in statusMap) {
if (fulfillmentCollection[key]) { if (fulfillmentCollection[key]) {
fulfillmentStatus[statusMap[key]] += 1 fulfillmentStatus[statusMap[key]] += 1
@@ -126,10 +131,20 @@ export const getLastFulfillmentStatus = (order: OrderDetailDTO) => {
const totalFulfillmentsExceptCanceled = const totalFulfillmentsExceptCanceled =
totalFulfillments - fulfillmentStatus[FulfillmentStatus.CANCELED] totalFulfillments - fulfillmentStatus[FulfillmentStatus.CANCELED]
// Whenever there are any unfulfilled items in the order, it should be
// considered partially_[STATUS] where status is picked up from the hierarchy
// of statuses
const hasUnfulfilledItems = (order.items || [])?.filter(
(i) =>
isDefined(i?.detail?.raw_fulfilled_quantity) &&
MathBN.lt(i.detail.raw_fulfilled_quantity, i.raw_quantity)
).length > 0
if (fulfillmentStatus[FulfillmentStatus.DELIVERED] > 0) { if (fulfillmentStatus[FulfillmentStatus.DELIVERED] > 0) {
if ( if (
fulfillmentStatus[FulfillmentStatus.DELIVERED] === fulfillmentStatus[FulfillmentStatus.DELIVERED] ===
totalFulfillmentsExceptCanceled totalFulfillmentsExceptCanceled &&
!hasUnfulfilledItems
) { ) {
return FulfillmentStatus.DELIVERED return FulfillmentStatus.DELIVERED
} }
@@ -140,7 +155,8 @@ export const getLastFulfillmentStatus = (order: OrderDetailDTO) => {
if (fulfillmentStatus[FulfillmentStatus.SHIPPED] > 0) { if (fulfillmentStatus[FulfillmentStatus.SHIPPED] > 0) {
if ( if (
fulfillmentStatus[FulfillmentStatus.SHIPPED] === fulfillmentStatus[FulfillmentStatus.SHIPPED] ===
totalFulfillmentsExceptCanceled totalFulfillmentsExceptCanceled &&
!hasUnfulfilledItems
) { ) {
return FulfillmentStatus.SHIPPED return FulfillmentStatus.SHIPPED
} }
@@ -151,7 +167,8 @@ export const getLastFulfillmentStatus = (order: OrderDetailDTO) => {
if (fulfillmentStatus[FulfillmentStatus.FULFILLED] > 0) { if (fulfillmentStatus[FulfillmentStatus.FULFILLED] > 0) {
if ( if (
fulfillmentStatus[FulfillmentStatus.FULFILLED] === fulfillmentStatus[FulfillmentStatus.FULFILLED] ===
totalFulfillmentsExceptCanceled totalFulfillmentsExceptCanceled &&
!hasUnfulfilledItems
) { ) {
return FulfillmentStatus.FULFILLED return FulfillmentStatus.FULFILLED
} }
@@ -37,6 +37,7 @@ export const getOrdersListWorkflow = createWorkflow(
"id", "id",
"status", "status",
"version", "version",
"items.*",
"payment_collections.status", "payment_collections.status",
"payment_collections.amount", "payment_collections.amount",
"payment_collections.captured_amount", "payment_collections.captured_amount",