Feat(order): post purchase support (#7666)
This commit is contained in:
committed by
GitHub
parent
39ddba2491
commit
37426939da
@@ -1,6 +1,7 @@
|
||||
import { MathBN, MedusaError, isDefined } from "@medusajs/utils"
|
||||
import { ChangeActionType } from "../action-key"
|
||||
import { OrderChangeProcessing } from "../calculate-order-change"
|
||||
import { setActionReference } from "../set-action-reference"
|
||||
|
||||
OrderChangeProcessing.registerActionType(
|
||||
ChangeActionType.CANCEL_ITEM_FULFILLMENT,
|
||||
@@ -16,6 +17,8 @@ OrderChangeProcessing.registerActionType(
|
||||
existing.detail.fulfilled_quantity,
|
||||
action.details.quantity
|
||||
)
|
||||
|
||||
setActionReference(existing, action)
|
||||
},
|
||||
revert({ action, currentOrder }) {
|
||||
const existing = currentOrder.items.find(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { MathBN, MedusaError, isDefined } from "@medusajs/utils"
|
||||
import { ChangeActionType } from "../action-key"
|
||||
import { OrderChangeProcessing } from "../calculate-order-change"
|
||||
import { setActionReference } from "../set-action-reference"
|
||||
|
||||
OrderChangeProcessing.registerActionType(ChangeActionType.CANCEL_RETURN, {
|
||||
operation({ action, currentOrder }) {
|
||||
@@ -15,6 +16,8 @@ OrderChangeProcessing.registerActionType(ChangeActionType.CANCEL_RETURN, {
|
||||
action.details.quantity
|
||||
)
|
||||
|
||||
setActionReference(existing, action)
|
||||
|
||||
return action.details.unit_price * action.details.quantity
|
||||
},
|
||||
revert({ action, currentOrder }) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { MathBN, MedusaError, isDefined } from "@medusajs/utils"
|
||||
import { ChangeActionType } from "../action-key"
|
||||
import { OrderChangeProcessing } from "../calculate-order-change"
|
||||
import { setActionReference } from "../set-action-reference"
|
||||
|
||||
OrderChangeProcessing.registerActionType(ChangeActionType.FULFILL_ITEM, {
|
||||
operation({ action, currentOrder }) {
|
||||
@@ -14,6 +15,8 @@ OrderChangeProcessing.registerActionType(ChangeActionType.FULFILL_ITEM, {
|
||||
existing.detail.fulfilled_quantity,
|
||||
action.details.quantity
|
||||
)
|
||||
|
||||
setActionReference(existing, action)
|
||||
},
|
||||
revert({ action, currentOrder }) {
|
||||
const existing = currentOrder.items.find(
|
||||
|
||||
@@ -2,6 +2,7 @@ import { MathBN, MedusaError, isDefined } from "@medusajs/utils"
|
||||
import { VirtualOrder } from "@types"
|
||||
import { ChangeActionType } from "../action-key"
|
||||
import { OrderChangeProcessing } from "../calculate-order-change"
|
||||
import { setActionReference } from "../set-action-reference"
|
||||
|
||||
OrderChangeProcessing.registerActionType(ChangeActionType.ITEM_ADD, {
|
||||
operation({ action, currentOrder }) {
|
||||
@@ -18,9 +19,16 @@ OrderChangeProcessing.registerActionType(ChangeActionType.ITEM_ADD, {
|
||||
existing.detail.quantity,
|
||||
action.details.quantity
|
||||
)
|
||||
|
||||
setActionReference(existing, action)
|
||||
} else {
|
||||
currentOrder.items.push({
|
||||
id: action.reference_id!,
|
||||
order_id: currentOrder.id,
|
||||
return_id: action.details.return_id,
|
||||
claim_id: action.details.claim_id,
|
||||
exchange_id: action.details.exchange_id,
|
||||
|
||||
unit_price: action.details.unit_price,
|
||||
quantity: action.details.quantity,
|
||||
} as VirtualOrder["items"][0])
|
||||
|
||||
@@ -2,6 +2,7 @@ import { MathBN, MedusaError, isDefined } from "@medusajs/utils"
|
||||
import { VirtualOrder } from "@types"
|
||||
import { ChangeActionType } from "../action-key"
|
||||
import { OrderChangeProcessing } from "../calculate-order-change"
|
||||
import { setActionReference } from "../set-action-reference"
|
||||
|
||||
OrderChangeProcessing.registerActionType(ChangeActionType.ITEM_REMOVE, {
|
||||
isDeduction: true,
|
||||
@@ -20,6 +21,8 @@ OrderChangeProcessing.registerActionType(ChangeActionType.ITEM_REMOVE, {
|
||||
action.details.quantity
|
||||
)
|
||||
|
||||
setActionReference(existing, action)
|
||||
|
||||
if (MathBN.lte(existing.quantity, 0)) {
|
||||
currentOrder.items.splice(existingIndex, 1)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ import { MathBN, MedusaError, isDefined } from "@medusajs/utils"
|
||||
import { EVENT_STATUS } from "@types"
|
||||
import { ChangeActionType } from "../action-key"
|
||||
import { OrderChangeProcessing } from "../calculate-order-change"
|
||||
import { setActionReference } from "../set-action-reference"
|
||||
|
||||
OrderChangeProcessing.registerActionType(
|
||||
ChangeActionType.RECEIVE_DAMAGED_RETURN_ITEM,
|
||||
@@ -27,6 +28,8 @@ OrderChangeProcessing.registerActionType(
|
||||
toReturn
|
||||
)
|
||||
|
||||
setActionReference(existing, action)
|
||||
|
||||
if (previousEvents) {
|
||||
for (const previousEvent of previousEvents) {
|
||||
previousEvent.original_ = JSON.parse(JSON.stringify(previousEvent))
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
import { EVENT_STATUS } from "@types"
|
||||
import { ChangeActionType } from "../action-key"
|
||||
import { OrderChangeProcessing } from "../calculate-order-change"
|
||||
import { setActionReference } from "../set-action-reference"
|
||||
|
||||
OrderChangeProcessing.registerActionType(ChangeActionType.RECEIVE_RETURN_ITEM, {
|
||||
isDeduction: true,
|
||||
@@ -30,6 +31,8 @@ OrderChangeProcessing.registerActionType(ChangeActionType.RECEIVE_RETURN_ITEM, {
|
||||
toReturn
|
||||
)
|
||||
|
||||
setActionReference(existing, action)
|
||||
|
||||
if (previousEvents) {
|
||||
for (const previousEvent of previousEvents) {
|
||||
previousEvent.original_ = JSON.parse(JSON.stringify(previousEvent))
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { MathBN, MedusaError, isDefined } from "@medusajs/utils"
|
||||
import { ChangeActionType } from "../action-key"
|
||||
import { OrderChangeProcessing } from "../calculate-order-change"
|
||||
import { setActionReference } from "../set-action-reference"
|
||||
|
||||
OrderChangeProcessing.registerActionType(ChangeActionType.RETURN_ITEM, {
|
||||
isDeduction: true,
|
||||
@@ -16,6 +17,8 @@ OrderChangeProcessing.registerActionType(ChangeActionType.RETURN_ITEM, {
|
||||
action.details.quantity
|
||||
)
|
||||
|
||||
setActionReference(existing, action)
|
||||
|
||||
return MathBN.mult(existing.unit_price, action.details.quantity)
|
||||
},
|
||||
revert({ action, currentOrder }) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { MathBN, MedusaError, isDefined } from "@medusajs/utils"
|
||||
import { ChangeActionType } from "../action-key"
|
||||
import { OrderChangeProcessing } from "../calculate-order-change"
|
||||
import { setActionReference } from "../set-action-reference"
|
||||
|
||||
OrderChangeProcessing.registerActionType(ChangeActionType.SHIP_ITEM, {
|
||||
operation({ action, currentOrder }) {
|
||||
@@ -14,6 +15,8 @@ OrderChangeProcessing.registerActionType(ChangeActionType.SHIP_ITEM, {
|
||||
existing.detail.shipped_quantity,
|
||||
action.details.quantity
|
||||
)
|
||||
|
||||
setActionReference(existing, action)
|
||||
},
|
||||
revert({ action, currentOrder }) {
|
||||
const existing = currentOrder.items.find(
|
||||
|
||||
@@ -9,7 +9,12 @@ OrderChangeProcessing.registerActionType(ChangeActionType.SHIPPING_ADD, {
|
||||
: [currentOrder.shipping_methods]
|
||||
|
||||
shipping.push({
|
||||
id: action.reference_id!,
|
||||
shipping_method_id: action.reference_id!,
|
||||
order_id: currentOrder.id,
|
||||
return_id: action.return_id,
|
||||
claim_id: action.claim_id,
|
||||
exchange_id: action.exchange_id,
|
||||
|
||||
price: action.amount as number,
|
||||
})
|
||||
|
||||
@@ -21,7 +26,7 @@ OrderChangeProcessing.registerActionType(ChangeActionType.SHIPPING_ADD, {
|
||||
: [currentOrder.shipping_methods]
|
||||
|
||||
const existingIndex = shipping.findIndex(
|
||||
(item) => item.id === action.reference_id
|
||||
(item) => item.shipping_method_id === action.reference_id
|
||||
)
|
||||
|
||||
if (existingIndex > -1) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { MathBN, MedusaError, isDefined } from "@medusajs/utils"
|
||||
import { ChangeActionType } from "../action-key"
|
||||
import { OrderChangeProcessing } from "../calculate-order-change"
|
||||
import { setActionReference } from "../set-action-reference"
|
||||
|
||||
OrderChangeProcessing.registerActionType(ChangeActionType.WRITE_OFF_ITEM, {
|
||||
operation({ action, currentOrder }) {
|
||||
@@ -13,6 +14,8 @@ OrderChangeProcessing.registerActionType(ChangeActionType.WRITE_OFF_ITEM, {
|
||||
existing.detail.written_off_quantity,
|
||||
action.details.quantity
|
||||
)
|
||||
|
||||
setActionReference(existing, action)
|
||||
},
|
||||
revert({ action, currentOrder }) {
|
||||
const existing = currentOrder.items.find(
|
||||
|
||||
89
packages/modules/order/src/utils/apply-order-changes.ts
Normal file
89
packages/modules/order/src/utils/apply-order-changes.ts
Normal file
@@ -0,0 +1,89 @@
|
||||
import { OrderChangeActionDTO } from "@medusajs/types"
|
||||
import { createRawPropertiesFromBigNumber } from "@medusajs/utils"
|
||||
import { OrderItem, OrderShippingMethod } from "@models"
|
||||
import { calculateOrderChange } from "./calculate-order-change"
|
||||
|
||||
export interface ApplyOrderChangeDTO extends OrderChangeActionDTO {
|
||||
id: string
|
||||
order_id: string
|
||||
version: number
|
||||
applied: boolean
|
||||
}
|
||||
|
||||
export function applyChangesToOrder(
|
||||
orders: any[],
|
||||
actionsMap: Record<string, any[]>
|
||||
) {
|
||||
const itemsToUpsert: OrderItem[] = []
|
||||
const shippingMethodsToInsert: OrderShippingMethod[] = []
|
||||
const summariesToUpsert: any[] = []
|
||||
const orderToUpdate: any[] = []
|
||||
|
||||
for (const order of orders) {
|
||||
const calculated = calculateOrderChange({
|
||||
order: order as any,
|
||||
actions: actionsMap[order.id],
|
||||
transactions: order.transactions ?? [],
|
||||
})
|
||||
|
||||
createRawPropertiesFromBigNumber(calculated)
|
||||
|
||||
const version = actionsMap[order.id][0].version ?? 1
|
||||
|
||||
for (const item of calculated.order.items) {
|
||||
const orderItem = item.detail as any
|
||||
itemsToUpsert.push({
|
||||
id: orderItem.version === version ? orderItem.id : undefined,
|
||||
item_id: item.id,
|
||||
order_id: order.id,
|
||||
version,
|
||||
return_id: item.detail.return_id,
|
||||
claim_id: item.detail.claim_id,
|
||||
exchange_id: item.detail.exchange_id,
|
||||
quantity: item.detail.quantity,
|
||||
fulfilled_quantity: item.detail.fulfilled_quantity,
|
||||
shipped_quantity: item.detail.shipped_quantity,
|
||||
return_requested_quantity: item.detail.return_requested_quantity,
|
||||
return_received_quantity: item.detail.return_received_quantity,
|
||||
return_dismissed_quantity: item.detail.return_dismissed_quantity,
|
||||
written_off_quantity: item.detail.written_off_quantity,
|
||||
metadata: item.detail.metadata,
|
||||
} as any)
|
||||
}
|
||||
|
||||
const orderSummary = order.summary as any
|
||||
summariesToUpsert.push({
|
||||
id: orderSummary?.version === version ? orderSummary.id : undefined,
|
||||
order_id: order.id,
|
||||
version,
|
||||
totals: calculated.summary,
|
||||
})
|
||||
|
||||
if (version > order.version) {
|
||||
for (const shippingMethod of calculated.order.shipping_methods ?? []) {
|
||||
const sm = {
|
||||
...((shippingMethod as any).detail ?? shippingMethod),
|
||||
version,
|
||||
}
|
||||
delete sm.id
|
||||
shippingMethodsToInsert.push(sm)
|
||||
}
|
||||
|
||||
orderToUpdate.push({
|
||||
selector: {
|
||||
id: order.id,
|
||||
},
|
||||
data: {
|
||||
version,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
itemsToUpsert,
|
||||
shippingMethodsToInsert,
|
||||
summariesToUpsert,
|
||||
orderToUpdate,
|
||||
}
|
||||
}
|
||||
151
packages/modules/order/src/utils/base-repository-find.ts
Normal file
151
packages/modules/order/src/utils/base-repository-find.ts
Normal file
@@ -0,0 +1,151 @@
|
||||
import { Constructor, Context, DAL } from "@medusajs/types"
|
||||
import { LoadStrategy } from "@mikro-orm/core"
|
||||
import { Order } from "@models"
|
||||
import { mapRepositoryToOrderModel } from "."
|
||||
|
||||
export function setFindMethods<T>(klass: Constructor<T>, entity: any) {
|
||||
klass.prototype.find = async function find(
|
||||
this: any,
|
||||
options?: DAL.FindOptions<T>,
|
||||
context?: Context
|
||||
): Promise<T[]> {
|
||||
const manager = this.getActiveManager(context)
|
||||
const knex = manager.getKnex()
|
||||
|
||||
const findOptions_ = { ...options } as any
|
||||
findOptions_.options ??= {}
|
||||
findOptions_.where ??= {}
|
||||
findOptions_.populate ??= []
|
||||
|
||||
if (!("strategy" in findOptions_.options)) {
|
||||
if (findOptions_.options.limit != null || findOptions_.options.offset) {
|
||||
Object.assign(findOptions_.options, {
|
||||
strategy: LoadStrategy.SELECT_IN,
|
||||
})
|
||||
} else {
|
||||
Object.assign(findOptions_.options, {
|
||||
strategy: LoadStrategy.JOINED,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const config = mapRepositoryToOrderModel(findOptions_)
|
||||
|
||||
let orderAlias = "o0"
|
||||
if (entity !== Order) {
|
||||
// first relation is always order if entity is not Order
|
||||
config.options.populate.unshift("order")
|
||||
orderAlias = "o1"
|
||||
}
|
||||
|
||||
let defaultVersion = knex.raw(`"${orderAlias}"."version"`)
|
||||
const strategy = config.options.strategy ?? LoadStrategy.JOINED
|
||||
if (strategy === LoadStrategy.SELECT_IN) {
|
||||
const sql = manager
|
||||
.qb(Order, "_sub0")
|
||||
.select("version")
|
||||
.where({ id: knex.raw(`"o0"."order_id"`) })
|
||||
.getKnexQuery()
|
||||
.toString()
|
||||
|
||||
defaultVersion = knex.raw(`(${sql})`)
|
||||
}
|
||||
|
||||
const version = config.where.version ?? defaultVersion
|
||||
delete config.where?.version
|
||||
|
||||
config.options.populateWhere ??= {}
|
||||
|
||||
if (entity !== Order) {
|
||||
config.options.populateWhere.order ??= {}
|
||||
config.options.populateWhere.order.version = version
|
||||
|
||||
config.options.populateWhere.order.summary ??= {}
|
||||
config.options.populateWhere.order.summary.version = version
|
||||
} else {
|
||||
config.options.populateWhere.summary ??= {}
|
||||
config.options.populateWhere.summary.version = version
|
||||
}
|
||||
|
||||
config.options.populateWhere.items ??= {}
|
||||
config.options.populateWhere.items.version = version
|
||||
|
||||
config.options.populateWhere.shipping_methods ??= {}
|
||||
config.options.populateWhere.shipping_methods.version = version
|
||||
|
||||
if (!config.options.orderBy) {
|
||||
config.options.orderBy = { id: "ASC" }
|
||||
}
|
||||
|
||||
return await manager.find(entity, config.where, config.options)
|
||||
}
|
||||
|
||||
klass.prototype.findAndCount = async function findAndCount(
|
||||
this: any,
|
||||
findOptions: DAL.FindOptions<T> = { where: {} },
|
||||
context: Context = {}
|
||||
): Promise<[T[], number]> {
|
||||
const manager = this.getActiveManager(context)
|
||||
const knex = manager.getKnex()
|
||||
|
||||
const findOptions_ = { ...findOptions } as any
|
||||
findOptions_.options ??= {}
|
||||
findOptions_.where ??= {}
|
||||
|
||||
if (!("strategy" in findOptions_.options)) {
|
||||
Object.assign(findOptions_.options, {
|
||||
strategy: LoadStrategy.SELECT_IN,
|
||||
})
|
||||
}
|
||||
|
||||
const config = mapRepositoryToOrderModel(findOptions_)
|
||||
|
||||
let orderAlias = "o0"
|
||||
if (entity !== Order) {
|
||||
// first relation is always order if entity is not Order
|
||||
config.options.populate.unshift("order")
|
||||
orderAlias = "o1"
|
||||
}
|
||||
|
||||
let defaultVersion = knex.raw(`"${orderAlias}"."version"`)
|
||||
const strategy = config.options.strategy ?? LoadStrategy.JOINED
|
||||
if (strategy === LoadStrategy.SELECT_IN) {
|
||||
const sql = manager
|
||||
.qb(Order, "_sub0")
|
||||
.select("version")
|
||||
.where({ id: knex.raw(`"o0"."order_id"`) })
|
||||
.getKnexQuery()
|
||||
.toString()
|
||||
|
||||
defaultVersion = knex.raw(`(${sql})`)
|
||||
}
|
||||
|
||||
const version = config.where.version ?? defaultVersion
|
||||
delete config.where.version
|
||||
|
||||
config.options.populateWhere ??= {}
|
||||
|
||||
if (entity !== Order) {
|
||||
config.options.populateWhere.order ??= {}
|
||||
config.options.populateWhere.order.version = version
|
||||
|
||||
config.options.populateWhere.order.summary ??= {}
|
||||
config.options.populateWhere.order.summary.version = version
|
||||
} else {
|
||||
config.options.populateWhere.summary ??= {}
|
||||
config.options.populateWhere.summary.version = version
|
||||
}
|
||||
|
||||
config.options.populateWhere.items ??= {}
|
||||
config.options.populateWhere.items.version = version
|
||||
|
||||
config.options.populateWhere.shipping_methods ??= {}
|
||||
config.options.populateWhere.shipping_methods.version = version
|
||||
|
||||
if (!config.options.orderBy) {
|
||||
config.options.orderBy = { id: "ASC" }
|
||||
}
|
||||
|
||||
return await manager.findAndCount(entity, config.where, config.options)
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,6 @@
|
||||
export * from "./action-key"
|
||||
export * from "./actions"
|
||||
export * from "./apply-order-changes"
|
||||
export * from "./calculate-order-change"
|
||||
export * from "./set-action-reference"
|
||||
export * from "./transform-order"
|
||||
|
||||
6
packages/modules/order/src/utils/set-action-reference.ts
Normal file
6
packages/modules/order/src/utils/set-action-reference.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
export function setActionReference(existing, action) {
|
||||
existing.detail.order_id ??= action.order_id
|
||||
existing.detail.return_id ??= action.return_id
|
||||
existing.detail.claim_id ??= action.claim_id
|
||||
existing.detail.exchange_id ??= action.exchange_id
|
||||
}
|
||||
Reference in New Issue
Block a user