feat: add a line item to an order edit (#2243)

**What**
- Implement adding a line item to order (edit)

**How**
- _by implementing the following "flow"_
  - generate a line item
  - computing line item adjustments for that line item
  - creating tax lines
  - creating a change record

**Testing**
- **_integration tests_**
  - check if line item and order item change objects are created (with correct tax lines)
  - line item adjustments are generated if
    - fixed discount is applied to cart
    - percentage discount is applied
- **_unit tests_** 
  - ensure that methods from Inventory, LineItem, LineItemAdjustment etc. services are called 

---

RESOLVES CORE-495
This commit is contained in:
Frane Polić
2022-09-28 11:51:13 +00:00
committed by GitHub
parent 474e97252c
commit 884f36e8a8
19 changed files with 679 additions and 80 deletions
@@ -3,13 +3,7 @@ import {
DraftOrderService,
LineItemService,
} from "../../../../services"
import {
IsBoolean,
IsInt,
IsObject,
IsOptional,
IsString,
} from "class-validator"
import { IsInt, IsObject, IsOptional, IsString } from "class-validator"
import {
defaultAdminDraftOrdersCartFields,
defaultAdminDraftOrdersCartRelations,
@@ -17,7 +11,6 @@ import {
} from "."
import { EntityManager } from "typeorm"
import { FlagRouter } from "../../../../utils/flag-router"
import { MedusaError } from "medusa-core-utils"
import { validator } from "../../../../utils/validator"
@@ -0,0 +1,101 @@
import { Request, Response } from "express"
import { IsInt, IsOptional, IsString } from "class-validator"
import { EntityManager } from "typeorm"
import { OrderEditService } from "../../../../services"
import {
defaultOrderEditFields,
defaultOrderEditRelations,
} from "../../../../types/order-edit"
/**
* @oas [post] /order-edits/{id}/items
* operationId: "PostOrderEditsEditLineItems"
* summary: "Add an line item to an order (edit)"
* description: "Create an OrderEdit LineItem."
* parameters:
* - (path) id=* {string} The ID of the Order Edit.
* x-authenticated: true
* x-codeSamples:
* - lang: JavaScript
* label: JS Client
* source: |
* import Medusa from "@medusajs/medusa-js"
* const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 })
* // must be previously logged in or use api token
* medusa.admin.orderEdit.addLineItem(order_edit_id, { variant_id, quantity })
* .then(({ order_edit }) => {
* console.log(order_edit.id)
* })
* - lang: Shell
* label: cURL
* source: |
* curl --location --request POST 'https://medusa-url.com/admin/order-edits/{id}/items' \
* --header 'Authorization: Bearer {api_token}'
* -d '{ "variant_id": "some_variant_id", "quantity": 3 }'
* security:
* - api_token: []
* - cookie_auth: []
* tags:
* - OrderEdit
* responses:
* 200:
* description: OK
* content:
* application/json:
* schema:
* properties:
* order_edit:
* $ref: "#/components/schemas/order_edit"
* "400":
* $ref: "#/components/responses/400_error"
* "401":
* $ref: "#/components/responses/unauthorized"
* "404":
* $ref: "#/components/responses/not_found_error"
* "409":
* $ref: "#/components/responses/invalid_state_error"
* "422":
* $ref: "#/components/responses/invalid_request_error"
* "500":
* $ref: "#/components/responses/500_error"
*/
export default async (req: Request, res: Response) => {
const orderEditService = req.scope.resolve(
"orderEditService"
) as OrderEditService
const { id } = req.params
const manager = req.scope.resolve("manager") as EntityManager
const data = req.validatedBody as AdminPostOrderEditsEditLineItemsReq
await manager.transaction(async (transactionManager) => {
await orderEditService
.withTransaction(transactionManager)
.addLineItem(id, data)
})
let orderEdit = await orderEditService.retrieve(id, {
select: defaultOrderEditFields,
relations: defaultOrderEditRelations,
})
orderEdit = await orderEditService.decorateTotals(orderEdit)
res.status(200).send({
order_edit: orderEdit,
})
}
export class AdminPostOrderEditsEditLineItemsReq {
@IsString()
variant_id: string
@IsInt()
quantity: number
@IsOptional()
metadata?: Record<string, unknown> | undefined
}
@@ -8,7 +8,7 @@ import { OrderEditService } from "../../../../services"
* description: "Deletes an Order Edit"
* x-authenticated: true
* parameters:
* - (path) id=* {string} The ID of the Note to delete.
* - (path) id=* {string} The ID of the Order Edit to delete.
* x-codeSamples:
* - lang: JavaScript
* label: JS Client
@@ -14,6 +14,7 @@ import {
import { OrderEdit } from "../../../../models"
import { AdminPostOrderEditsOrderEditReq } from "./update-order-edit"
import { AdminPostOrderEditsReq } from "./create-order-edit"
import { AdminPostOrderEditsEditLineItemsReq } from "./add-line-item"
import { AdminPostOrderEditsEditLineItemsLineItemReq } from "./update-order-edit-line-item"
const route = Router()
@@ -52,6 +53,12 @@ export default (app) => {
middlewares.wrap(require("./cancel-order-edit").default)
)
route.post(
"/:id/items",
transformBody(AdminPostOrderEditsEditLineItemsReq),
middlewares.wrap(require("./add-line-item").default)
)
route.delete("/:id", middlewares.wrap(require("./delete-order-edit").default))
route.delete(
@@ -86,3 +93,5 @@ export type AdminOrderEditItemChangeDeleteRes = {
export * from "./update-order-edit"
export * from "./update-order-edit-line-item"
export * from "./create-order-edit"
export * from "./add-line-item"