Skip to content

Commit

Permalink
add return reason
Browse files Browse the repository at this point in the history
  • Loading branch information
carlos-r-l-rodrigues committed May 11, 2024
1 parent 45e2228 commit a0cf899
Show file tree
Hide file tree
Showing 12 changed files with 540 additions and 1 deletion.
89 changes: 89 additions & 0 deletions packages/core/types/src/order/common.ts
Expand Up @@ -1255,6 +1255,95 @@ export interface OrderTransactionDTO {
updated_at: Date | string
}

export interface OrderTransactionDTO {
/**
* The ID of the transaction
*/
id: string
/**
* The ID of the associated order
*/
order_id: string
/**
* The associated order
*
* @expandable
*/
order: OrderDTO
/**
* The amount of the transaction
*/
amount: BigNumberValue
/**
* The raw amount of the transaction
*/
raw_amount: BigNumberRawValue
/**
* The currency code of the transaction
*/
currency_code: string
/**
* The reference of the transaction
*/
reference: string
/**
* The ID of the reference
*/
reference_id: string
/**
* The metadata of the transaction
*/
metadata: Record<string, unknown> | null
/**
* When the transaction was created
*/
created_at: Date | string
/**
* When the transaction was updated
*/
updated_at: Date | string
}

export interface OrderReturnReasonDTO {
/**
* The ID of the return reason
*/
id: string
/**
* The unique value of the return reason
*/
value: string
/**
* The label of the return reason
*/
label: string
/**
* The description of the return reason
*/
description?: string
/**
* The parent return reason ID
*/
parent_return_reason_id?: string

parent_return_reason?: OrderReturnReasonDTO

return_reason_children?: OrderReturnReasonDTO[]

/**
* The metadata of the return reason
*/
metadata: Record<string, unknown> | null
/**
* When the return reason was created
*/
created_at: Date | string
/**
* When the return reason was updated
*/
updated_at: Date | string
}

