Feat(order): return reason and transaction methods (#7303)

This commit is contained in:
Carlos R. L. Rodrigues
2024-05-13 16:15:25 +00:00
committed by GitHub
parent 8958214350
commit 6c94d0205c
23 changed files with 1036 additions and 6 deletions
+9 -1
View File
@@ -1,12 +1,14 @@
import { Modules } from "@medusajs/modules-sdk"
import { ModuleJoinerConfig } from "@medusajs/types"
import { MapToConfig } from "@medusajs/utils"
import { LineItem } from "@models"
import { LineItem, ReturnReason } from "@models"
import Order from "./models/order"
export const LinkableKeys: Record<string, string> = {
order_id: Order.name,
order_item_id: LineItem.name,
return_reason_id: ReturnReason.name,
return_reason_value: ReturnReason.name,
}
const entityLinkableKeysMap: MapToConfig = {}
@@ -31,5 +33,11 @@ export const joinerConfig: ModuleJoinerConfig = {
entity: Order.name,
},
},
{
name: ["return_reason", "return_reasons"],
args: {
entity: ReturnReason.name,
},
},
],
} as ModuleJoinerConfig
@@ -466,6 +466,28 @@ export class Migration20240219102530 extends Migration {
CREATE INDEX IF NOT EXISTS "IDX_order_transaction_reference_id" ON "order_transaction" (
reference_id
);
CREATE TABLE IF NOT EXISTS "return_reason"
(
id character varying NOT NULL,
value character varying NOT NULL,
label character varying NOT NULL,
description character varying,
metadata JSONB NULL,
parent_return_reason_id character varying,
created_at timestamp with time zone NOT NULL DEFAULT now(),
updated_at timestamp with time zone NOT NULL DEFAULT now(),
deleted_at timestamp with time zone,
CONSTRAINT "return_reason_pkey" PRIMARY KEY (id),
CONSTRAINT "return_reason_parent_return_reason_id_foreign" FOREIGN KEY (parent_return_reason_id)
REFERENCES "return_reason" (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION
);
CREATE UNIQUE INDEX IF NOT EXISTS "IDX_return_reason_value" ON "return_reason" USING btree (value ASC NULLS LAST)
WHERE deleted_at IS NOT NULL;
ALTER TABLE if exists "order"
ADD CONSTRAINT "order_shipping_address_id_foreign" FOREIGN KEY ("shipping_address_id") REFERENCES "order_address" ("id") ON
@@ -8,6 +8,7 @@ export { default as OrderChangeAction } from "./order-change-action"
export { default as OrderItem } from "./order-item"
export { default as OrderShippingMethod } from "./order-shipping-method"
export { default as OrderSummary } from "./order-summary"
export { default as ReturnReason } from "./return-reason"
export { default as ShippingMethod } from "./shipping-method"
export { default as ShippingMethodAdjustment } from "./shipping-method-adjustment"
export { default as ShippingMethodTaxLine } from "./shipping-method-tax-line"
@@ -0,0 +1,105 @@
import { DAL } from "@medusajs/types"
import {
createPsqlIndexStatementHelper,
generateEntityId,
} from "@medusajs/utils"
import {
BeforeCreate,
Cascade,
Entity,
ManyToOne,
OnInit,
OneToMany,
OptionalProps,
PrimaryKey,
Property,
} from "@mikro-orm/core"
const DeletedAtIndex = createPsqlIndexStatementHelper({
tableName: "return_reason",
columns: "deleted_at",
where: "deleted_at IS NOT NULL",
})
const ValueIndex = createPsqlIndexStatementHelper({
tableName: "return_reason",
columns: "value",
where: "deleted_at IS NOT NULL",
})
const ParentIndex = createPsqlIndexStatementHelper({
tableName: "return_reason",
columns: "parent_return_reason_id",
where: "deleted_at IS NOT NULL",
})
type OptionalOrderProps = "parent_return_reason" | DAL.EntityDateColumns
@Entity({ tableName: "return_reason" })
export default class ReturnReason {
[OptionalProps]?: OptionalOrderProps
@PrimaryKey({ columnType: "text" })
id: string
@Property({ columnType: "text" })
@ValueIndex.MikroORMIndex()
value: string
@Property({ columnType: "text" })
label: string
@Property({ columnType: "text", nullable: true })
description: string | null = null
@Property({ columnType: "text", nullable: true })
@ParentIndex.MikroORMIndex()
parent_return_reason_id?: string | null
@ManyToOne({
entity: () => ReturnReason,
fieldName: "parent_return_reason_id",
nullable: true,
cascade: [Cascade.PERSIST],
})
parent_return_reason?: ReturnReason | null
@OneToMany(
() => ReturnReason,
(return_reason) => return_reason.parent_return_reason,
{ cascade: [Cascade.PERSIST] }
)
return_reason_children: ReturnReason[]
@Property({ columnType: "jsonb", nullable: true })
metadata: Record<string, unknown> | null = null
@Property({
onCreate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
created_at: Date
@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
updated_at: Date
@Property({ columnType: "timestamptz", nullable: true })
@DeletedAtIndex.MikroORMIndex()
deleted_at: Date | null = null
@BeforeCreate()
onCreate() {
this.id = generateEntityId(this.id, "rr")
}
@OnInit()
onInit() {
this.id = generateEntityId(this.id, "rr")
}
}
@@ -10,6 +10,8 @@ import {
OrderDTO,
OrderTypes,
UpdateOrderItemWithSelectorDTO,
UpdateOrderReturnReasonDTO,
UpdateOrderTransactionDTO,
} from "@medusajs/types"
import {
createRawPropertiesFromBigNumber,
@@ -37,6 +39,7 @@ import {
OrderItem,
OrderShippingMethod,
OrderSummary,
ReturnReason,
ShippingMethod,
ShippingMethodAdjustment,
ShippingMethodTaxLine,
@@ -75,6 +78,7 @@ type InjectedDependencies = {
orderItemService: ModulesSdkTypes.InternalModuleService<any>
orderSummaryService: ModulesSdkTypes.InternalModuleService<any>
orderShippingMethodService: ModulesSdkTypes.InternalModuleService<any>
returnReasonService: ModulesSdkTypes.InternalModuleService<any>
}
const generateMethodForModels = [
@@ -91,6 +95,7 @@ const generateMethodForModels = [
OrderItem,
OrderSummary,
OrderShippingMethod,
ReturnReason,
]
export default class OrderModuleService<
@@ -107,7 +112,8 @@ export default class OrderModuleService<
TOrderChangeAction extends OrderChangeAction = OrderChangeAction,
TOrderItem extends OrderItem = OrderItem,
TOrderSummary extends OrderSummary = OrderSummary,
TOrderShippingMethod extends OrderShippingMethod = OrderShippingMethod
TOrderShippingMethod extends OrderShippingMethod = OrderShippingMethod,
TReturnReason extends ReturnReason = ReturnReason
>
extends ModulesSdkUtils.abstractModuleServiceFactory<
InjectedDependencies,
@@ -128,6 +134,7 @@ export default class OrderModuleService<
OrderItem: { dto: OrderTypes.OrderItemDTO }
OrderSummary: { dto: OrderTypes.OrderSummaryDTO }
OrderShippingMethod: { dto: OrderShippingMethod }
ReturnReason: { dto: OrderTypes.OrderReturnReasonDTO }
}
>(Order, generateMethodForModels, entityNameToLinkableKeysMap)
implements IOrderModuleService
@@ -147,6 +154,7 @@ export default class OrderModuleService<
protected orderItemService_: ModulesSdkTypes.InternalModuleService<TOrderItem>
protected orderSummaryService_: ModulesSdkTypes.InternalModuleService<TOrderSummary>
protected orderShippingMethodService_: ModulesSdkTypes.InternalModuleService<TOrderShippingMethod>
protected returnReasonService_: ModulesSdkTypes.InternalModuleService<TReturnReason>
constructor(
{
@@ -165,6 +173,7 @@ export default class OrderModuleService<
orderItemService,
orderSummaryService,
orderShippingMethodService,
returnReasonService,
}: InjectedDependencies,
protected readonly moduleDeclaration: InternalModuleDeclaration
) {
@@ -186,6 +195,7 @@ export default class OrderModuleService<
this.orderItemService_ = orderItemService
this.orderSummaryService_ = orderSummaryService
this.orderShippingMethodService_ = orderShippingMethodService
this.returnReasonService_ = returnReasonService
}
__joinerConfig(): ModuleJoinerConfig {
@@ -2261,4 +2271,277 @@ export default class OrderModuleService<
await this.confirmOrderChange(change[0].id, sharedContext)
}
public async addTransactions(
transactionData: OrderTypes.CreateOrderTransactionDTO,
sharedContext?: Context
): Promise<OrderTypes.OrderTransactionDTO>
public async addTransactions(
transactionData: OrderTypes.CreateOrderTransactionDTO[],
sharedContext?: Context
): Promise<OrderTypes.OrderTransactionDTO[]>
@InjectTransactionManager("baseRepository_")
public async addTransactions(
transactionData:
| OrderTypes.CreateOrderTransactionDTO
| OrderTypes.CreateOrderTransactionDTO[],
sharedContext?: Context
): Promise<
OrderTypes.OrderTransactionDTO | OrderTypes.OrderTransactionDTO[]
> {
const data = Array.isArray(transactionData)
? transactionData
: [transactionData]
const created = await this.transactionService_.create(data, sharedContext)
return await this.baseRepository_.serialize<OrderTypes.OrderTransactionDTO>(
!Array.isArray(transactionData) ? created[0] : created,
{
populate: true,
}
)
}
updateTransactions(
data: OrderTypes.UpdateOrderTransactionWithSelectorDTO[]
): Promise<OrderTypes.OrderTransactionDTO[]>
updateTransactions(
selector: Partial<OrderTypes.FilterableOrderTransactionProps>,
data: OrderTypes.UpdateOrderTransactionDTO,
sharedContext?: Context
): Promise<OrderTypes.OrderTransactionDTO[]>
updateTransactions(
id: string,
data: Partial<OrderTypes.UpdateOrderTransactionDTO>,
sharedContext?: Context
): Promise<OrderTypes.OrderTransactionDTO>
@InjectManager("baseRepository_")
async updateTransactions(
idOrDataOrSelector:
| string
| OrderTypes.UpdateOrderTransactionWithSelectorDTO[]
| Partial<OrderTypes.FilterableOrderTransactionProps>,
data?:
| OrderTypes.UpdateOrderTransactionDTO
| Partial<OrderTypes.UpdateOrderTransactionDTO>,
@MedusaContext() sharedContext: Context = {}
): Promise<
OrderTypes.OrderTransactionDTO[] | OrderTypes.OrderTransactionDTO
> {
let trxs: Transaction[] = []
if (isString(idOrDataOrSelector)) {
const trx = await this.updateTransaction_(
idOrDataOrSelector,
data as Partial<OrderTypes.UpdateOrderTransactionDTO>,
sharedContext
)
return await this.baseRepository_.serialize<OrderTypes.OrderTransactionDTO>(
trx,
{
populate: true,
}
)
}
const toUpdate = Array.isArray(idOrDataOrSelector)
? idOrDataOrSelector
: [
{
selector: idOrDataOrSelector,
data: data,
} as OrderTypes.UpdateOrderTransactionWithSelectorDTO,
]
trxs = await this.updateTransactionsWithSelector_(toUpdate, sharedContext)
return await this.baseRepository_.serialize<
OrderTypes.OrderTransactionDTO[]
>(trxs, {
populate: true,
})
}
@InjectTransactionManager("baseRepository_")
protected async updateTransaction_(
trxId: string,
data: Partial<OrderTypes.UpdateOrderTransactionDTO>,
@MedusaContext() sharedContext: Context = {}
): Promise<Transaction> {
const [trx] = await this.transactionService_.update(
[{ id: trxId, ...data }],
sharedContext
)
return trx
}
@InjectTransactionManager("baseRepository_")
protected async updateTransactionsWithSelector_(
updates: OrderTypes.UpdateOrderTransactionWithSelectorDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<Transaction[]> {
let toUpdate: UpdateOrderTransactionDTO[] = []
for (const { selector, data } of updates) {
const trxs = await super.listTransactions(
{ ...selector },
{},
sharedContext
)
trxs.forEach((trx) => {
toUpdate.push({
...data,
id: trx.id,
})
})
}
return await this.transactionService_.update(toUpdate, sharedContext)
}
public async createReturnReasons(
transactionData: OrderTypes.CreateOrderReturnReasonDTO,
sharedContext?: Context
): Promise<OrderTypes.OrderReturnReasonDTO>
public async createReturnReasons(
transactionData: OrderTypes.CreateOrderReturnReasonDTO[],
sharedContext?: Context
): Promise<OrderTypes.OrderReturnReasonDTO[]>
@InjectTransactionManager("baseRepository_")
public async createReturnReasons(
returnReasonData:
| OrderTypes.CreateOrderReturnReasonDTO
| OrderTypes.CreateOrderReturnReasonDTO[],
sharedContext?: Context
): Promise<
OrderTypes.OrderReturnReasonDTO | OrderTypes.OrderReturnReasonDTO[]
> {
const data = Array.isArray(returnReasonData)
? returnReasonData
: [returnReasonData]
const created = await this.returnReasonService_.create(data, sharedContext)
return await this.baseRepository_.serialize<OrderTypes.OrderReturnReasonDTO>(
!Array.isArray(returnReasonData) ? created[0] : created,
{
populate: true,
}
)
}
updateReturnReasons(
data: OrderTypes.UpdateOrderReturnReasonWithSelectorDTO[]
): Promise<OrderTypes.OrderReturnReasonDTO[]>
updateReturnReasons(
selector: Partial<OrderTypes.FilterableOrderReturnReasonProps>,
data: OrderTypes.UpdateOrderReturnReasonDTO,
sharedContext?: Context
): Promise<OrderTypes.OrderReturnReasonDTO[]>
updateReturnReasons(
id: string,
data: Partial<OrderTypes.UpdateOrderReturnReasonDTO>,
sharedContext?: Context
): Promise<OrderTypes.OrderReturnReasonDTO>
@InjectManager("baseRepository_")
async updateReturnReasons(
idOrDataOrSelector:
| string
| OrderTypes.UpdateOrderReturnReasonWithSelectorDTO[]
| Partial<OrderTypes.FilterableOrderReturnReasonProps>,
data?:
| OrderTypes.UpdateOrderReturnReasonDTO
| Partial<OrderTypes.UpdateOrderReturnReasonDTO>,
@MedusaContext() sharedContext: Context = {}
): Promise<
OrderTypes.OrderReturnReasonDTO[] | OrderTypes.OrderReturnReasonDTO
> {
let reasons: ReturnReason[] = []
if (isString(idOrDataOrSelector)) {
const reason = await this.updateReturnReason_(
idOrDataOrSelector,
data as Partial<OrderTypes.UpdateOrderReturnReasonDTO>,
sharedContext
)
return await this.baseRepository_.serialize<OrderTypes.OrderReturnReasonDTO>(
reason,
{
populate: true,
}
)
}
const toUpdate = Array.isArray(idOrDataOrSelector)
? idOrDataOrSelector
: [
{
selector: idOrDataOrSelector,
data: data,
} as OrderTypes.UpdateOrderReturnReasonWithSelectorDTO,
]
reasons = await this.updateReturnReasonsWithSelector_(
toUpdate,
sharedContext
)
return await this.baseRepository_.serialize<
OrderTypes.OrderReturnReasonDTO[]
>(reasons, {
populate: true,
})
}
@InjectTransactionManager("baseRepository_")
protected async updateReturnReason_(
reasonId: string,
data: Partial<OrderTypes.UpdateOrderReturnReasonDTO>,
@MedusaContext() sharedContext: Context = {}
): Promise<ReturnReason> {
const [reason] = await this.returnReasonService_.update(
[{ id: reasonId, ...data }],
sharedContext
)
return reason
}
@InjectTransactionManager("baseRepository_")
protected async updateReturnReasonsWithSelector_(
updates: OrderTypes.UpdateOrderReturnReasonWithSelectorDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<ReturnReason[]> {
let toUpdate: UpdateOrderReturnReasonDTO[] = []
for (const { selector, data } of updates) {
const reasons = await super.listReturnReasons(
{ ...selector },
{},
sharedContext
)
reasons.forEach((reason) => {
toUpdate.push({
...data,
id: reason.id,
})
})
}
return await this.returnReasonService_.update(toUpdate, sharedContext)
}
}