diff --git a/.changeset/eleven-kids-tan.md b/.changeset/eleven-kids-tan.md new file mode 100644 index 0000000000..6eb64a2ba7 --- /dev/null +++ b/.changeset/eleven-kids-tan.md @@ -0,0 +1,5 @@ +--- +"@medusajs/medusa": patch +--- + +feat(medusa): Configurable returnable_items on order decorate totals diff --git a/integration-tests/api/__tests__/admin/__snapshots__/price-list.js.snap b/integration-tests/api/__tests__/admin/__snapshots__/price-list.js.snap index 5d7eb27d4a..08b9f4d089 100644 --- a/integration-tests/api/__tests__/admin/__snapshots__/price-list.js.snap +++ b/integration-tests/api/__tests__/admin/__snapshots__/price-list.js.snap @@ -292,46 +292,3 @@ Array [ ] `; -exports[`/admin/price-lists POST /admin/price-lists/:id/prices/batch Adds a batch of new prices where a MA record have a \`region_id\` instead of \`currency_code\` 1`] = ` -Array [ - Object { - "amount": 70, - "created_at": Any, - "currency_code": "usd", - "deleted_at": null, - "id": "ma_test_4", - "max_quantity": null, - "min_quantity": null, - "price_list_id": "pl_with_some_ma", - "region_id": null, - "updated_at": Any, - "variant_id": "test-variant", - }, - Object { - "amount": 100, - "created_at": Any, - "currency_code": "eur", - "deleted_at": null, - "id": Any, - "max_quantity": null, - "min_quantity": null, - "price_list_id": "pl_with_some_ma", - "region_id": "region-pl", - "updated_at": Any, - "variant_id": "test-variant", - }, - Object { - "amount": 200, - "created_at": Any, - "currency_code": "usd", - "deleted_at": null, - "id": Any, - "max_quantity": null, - "min_quantity": null, - "price_list_id": "pl_with_some_ma", - "region_id": null, - "updated_at": Any, - "variant_id": "test-variant", - }, -] -`; diff --git a/integration-tests/api/__tests__/admin/price-list.js b/integration-tests/api/__tests__/admin/price-list.js index d0bdc1aa1c..f00c5f4d79 100644 --- a/integration-tests/api/__tests__/admin/price-list.js +++ b/integration-tests/api/__tests__/admin/price-list.js @@ -859,45 +859,47 @@ describe("/admin/price-lists", () => { expect(response.status).toEqual(200) expect(response.data.price_list.prices.length).toEqual(3) // initially this PL has 1 MA record - expect(response.data.price_list.prices).toMatchSnapshot([ - { - id: "ma_test_4", - currency_code: "usd", - amount: 70, - price_list_id: "pl_with_some_ma", - variant_id: "test-variant", - region_id: null, - created_at: expect.any(String), - updated_at: expect.any(String), - deleted_at: null, - }, - { - id: expect.any(String), - currency_code: "eur", - amount: 100, - min_quantity: null, - max_quantity: null, - price_list_id: "pl_with_some_ma", - variant_id: "test-variant", - region_id: "region-pl", - created_at: expect.any(String), - updated_at: expect.any(String), - deleted_at: null, - }, - { - id: expect.any(String), - currency_code: "usd", - amount: 200, - min_quantity: null, - max_quantity: null, - price_list_id: "pl_with_some_ma", - variant_id: "test-variant", - region_id: null, - created_at: expect.any(String), - updated_at: expect.any(String), - deleted_at: null, - }, - ]) + expect(response.data.price_list.prices).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: "ma_test_4", + currency_code: "usd", + amount: 70, + price_list_id: "pl_with_some_ma", + variant_id: "test-variant", + region_id: null, + created_at: expect.any(String), + updated_at: expect.any(String), + deleted_at: null, + }), + expect.objectContaining({ + id: expect.any(String), + currency_code: "usd", + amount: 200, + min_quantity: null, + max_quantity: null, + price_list_id: "pl_with_some_ma", + variant_id: "test-variant", + region_id: null, + created_at: expect.any(String), + updated_at: expect.any(String), + deleted_at: null, + }), + expect.objectContaining({ + id: expect.any(String), + currency_code: "eur", + amount: 100, + min_quantity: null, + max_quantity: null, + price_list_id: "pl_with_some_ma", + variant_id: "test-variant", + region_id: "region-pl", + created_at: expect.any(String), + updated_at: expect.any(String), + deleted_at: null, + }), + ]) + ) }) }) diff --git a/integration-tests/api/__tests__/admin/swaps.js b/integration-tests/api/__tests__/admin/swaps.js index 577bae9b74..814da8fe22 100644 --- a/integration-tests/api/__tests__/admin/swaps.js +++ b/integration-tests/api/__tests__/admin/swaps.js @@ -301,7 +301,7 @@ describe("/admin/swaps", () => { // ********* CREATE SWAP ********* const createSwap = await api.post( - `/admin/orders/${completedOrder.data.data.id}/swaps`, + `/admin/orders/${completedOrder.data.data.id}/swaps?fields=returnable_items`, { return_items: [ { @@ -318,6 +318,13 @@ describe("/admin/swaps", () => { } ) + expect(createSwap.data.order.returnable_items).toHaveLength(1) + expect(createSwap.data.order.returnable_items[0]).toEqual( + expect.objectContaining({ + id: "line-item", + }) + ) + let swap = createSwap.data.order.swaps[0] // ********* PREPARE SWAP CART ********* @@ -349,7 +356,7 @@ describe("/admin/swaps", () => { {} ) - // ********* VALIDATE ********* + // ********* VALIDATE ********* expect(swap.data.swap.difference_due).toBe(swapCart.data.cart.total) }) }) diff --git a/packages/medusa/src/api/middlewares/index.ts b/packages/medusa/src/api/middlewares/index.ts index 0647f8e822..68aa757c54 100644 --- a/packages/medusa/src/api/middlewares/index.ts +++ b/packages/medusa/src/api/middlewares/index.ts @@ -7,6 +7,7 @@ import { default as requireCustomerAuthentication } from "./require-customer-aut export { canAccessBatchJob } from "./batch-job/can-access-batch-job" export { getRequestedBatchJob } from "./batch-job/get-requested-batch-job" export { doesConditionBelongToDiscount } from "./discount/does-condition-belong-to-discount" +export { transformIncludesOptions } from "./transform-includes-options" export { transformBody } from "./transform-body" export { transformQuery } from "./transform-query" diff --git a/packages/medusa/src/api/middlewares/transform-includes-options.ts b/packages/medusa/src/api/middlewares/transform-includes-options.ts new file mode 100644 index 0000000000..da10b2dbae --- /dev/null +++ b/packages/medusa/src/api/middlewares/transform-includes-options.ts @@ -0,0 +1,58 @@ +import { NextFunction, Request, Response } from "express" +import { Order } from "../../models" +import { MedusaError } from "medusa-core-utils" + +/** + * Retrieve the includes options from the fields query param. + * If the include option is present then assigned it to includes on req + * @param allowedIncludesFields The list of fields that can be passed and assign to req.includes + * @param expectedIncludesFields The list of fields that the consumer can pass to the end point using this middleware. It is a subset of `allowedIncludesFields` + */ +export function transformIncludesOptions( + allowedIncludesFields: string[] = [], + expectedIncludesFields: string[] = [] +) { + return (req: Request, res: Response, next: NextFunction): void => { + if (!allowedIncludesFields.length || !req.query["fields"]) { + return next() + } + + const fields = (req.query["fields"] as string).split(",") ?? [] + + for (const includesField of allowedIncludesFields) { + const fieldIndex = fields.indexOf(includesField as keyof Order) ?? -1 + + const isPresent = fieldIndex !== -1 + + if (isPresent) { + fields.splice(fieldIndex, 1) + + if (!expectedIncludesFields.includes(includesField)) { + throw new MedusaError( + MedusaError.Types.INVALID_DATA, + `The field "${includesField}" is not supported by this end point. ${ + expectedIncludesFields.length + ? `The includes fields can be one of entity properties or in [${expectedIncludesFields.join( + ", " + )}]` + : "" + }` + ) + } + + req["includes"] = req["includes"] ?? {} + req["includes"][includesField] = true + } + } + + if (req.query["fields"]) { + if (fields.length) { + req.query["fields"] = fields.join(",") + } else { + delete req.query["fields"] + } + } + + next() + } +} diff --git a/packages/medusa/src/api/middlewares/transform-query.ts b/packages/medusa/src/api/middlewares/transform-query.ts index 1fe4b967c7..6d3f93c9fe 100644 --- a/packages/medusa/src/api/middlewares/transform-query.ts +++ b/packages/medusa/src/api/middlewares/transform-query.ts @@ -53,6 +53,12 @@ export function transformQuery< ] as unknown as string[] } + const includesFields = Object.keys(req["includes"] ?? {}) + if (includesFields.length) { + req.allowedProperties = req.allowedProperties ?? [] + req.allowedProperties.push(...includesFields) + } + if (queryConfig?.isList) { req.listConfig = prepareListQuery( validated, diff --git a/packages/medusa/src/api/routes/admin/orders/__tests__/get-order.js b/packages/medusa/src/api/routes/admin/orders/__tests__/get-order.js index 0145ffa4a4..a54a9d8c3e 100644 --- a/packages/medusa/src/api/routes/admin/orders/__tests__/get-order.js +++ b/packages/medusa/src/api/routes/admin/orders/__tests__/get-order.js @@ -48,6 +48,9 @@ describe("GET /admin/orders", () => { ), // TODO [MEDUSA_FF_SALES_CHANNELS]: Remove when sales channel flag is removed entirely relations: [...defaultAdminOrdersRelations, "sales_channel"], + }, + { + includes: undefined, } ) }) diff --git a/packages/medusa/src/api/routes/admin/orders/add-shipping-method.ts b/packages/medusa/src/api/routes/admin/orders/add-shipping-method.ts index 68814b7ba8..e5664f7de5 100644 --- a/packages/medusa/src/api/routes/admin/orders/add-shipping-method.ts +++ b/packages/medusa/src/api/routes/admin/orders/add-shipping-method.ts @@ -5,11 +5,10 @@ import { IsOptional, IsString, } from "class-validator" -import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "." import { OrderService } from "../../../../services" -import { validator } from "../../../../utils/validator" import { EntityManager } from "typeorm" +import { FindParams } from "../../../../types/common" /** * @oas [post] /orders/{id}/shipping-methods @@ -18,6 +17,8 @@ import { EntityManager } from "typeorm" * description: "Adds a Shipping Method to an Order. If another Shipping Method exists with the same Shipping Profile, the previous Shipping Method will be replaced." * parameters: * - (path) id=* {string} The ID of the Order. + * - (query) expand {string} Comma separated list of relations to include in the result. + * - (query) fields {string} Comma separated list of fields to include in the result. * requestBody: * content: * application/json: @@ -26,6 +27,7 @@ import { EntityManager } from "typeorm" * x-authenticated: true * x-codegen: * method: addShippingMethod + * params: AdminPostOrdersOrderShippingMethodsParams * x-codeSamples: * - lang: JavaScript * label: JS Client @@ -78,10 +80,7 @@ import { EntityManager } from "typeorm" export default async (req, res) => { const { id } = req.params - const validated = await validator( - AdminPostOrdersOrderShippingMethodsReq, - req.body - ) + const validated = req.validatedBody const orderService: OrderService = req.scope.resolve("orderService") @@ -94,9 +93,8 @@ export default async (req, res) => { }) }) - const order = await orderService.retrieve(id, { - select: defaultAdminOrdersFields, - relations: defaultAdminOrdersRelations, + const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { + includes: req.includes, }) res.status(200).json({ order }) @@ -132,3 +130,5 @@ export class AdminPostOrdersOrderShippingMethodsReq { @IsOptional() data?: Record = {} } + +export class AdminPostOrdersOrderShippingMethodsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/archive-order.ts b/packages/medusa/src/api/routes/admin/orders/archive-order.ts index 81ce7c3ea3..e6c39fbd30 100644 --- a/packages/medusa/src/api/routes/admin/orders/archive-order.ts +++ b/packages/medusa/src/api/routes/admin/orders/archive-order.ts @@ -1,5 +1,6 @@ import { OrderService } from "../../../../services" import { EntityManager } from "typeorm" +import { FindParams } from "../../../../types/common" /** * @oas [post] /orders/{id}/archive @@ -9,8 +10,11 @@ import { EntityManager } from "typeorm" * x-authenticated: true * parameters: * - (path) id=* {string} The ID of the Order. + * - (query) expand {string} Comma separated list of relations to include in the result. + * - (query) fields {string} Comma separated list of fields to include in the result. * x-codegen: * method: archive + * params: AdminPostOrdersOrderArchiveParams * x-codeSamples: * - lang: JavaScript * label: JS Client @@ -62,9 +66,11 @@ export default async (req, res) => { return await orderService.withTransaction(transactionManager).archive(id) }) - const order = await orderService.retrieve(id, { - relations: ["region", "customer", "swaps"], + const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { + includes: req.includes, }) res.json({ order }) } + +export class AdminPostOrdersOrderArchiveParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/cancel-claim.ts b/packages/medusa/src/api/routes/admin/orders/cancel-claim.ts index 3c11518088..6e5b1797b2 100644 --- a/packages/medusa/src/api/routes/admin/orders/cancel-claim.ts +++ b/packages/medusa/src/api/routes/admin/orders/cancel-claim.ts @@ -1,8 +1,8 @@ import { ClaimService, OrderService } from "../../../../services" -import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "." import { EntityManager } from "typeorm" import { MedusaError } from "medusa-core-utils" +import { FindParams } from "../../../../types/common" /** * @oas [post] /orders/{id}/claims/{claim_id}/cancel @@ -13,8 +13,11 @@ import { MedusaError } from "medusa-core-utils" * parameters: * - (path) id=* {string} The ID of the Order. * - (path) claim_id=* {string} The ID of the Claim. + * - (query) expand {string} Comma separated list of relations to include in the result. + * - (query) fields {string} Comma separated list of fields to include in the result. * x-codegen: * method: cancelClaim + * params: AdminPostOrdersClaimCancel * x-codeSamples: * - lang: JavaScript * label: JS Client @@ -78,10 +81,11 @@ export default async (req, res) => { .cancel(claim_id) }) - const order = await orderService.retrieve(id, { - select: defaultAdminOrdersFields, - relations: defaultAdminOrdersRelations, + const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { + includes: req.includes, }) res.json({ order }) } + +export class AdminPostOrdersClaimCancel extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment-claim.ts b/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment-claim.ts index 56c7acedbb..d16af0b62d 100644 --- a/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment-claim.ts +++ b/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment-claim.ts @@ -3,10 +3,10 @@ import { FulfillmentService, OrderService, } from "../../../../services" -import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "." import { EntityManager } from "typeorm" import { MedusaError } from "medusa-core-utils" +import { FindParams } from "../../../../types/common" /** * @oas [post] /orders/{id}/claims/{claim_id}/fulfillments/{fulfillment_id}/cancel @@ -18,8 +18,11 @@ import { MedusaError } from "medusa-core-utils" * - (path) id=* {string} The ID of the Order which the Claim relates to. * - (path) claim_id=* {string} The ID of the Claim which the Fulfillment relates to. * - (path) fulfillment_id=* {string} The ID of the Fulfillment. + * - (query) expand {string} Comma separated list of relations to include in the result. + * - (query) fields {string} Comma separated list of fields to include in the result. * x-codegen: * method: cancelClaimFulfillment + * params: AdminPostOrdersClaimFulfillmentsCancelParams * x-codeSamples: * - lang: JavaScript * label: JS Client @@ -94,9 +97,11 @@ export default async (req, res) => { .cancelFulfillment(fulfillment_id) }) - const order = await orderService.retrieve(id, { - select: defaultAdminOrdersFields, - relations: defaultAdminOrdersRelations, + const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { + includes: req.includes, }) + res.json({ order }) } + +export class AdminPostOrdersClaimFulfillmentsCancelParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment-swap.ts b/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment-swap.ts index b0505a682e..82d4464017 100644 --- a/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment-swap.ts +++ b/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment-swap.ts @@ -3,10 +3,10 @@ import { OrderService, SwapService, } from "../../../../services" -import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "." import { EntityManager } from "typeorm" import { MedusaError } from "medusa-core-utils" +import { FindParams } from "../../../../types/common" /** * @oas [post] /orders/{id}/swaps/{swap_id}/fulfillments/{fulfillment_id}/cancel @@ -18,8 +18,11 @@ import { MedusaError } from "medusa-core-utils" * - (path) id=* {string} The ID of the Order which the Swap relates to. * - (path) swap_id=* {string} The ID of the Swap which the Fulfillment relates to. * - (path) fulfillment_id=* {string} The ID of the Fulfillment. + * - (query) expand {string} Comma separated list of relations to include in the result. + * - (query) fields {string} Comma separated list of fields to include in the result. * x-codegen: * method: cancelSwapFulfillment + * params: AdminPostOrdersSwapFulfillementsCancelParams * x-codeSamples: * - lang: JavaScript * label: JS Client @@ -94,10 +97,12 @@ export default async (req, res) => { .cancelFulfillment(fulfillment_id) }) - const order = await orderService.retrieve(id, { - select: defaultAdminOrdersFields, - relations: defaultAdminOrdersRelations, + const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { + includes: req.includes, }) res.json({ order }) } + +// eslint-disable-next-line max-len +export class AdminPostOrdersOrderSwapFulfillementsCancelParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment.ts b/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment.ts index 56c21d7615..464872e1b1 100644 --- a/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment.ts +++ b/packages/medusa/src/api/routes/admin/orders/cancel-fulfillment.ts @@ -3,12 +3,12 @@ import { OrderService, ProductVariantInventoryService, } from "../../../../services" -import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "." import { EntityManager } from "typeorm" import { MedusaError } from "medusa-core-utils" import { Fulfillment } from "../../../../models" import { IInventoryService } from "../../../../interfaces" +import { FindParams } from "../../../../types/common" /** * @oas [post] /orders/{id}/fulfillments/{fulfillment_id}/cancel @@ -19,8 +19,11 @@ import { IInventoryService } from "../../../../interfaces" * parameters: * - (path) id=* {string} The ID of the Order which the Fulfillment relates to. * - (path) fulfillment_id=* {string} The ID of the Fulfillment + * - (query) expand {string} Comma separated list of relations to include in the result. + * - (query) fields {string} Comma separated list of fields to include in the result. * x-codegen: * method: cancelFulfillment + * params: AdminPostOrdersOrderFulfillementsCancelParams * x-codeSamples: * - lang: JavaScript * label: JS Client @@ -101,9 +104,8 @@ export default async (req, res) => { } }) - const order = await orderService.retrieve(id, { - select: defaultAdminOrdersFields, - relations: defaultAdminOrdersRelations, + const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { + includes: req.includes, }) res.json({ order }) @@ -128,3 +130,5 @@ export const adjustInventoryForCancelledFulfillment = async ( }) ) } + +export class AdminPostOrdersOrderFulfillementsCancelParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/cancel-order.ts b/packages/medusa/src/api/routes/admin/orders/cancel-order.ts index dc2134f644..d9a9070d5a 100644 --- a/packages/medusa/src/api/routes/admin/orders/cancel-order.ts +++ b/packages/medusa/src/api/routes/admin/orders/cancel-order.ts @@ -1,7 +1,6 @@ -import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "." - import { OrderService } from "../../../../services" import { EntityManager } from "typeorm" +import { FindParams } from "../../../../types/common" /** * @oas [post] /orders/{id}/cancel @@ -11,8 +10,11 @@ import { EntityManager } from "typeorm" * x-authenticated: true * parameters: * - (path) id=* {string} The ID of the Order. + * - (query) expand {string} Comma separated list of relations to include in the result. + * - (query) fields {string} Comma separated list of fields to include in the result. * x-codegen: * method: cancel + * params: AdminPostOrdersOrderCancel * x-codeSamples: * - lang: JavaScript * label: JS Client @@ -63,10 +65,11 @@ export default async (req, res) => { return await orderService.withTransaction(transactionManager).cancel(id) }) - const order = await orderService.retrieve(id, { - select: defaultAdminOrdersFields, - relations: defaultAdminOrdersRelations, + const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { + includes: req.includes, }) res.json({ order }) } + +export class AdminPostOrdersOrderCancel extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/cancel-swap.ts b/packages/medusa/src/api/routes/admin/orders/cancel-swap.ts index 2ecae0b1e5..9d04d0da7e 100644 --- a/packages/medusa/src/api/routes/admin/orders/cancel-swap.ts +++ b/packages/medusa/src/api/routes/admin/orders/cancel-swap.ts @@ -1,8 +1,8 @@ import { OrderService, SwapService } from "../../../../services" -import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "." import { EntityManager } from "typeorm" import { MedusaError } from "medusa-core-utils" +import { FindParams } from "../../../../types/common" /** * @oas [post] /orders/{id}/swaps/{swap_id}/cancel @@ -13,8 +13,11 @@ import { MedusaError } from "medusa-core-utils" * parameters: * - (path) id=* {string} The ID of the Order. * - (path) swap_id=* {string} The ID of the Swap. + * - (query) expand {string} Comma separated list of relations to include in the result. + * - (query) fields {string} Comma separated list of fields to include in the result. * x-codegen: * method: cancelSwap + * params: AdminPostOrdersSwapCancelParams * x-codeSamples: * - lang: JavaScript * label: JS Client @@ -76,10 +79,11 @@ export default async (req, res) => { return await swapService.withTransaction(transactionManager).cancel(swap_id) }) - const order = await orderService.retrieve(id, { - select: defaultAdminOrdersFields, - relations: defaultAdminOrdersRelations, + const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { + includes: req.includes, }) res.json({ order }) } + +export class AdminPostOrdersSwapCancelParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/capture-payment.ts b/packages/medusa/src/api/routes/admin/orders/capture-payment.ts index b5c025c2ee..9cbfe80c75 100644 --- a/packages/medusa/src/api/routes/admin/orders/capture-payment.ts +++ b/packages/medusa/src/api/routes/admin/orders/capture-payment.ts @@ -1,7 +1,6 @@ -import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "." - import { OrderService } from "../../../../services" import { EntityManager } from "typeorm" +import { FindParams } from "../../../../types/common" /** * @oas [post] /orders/{id}/capture @@ -11,8 +10,11 @@ import { EntityManager } from "typeorm" * x-authenticated: true * parameters: * - (path) id=* {string} The ID of the Order. + * - (query) expand {string} Comma separated list of relations to include in the result. + * - (query) fields {string} Comma separated list of fields to include in the result. * x-codegen: * method: capturePayment + * params: AdminPostOrdersOrderCaptureParams * x-codeSamples: * - lang: JavaScript * label: JS Client @@ -66,10 +68,11 @@ export default async (req, res) => { .capturePayment(id) }) - const order = await orderService.retrieve(id, { - select: defaultAdminOrdersFields, - relations: defaultAdminOrdersRelations, + const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { + includes: req.includes, }) res.json({ order }) } + +export class AdminPostOrdersOrderCaptureParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/complete-order.ts b/packages/medusa/src/api/routes/admin/orders/complete-order.ts index 3ed8b4fc00..e3b69958ba 100644 --- a/packages/medusa/src/api/routes/admin/orders/complete-order.ts +++ b/packages/medusa/src/api/routes/admin/orders/complete-order.ts @@ -1,5 +1,6 @@ import { OrderService } from "../../../../services" import { EntityManager } from "typeorm" +import { FindParams } from "../../../../types/common" /** * @oas [post] /orders/{id}/complete @@ -9,8 +10,11 @@ import { EntityManager } from "typeorm" * x-authenticated: true * parameters: * - (path) id=* {string} The ID of the Order. + * - (query) expand {string} Comma separated list of relations to include in the result. + * - (query) fields {string} Comma separated list of fields to include in the result. * x-codegen: * method: complete + * params: AdminPostOrdersOrderCompleteParams * x-codeSamples: * - lang: JavaScript * label: JS Client @@ -64,9 +68,11 @@ export default async (req, res) => { .completeOrder(id) }) - const order = await orderService.retrieve(id, { - relations: ["region", "customer", "swaps"], + const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { + includes: req.includes, }) res.json({ order }) } + +export class AdminPostOrdersOrderCompleteParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/create-claim-shipment.ts b/packages/medusa/src/api/routes/admin/orders/create-claim-shipment.ts index f3ca645046..025e640e01 100644 --- a/packages/medusa/src/api/routes/admin/orders/create-claim-shipment.ts +++ b/packages/medusa/src/api/routes/admin/orders/create-claim-shipment.ts @@ -1,9 +1,7 @@ import { ClaimService, OrderService } from "../../../../services" import { IsArray, IsNotEmpty, IsOptional, IsString } from "class-validator" -import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "." - -import { validator } from "../../../../utils/validator" import { EntityManager } from "typeorm" +import { FindParams } from "../../../../types/common" /** * @oas [post] /orders/{id}/claims/{claim_id}/shipments @@ -14,6 +12,8 @@ import { EntityManager } from "typeorm" * parameters: * - (path) id=* {string} The ID of the Order. * - (path) claim_id=* {string} The ID of the Claim. + * - (query) expand {string} Comma separated list of relations to include in the result. + * - (query) fields {string} Comma separated list of fields to include in the result. * requestBody: * content: * application/json: @@ -21,6 +21,7 @@ import { EntityManager } from "typeorm" * $ref: "#/components/schemas/AdminPostOrdersOrderClaimsClaimShipmentsReq" * x-codegen: * method: createClaimShipment + * params: AdminPostOrdersOrderClaimsClaimShipmentsParams * x-codeSamples: * - lang: JavaScript * label: JS Client @@ -71,10 +72,7 @@ import { EntityManager } from "typeorm" export default async (req, res) => { const { id, claim_id } = req.params - const validated = await validator( - AdminPostOrdersOrderClaimsClaimShipmentsReq, - req.body - ) + const validated = req.validatedBody const orderService: OrderService = req.scope.resolve("orderService") const claimService: ClaimService = req.scope.resolve("claimService") @@ -90,9 +88,8 @@ export default async (req, res) => { ) }) - const order = await orderService.retrieve(id, { - select: defaultAdminOrdersFields, - relations: defaultAdminOrdersRelations, + const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { + includes: req.includes, }) res.json({ order }) @@ -123,3 +120,6 @@ export class AdminPostOrdersOrderClaimsClaimShipmentsReq { @IsString({ each: true }) tracking_numbers?: string[] } + +// eslint-disable-next-line max-len +export class AdminPostOrdersOrderClaimsClaimShipmentsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/create-claim.ts b/packages/medusa/src/api/routes/admin/orders/create-claim.ts index 5fecd6c2ee..0f24d9d68a 100644 --- a/packages/medusa/src/api/routes/admin/orders/create-claim.ts +++ b/packages/medusa/src/api/routes/admin/orders/create-claim.ts @@ -9,15 +9,13 @@ import { IsString, ValidateNested, } from "class-validator" -import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "." import { ClaimReason, ClaimType } from "../../../../models" import { Type } from "class-transformer" import { MedusaError } from "medusa-core-utils" import { EntityManager } from "typeorm" import { ClaimTypeValue } from "../../../../types/claim" -import { AddressPayload } from "../../../../types/common" -import { validator } from "../../../../utils/validator" +import { AddressPayload, FindParams } from "../../../../types/common" /** * @oas [post] /order/{id}/claims @@ -27,6 +25,8 @@ import { validator } from "../../../../utils/validator" * x-authenticated: true * parameters: * - (path) id=* {string} The ID of the Order. + * - (query) expand {string} Comma separated list of relations to include in the result. + * - (query) fields {string} Comma separated list of fields to include in the result. * requestBody: * content: * application/json: @@ -34,6 +34,7 @@ import { validator } from "../../../../utils/validator" * $ref: "#/components/schemas/AdminPostOrdersOrderClaimsReq" * x-codegen: * method: createClaim + * params: AdminPostOrdersOrderClaimsParams * x-codeSamples: * - lang: JavaScript * label: JS Client @@ -97,7 +98,7 @@ import { validator } from "../../../../utils/validator" export default async (req, res) => { const { id } = req.params - const value = await validator(AdminPostOrdersOrderClaimsReq, req.body) + const value = req.validatedBody const idempotencyKeyService = req.scope.resolve("idempotencyKeyService") const manager: EntityManager = req.scope.resolve("manager") @@ -247,9 +248,8 @@ export default async (req, res) => { order = await orderService .withTransaction(manager) - .retrieve(id, { - select: defaultAdminOrdersFields, - relations: defaultAdminOrdersRelations, + .retrieveWithTotals(id, req.retrieveConfig, { + includes: req.includes, }) return { @@ -508,3 +508,5 @@ class AdditionalItem { @IsNotEmpty() quantity: number } + +export class AdminPostOrdersOrderClaimsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/create-fulfillment.ts b/packages/medusa/src/api/routes/admin/orders/create-fulfillment.ts index 61434c7791..7484e565c7 100644 --- a/packages/medusa/src/api/routes/admin/orders/create-fulfillment.ts +++ b/packages/medusa/src/api/routes/admin/orders/create-fulfillment.ts @@ -9,16 +9,15 @@ import { ValidateNested, } from "class-validator" import { Transform, Type } from "class-transformer" -import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "." import { EntityManager } from "typeorm" import { OrderService, ProductVariantInventoryService, } from "../../../../services" -import { validator } from "../../../../utils/validator" import { optionalBooleanMapper } from "../../../../utils/validators/is-boolean" import { Fulfillment, LineItem } from "../../../../models" +import { FindParams } from "../../../../types/common" /** * @oas [post] /orders/{id}/fulfillment @@ -28,6 +27,8 @@ import { Fulfillment, LineItem } from "../../../../models" * x-authenticated: true * parameters: * - (path) id=* {string} The ID of the Order. + * - (query) expand {string} Comma separated list of relations to include in the result. + * - (query) fields {string} Comma separated list of fields to include in the result. * requestBody: * content: * application/json: @@ -35,6 +36,7 @@ import { Fulfillment, LineItem } from "../../../../models" * $ref: "#/components/schemas/AdminPostOrdersOrderFulfillmentsReq" * x-codegen: * method: createFulfillment + * params: AdminPostOrdersOrderFulfillmentsParams * x-codeSamples: * - lang: JavaScript * label: JS Client @@ -95,10 +97,7 @@ import { Fulfillment, LineItem } from "../../../../models" export default async (req, res) => { const { id } = req.params - const validated = await validator( - AdminPostOrdersOrderFulfillmentsReq, - req.body - ) + const validated = req.validatedBody const orderService: OrderService = req.scope.resolve("orderService") const pvInventoryService: ProductVariantInventoryService = req.scope.resolve( @@ -136,9 +135,8 @@ export default async (req, res) => { } }) - const order = await orderService.retrieve(id, { - select: defaultAdminOrdersFields, - relations: defaultAdminOrdersRelations, + const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { + includes: req.includes, }) res.json({ order }) @@ -239,3 +237,5 @@ class Item { @IsNotEmpty() quantity: number } + +export class AdminPostOrdersOrderFulfillmentsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/create-shipment.ts b/packages/medusa/src/api/routes/admin/orders/create-shipment.ts index 2435626b82..a3984fdfc7 100644 --- a/packages/medusa/src/api/routes/admin/orders/create-shipment.ts +++ b/packages/medusa/src/api/routes/admin/orders/create-shipment.ts @@ -5,12 +5,11 @@ import { IsOptional, IsString, } from "class-validator" -import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "." import { EntityManager } from "typeorm" import { OrderService } from "../../../../services" import { TrackingLink } from "../../../../models" -import { validator } from "../../../../utils/validator" +import { FindParams } from "../../../../types/common" /** * @oas [post] /orders/{id}/shipment @@ -20,6 +19,8 @@ import { validator } from "../../../../utils/validator" * x-authenticated: true * parameters: * - (path) id=* {string} The ID of the Order. + * - (query) expand {string} Comma separated list of relations to include in the result. + * - (query) fields {string} Comma separated list of fields to include in the result. * requestBody: * content: * application/json: @@ -27,6 +28,7 @@ import { validator } from "../../../../utils/validator" * $ref: "#/components/schemas/AdminPostOrdersOrderShipmentReq" * x-codegen: * method: createShipment + * params: AdminPostOrdersOrderShipmentParams * x-codeSamples: * - lang: JavaScript * label: JS Client @@ -77,7 +79,7 @@ import { validator } from "../../../../utils/validator" export default async (req, res) => { const { id } = req.params - const validated = await validator(AdminPostOrdersOrderShipmentReq, req.body) + const validated = req.validatedBody const orderService: OrderService = req.scope.resolve("orderService") @@ -98,9 +100,8 @@ export default async (req, res) => { ) }) - const order = await orderService.retrieve(id, { - select: defaultAdminOrdersFields, - relations: defaultAdminOrdersRelations, + const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { + includes: req.includes, }) res.json({ order }) @@ -138,3 +139,5 @@ export class AdminPostOrdersOrderShipmentReq { @IsOptional() no_notification?: boolean } + +export class AdminPostOrdersOrderShipmentParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/create-swap-shipment.ts b/packages/medusa/src/api/routes/admin/orders/create-swap-shipment.ts index 515c62036b..c914d1236e 100644 --- a/packages/medusa/src/api/routes/admin/orders/create-swap-shipment.ts +++ b/packages/medusa/src/api/routes/admin/orders/create-swap-shipment.ts @@ -6,10 +6,10 @@ import { IsString, } from "class-validator" import { OrderService, SwapService } from "../../../../services" -import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "." import { EntityManager } from "typeorm" import { validator } from "../../../../utils/validator" +import { FindParams } from "../../../../types/common" /** * @oas [post] /orders/{id}/swaps/{swap_id}/shipments @@ -20,6 +20,8 @@ import { validator } from "../../../../utils/validator" * parameters: * - (path) id=* {string} The ID of the Order. * - (path) swap_id=* {string} The ID of the Swap. + * - (query) expand {string} Comma separated list of relations to include in the result. + * - (query) fields {string} Comma separated list of fields to include in the result. * requestBody: * content: * application/json: @@ -27,6 +29,7 @@ import { validator } from "../../../../utils/validator" * $ref: "#/components/schemas/AdminPostOrdersOrderSwapsSwapShipmentsReq" * x-codegen: * method: createSwapShipment + * params: AdminPostOrdersOrderSwapsSwapShipmentsParams * x-codeSamples: * - lang: JavaScript * label: JS Client @@ -95,9 +98,8 @@ export default async (req, res) => { ) }) - const order = await orderService.retrieve(id, { - select: defaultAdminOrdersFields, - relations: defaultAdminOrdersRelations, + const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { + includes: req.includes, }) res.json({ order }) @@ -135,3 +137,5 @@ export class AdminPostOrdersOrderSwapsSwapShipmentsReq { @IsOptional() no_notification?: boolean } + +export class AdminPostOrdersOrderSwapsSwapShipmentsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/create-swap.ts b/packages/medusa/src/api/routes/admin/orders/create-swap.ts index 25ade65707..38c38ffdc7 100644 --- a/packages/medusa/src/api/routes/admin/orders/create-swap.ts +++ b/packages/medusa/src/api/routes/admin/orders/create-swap.ts @@ -16,12 +16,11 @@ import { Min, ValidateNested, } from "class-validator" -import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "." import { EntityManager } from "typeorm" import { MedusaError } from "medusa-core-utils" import { Type } from "class-transformer" -import { validator } from "../../../../utils/validator" +import { FindParams } from "../../../../types/common" /** * @oas [post] /order/{id}/swaps @@ -31,6 +30,8 @@ import { validator } from "../../../../utils/validator" * x-authenticated: true * parameters: * - (path) id=* {string} The ID of the Order. + * - (query) expand {string} (Comma separated) Which fields should be expanded the order of the result. + * - (query) fields {string} (Comma separated) Which fields should be included the order of the result. * requestBody: * content: * application/json: @@ -38,6 +39,7 @@ import { validator } from "../../../../utils/validator" * $ref: "#/components/schemas/AdminPostOrdersOrderSwapsReq" * x-codegen: * method: createSwap + * queryParams: AdminPostOrdersOrderSwapsParams * x-codeSamples: * - lang: JavaScript * label: JS Client @@ -98,7 +100,7 @@ import { validator } from "../../../../utils/validator" export default async (req, res) => { const { id } = req.params - const validated = await validator(AdminPostOrdersOrderSwapsReq, req.body) + const validated = req.validatedBody const idempotencyKeyService: IdempotencyKeyService = req.scope.resolve( "idempotencyKeyService" @@ -208,9 +210,8 @@ export default async (req, res) => { const order = await orderService .withTransaction(transactionManager) - .retrieve(id, { - select: defaultAdminOrdersFields, - relations: defaultAdminOrdersRelations, + .retrieveWithTotals(id, req.retrieveConfig, { + includes: req.includes, }) return { @@ -411,3 +412,5 @@ class AdditionalItem { @IsNotEmpty() quantity: number } + +export class AdminPostOrdersOrderSwapsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/fulfill-claim.ts b/packages/medusa/src/api/routes/admin/orders/fulfill-claim.ts index 4551d33aca..ad7ef08093 100644 --- a/packages/medusa/src/api/routes/admin/orders/fulfill-claim.ts +++ b/packages/medusa/src/api/routes/admin/orders/fulfill-claim.ts @@ -1,9 +1,8 @@ import { ClaimService, OrderService } from "../../../../services" import { IsBoolean, IsObject, IsOptional } from "class-validator" -import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "." import { EntityManager } from "typeorm" -import { validator } from "../../../../utils/validator" +import { FindParams } from "../../../../types/common" /** * @oas [post] /orders/{id}/claims/{claim_id}/fulfillments @@ -14,6 +13,8 @@ import { validator } from "../../../../utils/validator" * parameters: * - (path) id=* {string} The ID of the Order. * - (path) claim_id=* {string} The ID of the Claim. + * - (query) expand {string} Comma separated list of relations to include in the result. + * - (query) fields {string} Comma separated list of fields to include in the result. * requestBody: * content: * application/json: @@ -21,6 +22,7 @@ import { validator } from "../../../../utils/validator" * $ref: "#/components/schemas/AdminPostOrdersOrderClaimsClaimFulfillmentsReq" * x-codegen: * method: fulfillClaim + * params: AdminPostOrdersOrderClaimsClaimFulfillmentsReq * x-codeSamples: * - lang: JavaScript * label: JS Client @@ -65,10 +67,7 @@ import { validator } from "../../../../utils/validator" export default async (req, res) => { const { id, claim_id } = req.params - const validated = await validator( - AdminPostOrdersOrderClaimsClaimFulfillmentsReq, - req.body - ) + const validated = req.validatedBody const orderService: OrderService = req.scope.resolve("orderService") const claimService: ClaimService = req.scope.resolve("claimService") @@ -81,9 +80,8 @@ export default async (req, res) => { }) }) - const order = await orderService.retrieve(id, { - select: defaultAdminOrdersFields, - relations: defaultAdminOrdersRelations, + const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { + includes: req.includes, }) res.status(200).json({ order }) @@ -109,3 +107,6 @@ export class AdminPostOrdersOrderClaimsClaimFulfillmentsReq { @IsOptional() no_notification?: boolean } + +// eslint-disable-next-line max-len +export class AdminPostOrdersOrderClaimsClaimFulfillmentsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/fulfill-swap.ts b/packages/medusa/src/api/routes/admin/orders/fulfill-swap.ts index 878df88c20..4edfc7a521 100644 --- a/packages/medusa/src/api/routes/admin/orders/fulfill-swap.ts +++ b/packages/medusa/src/api/routes/admin/orders/fulfill-swap.ts @@ -1,9 +1,9 @@ import { IsBoolean, IsObject, IsOptional } from "class-validator" import { OrderService, SwapService } from "../../../../services" -import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "." import { EntityManager } from "typeorm" import { validator } from "../../../../utils/validator" +import { FindParams } from "../../../../types/common" /** * @oas [post] /orders/{id}/swaps/{swap_id}/fulfillments @@ -14,6 +14,8 @@ import { validator } from "../../../../utils/validator" * parameters: * - (path) id=* {string} The ID of the Order. * - (path) swap_id=* {string} The ID of the Swap. + * - (query) expand {string} Comma separated list of relations to include in the result. + * - (query) fields {string} Comma separated list of fields to include in the result. * requestBody: * content: * application/json: @@ -21,6 +23,7 @@ import { validator } from "../../../../utils/validator" * $ref: "#/components/schemas/AdminPostOrdersOrderSwapsSwapFulfillmentsReq" * x-codegen: * method: fulfillSwap + * params: AdminPostOrdersOrderSwapsSwapFulfillmentsParams * x-codeSamples: * - lang: JavaScript * label: JS Client @@ -81,9 +84,8 @@ export default async (req, res) => { }) }) - const order = await orderService.retrieve(id, { - select: defaultAdminOrdersFields, - relations: defaultAdminOrdersRelations, + const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { + includes: req.includes, }) res.status(200).json({ order }) @@ -109,3 +111,6 @@ export class AdminPostOrdersOrderSwapsSwapFulfillmentsReq { @IsOptional() no_notification?: boolean } + +// eslint-disable-next-line max-len +export class AdminPostOrdersOrderSwapsSwapFulfillmentsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/get-order.ts b/packages/medusa/src/api/routes/admin/orders/get-order.ts index 6b2020460f..1ae1a6c26c 100644 --- a/packages/medusa/src/api/routes/admin/orders/get-order.ts +++ b/packages/medusa/src/api/routes/admin/orders/get-order.ts @@ -60,9 +60,11 @@ export default async (req, res) => { const orderService: OrderService = req.scope.resolve("orderService") - const order = await orderService.retrieveWithTotals(id, req.retrieveConfig) + const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { + includes: req.includes, + }) - res.json({ order }) + res.json({ order: order }) } export class AdminGetOrdersOrderParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/index.ts b/packages/medusa/src/api/routes/admin/orders/index.ts index 7ba42e6629..cce3b2288c 100644 --- a/packages/medusa/src/api/routes/admin/orders/index.ts +++ b/packages/medusa/src/api/routes/admin/orders/index.ts @@ -6,12 +6,72 @@ import { FindParams, PaginatedResponse } from "../../../../types/common" import { FlagRouter } from "../../../../utils/flag-router" import middlewares, { transformBody, + transformIncludesOptions, transformQuery, } from "../../../middlewares" import { checkRegisteredModules } from "../../../middlewares/check-registered-modules" import { AdminOrdersOrderLineItemReservationReq } from "./create-reservation-for-line-item" import { AdminGetOrdersOrderReservationsParams } from "./get-reservations" import { AdminGetOrdersParams } from "./list-orders" +import { + AdminPostOrdersOrderSwapsParams, + AdminPostOrdersOrderSwapsReq, +} from "./create-swap" +import { + AdminPostOrdersOrderParams, + AdminPostOrdersOrderReq, +} from "./update-order" +import { AdminPostOrdersOrderCompleteParams } from "./complete-order" +import { + AdminPostOrdersOrderRefundsParams, + AdminPostOrdersOrderRefundsReq, +} from "./refund-payment" +import { AdminPostOrdersOrderCaptureParams } from "./capture-payment" +import { + AdminPostOrdersOrderFulfillmentsParams, + AdminPostOrdersOrderFulfillmentsReq, +} from "./create-fulfillment" +import { AdminPostOrdersOrderFulfillementsCancelParams } from "./cancel-fulfillment" +import { AdminPostOrdersOrderSwapFulfillementsCancelParams } from "./cancel-fulfillment-swap" +import { AdminPostOrdersClaimFulfillmentsCancelParams } from "./cancel-fulfillment-claim" +import { + AdminPostOrdersOrderShipmentParams, + AdminPostOrdersOrderShipmentReq, +} from "./create-shipment" +import { + AdminPostOrdersOrderReturnsParams, + AdminPostOrdersOrderReturnsReq, +} from "./request-return" +import { AdminPostOrdersOrderCancel } from "./cancel-order" +import { + AdminPostOrdersOrderShippingMethodsParams, + AdminPostOrdersOrderShippingMethodsReq, +} from "./add-shipping-method" +import { AdminPostOrdersOrderArchiveParams } from "./archive-order" +import { AdminPostOrdersSwapCancelParams } from "./cancel-swap" +import { AdminPostOrdersOrderSwapsSwapFulfillmentsParams } from "./fulfill-swap" +import { + AdminPostOrdersOrderSwapsSwapShipmentsParams, + AdminPostOrdersOrderSwapsSwapShipmentsReq, +} from "./create-swap-shipment" +import { AdminPostOrdersOrderSwapsSwapProcessPaymentParams } from "./process-swap-payment" +import { + AdminPostOrdersOrderClaimsParams, + AdminPostOrdersOrderClaimsReq, +} from "./create-claim" +import { AdminPostOrdersClaimCancel } from "./cancel-claim" +import { + AdminPostOrdersOrderClaimsClaimParams, + AdminPostOrdersOrderClaimsClaimReq, +} from "./update-claim" +import { + AdminPostOrdersOrderClaimsClaimFulfillmentsParams, + AdminPostOrdersOrderClaimsClaimFulfillmentsReq, +} from "./fulfill-claim" +import { + AdminPostOrdersOrderClaimsClaimShipmentsParams, + AdminPostOrdersOrderClaimsClaimShipmentsReq, +} from "./create-claim-shipment" const route = Router() @@ -31,6 +91,7 @@ export default (app, featureFlagRouter: FlagRouter) => { */ route.get( "/", + transformIncludesOptions(allowedOrderIncludesFields), transformQuery(AdminGetOrdersParams, { defaultRelations: relations, defaultFields: defaultAdminOrdersFields, @@ -44,21 +105,12 @@ export default (app, featureFlagRouter: FlagRouter) => { */ route.get( "/:id", - transformQuery(FindParams, { + transformIncludesOptions(allowedOrderIncludesFields, [ + AvailableOrderIncludesFields.RETURNABLE_ITEMS, + ]), + transformQuery(AdminPostOrdersOrderParams, { defaultRelations: relations, - defaultFields: defaultFields.filter((field) => { - return ![ - "shipping_total", - "discount_total", - "tax_total", - "refunded_total", - "total", - "subtotal", - "refundable_amount", - "gift_card_total", - "gift_card_tax_total", - ].includes(field) - }), + defaultFields: defaultFields, isList: false, }), middlewares.wrap(require("./get-order").default) @@ -67,13 +119,29 @@ export default (app, featureFlagRouter: FlagRouter) => { /** * Update an order */ - route.post("/:id", middlewares.wrap(require("./update-order").default)) + route.post( + "/:id", + transformIncludesOptions(allowedOrderIncludesFields), + transformBody(AdminPostOrdersOrderReq), + transformQuery(FindParams, { + defaultRelations: relations, + defaultFields: defaultFields, + isList: false, + }), + middlewares.wrap(require("./update-order").default) + ) /** * Mark an order as completed */ route.post( "/:id/complete", + transformIncludesOptions(allowedOrderIncludesFields), + transformQuery(AdminPostOrdersOrderCompleteParams, { + defaultRelations: relations, + defaultFields: defaultFields, + isList: false, + }), middlewares.wrap(require("./complete-order").default) ) @@ -82,6 +150,13 @@ export default (app, featureFlagRouter: FlagRouter) => { */ route.post( "/:id/refund", + transformIncludesOptions(allowedOrderIncludesFields), + transformBody(AdminPostOrdersOrderRefundsReq), + transformQuery(AdminPostOrdersOrderRefundsParams, { + defaultRelations: relations, + defaultFields: defaultFields, + isList: false, + }), middlewares.wrap(require("./refund-payment").default) ) @@ -90,6 +165,12 @@ export default (app, featureFlagRouter: FlagRouter) => { */ route.post( "/:id/capture", + transformIncludesOptions(allowedOrderIncludesFields), + transformQuery(AdminPostOrdersOrderCaptureParams, { + defaultRelations: relations, + defaultFields: defaultFields, + isList: false, + }), middlewares.wrap(require("./capture-payment").default) ) @@ -98,6 +179,13 @@ export default (app, featureFlagRouter: FlagRouter) => { */ route.post( "/:id/fulfillment", + transformIncludesOptions(allowedOrderIncludesFields), + transformBody(AdminPostOrdersOrderFulfillmentsReq), + transformQuery(AdminPostOrdersOrderFulfillmentsParams, { + defaultRelations: relations, + defaultFields: defaultFields, + isList: false, + }), middlewares.wrap(require("./create-fulfillment").default) ) @@ -106,6 +194,12 @@ export default (app, featureFlagRouter: FlagRouter) => { */ route.post( "/:id/fulfillments/:fulfillment_id/cancel", + transformIncludesOptions(allowedOrderIncludesFields), + transformQuery(AdminPostOrdersOrderFulfillementsCancelParams, { + defaultRelations: relations, + defaultFields: defaultFields, + isList: false, + }), middlewares.wrap(require("./cancel-fulfillment").default) ) @@ -114,6 +208,12 @@ export default (app, featureFlagRouter: FlagRouter) => { */ route.post( "/:id/swaps/:swap_id/fulfillments/:fulfillment_id/cancel", + transformIncludesOptions(allowedOrderIncludesFields), + transformQuery(AdminPostOrdersOrderSwapFulfillementsCancelParams, { + defaultRelations: relations, + defaultFields: defaultFields, + isList: false, + }), middlewares.wrap(require("./cancel-fulfillment-swap").default) ) @@ -122,6 +222,12 @@ export default (app, featureFlagRouter: FlagRouter) => { */ route.post( "/:id/claims/:claim_id/fulfillments/:fulfillment_id/cancel", + transformIncludesOptions(allowedOrderIncludesFields), + transformQuery(AdminPostOrdersClaimFulfillmentsCancelParams, { + defaultRelations: relations, + defaultFields: defaultFields, + isList: false, + }), middlewares.wrap(require("./cancel-fulfillment-claim").default) ) @@ -130,6 +236,13 @@ export default (app, featureFlagRouter: FlagRouter) => { */ route.post( "/:id/shipment", + transformIncludesOptions(allowedOrderIncludesFields), + transformBody(AdminPostOrdersOrderShipmentReq), + transformQuery(AdminPostOrdersOrderShipmentParams, { + defaultRelations: relations, + defaultFields: defaultFields, + isList: false, + }), middlewares.wrap(require("./create-shipment").default) ) @@ -138,19 +251,42 @@ export default (app, featureFlagRouter: FlagRouter) => { */ route.post( "/:id/return", + transformIncludesOptions(allowedOrderIncludesFields), + transformBody(AdminPostOrdersOrderReturnsReq), + transformQuery(AdminPostOrdersOrderReturnsParams, { + defaultRelations: relations, + defaultFields: defaultFields, + isList: false, + }), middlewares.wrap(require("./request-return").default) ) /** * Cancel an order. */ - route.post("/:id/cancel", middlewares.wrap(require("./cancel-order").default)) + route.post( + "/:id/cancel", + transformIncludesOptions(allowedOrderIncludesFields), + transformQuery(AdminPostOrdersOrderCancel, { + defaultRelations: relations, + defaultFields: defaultFields, + isList: false, + }), + middlewares.wrap(require("./cancel-order").default) + ) /** * Add a shipping method */ route.post( "/:id/shipping-methods", + transformIncludesOptions(allowedOrderIncludesFields), + transformBody(AdminPostOrdersOrderShippingMethodsReq), + transformQuery(AdminPostOrdersOrderShippingMethodsParams, { + defaultRelations: relations, + defaultFields: defaultFields, + isList: false, + }), middlewares.wrap(require("./add-shipping-method").default) ) @@ -159,19 +295,43 @@ export default (app, featureFlagRouter: FlagRouter) => { */ route.post( "/:id/archive", + transformIncludesOptions(allowedOrderIncludesFields), + transformQuery(AdminPostOrdersOrderArchiveParams, { + defaultRelations: relations, + defaultFields: defaultFields, + isList: false, + }), middlewares.wrap(require("./archive-order").default) ) /** * Creates a swap, requests a return and prepares a cart for payment. */ - route.post("/:id/swaps", middlewares.wrap(require("./create-swap").default)) + route.post( + "/:id/swaps", + transformIncludesOptions(allowedOrderIncludesFields, [ + AvailableOrderIncludesFields.RETURNABLE_ITEMS, + ]), + transformBody(AdminPostOrdersOrderSwapsReq), + transformQuery(AdminPostOrdersOrderSwapsParams, { + defaultRelations: relations, + defaultFields: defaultFields, + isList: false, + }), + middlewares.wrap(require("./create-swap").default) + ) /** * Cancels a swap. */ route.post( "/:id/swaps/:swap_id/cancel", + transformIncludesOptions(allowedOrderIncludesFields), + transformQuery(AdminPostOrdersSwapCancelParams, { + defaultRelations: relations, + defaultFields: defaultFields, + isList: false, + }), middlewares.wrap(require("./cancel-swap").default) ) @@ -180,6 +340,12 @@ export default (app, featureFlagRouter: FlagRouter) => { */ route.post( "/:id/swaps/:swap_id/fulfillments", + transformIncludesOptions(allowedOrderIncludesFields), + transformQuery(AdminPostOrdersOrderSwapsSwapFulfillmentsParams, { + defaultRelations: relations, + defaultFields: defaultFields, + isList: false, + }), middlewares.wrap(require("./fulfill-swap").default) ) @@ -188,6 +354,13 @@ export default (app, featureFlagRouter: FlagRouter) => { */ route.post( "/:id/swaps/:swap_id/shipments", + transformIncludesOptions(allowedOrderIncludesFields), + transformBody(AdminPostOrdersOrderSwapsSwapShipmentsReq), + transformQuery(AdminPostOrdersOrderSwapsSwapShipmentsParams, { + defaultRelations: relations, + defaultFields: defaultFields, + isList: false, + }), middlewares.wrap(require("./create-swap-shipment").default) ) @@ -196,19 +369,41 @@ export default (app, featureFlagRouter: FlagRouter) => { */ route.post( "/:id/swaps/:swap_id/process-payment", + transformIncludesOptions(allowedOrderIncludesFields), + transformQuery(AdminPostOrdersOrderSwapsSwapProcessPaymentParams, { + defaultRelations: relations, + defaultFields: defaultFields, + isList: false, + }), middlewares.wrap(require("./process-swap-payment").default) ) /** * Creates a claim */ - route.post("/:id/claims", middlewares.wrap(require("./create-claim").default)) + route.post( + "/:id/claims", + transformIncludesOptions(allowedOrderIncludesFields), + transformBody(AdminPostOrdersOrderClaimsReq), + transformQuery(AdminPostOrdersOrderClaimsParams, { + defaultRelations: relations, + defaultFields: defaultFields, + isList: false, + }), + middlewares.wrap(require("./create-claim").default) + ) /** * Cancels a claim */ route.post( "/:id/claims/:claim_id/cancel", + transformIncludesOptions(allowedOrderIncludesFields), + transformQuery(AdminPostOrdersClaimCancel, { + defaultRelations: relations, + defaultFields: defaultFields, + isList: false, + }), middlewares.wrap(require("./cancel-claim").default) ) @@ -217,6 +412,13 @@ export default (app, featureFlagRouter: FlagRouter) => { */ route.post( "/:id/claims/:claim_id", + transformIncludesOptions(allowedOrderIncludesFields), + transformBody(AdminPostOrdersOrderClaimsClaimReq), + transformQuery(AdminPostOrdersOrderClaimsClaimParams, { + defaultRelations: relations, + defaultFields: defaultFields, + isList: false, + }), middlewares.wrap(require("./update-claim").default) ) @@ -225,6 +427,13 @@ export default (app, featureFlagRouter: FlagRouter) => { */ route.post( "/:id/claims/:claim_id/fulfillments", + transformIncludesOptions(allowedOrderIncludesFields), + transformBody(AdminPostOrdersOrderClaimsClaimFulfillmentsReq), + transformQuery(AdminPostOrdersOrderClaimsClaimFulfillmentsParams, { + defaultRelations: relations, + defaultFields: defaultFields, + isList: false, + }), middlewares.wrap(require("./fulfill-claim").default) ) @@ -233,6 +442,13 @@ export default (app, featureFlagRouter: FlagRouter) => { */ route.post( "/:id/claims/:claim_id/shipments", + transformIncludesOptions(allowedOrderIncludesFields), + transformBody(AdminPostOrdersOrderClaimsClaimShipmentsReq), + transformQuery(AdminPostOrdersOrderClaimsClaimShipmentsParams, { + defaultRelations: relations, + defaultFields: defaultFields, + isList: false, + }), middlewares.wrap(require("./create-claim-shipment").default) ) @@ -358,15 +574,6 @@ export const defaultAdminOrdersFields = [ "items.refundable", "swaps.additional_items.refundable", "claims.additional_items.refundable", - "shipping_total", - "discount_total", - "tax_total", - "refunded_total", - "gift_card_total", - "subtotal", - "total", - "paid_total", - "refundable_amount", "no_notification", ] as (keyof Order)[] @@ -387,6 +594,14 @@ export const filterableAdminOrdersFields = [ "updated_at", ] +export const AvailableOrderIncludesFields = { + RETURNABLE_ITEMS: "returnable_items", +} + +export const allowedOrderIncludesFields = [ + AvailableOrderIncludesFields.RETURNABLE_ITEMS, +] + export * from "./add-shipping-method" export * from "./archive-order" export * from "./cancel-claim" diff --git a/packages/medusa/src/api/routes/admin/orders/process-swap-payment.ts b/packages/medusa/src/api/routes/admin/orders/process-swap-payment.ts index 321322d9ca..1e1ec5481a 100644 --- a/packages/medusa/src/api/routes/admin/orders/process-swap-payment.ts +++ b/packages/medusa/src/api/routes/admin/orders/process-swap-payment.ts @@ -1,7 +1,7 @@ import { OrderService, SwapService } from "../../../../services" -import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "." import { EntityManager } from "typeorm" +import { FindParams } from "../../../../types/common" /** * @oas [post] /orders/{id}/swaps/{swap_id}/process-payment @@ -12,8 +12,11 @@ import { EntityManager } from "typeorm" * parameters: * - (path) id=* {string} The ID of the Order. * - (path) swap_id=* {string} The ID of the Swap. + * - (query) expand {string} Comma separated list of relations to include in the result. + * - (query) fields {string} Comma separated list of fields to include in the result. * x-codegen: * method: processSwapPayment + * params: AdminPostOrdersOrderSwapsSwapProcessPaymentParams * x-codeSamples: * - lang: JavaScript * label: JS Client @@ -64,12 +67,14 @@ export default async (req, res) => { await entityManager.transaction(async (manager) => { await swapService.withTransaction(manager).processDifference(swap_id) - - const order = await orderService.withTransaction(manager).retrieve(id, { - select: defaultAdminOrdersFields, - relations: defaultAdminOrdersRelations, - }) - - res.json({ order }) }) + + const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { + includes: req.includes, + }) + + res.json({ order }) } + +// eslint-disable-next-line max-len +export class AdminPostOrdersOrderSwapsSwapProcessPaymentParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/refund-payment.ts b/packages/medusa/src/api/routes/admin/orders/refund-payment.ts index 7b8bcceb44..a18a6316e8 100644 --- a/packages/medusa/src/api/routes/admin/orders/refund-payment.ts +++ b/packages/medusa/src/api/routes/admin/orders/refund-payment.ts @@ -5,11 +5,10 @@ import { IsOptional, IsString, } from "class-validator" -import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "." import { OrderService } from "../../../../services" -import { validator } from "../../../../utils/validator" import { EntityManager } from "typeorm" +import { FindParams } from "../../../../types/common" /** * @oas [post] /orders/{id}/refund @@ -19,6 +18,8 @@ import { EntityManager } from "typeorm" * x-authenticated: true * parameters: * - (path) id=* {string} The ID of the Order. + * - (query) expand {string} Comma separated list of relations to include in the result. + * - (query) fields {string} Comma separated list of fields to include in the result. * requestBody: * content: * application/json: @@ -26,6 +27,7 @@ import { EntityManager } from "typeorm" * $ref: "#/components/schemas/AdminPostOrdersOrderRefundsReq" * x-codegen: * method: refundPayment + * params: AdminPostOrdersOrderRefundsParams * x-codeSamples: * - lang: JavaScript * label: JS Client @@ -78,7 +80,7 @@ import { EntityManager } from "typeorm" export default async (req, res) => { const { id } = req.params - const validated = await validator(AdminPostOrdersOrderRefundsReq, req.body) + const validated = req.validatedBody const orderService: OrderService = req.scope.resolve("orderService") @@ -91,9 +93,8 @@ export default async (req, res) => { }) }) - const order = await orderService.retrieve(id, { - select: defaultAdminOrdersFields, - relations: defaultAdminOrdersRelations, + const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { + includes: req.includes, }) res.status(200).json({ order }) @@ -136,3 +137,5 @@ export class AdminPostOrdersOrderRefundsReq { @IsOptional() no_notification?: boolean } + +export class AdminPostOrdersOrderRefundsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/request-return.ts b/packages/medusa/src/api/routes/admin/orders/request-return.ts index eff4cac4d8..35040c54a0 100644 --- a/packages/medusa/src/api/routes/admin/orders/request-return.ts +++ b/packages/medusa/src/api/routes/admin/orders/request-return.ts @@ -6,7 +6,6 @@ import { IsString, ValidateNested, } from "class-validator" -import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "." import { EventBusService, OrderService, @@ -18,7 +17,7 @@ import { isDefined, MedusaError } from "medusa-core-utils" import { EntityManager } from "typeorm" import { Order, Return } from "../../../../models" import { OrdersReturnItem } from "../../../../types/orders" -import { validator } from "../../../../utils/validator" +import { FindParams } from "../../../../types/common" /** * @oas [post] /orders/{id}/return @@ -28,6 +27,8 @@ import { validator } from "../../../../utils/validator" * x-authenticated: true * parameters: * - (path) id=* {string} The ID of the Order. + * - (query) expand {string} Comma separated list of relations to include in the result. + * - (query) fields {string} Comma separated list of fields to include in the result. * requestBody: * content: * application/json: @@ -35,6 +36,7 @@ import { validator } from "../../../../utils/validator" * $ref: "#/components/schemas/AdminPostOrdersOrderReturnsReq" * x-codegen: * method: requestReturn + * params: AdminPostOrdersOrderReturnsParams * x-codeSamples: * - lang: JavaScript * label: JS Client @@ -96,7 +98,7 @@ import { validator } from "../../../../utils/validator" export default async (req, res) => { const { id } = req.params - const value = await validator(AdminPostOrdersOrderReturnsReq, req.body) + const value = req.validatedBody const idempotencyKeyService = req.scope.resolve("idempotencyKeyService") const manager: EntityManager = req.scope.resolve("manager") @@ -152,14 +154,16 @@ export default async (req, res) => { } } - const order = await orderService - .withTransaction(manager) - .retrieve(id) + let evaluatedNoNotification = value.no_notification + + if (!isDefined(evaluatedNoNotification)) { + const order = await orderService + .withTransaction(manager) + .retrieve(id) + + evaluatedNoNotification = order.no_notification + } - const evaluatedNoNotification = - value.no_notification !== undefined - ? value.no_notification - : order.no_notification returnObj.no_notification = evaluatedNoNotification const createdReturn = await returnService @@ -174,7 +178,7 @@ export default async (req, res) => { await eventBus .withTransaction(manager) - .emit("order.return_requested", { + .emit(OrderService.Events.RETURN_REQUESTED, { id, return_id: createdReturn.id, no_notification: evaluatedNoNotification, @@ -198,9 +202,7 @@ export default async (req, res) => { idempotencyKey = await idempotencyKeyService .withTransaction(transactionManager) .workStage(idempotencyKey.idempotency_key, async (manager) => { - let order: Order | Return = await orderService - .withTransaction(manager) - .retrieve(id, { relations: ["returns"] }) + let order: Order | Return /** * If we are ready to receive immediately, we find the newly created return @@ -229,9 +231,8 @@ export default async (req, res) => { order = await orderService .withTransaction(manager) - .retrieve(id, { - select: defaultAdminOrdersFields, - relations: defaultAdminOrdersRelations, + .retrieveWithTotals(id, req.retrieveConfig, { + includes: req.includes, }) return { @@ -374,3 +375,5 @@ class ReturnShipping { @IsOptional() price?: number } + +export class AdminPostOrdersOrderReturnsParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/update-claim.ts b/packages/medusa/src/api/routes/admin/orders/update-claim.ts index 41787f69d1..e3f65aacdc 100644 --- a/packages/medusa/src/api/routes/admin/orders/update-claim.ts +++ b/packages/medusa/src/api/routes/admin/orders/update-claim.ts @@ -8,12 +8,12 @@ import { IsString, ValidateNested, } from "class-validator" -import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "." import { ClaimService, OrderService } from "../../../../services" import { Type } from "class-transformer" import { EntityManager } from "typeorm" import { validator } from "../../../../utils/validator" +import { FindParams } from "../../../../types/common" /** * @oas [post] /order/{id}/claims/{claim_id} @@ -24,6 +24,8 @@ import { validator } from "../../../../utils/validator" * parameters: * - (path) id=* {string} The ID of the Order. * - (path) claim_id=* {string} The ID of the Claim. + * - (query) expand {string} Comma separated list of relations to include in the result. + * - (query) fields {string} Comma separated list of fields to include in the result. * requestBody: * content: * application/json: @@ -31,6 +33,7 @@ import { validator } from "../../../../utils/validator" * $ref: "#/components/schemas/AdminPostOrdersOrderClaimsClaimReq" * x-codegen: * method: updateClaim + * params: AdminPostOrdersOrderClaimsClaimParams * x-codeSamples: * - lang: JavaScript * label: JS Client @@ -96,9 +99,8 @@ export default async (req, res) => { .update(claim_id, validated) }) - const data = await orderService.retrieve(id, { - select: defaultAdminOrdersFields, - relations: defaultAdminOrdersRelations, + const data = await orderService.retrieveWithTotals(id, req.retrieveConfig, { + includes: req.includes, }) res.json({ order: data }) @@ -277,3 +279,5 @@ class Tag { @IsOptional() value?: string } + +export class AdminPostOrdersOrderClaimsClaimParams extends FindParams {} diff --git a/packages/medusa/src/api/routes/admin/orders/update-order.ts b/packages/medusa/src/api/routes/admin/orders/update-order.ts index c44d1215dc..afdad2065f 100644 --- a/packages/medusa/src/api/routes/admin/orders/update-order.ts +++ b/packages/medusa/src/api/routes/admin/orders/update-order.ts @@ -8,13 +8,11 @@ import { IsString, ValidateNested, } from "class-validator" -import { defaultAdminOrdersFields, defaultAdminOrdersRelations } from "." -import { AddressPayload } from "../../../../types/common" +import { AddressPayload, FindParams } from "../../../../types/common" import { EntityManager } from "typeorm" import { OrderService } from "../../../../services" import { Type } from "class-transformer" -import { validator } from "../../../../utils/validator" /** * @oas [post] /orders/{id} @@ -24,6 +22,8 @@ import { validator } from "../../../../utils/validator" * x-authenticated: true * parameters: * - (path) id=* {string} The ID of the Order. + * - (query) expand {string} Comma separated list of relations to include in the result. + * - (query) fields {string} Comma separated list of fields to include in the result. * requestBody: * content: * application/json: @@ -31,6 +31,7 @@ import { validator } from "../../../../utils/validator" * $ref: "#/components/schemas/AdminPostOrdersOrderReq" * x-codegen: * method: update + * params: AdminPostOrdersOrderParams * x-codeSamples: * - lang: JavaScript * label: JS Client @@ -82,20 +83,17 @@ import { validator } from "../../../../utils/validator" export default async (req, res) => { const { id } = req.params - const value = await validator(AdminPostOrdersOrderReq, req.body) - const orderService: OrderService = req.scope.resolve("orderService") const manager: EntityManager = req.scope.resolve("manager") await manager.transaction(async (transactionManager) => { return await orderService .withTransaction(transactionManager) - .update(id, value) + .update(id, req.validatedBody) }) - const order = await orderService.retrieve(id, { - select: defaultAdminOrdersFields, - relations: defaultAdminOrdersRelations, + const order = await orderService.retrieveWithTotals(id, req.retrieveConfig, { + includes: req.includes, }) res.status(200).json({ order }) @@ -244,3 +242,5 @@ class ShippingMethod { @IsOptional() items?: Record[] } + +export class AdminPostOrdersOrderParams extends FindParams {} diff --git a/packages/medusa/src/models/order.ts b/packages/medusa/src/models/order.ts index 06453adb1d..f0bbc72758 100644 --- a/packages/medusa/src/models/order.ts +++ b/packages/medusa/src/models/order.ts @@ -257,6 +257,8 @@ export class Order extends BaseEntity { gift_card_total: number gift_card_tax_total: number + returnable_items?: LineItem[] + @BeforeInsert() private async beforeInsert(): Promise { this.id = generateEntityId(this.id, "order") @@ -547,6 +549,11 @@ export class Order extends BaseEntity { * description: The total of gift cards with taxes * type: integer * example: 0 + * returnable_items: + * description: The items that are returnable as part of the order, order swaps or order claims + * type: array + * items: + * $ref: "#/components/schemas/LineItem" * created_at: * description: The date with timezone at which the resource was created. * type: string diff --git a/packages/medusa/src/services/order.ts b/packages/medusa/src/services/order.ts index 5bea5d912e..165c48d153 100644 --- a/packages/medusa/src/services/order.ts +++ b/packages/medusa/src/services/order.ts @@ -26,7 +26,7 @@ import { CreateFulfillmentOrder, FulFillmentItemType, } from "../types/fulfillment" -import { UpdateOrderInput } from "../types/orders" +import { TotalsContext, UpdateOrderInput } from "../types/orders" import { CreateShippingMethodDto } from "../types/shipping-options" import { buildQuery, isString, setMetadata } from "../utils" import { FlagRouter } from "../utils/flag-router" @@ -77,10 +77,6 @@ type InjectedDependencies = { productVariantInventoryService: ProductVariantInventoryService } -type TotalsConfig = { - force_taxes?: boolean -} - class OrderService extends TransactionBaseService { static readonly Events = { GIFT_CARD_CREATED: "order.gift_card_created", @@ -422,12 +418,12 @@ class OrderService extends TransactionBaseService { async retrieveWithTotals( orderId: string, options: FindConfig = {}, - totalsConfig: TotalsConfig = {} + context: TotalsContext = {} ): Promise { const relations = this.getTotalsRelations(options) const order = await this.retrieve(orderId, { ...options, relations }) - return await this.decorateTotals(order, totalsConfig) + return await this.decorateTotals(order, context) } /** @@ -1702,17 +1698,24 @@ class OrderService extends TransactionBaseService { return order } + async decorateTotals(order: Order, totalsFields?: string[]): Promise + + async decorateTotals(order: Order, context?: TotalsContext): Promise + /** * Calculate and attach the different total fields on the object * @param order - * @param totalsFieldsOrConfig + * @param totalsFieldsOrContext */ async decorateTotals( order: Order, - totalsFieldsOrConfig?: string[] | TotalsConfig + totalsFieldsOrContext?: string[] | TotalsContext ): Promise { - if (Array.isArray(totalsFieldsOrConfig)) { - return await this.decorateTotalsLegacy(order, totalsFieldsOrConfig) + if (Array.isArray(totalsFieldsOrContext)) { + if (totalsFieldsOrContext.length) { + return await this.decorateTotalsLegacy(order, totalsFieldsOrContext) + } + totalsFieldsOrContext = {} } const manager = this.transactionManager_ ?? this.manager_ @@ -1721,10 +1724,31 @@ class OrderService extends TransactionBaseService { const calculationContext = await this.totalsService_.getCalculationContext( order ) - const orderItems = [...(order.items ?? [])] + + const { returnable_items } = totalsFieldsOrContext?.includes ?? {} + + const returnableItems: LineItem[] | undefined = isDefined(returnable_items) + ? [] + : undefined + + const isReturnableItem = (item) => + returnable_items && + (item.returned_quantity ?? 0) < (item.shipped_quantity ?? 0) + + const allItems: LineItem[] = [...(order.items ?? [])] + + if (returnable_items) { + // All items must receive their totals and if some of them are returnable + // They will be pushed to `returnable_items` at a later point + allItems.push( + ...(order.swaps?.map((s) => s.additional_items ?? []).flat() ?? []), + ...(order.claims?.map((c) => c.additional_items ?? []).flat() ?? []) + ) + } + const orderShippingMethods = [...(order.shipping_methods ?? [])] - const itemsTotals = await newTotalsServiceTx.getLineItemTotals(orderItems, { + const itemsTotals = await newTotalsServiceTx.getLineItemTotals(allItems, { taxRate: order.tax_rate, includeTax: true, calculationContext, @@ -1752,28 +1776,23 @@ class OrderService extends TransactionBaseService { let shipping_tax_total = 0 order.items = (order.items || []).map((item) => { - const refundable = newTotalsServiceTx.getLineItemRefund( - { - ...item, - quantity: item.quantity - (item.returned_quantity || 0), - }, - { - calculationContext, - taxRate: order.tax_rate, - } - ) + item.quantity = item.quantity - (item.returned_quantity || 0) + const refundable = newTotalsServiceTx.getLineItemRefund(item, { + calculationContext, + taxRate: order.tax_rate, + }) - const itemWithTotals = { - ...item, - ...(itemsTotals[item.id] ?? {}), - refundable, + Object.assign(item, itemsTotals[item.id] ?? {}, { refundable }) + + order.subtotal += item.subtotal ?? 0 + order.discount_total += item.discount_total ?? 0 + item_tax_total += item.tax_total ?? 0 + + if (isReturnableItem(item)) { + returnableItems?.push(item) } - order.subtotal += itemWithTotals.subtotal ?? 0 - order.discount_total += itemWithTotals.discount_total ?? 0 - item_tax_total += itemWithTotals.tax_total ?? 0 - - return itemWithTotals as LineItem + return item }) order.shipping_methods = (order.shipping_methods || []).map( @@ -1806,32 +1825,36 @@ class OrderService extends TransactionBaseService { for (const swap of order.swaps ?? []) { swap.additional_items = swap.additional_items.map((item) => { - item.refundable = newTotalsServiceTx.getLineItemRefund( - { - ...item, - quantity: item.quantity - (item.returned_quantity || 0), - }, - { - calculationContext, - taxRate: order.tax_rate, - } - ) + item.quantity = item.quantity - (item.returned_quantity || 0) + const refundable = newTotalsServiceTx.getLineItemRefund(item, { + calculationContext, + taxRate: order.tax_rate, + }) + + Object.assign(item, itemsTotals[item.id] ?? {}, { refundable }) + + if (isReturnableItem(item)) { + returnableItems?.push(item) + } + return item }) } for (const claim of order.claims ?? []) { claim.additional_items = claim.additional_items.map((item) => { - item.refundable = newTotalsServiceTx.getLineItemRefund( - { - ...item, - quantity: item.quantity - (item.returned_quantity || 0), - }, - { - calculationContext, - taxRate: order.tax_rate, - } - ) + item.quantity = item.quantity - (item.returned_quantity || 0) + const refundable = newTotalsServiceTx.getLineItemRefund(item, { + calculationContext, + taxRate: order.tax_rate, + }) + + Object.assign(item, itemsTotals[item.id] ?? {}, { refundable }) + + if (isReturnableItem(item)) { + returnableItems?.push(item) + } + return item }) } @@ -1842,6 +1865,8 @@ class OrderService extends TransactionBaseService { order.tax_total - (order.gift_card_total + order.discount_total) + order.returnable_items = returnableItems + return order } diff --git a/packages/medusa/src/types/orders.ts b/packages/medusa/src/types/orders.ts index 30b02e3472..e3127f4959 100644 --- a/packages/medusa/src/types/orders.ts +++ b/packages/medusa/src/types/orders.ts @@ -17,6 +17,11 @@ export function isOrder(object: any): object is Order { return object.object === "order" } +export type TotalsContext = { + force_taxes?: boolean + includes?: { returnable_items?: boolean } +} + enum OrderStatus { pending = "pending", completed = "completed",