export interface FilterableOrderProps
extends BaseFilterable<FilterableOrderProps> {
id?: string | string[]
Expand Down
19 changes: 19 additions & 0 deletions packages/core/types/src/order/mutations.ts
Expand Up @@ -401,3 +401,22 @@ export interface CreateOrderReturnDTO {
}

/** ORDER bundled action flows */

export interface CreateOrderTransactionDTO {
order_id: string
description?: string
reference_type?: string
reference_id?: string
internal_note?: string
created_by?: string
amount: BigNumberInput
metadata?: Record<string, unknown> | null
}

export interface CreateOrderReturnReasonDTO {
value: string
label: string
description?: string
parent_return_reason_id?: string
metadata?: Record<string, unknown> | null
}
34 changes: 34 additions & 0 deletions packages/core/types/src/order/service.ts
Expand Up @@ -19,9 +19,11 @@ import {
OrderLineItemAdjustmentDTO,
OrderLineItemDTO,
OrderLineItemTaxLineDTO,
OrderReturnReasonDTO,
OrderShippingMethodAdjustmentDTO,
OrderShippingMethodDTO,
OrderShippingMethodTaxLineDTO,
OrderTransactionDTO,
} from "./common"
import {
CancelOrderChangeDTO,
Expand All @@ -35,9 +37,11 @@ import {
CreateOrderLineItemForOrderDTO,
CreateOrderLineItemTaxLineDTO,
CreateOrderReturnDTO,
CreateOrderReturnReasonDTO,
CreateOrderShippingMethodAdjustmentDTO,
CreateOrderShippingMethodDTO,
CreateOrderShippingMethodTaxLineDTO,
CreateOrderTransactionDTO,
DeclineOrderChangeDTO,
RegisterOrderFulfillmentDTO,
RegisterOrderShipmentDTO,
Expand Down Expand Up @@ -1389,6 +1393,36 @@ export interface IOrderModuleService extends IModuleService {

revertLastVersion(orderId: string, sharedContext?: Context): Promise<void>

addTransaction(
transactionData: CreateOrderTransactionDTO,
sharedContext?: Context
): Promise<OrderTransactionDTO>

addTransaction(
transactionData: CreateOrderTransactionDTO[],
sharedContext?: Context
): Promise<OrderTransactionDTO>

deleteTransaction(
transactionIds: string[],
sharedContext?: Context
): Promise<void>

createReturnReason(
returnReasonData: CreateOrderReturnReasonDTO,
sharedContext?: Context
): Promise<OrderReturnReasonDTO>

createReturnReason(
returnReasonData: CreateOrderReturnReasonDTO[],
sharedContext?: Context
): Promise<OrderReturnReasonDTO>

deleteReturnReason(
returnReasonIds: string[],
sharedContext?: Context
): Promise<void>

// Bundled flows
registerFulfillment(
data: RegisterOrderFulfillmentDTO,
Expand Down
19 changes: 19 additions & 0 deletions packages/medusa/src/api-v2/store/return/middlewares.ts
@@ -0,0 +1,19 @@
import { MiddlewareRoute } from "../../../loaders/helpers/routing/types"
import { validateAndTransformBody } from "../../utils/validate-body"
import { validateAndTransformQuery } from "../../utils/validate-query"
import * as QueryConfig from "./query-config"
import { ReturnsParams, StorePostReturnsReqSchema } from "./validators"

export const storeRegionRoutesMiddlewares: MiddlewareRoute[] = [
{
method: ["POST"],
matcher: "/store/returns/create-return",
middlewares: [
validateAndTransformBody(StorePostReturnsReqSchema),
validateAndTransformQuery(
ReturnsParams,
QueryConfig.retrieveTransformQueryConfig
),
],
},
]
13 changes: 13 additions & 0 deletions packages/medusa/src/api-v2/store/return/query-config.ts
@@ -0,0 +1,13 @@
export const defaultReturnFields = [
"id",
"order_id",
"created_at",
"updated_at",
"deleted_at",
"metadata",
]

export const retrieveTransformQueryConfig = {
defaults: defaultReturnFields,
isList: false,
}
17 changes: 17 additions & 0 deletions packages/medusa/src/api-v2/store/return/route.ts
@@ -0,0 +1,17 @@
import { CreateOrderReturnDTO } from "@medusajs/types"
import { MedusaRequest, MedusaResponse } from "../../../types/routing"

export const POST = async (req: MedusaRequest, res: MedusaResponse) => {
const input = [req.validatedBody as CreateOrderReturnDTO]

const { result, errors } = await createReturnsWorkflow(req.scope).run({
input: { products: input },
throwOnError: false,
})

if (Array.isArray(errors) && errors[0]) {
throw errors[0].error
}

res.status(200).json({ return: result })
}
32 changes: 32 additions & 0 deletions packages/medusa/src/api-v2/store/return/validators.ts
@@ -0,0 +1,32 @@
import { z } from "zod"
import { createFindParams, createSelectParams } from "../../utils/validators"

export type ReturnParamsType = z.infer<typeof ReturnParams>
export const ReturnParams = createSelectParams()

export type ReturnsParamsType = z.infer<typeof ReturnsParams>
export const ReturnsParams = createFindParams().merge(
z.object({
id: z.union([z.string(), z.array(z.string())]).optional(),
order_id: z.union([z.string(), z.array(z.string())]).optional(),
$and: z.lazy(() => ReturnsParams.array()).optional(),
$or: z.lazy(() => ReturnsParams.array()).optional(),
})
)

const ReturnShippingSchema = z.object({
option_id: z.string(),
})

const ItemSchema = z.object({
item_id: z.string(),
quantity: z.number().min(1),
reason_id: z.string().optional(),
note: z.string().optional(),
})

export const StorePostReturnsReqSchema = z.object({
order_id: z.string(),
items: z.array(ItemSchema),
return_shipping: ReturnShippingSchema.optional(),
})
96 changes: 96 additions & 0 deletions packages/modules/order/integration-tests/__tests__/returns.ts
@@ -0,0 +1,96 @@
import { Modules } from "@medusajs/modules-sdk"
import { IOrderModuleService } from "@medusajs/types"
import { SuiteOptions, moduleIntegrationTestRunner } from "medusa-test-utils"

jest.setTimeout(100000)

moduleIntegrationTestRunner({
moduleName: Modules.ORDER,
testSuite: ({ service }: SuiteOptions<IOrderModuleService>) => {
describe("Order Module Service - Returns", () => {
it("should create return reasons", async function () {
const reason = await service.createReturnReason({
value: "test",
label: "label test",
description: "description test",
})

expect(reason).toEqual({
id: expect.any(String),
value: "test",
label: "label test",
description: "description test",
return_reason_children: [],
metadata: null,
created_at: expect.any(Date),
updated_at: expect.any(Date),
deleted_at: null,
})
})

it("should create return reasons with parent", async function () {
const reason = await service.createReturnReason({
value: "test",
label: "label test",
description: "description test",
})

const reason2 = await service.createReturnReason({
value: "test 2.0",
label: "child",
parent_return_reason_id: reason.id,
})
const reason3 = await service.createReturnReason({
value: "test 3.0",
label: "child 3",
parent_return_reason_id: reason.id,
})

const getChild = await service.retrieveReturnReason(reason2.id, {
relations: ["parent_return_reason"],
})
expect(getChild).toEqual(
expect.objectContaining({
id: reason2.id,
value: "test 2.0",
label: "child",
parent_return_reason_id: reason.id,
parent_return_reason: expect.objectContaining({
id: reason.id,
value: "test",
label: "label test",
description: "description test",
parent_return_reason_id: null,
}),
})
)

const getParent = await service.retrieveReturnReason(reason.id, {
relations: ["return_reason_children"],
})
expect(getParent).toEqual(
expect.objectContaining({
id: reason.id,
value: "test",
label: "label test",
description: "description test",
return_reason_children: [
expect.objectContaining({
id: reason2.id,
value: "test 2.0",
label: "child",
parent_return_reason_id: reason.id,
}),
expect.objectContaining({
id: reason3.id,
value: "test 3.0",
label: "child 3",
parent_return_reason_id: reason.id,
}),
],
})
)
})
})
},
})
22 changes: 22 additions & 0 deletions packages/modules/order/src/migrations/Migration20240219102530.ts
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions packages/modules/order/src/models/index.ts
Expand Up @@ -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"
Expand Down

0 comments on commit a0cf899

Please sign in to comment.