Files
medusa-store/packages/modules/order/src/services/order-module-service.ts
Adrien de Peretti 2f70f13351 fix(): Order constraint and receive return (#12889)
**What**
- Fix missing `ON DELETE CASCADE` constraint on order credit lines
- Fix `receiveReturn` miss usage
- Make all order integration tests to run and rename them all to `*.spec.ts`
- Fix package.json typo
2025-07-04 12:59:50 +00:00

3921 lines
106 KiB
TypeScript

import {
BigNumberInput,
Context,
CreateOrderCreditLineDTO,
DAL,
FilterableOrderReturnReasonProps,
FindConfig,
InferEntityType,
InternalModuleDeclaration,
IOrderModuleService,
ModuleJoinerConfig,
ModulesSdkTypes,
OrderChangeDTO,
OrderDTO,
OrderReturnReasonDTO,
OrderShippingMethodDTO,
OrderTypes,
RestoreReturn,
SoftDeleteReturn,
UpdateOrderItemWithSelectorDTO,
UpdateOrderReturnReasonDTO,
} from "@medusajs/framework/types"
import {
BigNumber,
ChangeActionType,
createRawPropertiesFromBigNumber,
DecorateCartLikeInputDTO,
decorateCartTotals,
deduplicate,
InjectManager,
InjectTransactionManager,
isDefined,
isObject,
isString,
MathBN,
MedusaContext,
MedusaError,
ModulesSdkUtils,
OrderChangeStatus,
OrderStatus,
promiseAll,
toMikroORMEntity,
transformPropertiesToBigNumber,
} from "@medusajs/framework/utils"
import { BeforeCreate, OnInit, rel } from "@mikro-orm/core"
import {
Order,
OrderAddress,
OrderChange,
OrderChangeAction,
OrderClaim,
OrderClaimItem,
OrderClaimItemImage,
OrderCreditLine,
OrderExchange,
OrderExchangeItem,
OrderItem,
OrderLineItem,
OrderLineItemAdjustment,
OrderLineItemTaxLine,
OrderShipping,
OrderShippingMethod,
OrderShippingMethodAdjustment,
OrderShippingMethodTaxLine,
OrderSummary,
OrderTransaction,
Return,
ReturnItem,
ReturnReason,
} from "@models"
import {
CreateOrderChangeDTO,
CreateOrderItemDTO,
CreateOrderLineItemDTO,
CreateOrderLineItemTaxLineDTO,
CreateOrderShippingMethodDTO,
CreateOrderShippingMethodTaxLineDTO,
UpdateOrderItemDTO,
UpdateOrderLineItemDTO,
UpdateOrderLineItemTaxLineDTO,
UpdateOrderShippingMethodTaxLineDTO,
UpdateReturnReasonDTO,
} from "@types"
import { joinerConfig } from "../joiner-config"
import {
applyChangesToOrder,
ApplyOrderChangeDTO,
calculateOrderChange,
formatOrder,
} from "../utils"
import * as BundledActions from "./actions"
import OrderService from "./order-service"
type InjectedDependencies = {
baseRepository: DAL.RepositoryService
orderService: OrderService
orderAddressService: ModulesSdkTypes.IMedusaInternalService<any>
orderLineItemService: ModulesSdkTypes.IMedusaInternalService<any>
orderShippingMethodAdjustmentService: ModulesSdkTypes.IMedusaInternalService<any>
orderShippingMethodService: ModulesSdkTypes.IMedusaInternalService<any>
orderLineItemAdjustmentService: ModulesSdkTypes.IMedusaInternalService<any>
orderLineItemTaxLineService: ModulesSdkTypes.IMedusaInternalService<any>
orderShippingMethodTaxLineService: ModulesSdkTypes.IMedusaInternalService<any>
orderTransactionService: ModulesSdkTypes.IMedusaInternalService<any>
orderChangeService: ModulesSdkTypes.IMedusaInternalService<any>
orderChangeActionService: ModulesSdkTypes.IMedusaInternalService<any>
orderItemService: ModulesSdkTypes.IMedusaInternalService<any>
orderSummaryService: ModulesSdkTypes.IMedusaInternalService<any>
orderShippingService: ModulesSdkTypes.IMedusaInternalService<any>
returnReasonService: ModulesSdkTypes.IMedusaInternalService<any>
returnService: ModulesSdkTypes.IMedusaInternalService<any>
returnItemService: ModulesSdkTypes.IMedusaInternalService<any>
orderClaimService: ModulesSdkTypes.IMedusaInternalService<any>
orderExchangeService: ModulesSdkTypes.IMedusaInternalService<any>
orderCreditLineService: ModulesSdkTypes.IMedusaInternalService<any>
}
const generateMethodForModels = {
Order,
OrderAddress,
OrderLineItem,
OrderLineItemAdjustment,
OrderLineItemTaxLine,
OrderShippingMethod,
OrderShippingMethodAdjustment,
OrderShippingMethodTaxLine,
OrderTransaction,
OrderChange,
OrderChangeAction,
OrderItem,
OrderSummary,
OrderShipping,
ReturnReason,
Return,
ReturnItem,
OrderClaim,
OrderClaimItem,
OrderClaimItemImage,
OrderExchange,
OrderExchangeItem,
OrderCreditLine,
}
{
const MikroORMEntity = toMikroORMEntity(OrderChangeAction)
MikroORMEntity.prototype["onInit_OrderChangeAction"] = function () {
this.version ??= this.order_change?.version ?? null
this.order_id ??= this.order_change?.order_id ?? null
this.claim_id ??= this.order_change?.claim_id ?? null
this.exchange_id ??= this.order_change?.exchange_id ?? null
if (!this.claim_id && !this.exchange_id) {
this.return_id = this.return?.id ?? this.order_change?.return_id ?? null
}
}
OnInit()(MikroORMEntity.prototype, "onInit_OrderChangeAction")
BeforeCreate()(MikroORMEntity.prototype, "onInit_OrderChangeAction")
}
{
const MikroORMEntity = toMikroORMEntity(OrderShipping)
MikroORMEntity.prototype["onInit_OrderShipping"] = function () {
this.version ??= this.order?.version ?? null
this.order ??= rel(toMikroORMEntity(Order), this.order?.id ?? null)
this.return ??= rel(toMikroORMEntity(Return), this.return?.id ?? null)
this.claim ??= rel(toMikroORMEntity(OrderClaim), this.claim?.id ?? null)
this.exchange ??= rel(
toMikroORMEntity(OrderExchange),
this.exchange?.id ?? null
)
this.shipping_method ??= rel(
toMikroORMEntity(OrderShippingMethod),
this.shipping_method?.id ?? null
)
}
OnInit()(MikroORMEntity.prototype, "onInit_OrderShipping")
BeforeCreate()(MikroORMEntity.prototype, "onInit_OrderShipping")
}
{
const MikroORMEntity = toMikroORMEntity(OrderItem)
MikroORMEntity.prototype["onInit_OrderItem"] = function () {
this.version ??= this.order?.version ?? null
this.order ??= rel(toMikroORMEntity(Order), this.order?.id ?? null)
this.item ??= rel(toMikroORMEntity(OrderLineItem), this.item?.id ?? null)
}
OnInit()(MikroORMEntity.prototype, "onInit_OrderItem")
BeforeCreate()(MikroORMEntity.prototype, "onInit_OrderItem")
}
// TODO: rm template args here, keep it for later to not collide with carlos work at least as little as possible
export default class OrderModuleService
extends ModulesSdkUtils.MedusaService<{
Order: { dto: OrderTypes.OrderDTO }
OrderAddress: { dto: OrderTypes.OrderAddressDTO }
OrderLineItem: { dto: OrderTypes.OrderLineItemDTO }
OrderLineItemAdjustment: { dto: OrderTypes.OrderLineItemAdjustmentDTO }
OrderLineItemTaxLine: { dto: OrderTypes.OrderLineItemTaxLineDTO }
OrderShippingMethod: { dto: OrderShippingMethodDTO }
OrderShippingMethodAdjustment: {
dto: OrderTypes.OrderShippingMethodAdjustmentDTO
}
OrderShippingMethodTaxLine: {
dto: OrderTypes.OrderShippingMethodTaxLineDTO
}
OrderShipping: { dto: any }
OrderChange: { dto: OrderTypes.OrderChangeDTO }
OrderChangeAction: { dto: OrderTypes.OrderChangeActionDTO }
OrderItem: { dto: OrderTypes.OrderItemDTO }
ReturnReason: { dto: OrderTypes.OrderReturnReasonDTO }
OrderSummary: { dto: OrderTypes.OrderSummaryDTO }
OrderTransaction: { dto: OrderTypes.OrderTransactionDTO }
Return: { dto: OrderTypes.ReturnDTO }
ReturnItem: { dto: OrderTypes.OrderReturnItemDTO }
OrderClaim: { dto: OrderTypes.OrderClaimDTO }
OrderClaimItem: { dto: OrderTypes.OrderClaimItemDTO }
OrderClaimItemImage: { dto: OrderTypes.OrderClaimItemImageDTO }
OrderExchange: { dto: OrderTypes.OrderExchangeDTO }
OrderExchangeItem: { dto: OrderTypes.OrderExchangeItemDTO }
OrderCreditLine: { dto: OrderTypes.OrderCreditLineDTO }
}>(generateMethodForModels)
implements IOrderModuleService
{
protected baseRepository_: DAL.RepositoryService
protected orderService_: OrderService
protected orderAddressService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof OrderAddress>
>
protected orderLineItemService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof OrderLineItem>
>
protected orderShippingMethodAdjustmentService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof OrderShippingMethodAdjustment>
>
protected orderShippingMethodService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof OrderShippingMethod>
>
protected orderLineItemAdjustmentService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof OrderLineItemAdjustment>
>
protected orderLineItemTaxLineService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof OrderLineItemTaxLine>
>
protected orderShippingMethodTaxLineService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof OrderShippingMethodTaxLine>
>
protected orderTransactionService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof OrderTransaction>
>
protected orderChangeService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof OrderChange>
>
protected orderChangeActionService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof OrderChangeAction>
>
protected orderItemService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof OrderItem>
>
protected orderSummaryService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof OrderSummary>
>
protected orderShippingService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof OrderShipping>
>
protected returnReasonService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof ReturnReason>
>
protected returnService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof Return>
>
protected returnItemService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof ReturnItem>
>
protected orderClaimService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof OrderClaim>
>
protected orderClaimItemService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof OrderClaimItem>
>
protected orderClaimItemImageService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof OrderClaimItemImage>
>
protected orderExchangeService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof OrderExchange>
>
protected orderExchangeItemService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof OrderExchangeItem>
>
protected orderCreditLineService_: ModulesSdkTypes.IMedusaInternalService<
InferEntityType<typeof OrderCreditLine>
>
constructor(
{
baseRepository,
orderService,
orderAddressService,
orderLineItemService,
orderShippingMethodAdjustmentService,
orderShippingMethodService,
orderLineItemAdjustmentService,
orderShippingMethodTaxLineService,
orderLineItemTaxLineService,
orderTransactionService,
orderChangeService,
orderChangeActionService,
orderItemService,
orderSummaryService,
orderShippingService,
returnReasonService,
returnService,
returnItemService,
orderClaimService,
orderExchangeService,
orderCreditLineService,
}: InjectedDependencies,
protected readonly moduleDeclaration: InternalModuleDeclaration
) {
// @ts-ignore
super(...arguments)
this.baseRepository_ = baseRepository
this.orderService_ = orderService
this.orderAddressService_ = orderAddressService
this.orderLineItemService_ = orderLineItemService
this.orderShippingMethodAdjustmentService_ =
orderShippingMethodAdjustmentService
this.orderShippingMethodService_ = orderShippingMethodService
this.orderLineItemAdjustmentService_ = orderLineItemAdjustmentService
this.orderShippingMethodTaxLineService_ = orderShippingMethodTaxLineService
this.orderLineItemTaxLineService_ = orderLineItemTaxLineService
this.orderTransactionService_ = orderTransactionService
this.orderChangeService_ = orderChangeService
this.orderChangeActionService_ = orderChangeActionService
this.orderItemService_ = orderItemService
this.orderSummaryService_ = orderSummaryService
this.orderShippingService_ = orderShippingService
this.returnReasonService_ = returnReasonService
this.returnService_ = returnService
this.returnItemService_ = returnItemService
this.orderClaimService_ = orderClaimService
this.orderExchangeService_ = orderExchangeService
this.orderCreditLineService_ = orderCreditLineService
}
__joinerConfig(): ModuleJoinerConfig {
return joinerConfig
}
private shouldIncludeTotals(config: FindConfig<any>): boolean {
const totalFields = [
"total",
"subtotal",
"tax_total",
"discount_total",
"discount_tax_total",
"original_total",
"original_tax_total",
"item_total",
"item_subtotal",
"item_tax_total",
"original_item_total",
"original_item_subtotal",
"original_item_tax_total",
"shipping_total",
"shipping_subtotal",
"shipping_tax_total",
"original_shipping_tax_total",
"original_shipping_subtotal",
"original_shipping_total",
"credit_line_total",
"credit_line_tax_total",
"credit_line_subtotal",
]
const includeTotals = (config?.select ?? []).some((field) =>
totalFields.includes(field as string)
)
if (includeTotals) {
this.addRelationsToCalculateTotals(config, totalFields)
}
return includeTotals
}
private addRelationsToCalculateTotals(config: FindConfig<any>, totalFields) {
config.relations ??= []
config.select ??= []
const requiredRelationsForTotals = [
"credit_lines",
"items",
"items.tax_lines",
"items.adjustments",
"shipping_methods",
"shipping_methods.tax_lines",
"shipping_methods.adjustments",
]
config.relations = deduplicate([
...config.relations,
...requiredRelationsForTotals,
])
config.select = config.select.filter((field) => {
return (
!requiredRelationsForTotals.some((val) =>
val.startsWith(field as string)
) && !totalFields.includes(field)
)
})
}
// @ts-expect-error
async retrieveOrder(
id: string,
config?: FindConfig<any> | undefined,
@MedusaContext() sharedContext?: Context | undefined
): Promise<OrderTypes.OrderDTO> {
config ??= {}
const includeTotals = this.shouldIncludeTotals(config)
const order = await super.retrieveOrder(id, config, sharedContext)
const orderChange = await this.getActiveOrderChange_(
order.id,
false,
sharedContext
)
order.order_change = orderChange
return formatOrder(order, {
entity: Order,
includeTotals,
}) as OrderTypes.OrderDTO
}
// @ts-expect-error
async listOrders(
filters?: any,
config?: FindConfig<any> | undefined,
@MedusaContext() sharedContext?: Context | undefined
): Promise<OrderTypes.OrderDTO[]> {
config ??= {}
const includeTotals = this.shouldIncludeTotals(config)
const orders = await super.listOrders(filters, config, sharedContext)
return formatOrder(orders, {
entity: Order,
includeTotals,
}) as OrderTypes.OrderDTO[]
}
// @ts-expect-error
async listAndCountOrders(
filters?: any,
config?: FindConfig<any> | undefined,
@MedusaContext() sharedContext?: Context | undefined
): Promise<[OrderTypes.OrderDTO[], number]> {
config ??= {}
const includeTotals = this.shouldIncludeTotals(config)
const [orders, count] = await super.listAndCountOrders(
filters,
config,
sharedContext
)
return [
formatOrder(orders, {
entity: Order,
includeTotals,
}) as OrderTypes.OrderDTO[],
count,
]
}
// @ts-ignore
async retrieveReturn(
id: string,
config?: FindConfig<any> | undefined,
@MedusaContext() sharedContext?: Context | undefined
): Promise<OrderTypes.ReturnDTO> {
config ??= {}
const includeTotals = this.shouldIncludeTotals(config)
const returnOrder = await super.retrieveReturn(id, config, sharedContext)
return formatOrder(returnOrder, {
entity: Return,
includeTotals,
}) as OrderTypes.ReturnDTO
}
// @ts-ignore
async listReturns(
filters?: any,
config?: FindConfig<any> | undefined,
@MedusaContext() sharedContext?: Context | undefined
): Promise<OrderTypes.ReturnDTO[]> {
config ??= {}
const includeTotals = this.shouldIncludeTotals(config)
const returnOrders = await super.listReturns(filters, config, sharedContext)
return formatOrder(returnOrders, {
entity: Return,
includeTotals,
}) as OrderTypes.ReturnDTO[]
}
// @ts-ignore
async listAndCountReturns(
filters?: any,
config?: FindConfig<any> | undefined,
@MedusaContext() sharedContext?: Context | undefined
): Promise<[OrderTypes.ReturnDTO[], number]> {
config ??= {}
const includeTotals = this.shouldIncludeTotals(config)
const [returnOrders, count] = await super.listAndCountReturns(
filters,
config,
sharedContext
)
return [
formatOrder(returnOrders, {
entity: Return,
includeTotals,
}) as OrderTypes.ReturnDTO[],
count,
]
}
// @ts-ignore
async retrieveOrderClaim(
id: string,
config?: FindConfig<any> | undefined,
@MedusaContext() sharedContext?: Context | undefined
): Promise<OrderTypes.OrderClaimDTO> {
config ??= {}
const includeTotals = this.shouldIncludeTotals(config)
const returnOrder = await super.retrieveOrderClaim(
id,
config,
sharedContext
)
return formatOrder(returnOrder, {
entity: OrderClaim,
includeTotals,
}) as OrderTypes.OrderClaimDTO
}
// @ts-ignore
async listOrderClaims(
filters?: any,
config?: FindConfig<any> | undefined,
@MedusaContext() sharedContext?: Context | undefined
): Promise<OrderTypes.OrderClaimDTO[]> {
config ??= {}
const includeTotals = this.shouldIncludeTotals(config)
const returnOrders = await super.listOrderClaims(
filters,
config,
sharedContext
)
return formatOrder(returnOrders, {
entity: OrderClaim,
includeTotals,
}) as OrderTypes.OrderClaimDTO[]
}
// @ts-ignore
async listAndCountOrderClaims(
filters?: any,
config?: FindConfig<any> | undefined,
@MedusaContext() sharedContext?: Context | undefined
): Promise<[OrderTypes.OrderClaimDTO[], number]> {
config ??= {}
const includeTotals = this.shouldIncludeTotals(config)
const [returnOrders, count] = await super.listAndCountOrderClaims(
filters,
config,
sharedContext
)
return [
formatOrder(returnOrders, {
entity: OrderClaim,
includeTotals,
}) as OrderTypes.OrderClaimDTO[],
count,
]
}
// @ts-ignore
async retrieveOrderExchange(
id: string,
config?: FindConfig<any> | undefined,
@MedusaContext() sharedContext?: Context | undefined
): Promise<OrderTypes.OrderExchangeDTO> {
config ??= {}
const includeTotals = this.shouldIncludeTotals(config)
const returnOrder = await super.retrieveOrderExchange(
id,
config,
sharedContext
)
return formatOrder(returnOrder, {
entity: OrderExchange,
includeTotals,
}) as OrderTypes.OrderExchangeDTO
}
// @ts-ignore
async listOrderExchanges(
filters?: any,
config?: FindConfig<any> | undefined,
@MedusaContext() sharedContext?: Context | undefined
): Promise<OrderTypes.OrderExchangeDTO[]> {
config ??= {}
const includeTotals = this.shouldIncludeTotals(config)
const returnOrders = await super.listOrderExchanges(
filters,
config,
sharedContext
)
return formatOrder(returnOrders, {
entity: OrderExchange,
includeTotals,
}) as OrderTypes.OrderExchangeDTO[]
}
// @ts-ignore
async listAndCountOrderExchanges(
filters?: any,
config?: FindConfig<any> | undefined,
@MedusaContext() sharedContext?: Context | undefined
): Promise<[OrderTypes.OrderExchangeDTO[], number]> {
config ??= {}
const includeTotals = this.shouldIncludeTotals(config)
const [returnOrders, count] = await super.listAndCountOrderExchanges(
filters,
config,
sharedContext
)
return [
formatOrder(returnOrders, {
entity: OrderExchange,
includeTotals,
}) as OrderTypes.OrderExchangeDTO[],
count,
]
}
// @ts-expect-error
async createOrders(
data: OrderTypes.CreateOrderDTO[],
sharedContext?: Context
): Promise<OrderTypes.OrderDTO[]>
// @ts-expect-error
async createOrders(
data: OrderTypes.CreateOrderDTO,
sharedContext?: Context
): Promise<OrderTypes.OrderDTO>
@InjectManager()
// @ts-expect-error
async createOrders(
data: OrderTypes.CreateOrderDTO[] | OrderTypes.CreateOrderDTO,
@MedusaContext() sharedContext: Context = {}
): Promise<OrderTypes.OrderDTO[] | OrderTypes.OrderDTO> {
const input = Array.isArray(data) ? data : [data]
const orders = await this.createOrders_(input, sharedContext)
const result = await this.listOrders(
{
id: orders.map((p) => p!.id),
},
{
relations: [
"shipping_address",
"billing_address",
"summary",
"items",
"credit_lines",
"items.tax_lines",
"items.adjustments",
"shipping_methods",
"shipping_methods.tax_lines",
"shipping_methods.adjustments",
"transactions",
],
},
sharedContext
)
return (Array.isArray(data) ? result : result[0]) as
| OrderTypes.OrderDTO
| OrderTypes.OrderDTO[]
}
@InjectTransactionManager()
protected async createOrders_(
data: OrderTypes.CreateOrderDTO[],
@MedusaContext() sharedContext: Context = {}
) {
await this.createOrderAddresses_(data, sharedContext)
const lineItemsToCreate: CreateOrderLineItemDTO[] = []
const creditLinesToCreate: CreateOrderCreditLineDTO[] = []
const createdOrders: InferEntityType<typeof Order>[] = []
for (const {
items,
shipping_methods,
credit_lines,
shipping_address,
billing_address,
...order
} of data) {
const ord = order as any
const shippingMethods = shipping_methods?.map((sm: any) => {
return {
shipping_method: { ...sm },
}
})
ord.shipping_methods = shippingMethods
const orderWithTotals = decorateCartTotals({
...ord,
shipping_methods,
items,
credit_lines,
}) as any
const calculated = calculateOrderChange({
order: orderWithTotals,
actions: [],
transactions: order.transactions,
})
createRawPropertiesFromBigNumber(calculated)
ord.summary = {
totals: calculated.summary,
}
const created = await this.orderService_.create(ord, sharedContext)
creditLinesToCreate.push(
...(credit_lines ?? []).map((creditLine) => ({
amount: MathBN.convert(creditLine.amount),
reference: creditLine.reference,
reference_id: creditLine.reference_id,
metadata: creditLine.metadata,
order_id: created.id,
}))
)
createdOrders.push(created)
if (items?.length) {
const orderItems = items.map((item) => {
return {
...item,
order_id: created.id,
}
})
lineItemsToCreate.push(...orderItems)
}
}
if (lineItemsToCreate.length) {
await this.createOrderLineItemsBulk_(lineItemsToCreate, sharedContext)
}
if (creditLinesToCreate.length) {
await this.orderCreditLineService_.create(
creditLinesToCreate,
sharedContext
)
}
return createdOrders
}
@InjectTransactionManager()
protected async createOrderAddresses_(
input: OrderTypes.CreateOrderDTO[],
@MedusaContext() sharedContext: Context = {}
) {
const allAddresses: {
data: any
type: "billing" | "shipping"
source: OrderTypes.CreateOrderDTO
}[] = []
input.forEach((inputData) => {
if (inputData.billing_address) {
allAddresses.push({
data: inputData.billing_address,
type: "billing",
source: inputData,
})
}
if (inputData.shipping_address) {
allAddresses.push({
data: inputData.shipping_address,
type: "shipping",
source: inputData,
})
}
})
const createdAddresses = allAddresses.length
? await this.orderAddressService_.create(
allAddresses.map((a) => a.data),
sharedContext
)
: []
createdAddresses.forEach((createdAddress, index) => {
const { type, source } = allAddresses[index]
if (type === "billing") {
source.billing_address_id = createdAddress.id
} else if (type === "shipping") {
source.shipping_address_id = createdAddress.id
}
})
}
@InjectTransactionManager()
// @ts-expect-error
async deleteOrders(
orderIds: string | string[],
@MedusaContext() sharedContext: Context = {}
): Promise<void> {
const ids = Array.isArray(orderIds) ? orderIds : [orderIds]
const orders = await this.orderService_.list(
{ id: ids },
{
select: ["id", "shipping_address_id", "billing_address_id"],
},
sharedContext
)
const orderAddressIds = orders
.map((order) => [order.shipping_address_id, order.billing_address_id])
.flat(1)
const orderChanges = await this.orderChangeService_.list(
{ order_id: ids },
{ select: ["id"] },
sharedContext
)
const orderChangeIds = orderChanges.map((orderChange) => orderChange.id)
const orderItems = await this.orderItemService_.list(
{ order_id: ids },
{ select: ["id", "item_id"] },
sharedContext
)
const lineItemIds = orderItems.map((orderItem) => orderItem.item_id)
const orderShipping = await this.orderShippingService_.list(
{ order_id: ids },
{ select: ["shipping_method_id"] },
sharedContext
)
const orderShippingMethodIds = orderShipping.map(
(orderShipping) => orderShipping.shipping_method_id
)
await this.orderAddressService_.delete(orderAddressIds, sharedContext)
await this.orderChangeService_.delete(orderChangeIds, sharedContext)
// Delete order, order items, summary, shipping methods, transactions and credit lines
await super.deleteOrders(ids, sharedContext)
await promiseAll([
this.orderLineItemService_.delete(lineItemIds, sharedContext),
this.orderShippingMethodService_.delete(
orderShippingMethodIds,
sharedContext
),
])
}
// @ts-expect-error
async updateOrders(
data: OrderTypes.UpdateOrderDTO[]
): Promise<OrderTypes.OrderDTO[]>
// @ts-expect-error
async updateOrders(
orderId: string,
data: OrderTypes.UpdateOrderDTO,
sharedContext?: Context
): Promise<OrderTypes.OrderDTO>
// @ts-expect-error
async updateOrders(
selector: Partial<OrderTypes.FilterableOrderProps>,
data: OrderTypes.UpdateOrderDTO,
sharedContext?: Context
): Promise<OrderTypes.OrderDTO[]>
@InjectManager()
// @ts-expect-error
async updateOrders(
dataOrIdOrSelector:
| OrderTypes.UpdateOrderDTO[]
| string
| Partial<OrderTypes.FilterableOrderProps>,
data?: OrderTypes.UpdateOrderDTO,
@MedusaContext() sharedContext: Context = {}
): Promise<OrderTypes.OrderDTO[] | OrderTypes.OrderDTO> {
const result = await this.updateOrders_(
dataOrIdOrSelector,
data,
sharedContext
)
const serializedResult = await this.baseRepository_.serialize<
OrderTypes.OrderDTO[]
>(result, {
populate: true,
})
return isString(dataOrIdOrSelector) ? serializedResult[0] : serializedResult
}
@InjectTransactionManager()
protected async updateOrders_(
dataOrIdOrSelector:
| OrderTypes.UpdateOrderDTO[]
| string
| Partial<OrderTypes.FilterableOrderProps>,
data?: OrderTypes.UpdateOrderDTO,
@MedusaContext() sharedContext: Context = {}
) {
let toUpdate: OrderTypes.UpdateOrderDTO[] = []
if (isString(dataOrIdOrSelector)) {
toUpdate = [
{
id: dataOrIdOrSelector,
...data,
},
]
} else if (Array.isArray(dataOrIdOrSelector)) {
toUpdate = dataOrIdOrSelector
} else {
const orders = await this.orderService_.list(
{ ...dataOrIdOrSelector },
{ select: ["id"] },
sharedContext
)
toUpdate = orders.map((order) => {
return {
...data,
id: order.id,
}
})
}
const result = await this.orderService_.update(toUpdate, sharedContext)
return result
}
// @ts-ignore
createOrderLineItems(
data: OrderTypes.CreateOrderLineItemForOrderDTO
): Promise<OrderTypes.OrderLineItemDTO[]>
// @ts-expect-error
createOrderLineItems(
data: OrderTypes.CreateOrderLineItemForOrderDTO[]
): Promise<OrderTypes.OrderLineItemDTO[]>
// @ts-expect-error
createOrderLineItems(
orderId: string,
items: OrderTypes.CreateOrderLineItemDTO[],
sharedContext?: Context
): Promise<OrderTypes.OrderLineItemDTO[]>
@InjectManager()
// @ts-expect-error
async createOrderLineItems(
orderIdOrData:
| string
| OrderTypes.CreateOrderLineItemForOrderDTO[]
| OrderTypes.CreateOrderLineItemForOrderDTO,
data?:
| OrderTypes.CreateOrderLineItemDTO[]
| OrderTypes.CreateOrderLineItemDTO,
@MedusaContext() sharedContext: Context = {}
): Promise<OrderTypes.OrderLineItemDTO[]> {
let items: InferEntityType<typeof OrderLineItem>[] = []
if (isString(orderIdOrData)) {
items = await this.createOrderLineItems_(
orderIdOrData,
data as OrderTypes.CreateOrderLineItemDTO[],
sharedContext
)
} else {
const data = Array.isArray(orderIdOrData)
? orderIdOrData
: [orderIdOrData]
const allOrderIds = data.map((dt) => dt.order_id)
const order = await this.listOrders(
{ id: allOrderIds },
{ select: ["id", "version"] },
sharedContext
)
const mapOrderVersion = order.reduce((acc, curr) => {
acc[curr.id] = curr.version
return acc
}, {})
const lineItems = data.map((dt) => {
return {
...dt,
version: mapOrderVersion[dt.order_id],
}
})
items = await this.createOrderLineItemsBulk_(lineItems, sharedContext)
}
return await this.baseRepository_.serialize<OrderTypes.OrderLineItemDTO[]>(
items,
{
populate: true,
}
)
}
@InjectTransactionManager()
protected async createOrderLineItems_(
orderId: string,
items: OrderTypes.CreateOrderLineItemDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<InferEntityType<typeof OrderLineItem>[]> {
const order = await this.retrieveOrder(
orderId,
{ select: ["id", "version"] },
sharedContext
)
const toUpdate: CreateOrderLineItemDTO[] = items.map((item) => {
return {
...item,
order_id: order.id,
version: order.version,
}
})
return await this.createOrderLineItemsBulk_(toUpdate, sharedContext)
}
@InjectTransactionManager()
protected async createOrderLineItemsBulk_(
data: CreateOrderLineItemDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<InferEntityType<typeof OrderLineItem>[]> {
const orderItemToCreate: CreateOrderItemDTO[] = []
const lineItems = await this.orderLineItemService_.create(
data,
sharedContext
)
for (let i = 0; i < lineItems.length; i++) {
const item = lineItems[i]
const toCreate = data[i]
if (toCreate.order_id) {
orderItemToCreate.push({
order_id: toCreate.order_id,
version: toCreate.version ?? 1,
item_id: item.id,
quantity: toCreate.quantity,
})
}
}
if (orderItemToCreate.length) {
await this.orderItemService_.create(orderItemToCreate, sharedContext)
}
return lineItems
}
// @ts-ignore
updateOrderLineItems(
data: OrderTypes.UpdateOrderLineItemWithSelectorDTO[]
): Promise<OrderTypes.OrderLineItemDTO[]>
// @ts-expect-error
updateOrderLineItems(
selector: Partial<OrderTypes.FilterableOrderLineItemProps>,
data: OrderTypes.UpdateOrderLineItemDTO,
sharedContext?: Context
): Promise<OrderTypes.OrderLineItemDTO[]>
// @ts-expect-error
updateOrderLineItems(
lineItemId: string,
data: Partial<OrderTypes.UpdateOrderLineItemDTO>,
sharedContext?: Context
): Promise<OrderTypes.OrderLineItemDTO>
@InjectManager()
// @ts-expect-error
async updateOrderLineItems(
lineItemIdOrDataOrSelector:
| string
| OrderTypes.UpdateOrderLineItemWithSelectorDTO[]
| Partial<OrderTypes.FilterableOrderLineItemProps>,
data?:
| OrderTypes.UpdateOrderLineItemDTO
| Partial<OrderTypes.UpdateOrderLineItemDTO>,
@MedusaContext() sharedContext: Context = {}
): Promise<OrderTypes.OrderLineItemDTO[] | OrderTypes.OrderLineItemDTO> {
let items: InferEntityType<typeof OrderLineItem>[] = []
if (isString(lineItemIdOrDataOrSelector)) {
const item = await this.updateOrderLineItem_(
lineItemIdOrDataOrSelector,
data as Partial<OrderTypes.UpdateOrderLineItemDTO>,
sharedContext
)
return await this.baseRepository_.serialize<OrderTypes.OrderLineItemDTO>(
item,
{
populate: true,
}
)
}
const toUpdate = Array.isArray(lineItemIdOrDataOrSelector)
? lineItemIdOrDataOrSelector
: [
{
selector: lineItemIdOrDataOrSelector,
data: data,
} as OrderTypes.UpdateOrderLineItemWithSelectorDTO,
]
items = await this.updateOrderLineItemsWithSelector_(
toUpdate,
sharedContext
)
return await this.baseRepository_.serialize<OrderTypes.OrderLineItemDTO[]>(
items,
{
populate: true,
}
)
}
@InjectTransactionManager()
protected async updateOrderLineItem_(
lineItemId: string,
data: Partial<OrderTypes.UpdateOrderLineItemDTO>,
@MedusaContext() sharedContext: Context = {}
): Promise<InferEntityType<typeof OrderLineItem>> {
const [item] = await this.orderLineItemService_.update(
[{ id: lineItemId, ...data }],
sharedContext
)
if ("quantity" in data) {
await this.updateOrderItemWithSelector_(
[
{
selector: { item_id: item.id },
data,
},
],
sharedContext
)
}
return item
}
@InjectTransactionManager()
protected async updateOrderLineItemsWithSelector_(
updates: OrderTypes.UpdateOrderLineItemWithSelectorDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<InferEntityType<typeof OrderLineItem>[]> {
let toUpdate: UpdateOrderLineItemDTO[] = []
const detailsToUpdate: UpdateOrderItemWithSelectorDTO[] = []
for (const { selector, data } of updates) {
const items = await this.listOrderLineItems(
{ ...selector },
{},
sharedContext
)
items.forEach((item) => {
toUpdate.push({
...data,
id: item.id,
})
if ("quantity" in data) {
detailsToUpdate.push({
selector: { item_id: item.id },
data,
})
}
})
}
if (detailsToUpdate.length) {
await this.updateOrderItemWithSelector_(detailsToUpdate, sharedContext)
}
return await this.orderLineItemService_.update(toUpdate, sharedContext)
}
updateOrderItem(
selector: Partial<OrderTypes.OrderItemDTO>,
data: OrderTypes.UpdateOrderItemDTO,
sharedContext?: Context
): Promise<OrderTypes.OrderItemDTO[]>
updateOrderItem(
orderItemId: string,
data: Partial<OrderTypes.UpdateOrderItemDTO>,
sharedContext?: Context
): Promise<OrderTypes.OrderItemDTO>
@InjectManager()
async updateOrderItem(
orderItemIdOrDataOrSelector:
| string
| OrderTypes.UpdateOrderItemWithSelectorDTO[]
| Partial<OrderTypes.OrderItemDTO>,
data?:
| OrderTypes.UpdateOrderItemDTO
| Partial<OrderTypes.UpdateOrderItemDTO>,
@MedusaContext() sharedContext: Context = {}
): Promise<OrderTypes.OrderItemDTO[] | OrderTypes.OrderItemDTO> {
let items: InferEntityType<typeof OrderItem>[] = []
if (isString(orderItemIdOrDataOrSelector)) {
const item = await this.updateOrderItem_(
orderItemIdOrDataOrSelector,
data as Partial<OrderTypes.UpdateOrderItemDTO>,
sharedContext
)
return await this.baseRepository_.serialize<OrderTypes.OrderItemDTO>(
item,
{
populate: true,
}
)
}
const toUpdate = Array.isArray(orderItemIdOrDataOrSelector)
? orderItemIdOrDataOrSelector
: [
{
selector: orderItemIdOrDataOrSelector,
data: data,
} as OrderTypes.UpdateOrderItemWithSelectorDTO,
]
items = await this.updateOrderItemWithSelector_(toUpdate, sharedContext)
return await this.baseRepository_.serialize<OrderTypes.OrderItemDTO[]>(
items,
{
populate: true,
}
)
}
@InjectTransactionManager()
protected async updateOrderItem_(
orderItemId: string,
data: Partial<OrderTypes.UpdateOrderItemDTO>,
@MedusaContext() sharedContext: Context = {}
): Promise<InferEntityType<typeof OrderItem>> {
const [detail] = await this.orderItemService_.update(
[{ id: orderItemId, ...data }],
sharedContext
)
return detail
}
@InjectTransactionManager()
protected async updateOrderItemWithSelector_(
updates: OrderTypes.UpdateOrderItemWithSelectorDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<InferEntityType<typeof OrderItem>[]> {
let toUpdate: UpdateOrderItemDTO[] = []
for (const { selector, data } of updates) {
const details = await this.listOrderItems(
{ ...selector },
{},
sharedContext
)
details.forEach((detail) => {
toUpdate.push({
...data,
id: detail.id,
})
})
}
return await this.orderItemService_.update(toUpdate, sharedContext)
}
// @ts-expect-error
async createOrderShippingMethods(
data: OrderTypes.CreateOrderShippingMethodDTO
): Promise<OrderTypes.OrderShippingMethodDTO>
// @ts-expect-error
async createOrderShippingMethods(
data: OrderTypes.CreateOrderShippingMethodDTO[]
): Promise<OrderTypes.OrderShippingMethodDTO[]>
// @ts-expect-error
async createOrderShippingMethods(
orderId: string,
methods: OrderTypes.CreateOrderShippingMethodDTO[],
sharedContext?: Context
): Promise<OrderTypes.OrderShippingMethodDTO[]>
@InjectManager()
// @ts-expect-error
async createOrderShippingMethods(
orderIdOrData:
| string
| OrderTypes.CreateOrderShippingMethodDTO[]
| OrderTypes.CreateOrderShippingMethodDTO,
data?: OrderTypes.CreateOrderShippingMethodDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<
OrderTypes.OrderShippingMethodDTO[] | OrderTypes.OrderShippingMethodDTO
> {
let methods: InferEntityType<typeof OrderShippingMethod>[]
if (isString(orderIdOrData)) {
methods = await this.createOrderShippingMethods_(
orderIdOrData,
data!,
sharedContext
)
} else {
const data = Array.isArray(orderIdOrData)
? orderIdOrData
: [orderIdOrData]
const allOrderIds = data.map((dt) => dt.order_id)
const order = await this.listOrders(
{ id: allOrderIds },
{ select: ["id", "version"] },
sharedContext
)
const mapOrderVersion = order.reduce((acc, curr) => {
acc[curr.id] = curr.version
return acc
}, {})
const orderShippingMethodData = data.map((dt) => {
return {
shipping_method: dt,
order_id: dt.order_id,
return_id: dt.return_id,
claim_id: dt.claim_id,
exchange_id: dt.exchange_id,
version: dt.version ?? mapOrderVersion[dt.order_id],
}
})
methods = await this.createOrderShippingMethodsBulk_(
orderShippingMethodData as any,
sharedContext
)
}
return await this.baseRepository_.serialize<
OrderTypes.OrderShippingMethodDTO[]
>(methods, { populate: true })
}
@InjectTransactionManager()
protected async createOrderShippingMethods_(
orderId: string,
data: CreateOrderShippingMethodDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<InferEntityType<typeof OrderShippingMethod>[]> {
const order = await this.retrieveOrder(
orderId,
{ select: ["id", "version"] },
sharedContext
)
const methods = data.map((methodData) => {
return {
shipping_method: methodData,
order_id: order.id,
return_id: methodData.return_id,
claim_id: methodData.claim_id,
exchange_id: methodData.exchange_id,
version: methodData.version ?? order.version ?? 1,
}
})
return await this.createOrderShippingMethodsBulk_(methods, sharedContext)
}
@InjectTransactionManager()
protected async createOrderShippingMethodsBulk_(
data: {
shipping_method: OrderTypes.CreateOrderShippingMethodDTO
order_id: string
version: number
}[],
@MedusaContext() sharedContext: Context = {}
): Promise<InferEntityType<typeof OrderShippingMethod>[]> {
const sm = await this.orderShippingService_.create(data, sharedContext)
return sm.map((s) => s.shipping_method) as any
}
@InjectManager()
// @ts-ignore
async softDeleteOrderShippingMethods<TReturnableLinkableKeys extends string>(
ids: string | object | string[] | object[],
config?: SoftDeleteReturn<TReturnableLinkableKeys>,
@MedusaContext() sharedContext?: Context
): Promise<Record<string, string[]> | void> {
const rel = await super.listOrderShippings(
{
shipping_method_id: ids,
},
{
select: ["id"],
},
sharedContext
)
const orderShippingIds = rel.map((r) => r.id)
const [returned] = await promiseAll([
super.softDeleteOrderShippingMethods(ids, config, sharedContext),
super.softDeleteOrderShippings(orderShippingIds, config, sharedContext),
])
return returned
}
@InjectManager()
// @ts-ignore
async restoreOrderShippingMethods<TReturnableLinkableKeys extends string>(
ids: string | object | string[] | object[],
config?: RestoreReturn<TReturnableLinkableKeys>,
@MedusaContext() sharedContext?: Context
): Promise<Record<string, string[]> | void> {
const rel = await super.listOrderShippings(
{
shipping_method_id: ids,
},
{
select: ["id"],
},
sharedContext
)
const shippingIds = rel.map((r) => r.id)
const [returned] = await promiseAll([
super.restoreOrderShippingMethods(ids, config, sharedContext),
super.restoreOrderShippings(shippingIds, config, sharedContext),
])
return returned
}
// @ts-ignore
async createOrderLineItemAdjustments(
adjustments: OrderTypes.CreateOrderLineItemAdjustmentDTO[]
): Promise<OrderTypes.OrderLineItemAdjustmentDTO[]>
// @ts-expect-error
async createOrderLineItemAdjustments(
adjustment: OrderTypes.CreateOrderLineItemAdjustmentDTO
): Promise<OrderTypes.OrderLineItemAdjustmentDTO[]>
// @ts-expect-error
async createOrderLineItemAdjustments(
orderId: string,
adjustments: OrderTypes.CreateOrderLineItemAdjustmentDTO[],
sharedContext?: Context
): Promise<OrderTypes.OrderLineItemAdjustmentDTO[]>
@InjectTransactionManager()
// @ts-expect-error
async createOrderLineItemAdjustments(
orderIdOrData:
| string
| OrderTypes.CreateOrderLineItemAdjustmentDTO[]
| OrderTypes.CreateOrderLineItemAdjustmentDTO,
adjustments?: OrderTypes.CreateOrderLineItemAdjustmentDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<OrderTypes.OrderLineItemAdjustmentDTO[]> {
let addedAdjustments: InferEntityType<typeof OrderLineItemAdjustment>[] = []
if (isString(orderIdOrData)) {
const order = await this.retrieveOrder(
orderIdOrData,
{ select: ["id"], relations: ["items.item"] },
sharedContext
)
const lineIds = order.items?.map((item) => item.id)
for (const adj of adjustments || []) {
if (!lineIds?.includes(adj.item_id)) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Line item with id ${adj.item_id} does not exist on order with id ${orderIdOrData}`
)
}
}
addedAdjustments = await this.orderLineItemAdjustmentService_.create(
adjustments as OrderTypes.CreateOrderLineItemAdjustmentDTO[],
sharedContext
)
} else {
const data = Array.isArray(orderIdOrData)
? orderIdOrData
: [orderIdOrData]
addedAdjustments = await this.orderLineItemAdjustmentService_.create(
data as OrderTypes.CreateOrderLineItemAdjustmentDTO[],
sharedContext
)
}
return await this.baseRepository_.serialize<
OrderTypes.OrderLineItemAdjustmentDTO[]
>(addedAdjustments, {
populate: true,
})
}
@InjectTransactionManager()
async upsertOrderLineItemAdjustments(
adjustments: (
| OrderTypes.CreateOrderLineItemAdjustmentDTO
| OrderTypes.UpdateOrderLineItemAdjustmentDTO
)[],
@MedusaContext() sharedContext: Context = {}
): Promise<OrderTypes.OrderLineItemAdjustmentDTO[]> {
let result = await this.orderLineItemAdjustmentService_.upsert(
adjustments,
sharedContext
)
return await this.baseRepository_.serialize<
OrderTypes.OrderLineItemAdjustmentDTO[]
>(result, {
populate: true,
})
}
@InjectTransactionManager()
async setOrderLineItemAdjustments(
orderId: string,
adjustments: (
| OrderTypes.CreateOrderLineItemAdjustmentDTO
| OrderTypes.UpdateOrderLineItemAdjustmentDTO
)[],
@MedusaContext() sharedContext: Context = {}
): Promise<OrderTypes.OrderLineItemAdjustmentDTO[]> {
const order = await this.retrieveOrder(
orderId,
{ select: ["id"], relations: ["items.item.adjustments"] },
sharedContext
)
const existingAdjustments = (order.items ?? [])
.map((item) => item.adjustments ?? [])
.flat()
.map((adjustment) => adjustment.id)
const adjustmentsSet = new Set(
adjustments
.map((a) => (a as OrderTypes.UpdateOrderLineItemAdjustmentDTO).id)
.filter(Boolean)
)
const toDelete: string[] = []
// From the existing adjustments, find the ones that are not passed in adjustments
existingAdjustments.forEach((adj) => {
if (!adjustmentsSet.has(adj)) {
toDelete.push(adj)
}
})
if (toDelete.length) {
await this.orderLineItemAdjustmentService_.delete(toDelete, sharedContext)
}
let result = await this.orderLineItemAdjustmentService_.upsert(
adjustments,
sharedContext
)
return await this.baseRepository_.serialize<
OrderTypes.OrderLineItemAdjustmentDTO[]
>(result, {
populate: true,
})
}
@InjectTransactionManager()
async upsertOrderShippingMethodAdjustments(
adjustments: (
| OrderTypes.CreateOrderShippingMethodAdjustmentDTO
| OrderTypes.UpdateOrderShippingMethodAdjustmentDTO
)[],
@MedusaContext() sharedContext: Context = {}
): Promise<OrderTypes.OrderShippingMethodAdjustmentDTO[]> {
const result = await this.orderShippingMethodAdjustmentService_.upsert(
adjustments,
sharedContext
)
return await this.baseRepository_.serialize<
OrderTypes.OrderShippingMethodAdjustmentDTO[]
>(result, {
populate: true,
})
}
@InjectTransactionManager()
async setOrderShippingMethodAdjustments(
orderId: string,
adjustments: (
| OrderTypes.CreateOrderShippingMethodAdjustmentDTO
| OrderTypes.UpdateOrderShippingMethodAdjustmentDTO
)[],
@MedusaContext() sharedContext: Context = {}
): Promise<OrderTypes.OrderShippingMethodAdjustmentDTO[]> {
const order = await this.retrieveOrder(
orderId,
{ select: ["id"], relations: ["shipping_methods.adjustments"] },
sharedContext
)
const existingAdjustments = (order.shipping_methods ?? [])
.map((shippingMethod) => shippingMethod.adjustments ?? [])
.flat()
.map((adjustment) => adjustment.id)
const adjustmentsSet = new Set(
adjustments
.map(
(a) => (a as OrderTypes.UpdateOrderShippingMethodAdjustmentDTO)?.id
)
.filter(Boolean)
)
const toDelete: string[] = []
// From the existing adjustments, find the ones that are not passed in adjustments
existingAdjustments.forEach((adj) => {
if (!adjustmentsSet.has(adj)) {
toDelete.push(adj)
}
})
if (toDelete.length) {
await this.orderShippingMethodAdjustmentService_.delete(
toDelete,
sharedContext
)
}
const result = await this.orderShippingMethodAdjustmentService_.upsert(
adjustments,
sharedContext
)
return await this.baseRepository_.serialize<
OrderTypes.OrderShippingMethodAdjustmentDTO[]
>(result, {
populate: true,
})
}
// @ts-ignore
async createOrderShippingMethodAdjustments(
adjustments: OrderTypes.CreateOrderShippingMethodAdjustmentDTO[]
): Promise<OrderTypes.OrderShippingMethodAdjustmentDTO[]>
// @ts-expect-error
async createOrderShippingMethodAdjustments(
adjustment: OrderTypes.CreateOrderShippingMethodAdjustmentDTO
): Promise<OrderTypes.OrderShippingMethodAdjustmentDTO>
// @ts-expect-error
async createOrderShippingMethodAdjustments(
orderId: string,
adjustments: OrderTypes.CreateOrderShippingMethodAdjustmentDTO[],
sharedContext?: Context
): Promise<OrderTypes.OrderShippingMethodAdjustmentDTO[]>
@InjectTransactionManager()
// @ts-expect-error
async createOrderShippingMethodAdjustments(
orderIdOrData:
| string
| OrderTypes.CreateOrderShippingMethodAdjustmentDTO[]
| OrderTypes.CreateOrderShippingMethodAdjustmentDTO,
adjustments?: OrderTypes.CreateOrderShippingMethodAdjustmentDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<
| OrderTypes.OrderShippingMethodAdjustmentDTO[]
| OrderTypes.OrderShippingMethodAdjustmentDTO
> {
let addedAdjustments: InferEntityType<
typeof OrderShippingMethodAdjustment
>[] = []
if (isString(orderIdOrData)) {
const order = await this.retrieveOrder(
orderIdOrData,
{ select: ["id"], relations: ["shipping_methods"] },
sharedContext
)
const methodIds = order.shipping_methods?.map((method) => method.id)
for (const adj of adjustments || []) {
if (!methodIds?.includes(adj.shipping_method_id)) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Shipping method with id ${adj.shipping_method_id} does not exist on order with id ${orderIdOrData}`
)
}
}
addedAdjustments =
await this.orderShippingMethodAdjustmentService_.create(
adjustments as OrderTypes.CreateOrderShippingMethodAdjustmentDTO[],
sharedContext
)
} else {
const data = Array.isArray(orderIdOrData)
? orderIdOrData
: [orderIdOrData]
addedAdjustments =
await this.orderShippingMethodAdjustmentService_.create(
data as OrderTypes.CreateOrderShippingMethodAdjustmentDTO[],
sharedContext
)
}
if (isObject(orderIdOrData)) {
return await this.baseRepository_.serialize<OrderTypes.OrderShippingMethodAdjustmentDTO>(
addedAdjustments[0],
{
populate: true,
}
)
}
return await this.baseRepository_.serialize<
OrderTypes.OrderShippingMethodAdjustmentDTO[]
>(addedAdjustments, {
populate: true,
})
}
// @ts-ignore
createOrderLineItemTaxLines(
taxLines: OrderTypes.CreateOrderLineItemTaxLineDTO[]
): Promise<OrderTypes.OrderLineItemTaxLineDTO[]>
// @ts-expect-error
createOrderLineItemTaxLines(
taxLine: OrderTypes.CreateOrderLineItemTaxLineDTO
): Promise<OrderTypes.OrderLineItemTaxLineDTO>
// @ts-expect-error
createOrderLineItemTaxLines(
orderId: string,
taxLines:
| OrderTypes.CreateOrderLineItemTaxLineDTO[]
| OrderTypes.CreateOrderShippingMethodTaxLineDTO,
sharedContext?: Context
): Promise<OrderTypes.OrderLineItemTaxLineDTO[]>
@InjectTransactionManager()
// @ts-expect-error
async createOrderLineItemTaxLines(
orderIdOrData:
| string
| OrderTypes.CreateOrderLineItemTaxLineDTO[]
| OrderTypes.CreateOrderLineItemTaxLineDTO,
taxLines?:
| OrderTypes.CreateOrderLineItemTaxLineDTO[]
| OrderTypes.CreateOrderLineItemTaxLineDTO,
@MedusaContext() sharedContext: Context = {}
): Promise<
OrderTypes.OrderLineItemTaxLineDTO[] | OrderTypes.OrderLineItemTaxLineDTO
> {
let addedTaxLines: InferEntityType<typeof OrderLineItemTaxLine>[]
if (isString(orderIdOrData)) {
const lines = Array.isArray(taxLines) ? taxLines : [taxLines]
addedTaxLines = await this.orderLineItemTaxLineService_.create(
lines as CreateOrderLineItemTaxLineDTO[],
sharedContext
)
} else {
const data = Array.isArray(orderIdOrData)
? orderIdOrData
: [orderIdOrData]
addedTaxLines = await this.orderLineItemTaxLineService_.create(
data as CreateOrderLineItemTaxLineDTO[],
sharedContext
)
}
const serialized = await this.baseRepository_.serialize<
OrderTypes.OrderLineItemTaxLineDTO[]
>(addedTaxLines, {
populate: true,
})
if (isObject(orderIdOrData)) {
return serialized[0]
}
return serialized
}
@InjectTransactionManager()
async upsertOrderLineItemTaxLines(
taxLines: (
| OrderTypes.CreateOrderLineItemTaxLineDTO
| OrderTypes.UpdateOrderLineItemTaxLineDTO
)[],
@MedusaContext() sharedContext: Context = {}
): Promise<OrderTypes.OrderLineItemTaxLineDTO[]> {
const result = await this.orderLineItemTaxLineService_.upsert(
taxLines as UpdateOrderLineItemTaxLineDTO[],
sharedContext
)
return await this.baseRepository_.serialize<
OrderTypes.OrderLineItemTaxLineDTO[]
>(result, {
populate: true,
})
}
@InjectTransactionManager()
async setOrderLineItemTaxLines(
orderId: string,
taxLines: (
| OrderTypes.CreateOrderLineItemTaxLineDTO
| OrderTypes.UpdateOrderLineItemTaxLineDTO
)[],
@MedusaContext() sharedContext: Context = {}
): Promise<OrderTypes.OrderLineItemTaxLineDTO[]> {
const order = await this.retrieveOrder(
orderId,
{ select: ["id"], relations: ["items.item.tax_lines"] },
sharedContext
)
const existingTaxLines = (order.items ?? [])
.map((item) => item.tax_lines ?? [])
.flat()
.map((taxLine) => taxLine.id)
const taxLinesSet = new Set(
taxLines
.map(
(taxLine) => (taxLine as OrderTypes.UpdateOrderLineItemTaxLineDTO)?.id
)
.filter(Boolean)
)
const toDelete: string[] = []
existingTaxLines.forEach((taxLine: string) => {
if (!taxLinesSet.has(taxLine)) {
toDelete.push(taxLine)
}
})
if (toDelete.length) {
await this.orderLineItemTaxLineService_.delete(toDelete, sharedContext)
}
const result = await this.orderLineItemTaxLineService_.upsert(
taxLines as UpdateOrderLineItemTaxLineDTO[],
sharedContext
)
return await this.baseRepository_.serialize<
OrderTypes.OrderLineItemTaxLineDTO[]
>(result, {
populate: true,
})
}
// @ts-ignore
createOrderShippingMethodTaxLines(
taxLines: OrderTypes.CreateOrderShippingMethodTaxLineDTO[]
): Promise<OrderTypes.OrderShippingMethodTaxLineDTO[]>
// @ts-expect-error
createOrderShippingMethodTaxLines(
taxLine: OrderTypes.CreateOrderShippingMethodTaxLineDTO
): Promise<OrderTypes.OrderShippingMethodTaxLineDTO>
// @ts-expect-error
createOrderShippingMethodTaxLines(
orderId: string,
taxLines:
| OrderTypes.CreateOrderShippingMethodTaxLineDTO[]
| OrderTypes.CreateOrderShippingMethodTaxLineDTO,
sharedContext?: Context
): Promise<OrderTypes.OrderShippingMethodTaxLineDTO[]>
@InjectTransactionManager()
// @ts-expect-error
async createOrderShippingMethodTaxLines(
orderIdOrData:
| string
| OrderTypes.CreateOrderShippingMethodTaxLineDTO[]
| OrderTypes.CreateOrderShippingMethodTaxLineDTO,
taxLines?:
| OrderTypes.CreateOrderShippingMethodTaxLineDTO[]
| OrderTypes.CreateOrderShippingMethodTaxLineDTO,
@MedusaContext() sharedContext: Context = {}
): Promise<
| OrderTypes.OrderShippingMethodTaxLineDTO[]
| OrderTypes.OrderShippingMethodTaxLineDTO
> {
let addedTaxLines: InferEntityType<typeof OrderShippingMethodTaxLine>[]
if (isString(orderIdOrData)) {
const lines = Array.isArray(taxLines) ? taxLines : [taxLines]
addedTaxLines = await this.orderShippingMethodTaxLineService_.create(
lines as CreateOrderShippingMethodTaxLineDTO[],
sharedContext
)
} else {
addedTaxLines = await this.orderShippingMethodTaxLineService_.create(
taxLines as CreateOrderShippingMethodTaxLineDTO[],
sharedContext
)
}
const serialized =
await this.baseRepository_.serialize<OrderTypes.OrderShippingMethodTaxLineDTO>(
addedTaxLines[0],
{
populate: true,
}
)
if (isObject(orderIdOrData)) {
return serialized[0]
}
return serialized
}
@InjectTransactionManager()
async upsertOrderShippingMethodTaxLines(
taxLines: (
| OrderTypes.CreateOrderShippingMethodTaxLineDTO
| OrderTypes.UpdateOrderShippingMethodTaxLineDTO
)[],
@MedusaContext() sharedContext: Context = {}
): Promise<OrderTypes.OrderShippingMethodTaxLineDTO[]> {
const result = await this.orderShippingMethodTaxLineService_.upsert(
taxLines as UpdateOrderShippingMethodTaxLineDTO[],
sharedContext
)
return await this.baseRepository_.serialize<
OrderTypes.OrderShippingMethodTaxLineDTO[]
>(result, {
populate: true,
})
}
@InjectTransactionManager()
async setOrderShippingMethodTaxLines(
orderId: string,
taxLines: (
| OrderTypes.CreateOrderShippingMethodTaxLineDTO
| OrderTypes.UpdateOrderShippingMethodTaxLineDTO
)[],
@MedusaContext() sharedContext: Context = {}
): Promise<OrderTypes.OrderShippingMethodTaxLineDTO[]> {
const order = await this.retrieveOrder(
orderId,
{ select: ["id"], relations: ["shipping_methods.tax_lines"] },
sharedContext
)
const existingTaxLines = (order.shipping_methods ?? [])
.map((shippingMethod) => shippingMethod.tax_lines ?? [])
.flat()
.map((taxLine) => taxLine.id)
const taxLinesSet = new Set(
taxLines
.map(
(taxLine) =>
(taxLine as OrderTypes.UpdateOrderShippingMethodTaxLineDTO)?.id
)
.filter(Boolean)
)
const toDelete: string[] = []
existingTaxLines.forEach((taxLine: string) => {
if (!taxLinesSet.has(taxLine)) {
toDelete.push(taxLine)
}
})
if (toDelete.length) {
await this.orderShippingMethodTaxLineService_.delete(
toDelete,
sharedContext
)
}
const result = await this.orderShippingMethodTaxLineService_.upsert(
taxLines as UpdateOrderShippingMethodTaxLineDTO[],
sharedContext
)
return await this.baseRepository_.serialize<
OrderTypes.OrderShippingMethodTaxLineDTO[]
>(result, {
populate: true,
})
}
// @ts-ignore
async createReturns(
data: OrderTypes.CreateOrderReturnDTO,
sharedContext?: Context
): Promise<OrderTypes.ReturnDTO>
// @ts-expect-error
async createReturns(
data: OrderTypes.CreateOrderReturnDTO[],
sharedContext?: Context
): Promise<OrderTypes.ReturnDTO[]>
@InjectTransactionManager()
// @ts-expect-error
async createReturns(
data: OrderTypes.CreateOrderReturnDTO | OrderTypes.CreateOrderReturnDTO[],
@MedusaContext() sharedContext?: Context
): Promise<OrderTypes.ReturnDTO | OrderTypes.ReturnDTO[]> {
const created = await this.createOrderRelatedEntity_(
data,
this.returnService_,
sharedContext
)
return await this.baseRepository_.serialize<OrderTypes.ReturnDTO>(
!Array.isArray(data) ? created[0] : created,
{
populate: true,
}
)
}
// @ts-ignore
async createOrderClaims(
data: OrderTypes.CreateOrderClaimDTO,
sharedContext?: Context
): Promise<OrderTypes.OrderClaimDTO>
// @ts-expect-error
async createOrderClaims(
data: OrderTypes.CreateOrderClaimDTO[],
sharedContext?: Context
): Promise<OrderTypes.OrderClaimDTO[]>
@InjectTransactionManager()
// @ts-expect-error
async createOrderClaims(
data: OrderTypes.CreateOrderClaimDTO | OrderTypes.CreateOrderClaimDTO[],
@MedusaContext() sharedContext?: Context
): Promise<OrderTypes.OrderClaimDTO | OrderTypes.OrderClaimDTO[]> {
const created = await this.createOrderRelatedEntity_(
data,
this.orderClaimService_,
sharedContext
)
return await this.baseRepository_.serialize<OrderTypes.OrderClaimDTO>(
!Array.isArray(data) ? created[0] : created,
{
populate: true,
}
)
}
// @ts-ignore
async createOrderExchanges(
data: OrderTypes.CreateOrderExchangeDTO,
sharedContext?: Context
): Promise<OrderTypes.OrderExchangeDTO>
// @ts-expect-error
async createOrderExchanges(
data: OrderTypes.CreateOrderExchangeDTO[],
sharedContext?: Context
): Promise<OrderTypes.OrderExchangeDTO[]>
@InjectTransactionManager()
// @ts-expect-error
async createOrderExchanges(
data:
| OrderTypes.CreateOrderExchangeDTO
| OrderTypes.CreateOrderExchangeDTO[],
@MedusaContext() sharedContext?: Context
): Promise<OrderTypes.OrderExchangeDTO | OrderTypes.OrderExchangeDTO[]> {
const created = await this.createOrderRelatedEntity_(
data,
this.orderExchangeService_,
sharedContext
)
return await this.baseRepository_.serialize<OrderTypes.OrderExchangeDTO>(
!Array.isArray(data) ? created[0] : created,
{
populate: true,
}
)
}
@InjectTransactionManager()
private async createOrderRelatedEntity_(
data: any,
service: any,
sharedContext?: Context
) {
const data_ = Array.isArray(data) ? data : [data]
const inputDataMap = data_.reduce((acc, curr) => {
acc[curr.order_id] = curr
return acc
}, {})
const orderIds = data_.map((d) => d.order_id)
const orders = await this.orderService_.list(
{ id: orderIds },
{ select: ["id", "version"] },
sharedContext
)
if (orders.length !== orderIds.length) {
const foundOrders = orders.map((o) => o.id)
const missing = orderIds.filter((id) => !foundOrders.includes(id))
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Order could not be found: ${missing.join(", ")}`
)
}
for (const order of orders) {
inputDataMap[order.id].order_version = order.version
}
return await service.create(data_, sharedContext)
}
async createOrderChange(
data: CreateOrderChangeDTO,
sharedContext?: Context
): Promise<OrderTypes.OrderChangeDTO>
async createOrderChange(
data: CreateOrderChangeDTO[],
sharedContext?: Context
): Promise<OrderTypes.OrderChangeDTO[]>
@InjectManager()
async createOrderChange(
data: CreateOrderChangeDTO | CreateOrderChangeDTO[],
@MedusaContext() sharedContext?: Context
): Promise<OrderTypes.OrderChangeDTO | OrderTypes.OrderChangeDTO[]> {
const changes = await this.createOrderChange_(data, sharedContext)
return await this.baseRepository_.serialize<OrderTypes.OrderChangeDTO>(
Array.isArray(data) ? changes : changes[0],
{
populate: true,
}
)
}
@InjectTransactionManager()
protected async createOrderChange_(
data: CreateOrderChangeDTO | CreateOrderChangeDTO[],
@MedusaContext() sharedContext?: Context
): Promise<InferEntityType<typeof OrderChange>[]> {
const dataArr = Array.isArray(data) ? data : [data]
const orderIds: string[] = []
const dataMap: Record<string, object> = {}
const orderChanges = await this.listOrderChanges(
{
order_id: dataArr.map((data) => data.order_id),
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
},
{},
sharedContext
)
const orderChangesMap = new Map<string, OrderTypes.OrderChangeDTO>(
orderChanges.map((item) => [item.order_id, item])
)
for (const change of dataArr) {
orderIds.push(change.order_id)
dataMap[change.order_id] = change
}
const orders = await this.orderService_.list(
{ id: orderIds },
{ select: ["id", "version"] },
sharedContext
)
if (orders.length !== orderIds.length) {
const foundOrders = orders.map((o) => o.id)
const missing = orderIds.filter((id) => !foundOrders.includes(id))
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Order could not be found: ${missing.join(", ")}`
)
}
const input = orders.map((order) => {
const existingOrderChange = orderChangesMap.get(order.id)
if (existingOrderChange) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Order (${order.id}) already has an existing active order change`
)
}
return {
...dataMap[order.id],
version: order.version! + 1,
} as any
})
return await this.orderChangeService_.create(input, sharedContext)
}
@InjectManager()
async previewOrderChange(orderId: string, sharedContext?: Context) {
const order = await this.retrieveOrder(
orderId,
{
select: ["id", "version", "items.detail", "summary", "total"],
relations: ["transactions", "credit_lines"],
},
sharedContext
)
if (!order.order_change) {
return order
}
const orderChange = await super.retrieveOrderChange(
order.order_change.id,
{ relations: ["actions"] },
sharedContext
)
const { itemsToUpsert, shippingMethodsToUpsert, calculatedOrders } =
await applyChangesToOrder(
[order],
{ [order.id]: orderChange.actions },
{ addActionReferenceToObject: true }
)
const calculated = calculatedOrders[order.id]
await this.includeTaxLinesAndAdjustementsToPreview(
calculated.order,
itemsToUpsert,
shippingMethodsToUpsert,
sharedContext
)
const calcOrder = calculated.order
const orderWithTotals = decorateCartTotals(
calcOrder as DecorateCartLikeInputDTO
)
calcOrder.summary = calculated.getSummaryFromOrder(orderWithTotals)
createRawPropertiesFromBigNumber(calcOrder)
return calcOrder
}
private async includeTaxLinesAndAdjustementsToPreview(
order,
itemsToUpsert,
shippingMethodsToUpsert,
sharedContext
) {
const addedItems = {}
const addedShippingMethods = {}
for (const item of order.items) {
const isExistingItem = item.id === item.detail?.item_id
if (!isExistingItem) {
addedItems[item.id] = {
...item,
quantity: item.detail?.quantity ?? item.quantity,
unit_price: item.detail?.unit_price || item.unit_price,
compare_at_unit_price:
item.detail?.compare_at_unit_price ||
item.compare_at_unit_price ||
null,
}
}
}
for (const sm of order.shipping_methods) {
if (!isDefined(sm.shipping_option_id)) {
addedShippingMethods[sm.id] = sm
}
}
if (Object.keys(addedItems).length > 0) {
const addedItemDetails = await this.listOrderLineItems(
{ id: Object.keys(addedItems) },
{
relations: ["adjustments", "tax_lines"],
},
sharedContext
)
order.items.forEach((item, idx) => {
if (!addedItems[item.id]) {
return
}
const lineItem = addedItemDetails.find((d) => d.id === item.id) as any
const actions = item.actions
delete item.actions
//@ts-ignore
const newItem = itemsToUpsert.find((d) => d.item_id === item.id)!
const unitPrice = newItem?.unit_price ?? item.unit_price
const compareAtUnitPrice =
newItem?.compare_at_unit_price ?? item.compare_at_unit_price
delete lineItem.raw_unit_price
delete lineItem.raw_compare_at_unit_price
order.items[idx] = {
...lineItem,
actions,
quantity: newItem.quantity,
unit_price: unitPrice,
compare_at_unit_price: compareAtUnitPrice || null,
detail: {
...newItem,
...item,
},
}
})
}
if (Object.keys(addedShippingMethods).length > 0) {
const addedShippingDetails = await this.listOrderShippingMethods(
{ id: Object.keys(addedShippingMethods) },
{
relations: ["adjustments", "tax_lines"],
},
sharedContext
)
order.shipping_methods.forEach((sm, idx) => {
if (!addedShippingMethods[sm.id]) {
return
}
const shippingMethod = addedShippingDetails.find(
(d) => d.id === sm.id
) as any
const actions = sm.actions
delete sm.actions
const newItem = shippingMethodsToUpsert.find((d) => d.id === sm.id)!
sm.shipping_method_id = sm.id
delete sm.id
order.shipping_methods[idx] = {
...shippingMethod,
actions,
detail: {
...sm,
...newItem,
},
}
})
}
}
async cancelOrderChange(
orderId: string,
sharedContext?: Context
): Promise<void>
async cancelOrderChange(
orderId: string[],
sharedContext?: Context
): Promise<void>
async cancelOrderChange(
data: OrderTypes.CancelOrderChangeDTO,
sharedContext?: Context
): Promise<void>
async cancelOrderChange(
data: OrderTypes.CancelOrderChangeDTO[],
sharedContext?: Context
): Promise<void>
@InjectTransactionManager()
async cancelOrderChange(
orderChangeIdOrData:
| string
| string[]
| OrderTypes.CancelOrderChangeDTO
| OrderTypes.CancelOrderChangeDTO[],
@MedusaContext() sharedContext?: Context
): Promise<void> {
const data = Array.isArray(orderChangeIdOrData)
? orderChangeIdOrData
: [orderChangeIdOrData]
const orderChangeIds = isString(data[0])
? data
: (data as any).map((dt) => dt.id)
await this.getAndValidateOrderChange_(orderChangeIds, false, sharedContext)
const updates = data.map((dt) => {
return {
...(isString(dt) ? { id: dt } : dt),
canceled_at: new Date(),
status: OrderChangeStatus.CANCELED,
}
})
await this.orderChangeService_.update(updates as any, sharedContext)
}
async confirmOrderChange(orderChangeId: string, sharedContext?: Context)
async confirmOrderChange(orderChangeId: string[], sharedContext?: Context)
async confirmOrderChange(
data: OrderTypes.ConfirmOrderChangeDTO,
sharedContext?: Context
)
async confirmOrderChange(
data: OrderTypes.ConfirmOrderChangeDTO[],
sharedContext?: Context
)
@InjectManager()
async confirmOrderChange(
orderChangeIdOrData:
| string
| string[]
| OrderTypes.ConfirmOrderChangeDTO
| OrderTypes.ConfirmOrderChangeDTO[],
@MedusaContext() sharedContext?: Context
): Promise<OrderTypes.OrderChangeReturn> {
const data = Array.isArray(orderChangeIdOrData)
? orderChangeIdOrData
: [orderChangeIdOrData]
const orderChangeIds = isString(data[0])
? data
: (data as any).map((dt) => dt.id)
const orderChange = await this.getAndValidateOrderChange_(
orderChangeIds,
true,
sharedContext
)
const updates = data.map((dt) => {
return {
...(isString(dt) ? { id: dt } : dt),
confirmed_at: new Date(),
status: OrderChangeStatus.CONFIRMED,
}
})
await this.orderChangeService_.update(updates as any, sharedContext)
const orderChanges = orderChange.map((change) => {
return change.actions
})
return await this.applyOrderChanges_(orderChanges.flat(), sharedContext)
}
async declineOrderChange(orderChangeId: string, sharedContext?: Context)
async declineOrderChange(orderChangeId: string[], sharedContext?: Context)
async declineOrderChange(
data: OrderTypes.DeclineOrderChangeDTO,
sharedContext?: Context
)
async declineOrderChange(
data: OrderTypes.DeclineOrderChangeDTO[],
sharedContext?: Context
)
@InjectTransactionManager()
async declineOrderChange(
orderChangeIdOrData:
| string
| string[]
| OrderTypes.DeclineOrderChangeDTO
| OrderTypes.DeclineOrderChangeDTO[],
@MedusaContext() sharedContext?: Context
): Promise<void> {
const data = Array.isArray(orderChangeIdOrData)
? orderChangeIdOrData
: [orderChangeIdOrData]
const orderChangeIds = isString(data[0])
? data
: (data as any).map((dt) => dt.id)
await this.getAndValidateOrderChange_(orderChangeIds, false, sharedContext)
const updates = data.map((dt) => {
return {
...(isString(dt) ? { id: dt } : dt),
declined_at: new Date(),
status: OrderChangeStatus.DECLINED,
}
})
await this.orderChangeService_.update(updates as any, sharedContext)
}
async registerOrderChange(
data: OrderTypes.RegisterOrderChangeDTO,
sharedContext?: Context
): Promise<OrderTypes.OrderChangeDTO>
async registerOrderChange(
data: OrderTypes.RegisterOrderChangeDTO[],
sharedContext?: Context
): Promise<OrderTypes.OrderChangeDTO[]>
@InjectManager()
async registerOrderChange(
data:
| OrderTypes.RegisterOrderChangeDTO
| OrderTypes.RegisterOrderChangeDTO[],
sharedContext?: Context
): Promise<OrderTypes.OrderChangeDTO | OrderTypes.OrderChangeDTO[]> {
const inputData = Array.isArray(data) ? data : [data]
const orders = await this.orderService_.list(
{ id: inputData.map((d) => d.order_id) },
{ select: ["id", "version"] },
sharedContext
)
const orderVersionsMap = new Map(orders.map((o) => [o.id, o.version]))
const changes = (await this.orderChangeService_.create(
inputData.map((d) => ({
order_id: d.order_id,
change_type: d.change_type,
internal_note: d.internal_note,
description: d.description,
metadata: d.metadata,
confirmed_at: new Date(),
created_by: d.created_by,
confirmed_by: d.confirmed_by,
status: OrderChangeStatus.CONFIRMED,
version: orderVersionsMap.get(d.order_id)!,
actions: [
{
action: ChangeActionType.UPDATE_ORDER_PROPERTIES,
details: d.details,
version: orderVersionsMap.get(d.order_id)!,
applied: true,
},
],
})),
sharedContext
)) as unknown as OrderTypes.OrderChangeDTO[]
return Array.isArray(data) ? changes : changes[0]
}
@InjectManager()
async applyPendingOrderActions(
orderId: string | string[],
@MedusaContext() sharedContext?: Context
): Promise<OrderTypes.OrderChangeReturn> {
const orderIds = Array.isArray(orderId) ? orderId : [orderId]
const orders = await this.orderService_.list(
{ id: orderIds },
{
select: ["id", "version"],
},
sharedContext
)
const changes = await this.orderChangeActionService_.list(
{
order_id: orders.map((order) => order.id),
version: orders[0].version,
applied: false,
},
{
select: [
"id",
"order_id",
"return_id",
"exchange_id",
"claim_id",
"ordering",
"version",
"applied",
"reference",
"reference_id",
"action",
"details",
"amount",
"raw_amount",
"internal_note",
],
order: {
ordering: "ASC",
},
},
sharedContext
)
return await this.applyOrderChanges_(
changes as unknown as ApplyOrderChangeDTO[],
sharedContext
)
}
@InjectManager()
async revertLastVersion(
orderId: string,
@MedusaContext() sharedContext?: Context
) {
const order = await super.retrieveOrder(
orderId,
{
select: ["id", "version"],
},
sharedContext
)
if (order.version < 2) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Order with id ${orderId} has no previous versions`
)
}
return await this.revertLastChange_(order, sharedContext)
}
@InjectManager()
async undoLastChange(
orderId: string,
lastOrderChange?: Partial<OrderChangeDTO>,
@MedusaContext() sharedContext?: Context
) {
const order = await super.retrieveOrder(
orderId,
{
select: ["id", "version"],
},
sharedContext
)
if (order.version < 2) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Order with id ${orderId} has no previous versions`
)
}
return await this.undoLastChange_(order, lastOrderChange, sharedContext)
}
@InjectTransactionManager()
protected async undoLastChange_(
order: OrderDTO,
lastOrderChange?: Partial<OrderChangeDTO>,
sharedContext?: Context
): Promise<void> {
const currentVersion = order.version
const updatePromises: Promise<any>[] = []
// Order Changes
const orderChanges = await this.orderChangeService_.list(
{
order_id: order.id,
version: currentVersion,
},
{ select: ["id", "version"] },
sharedContext
)
const orderChangesIds = orderChanges.map((change) => {
return {
id: change.id,
status: lastOrderChange?.status ?? OrderChangeStatus.PENDING,
confirmed_at: null,
}
})
updatePromises.push(
this.orderChangeService_.update(orderChangesIds, sharedContext)
)
// Order Changes Actions
const orderChangesActions = await this.orderChangeActionService_.list(
{
order_id: order.id,
version: currentVersion,
},
{ select: ["id", "version"] },
sharedContext
)
const orderChangeActionsIds = orderChangesActions.map((action) => {
return {
id: action.id,
applied: false,
}
})
updatePromises.push(
this.orderChangeActionService_.update(
orderChangeActionsIds,
sharedContext
)
)
// Order Summary
const orderSummary = await this.orderSummaryService_.list(
{
order_id: order.id,
version: currentVersion,
},
{ select: ["id", "version"] },
sharedContext
)
const orderSummaryIds = orderSummary.map((summary) => summary.id)
updatePromises.push(
this.orderSummaryService_.softDelete(orderSummaryIds, sharedContext)
)
// Order Items
const orderItems = await this.orderItemService_.list(
{
order_id: order.id,
version: currentVersion,
},
{ select: ["id", "version"] },
sharedContext
)
const orderItemIds = orderItems.map((summary) => summary.id)
updatePromises.push(
this.orderItemService_.softDelete(orderItemIds, sharedContext)
)
// Order Shipping
const orderShippings = await this.orderShippingService_.list(
{
order_id: order.id,
version: currentVersion,
},
{ select: ["id", "version"] },
sharedContext
)
const orderShippingIds = orderShippings.map((sh) => sh.id)
updatePromises.push(
this.orderShippingService_.softDelete(orderShippingIds, sharedContext)
)
// Order
updatePromises.push(
this.orderService_.update(
{
selector: {
id: order.id,
},
data: {
version: order.version - 1,
},
},
sharedContext
)
)
await promiseAll(updatePromises)
}
@InjectTransactionManager()
protected async revertLastChange_(
order: OrderDTO,
sharedContext?: Context
): Promise<void> {
const currentVersion = order.version
const updatePromises: Promise<any>[] = []
// Order Changes
const orderChanges = await this.orderChangeService_.list(
{
order_id: order.id,
version: currentVersion,
},
{ select: ["id", "version"] },
sharedContext
)
const orderChangesIds = orderChanges.map((change) => change.id)
updatePromises.push(
this.orderChangeService_.softDelete(orderChangesIds, sharedContext)
)
// Order Changes Actions
const orderChangesActions = await this.orderChangeActionService_.list(
{
order_id: order.id,
version: currentVersion,
},
{ select: ["id", "version"] },
sharedContext
)
const orderChangeActionsIds = orderChangesActions.map((action) => action.id)
updatePromises.push(
this.orderChangeActionService_.softDelete(
orderChangeActionsIds,
sharedContext
)
)
// Order Summary
const orderSummary = await this.orderSummaryService_.list(
{
order_id: order.id,
version: currentVersion,
},
{ select: ["id", "version"] },
sharedContext
)
const orderSummaryIds = orderSummary.map((summary) => summary.id)
updatePromises.push(
this.orderSummaryService_.softDelete(orderSummaryIds, sharedContext)
)
// Order Items
const orderItems = await this.orderItemService_.list(
{
order_id: order.id,
version: currentVersion,
},
{ select: ["id", "version"] },
sharedContext
)
const orderItemIds = orderItems.map((summary) => summary.id)
updatePromises.push(
this.orderItemService_.softDelete(orderItemIds, sharedContext)
)
// Order Shipping
const orderShippings = await this.orderShippingService_.list(
{
order_id: order.id,
version: currentVersion,
},
{ select: ["id", "version"] },
sharedContext
)
const orderShippingIds = orderShippings.map((sh) => sh.id)
updatePromises.push(
this.orderShippingService_.softDelete(orderShippingIds, sharedContext)
)
// Order
updatePromises.push(
this.orderService_.update(
{
selector: {
id: order.id,
},
data: {
version: order.version - 1,
},
},
sharedContext
)
)
// Returns
updatePromises.push(
this.returnService_.delete(
{
order_id: order.id,
order_version: currentVersion,
},
sharedContext
)
)
await promiseAll(updatePromises)
}
private async getActiveOrderChange_(
orderId: string,
includeActions: boolean,
sharedContext?: Context
): Promise<any> {
const options = {
select: [
"id",
"change_type",
"order_id",
"return_id",
"claim_id",
"exchange_id",
"version",
"requested_at",
"requested_by",
"status",
"description",
"internal_note",
],
relations: [] as string[],
order: {},
}
if (includeActions) {
options.select.push("actions")
options.relations.push("actions")
options.order = {
actions: {
ordering: "ASC",
},
}
}
const [orderChange] = await this.listOrderChanges(
{
order_id: orderId,
status: [OrderChangeStatus.PENDING, OrderChangeStatus.REQUESTED],
},
options,
sharedContext
)
return orderChange
}
private async getAndValidateOrderChange_(
orderChangeIds: string[],
includeActions: boolean,
sharedContext?: Context
): Promise<any> {
orderChangeIds = deduplicate(orderChangeIds)
const options = {
select: [
"id",
"order_id",
"return_id",
"claim_id",
"exchange_id",
"version",
"status",
],
relations: [] as string[],
order: {},
}
if (includeActions) {
options.select.push("actions")
options.relations.push("actions")
options.order = {
actions: {
ordering: "ASC",
},
}
}
const orderChanges = await this.listOrderChanges(
{
id: orderChangeIds,
},
options,
sharedContext
)
if (orderChanges.length !== orderChangeIds.length) {
const foundOrders = orderChanges.map((o) => o.id)
const missing = orderChangeIds.filter((id) => !foundOrders.includes(id))
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Order Change could not be found: ${missing.join(", ")}`
)
}
for (const orderChange of orderChanges) {
const notAllowed: string[] = []
if (
!(
orderChange.status === OrderChangeStatus.PENDING ||
orderChange.status === OrderChangeStatus.REQUESTED
)
) {
notAllowed.push(orderChange.id)
}
if (notAllowed.length) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Order Change cannot be modified: ${notAllowed.join(", ")}.`
)
}
}
return orderChanges
}
async addOrderAction(
data: OrderTypes.CreateOrderChangeActionDTO,
sharedContext?: Context
): Promise<OrderTypes.OrderChangeActionDTO>
async addOrderAction(
data: OrderTypes.CreateOrderChangeActionDTO[],
sharedContext?: Context
): Promise<OrderTypes.OrderChangeActionDTO[]>
@InjectTransactionManager()
async addOrderAction(
data:
| OrderTypes.CreateOrderChangeActionDTO
| OrderTypes.CreateOrderChangeActionDTO[],
@MedusaContext() sharedContext?: Context
): Promise<
OrderTypes.OrderChangeActionDTO | OrderTypes.OrderChangeActionDTO[]
> {
let dataArr = Array.isArray(data) ? data : [data]
const orderChangeMap = {}
const orderChangeIds = dataArr
.map((data, idx) => {
if (data.order_change_id) {
orderChangeMap[data.order_change_id] ??= []
orderChangeMap[data.order_change_id].push(dataArr[idx])
}
return data.order_change_id
})
.filter(Boolean) as string[]
if (orderChangeIds.length) {
const ordChanges = await this.getAndValidateOrderChange_(
orderChangeIds,
false,
sharedContext
)
for (const ordChange of ordChanges) {
orderChangeMap[ordChange.id].forEach((data) => {
if (data) {
data.order_id = ordChange.order_id
data.version = ordChange.version
}
})
}
}
const actions = (await this.orderChangeActionService_.create(
dataArr,
sharedContext
)) as unknown as OrderTypes.OrderChangeActionDTO[]
return Array.isArray(data) ? actions : actions[0]
}
@InjectTransactionManager()
private async applyOrderChanges_(
changeActions: ApplyOrderChangeDTO[],
sharedContext?: Context
): Promise<OrderTypes.OrderChangeReturn> {
const actionsMap: Record<string, any[]> = {}
const ordersIds: string[] = []
const usedActions: any[] = []
for (const action of changeActions) {
if (action.applied) {
continue
}
ordersIds.push(action.order_id)
actionsMap[action.order_id] ??= []
actionsMap[action.order_id].push(action)
usedActions.push({
selector: {
id: action.id,
},
data: {
applied: true,
},
})
}
if (!ordersIds.length) {
return {
items: [],
shipping_methods: [],
credit_lines: [],
}
}
let orders = await this.listOrders(
{ id: deduplicate(ordersIds) },
{
select: ["id", "version", "items.detail", "summary", "total"],
relations: ["transactions", "credit_lines"],
},
sharedContext
)
const {
itemsToUpsert,
shippingMethodsToUpsert,
summariesToUpsert,
orderToUpdate,
creditLinesToCreate,
} = await applyChangesToOrder(orders, actionsMap, {
addActionReferenceToObject: true,
includeTaxLinesAndAdjustementsToPreview: async (...args) => {
args.push(sharedContext)
return await this.includeTaxLinesAndAdjustementsToPreview.apply(
this,
args
)
},
})
const [
_orderUpdate,
_orderChangeActionUpdate,
orderItems,
_orderSummaryUpdate,
orderShippingMethods,
createdOrderCreditLines,
] = await promiseAll([
orderToUpdate.length
? this.orderService_.update(orderToUpdate, sharedContext)
: null,
usedActions.length
? this.orderChangeActionService_.update(usedActions, sharedContext)
: null,
itemsToUpsert.length
? this.orderItemService_.upsert(itemsToUpsert, sharedContext)
: null,
summariesToUpsert.length
? this.orderSummaryService_.upsert(summariesToUpsert, sharedContext)
: null,
shippingMethodsToUpsert.length
? this.orderShippingService_.upsert(
shippingMethodsToUpsert,
sharedContext
)
: null,
creditLinesToCreate.length
? this.orderCreditLineService_.create(
creditLinesToCreate,
sharedContext
)
: null,
])
return {
items: orderItems ?? [],
shipping_methods: orderShippingMethods ?? [],
credit_lines: createdOrderCreditLines ?? ([] as any),
}
}
async addOrderTransactions(
transactionData: OrderTypes.CreateOrderTransactionDTO,
sharedContext?: Context
): Promise<OrderTypes.OrderTransactionDTO>
async addOrderTransactions(
transactionData: OrderTypes.CreateOrderTransactionDTO[],
sharedContext?: Context
): Promise<OrderTypes.OrderTransactionDTO[]>
@InjectManager()
async addOrderTransactions(
transactionData:
| OrderTypes.CreateOrderTransactionDTO
| OrderTypes.CreateOrderTransactionDTO[],
@MedusaContext() sharedContext?: Context
): Promise<
OrderTypes.OrderTransactionDTO | OrderTypes.OrderTransactionDTO[]
> {
const orders = await this.orderService_.list(
{
id: Array.isArray(transactionData)
? transactionData.map((t) => t.order_id)
: transactionData.order_id,
},
{
select: ["id", "version"],
},
sharedContext
)
const data = Array.isArray(transactionData)
? transactionData
: [transactionData]
for (const order of orders) {
const trxs = data.filter((t) => t.order_id === order.id)
for (const trx of trxs) {
;(trx as any).version = order.version
}
}
const created = (await this.orderTransactionService_.create(
data,
sharedContext
)) as (InferEntityType<typeof OrderTransaction> & { order_id: string })[]
await this.updateOrderPaidRefundableAmount_(created, false, sharedContext)
return await this.baseRepository_.serialize<OrderTypes.OrderTransactionDTO>(
!Array.isArray(transactionData) ? created[0] : created,
{
populate: true,
}
)
}
@InjectManager()
// @ts-ignore
async deleteOrderTransactions(
transactionIds: string | object | string[] | object[],
@MedusaContext() sharedContext?: Context
): Promise<void> {
const data = Array.isArray(transactionIds)
? transactionIds
: [transactionIds]
const transactions = await super.listOrderTransactions(
{
id: data,
},
{
select: ["order_id", "version", "amount"],
},
sharedContext
)
await this.orderTransactionService_.delete(data, sharedContext)
await this.updateOrderPaidRefundableAmount_(
transactions,
true,
sharedContext
)
}
@InjectManager()
// @ts-ignore
async softDeleteOrderTransactions<TReturnableLinkableKeys extends string>(
transactionIds: string | object | string[] | object[],
config?: SoftDeleteReturn<TReturnableLinkableKeys>,
@MedusaContext() sharedContext?: Context
): Promise<Record<string, string[]> | void> {
const transactions = await super.listOrderTransactions(
{
id: transactionIds,
},
{
select: ["order_id", "version", "amount"],
},
sharedContext
)
const returned = await super.softDeleteOrderTransactions(
transactionIds,
config,
sharedContext
)
await this.updateOrderPaidRefundableAmount_(
transactions,
true,
sharedContext
)
return returned
}
@InjectManager()
// @ts-ignore
async restoreOrderTransactions<TReturnableLinkableKeys extends string>(
transactionIds: string | object | string[] | object[],
config?: RestoreReturn<TReturnableLinkableKeys>,
@MedusaContext() sharedContext?: Context
): Promise<Record<string, string[]> | void> {
const transactions = await super.listOrderTransactions(
{
id: transactionIds,
},
{
select: ["order_id", "version", "amount"],
withDeleted: true,
},
sharedContext
)
const returned = await super.restoreOrderTransactions(
transactionIds as string[],
config,
sharedContext
)
await this.updateOrderPaidRefundableAmount_(
transactions,
false,
sharedContext
)
return returned
}
@InjectTransactionManager()
private async updateOrderPaidRefundableAmount_(
transactionData: {
order_id: string
version: number
amount: BigNumber | number | BigNumberInput
}[],
isRemoved: boolean,
sharedContext?: Context
) {
const summaries: any = await super.listOrderSummaries(
{
order_id: transactionData.map((trx) => trx.order_id),
version: transactionData[0].version,
},
{},
sharedContext
)
summaries.forEach((summary) => {
let trxs = transactionData.filter(
(trx) => trx.order_id === summary.order_id
)
if (!trxs.length) {
return
}
transformPropertiesToBigNumber(trxs)
const op = isRemoved ? MathBN.sub : MathBN.add
const initialTrxTotal = summary.totals.transaction_total
for (const trx of trxs) {
if (MathBN.gt(trx.amount, 0)) {
summary.totals.paid_total = new BigNumber(
op(summary.totals.paid_total, trx.amount)
)
} else {
summary.totals.refunded_total = new BigNumber(
op(summary.totals.refunded_total, MathBN.abs(trx.amount))
)
}
summary.totals.transaction_total = new BigNumber(
op(summary.totals.transaction_total, trx.amount)
)
}
const initialDiff = MathBN.sub(
summary.totals.transaction_total,
initialTrxTotal
)
summary.totals.pending_difference = new BigNumber(
MathBN.sub(summary.totals.pending_difference, initialDiff)
)
})
createRawPropertiesFromBigNumber(summaries)
await this.orderSummaryService_.update(summaries, sharedContext)
}
async archive(
orderId: string,
sharedContext?: Context
): Promise<OrderTypes.OrderDTO>
async archive(
orderId: string[],
sharedContext?: Context
): Promise<OrderTypes.OrderDTO[]>
@InjectTransactionManager()
async archive(
orderId: string | string[],
@MedusaContext() sharedContext?: Context
): Promise<OrderTypes.OrderDTO | OrderTypes.OrderDTO[]> {
const orderIds = Array.isArray(orderId) ? orderId : [orderId]
const orders = await this.listOrders(
{
id: orderIds,
},
{},
sharedContext
)
const notAllowed: string[] = []
for (const order of orders) {
if (
![
OrderStatus.COMPLETED,
OrderStatus.CANCELED,
OrderStatus.DRAFT,
].includes(order.status as any)
) {
notAllowed.push(order.id)
}
order.status = OrderStatus.ARCHIVED
}
if (notAllowed.length) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Orders ${notAllowed.join(
", "
)} are completed, canceled, or in draft and cannot be archived`
)
}
await this.orderService_.update(
orderIds.map((id) => {
return {
id,
status: OrderStatus.ARCHIVED,
}
}),
sharedContext
)
return Array.isArray(orderId) ? orders : orders[0]
}
async completeOrder(
orderId: string,
sharedContext?: Context
): Promise<OrderTypes.OrderDTO>
async completeOrder(
orderId: string[],
sharedContext?: Context
): Promise<OrderTypes.OrderDTO[]>
@InjectTransactionManager()
async completeOrder(
orderId: string | string[],
@MedusaContext() sharedContext?: Context
): Promise<OrderTypes.OrderDTO | OrderTypes.OrderDTO[]> {
const orderIds = Array.isArray(orderId) ? orderId : [orderId]
const orders = await this.listOrders(
{
id: orderIds,
},
{},
sharedContext
)
const notAllowed: string[] = []
for (const order of orders) {
if ([OrderStatus.CANCELED].includes(order.status as any)) {
notAllowed.push(order.id)
}
order.status = OrderStatus.COMPLETED
}
if (notAllowed.length) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Orders ${notAllowed.join(", ")} are canceled and cannot be completed`
)
}
await this.orderService_.update(
orderIds.map((id) => {
return {
id,
status: OrderStatus.COMPLETED,
}
}),
sharedContext
)
return Array.isArray(orderId) ? orders : orders[0]
}
async cancel(
orderId: string,
sharedContext?: Context
): Promise<OrderTypes.OrderDTO>
async cancel(
orderId: string[],
sharedContext?: Context
): Promise<OrderTypes.OrderDTO[]>
@InjectTransactionManager()
async cancel(
orderId: string | string[],
@MedusaContext() sharedContext?: Context
): Promise<OrderTypes.OrderDTO | OrderTypes.OrderDTO[]> {
const orderIds = Array.isArray(orderId) ? orderId : [orderId]
const orders = await this.listOrders(
{
id: orderIds,
},
{},
sharedContext
)
const canceled_at = new Date()
for (const order of orders) {
order.status = OrderStatus.CANCELED
order.canceled_at = canceled_at
}
await this.orderService_.update(
orderIds.map((id) => {
return {
id,
status: OrderStatus.CANCELED,
canceled_at,
}
}),
sharedContext
)
return Array.isArray(orderId) ? orders : orders[0]
}
// ------------------- Bundled Order Actions
@InjectTransactionManager()
async createReturn(
data: OrderTypes.CreateOrderReturnDTO,
@MedusaContext() sharedContext?: Context
): Promise<OrderTypes.ReturnDTO> {
const ret = await BundledActions.createReturn.bind(this)(
data,
sharedContext
)
return await this.retrieveReturn(
ret.id,
{
relations: [
"items",
"shipping_methods",
"shipping_methods.tax_lines",
"shipping_methods.adjustments",
],
},
sharedContext
)
}
@InjectManager()
async receiveReturn(
data: OrderTypes.ReceiveOrderReturnDTO,
@MedusaContext() sharedContext?: Context
): Promise<OrderTypes.ReturnDTO> {
const ret = await this.receiveReturn_(data, sharedContext)
return await this.retrieveReturn(ret[0].id, {
relations: [
"items",
"items.item",
"shipping_methods",
"shipping_methods.tax_lines",
"shipping_methods.adjustments",
],
})
}
@InjectTransactionManager()
private async receiveReturn_(
data: OrderTypes.ReceiveOrderReturnDTO,
@MedusaContext() sharedContext?: Context
): Promise<any[]> {
return await BundledActions.receiveReturn.bind(this)(data, sharedContext)
}
@InjectManager()
async cancelReturn(
data: OrderTypes.CancelOrderReturnDTO,
@MedusaContext() sharedContext?: Context
): Promise<OrderTypes.ReturnDTO> {
const ret = await this.cancelReturn_(data, sharedContext)
return await this.retrieveReturn(ret.id, {
relations: [
"items",
"shipping_methods",
"shipping_methods.tax_lines",
"shipping_methods.adjustments",
],
})
}
@InjectTransactionManager()
private async cancelReturn_(
data: OrderTypes.CancelOrderReturnDTO,
@MedusaContext() sharedContext?: Context
): Promise<any> {
return await BundledActions.cancelReturn.bind(this)(data, sharedContext)
}
@InjectManager()
async createClaim(
data: OrderTypes.CreateOrderClaimDTO,
@MedusaContext() sharedContext?: Context
): Promise<OrderTypes.OrderClaimDTO> {
const ret = await this.createClaim_(data, sharedContext)
const claim = await this.retrieveOrderClaim(
ret.id,
{
relations: [
"additional_items",
"additional_items.item",
"claim_items",
"claim_items.item",
"return",
"return.items",
"shipping_methods",
"shipping_methods.tax_lines",
"shipping_methods.adjustments",
"transactions",
],
},
sharedContext
)
return await this.baseRepository_.serialize<OrderTypes.OrderClaimDTO>(
claim,
{
populate: true,
}
)
}
@InjectTransactionManager()
async createClaim_(
data: OrderTypes.CreateOrderClaimDTO,
@MedusaContext() sharedContext?: Context
): Promise<any> {
return await BundledActions.createClaim.bind(this)(data, sharedContext)
}
@InjectManager()
async cancelClaim(
data: OrderTypes.CancelOrderClaimDTO,
@MedusaContext() sharedContext?: Context
): Promise<OrderTypes.OrderClaimDTO> {
const ret = await this.cancelClaim_(data, sharedContext)
return await this.retrieveOrderClaim(ret.id, {
relations: ["additional_items", "claim_items", "return", "return.items"],
})
}
@InjectTransactionManager()
private async cancelClaim_(
data: OrderTypes.CancelOrderClaimDTO,
@MedusaContext() sharedContext?: Context
): Promise<any> {
return await BundledActions.cancelClaim.bind(this)(data, sharedContext)
}
@InjectManager()
async createExchange(
data: OrderTypes.CreateOrderExchangeDTO,
@MedusaContext() sharedContext?: Context
): Promise<OrderTypes.OrderExchangeDTO> {
const ret = await this.createExchange_(data, sharedContext)
const exchange = await this.retrieveOrderExchange(
ret.id,
{
relations: [
"additional_items",
"additional_items.item",
"return",
"return.items",
"shipping_methods",
"shipping_methods.tax_lines",
"shipping_methods.adjustments",
"transactions",
],
},
sharedContext
)
return await this.baseRepository_.serialize<OrderTypes.OrderExchangeDTO>(
exchange,
{
populate: true,
}
)
}
// @ts-expect-error
updateReturnReasons(
id: string,
data: UpdateOrderReturnReasonDTO,
sharedContext?: Context
): Promise<OrderReturnReasonDTO>
// @ts-expect-error
updateReturnReasons(
selector: FilterableOrderReturnReasonProps,
data: Partial<UpdateOrderReturnReasonDTO>,
sharedContext?: Context
): Promise<OrderReturnReasonDTO[]>
@InjectManager()
// @ts-expect-error
async updateReturnReasons(
idOrSelector: string | FilterableOrderReturnReasonProps,
data: UpdateOrderReturnReasonDTO,
@MedusaContext() sharedContext: Context = {}
): Promise<OrderReturnReasonDTO[] | OrderReturnReasonDTO> {
let normalizedInput: UpdateReturnReasonDTO[] = []
if (isString(idOrSelector)) {
// Check if the return reason exists in the first place
await this.returnReasonService_.retrieve(idOrSelector, {}, sharedContext)
normalizedInput = [{ id: idOrSelector, ...data }]
} else {
const reasons = await this.returnReasonService_.list(
idOrSelector,
{},
sharedContext
)
normalizedInput = reasons.map((reason) => ({
id: reason.id,
...data,
}))
}
const reasons = await this.returnReasonService_.update(
normalizedInput,
sharedContext
)
const updatedReturnReasons = await this.baseRepository_.serialize<
OrderReturnReasonDTO[]
>(reasons)
return isString(idOrSelector)
? updatedReturnReasons[0]
: updatedReturnReasons
}
@InjectTransactionManager()
async createExchange_(
data: OrderTypes.CreateOrderExchangeDTO,
@MedusaContext() sharedContext?: Context
): Promise<any> {
return await BundledActions.createExchange.bind(this)(data, sharedContext)
}
@InjectManager()
async cancelExchange(
data: OrderTypes.CancelOrderExchangeDTO,
@MedusaContext() sharedContext?: Context
): Promise<OrderTypes.OrderExchangeDTO> {
const ret = await this.cancelExchange_(data, sharedContext)
return await this.retrieveOrderExchange(ret.id, {
relations: ["additional_items", "return", "return.items"],
})
}
@InjectTransactionManager()
private async cancelExchange_(
data: OrderTypes.CancelOrderExchangeDTO,
@MedusaContext() sharedContext?: Context
): Promise<any> {
return await BundledActions.cancelExchange.bind(this)(data, sharedContext)
}
@InjectTransactionManager()
async registerFulfillment(
data: OrderTypes.RegisterOrderFulfillmentDTO,
@MedusaContext() sharedContext?: Context
): Promise<void> {
return await BundledActions.registerFulfillment.bind(this)(
data,
sharedContext
)
}
@InjectTransactionManager()
async cancelFulfillment(
data: OrderTypes.CancelOrderFulfillmentDTO,
@MedusaContext() sharedContext?: Context
): Promise<void> {
return await BundledActions.cancelFulfillment.bind(this)(
data,
sharedContext
)
}
@InjectTransactionManager()
async registerShipment(
data: OrderTypes.RegisterOrderShipmentDTO,
@MedusaContext() sharedContext?: Context
): Promise<void> {
return await BundledActions.registerShipment.bind(this)(data, sharedContext)
}
@InjectTransactionManager()
async registerDelivery(
data: OrderTypes.RegisterOrderDeliveryDTO,
@MedusaContext() sharedContext?: Context
): Promise<void> {
return await BundledActions.registerDelivery.bind(this)(data, sharedContext)
}
@InjectManager()
// @ts-expect-error
async createReturnItems(
data: OrderTypes.CreateOrderReturnItemDTO,
sharedContext?: Context
): Promise<OrderTypes.OrderReturnItemDTO> {
return super.createReturnItems(
data as unknown as OrderTypes.OrderReturnItemDTO,
sharedContext
)
}
}