feat: Line Items API Routes (#6478)

**What**
- `POST /store/carts/:id/line-items`
- `POST /store/carts/:id/line-items/:id`
- `DELETE /store/carts/:id/line-items/:id`

**Outstanding**
- Integration tests
- Module integrations: Payment, Fulfillment, Promotions

Depends on #6475 and #6449.
This commit is contained in:
Oli Juhl
2024-02-27 12:47:00 +00:00
committed by GitHub
parent f5c2256286
commit 3ee0f599c1
30 changed files with 937 additions and 208 deletions
@@ -2,3 +2,5 @@ export * from "./add-to-cart"
export * from "./create-carts"
export * from "./update-cart"
export * from "./update-cart-promotions"
export * from "./update-line-item-in-cart"
@@ -0,0 +1,62 @@
import { UpdateLineItemInCartWorkflowInputDTO } from "@medusajs/types"
import {
WorkflowData,
createWorkflow,
transform,
} from "@medusajs/workflows-sdk"
import { getVariantPriceSetsStep } from ".."
import { updateLineItemsStep } from "../../line-item/steps"
// TODO: The UpdateLineItemsWorkflow are missing the following steps:
// - Confirm inventory exists (inventory module)
// - Validate shipping methods for new items (fulfillment module)
// - Refresh line item adjustments (promotion module)
// - Update payment sessions (payment module)
export const updateLineItemInCartWorkflowId = "update-line-item-in-cart"
export const updateLineItemInCartWorkflow = createWorkflow(
updateLineItemInCartWorkflowId,
(input: WorkflowData<UpdateLineItemInCartWorkflowInputDTO>) => {
const item = transform({ input }, (data) => data.input.item)
const pricingContext = transform({ cart: input.cart, item }, (data) => {
return {
currency_code: data.cart.currency_code,
region_id: data.cart.region_id,
customer_id: data.cart.customer_id,
}
})
const variantIds = transform({ input }, (data) => [
data.input.item.variant_id!,
])
const priceSets = getVariantPriceSetsStep({
variantIds,
context: pricingContext,
})
const lineItemUpdate = transform({ input, priceSets, item }, (data) => {
const price = data.priceSets[data.item.variant_id!].calculated_amount
return {
data: {
...data.input.update,
unit_price: price,
},
selector: {
id: data.input.item.id,
},
}
})
const result = updateLineItemsStep({
data: lineItemUpdate.data,
selector: lineItemUpdate.selector,
})
const updatedItem = transform({ result }, (data) => data.result?.[0])
return updatedItem
}
)
@@ -1,4 +1,6 @@
export * from "./cart"
export * from "./inventory"
export * from "./line-item"
export * from "./price-list"
export * from "./product"
@@ -0,0 +1,2 @@
export * from "./steps"
export * from "./workflows"
@@ -0,0 +1,27 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { ICartModuleService } from "@medusajs/types"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
export const deleteLineItemsStepId = "delete-line-items"
export const deleteLineItemsStep = createStep(
deleteLineItemsStepId,
async (ids: string[], { container }) => {
const service = container.resolve<ICartModuleService>(
ModuleRegistrationName.CART
)
await service.removeLineItems(ids)
return new StepResponse(void 0, ids)
},
async (ids, { container }) => {
if (!ids?.length) {
return
}
const service = container.resolve<ICartModuleService>(
ModuleRegistrationName.CART
)
await service.restoreLineItems(ids)
}
)
@@ -0,0 +1,3 @@
export * from "./delete-line-items"
export * from "./list-line-items"
export * from "./update-line-items"
@@ -0,0 +1,27 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import {
CartLineItemDTO,
FilterableLineItemProps,
FindConfig,
ICartModuleService,
} from "@medusajs/types"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
interface StepInput {
filters: FilterableLineItemProps
config?: FindConfig<CartLineItemDTO>
}
export const listLineItemsStepId = "list-line-items"
export const listLineItemsStep = createStep(
listLineItemsStepId,
async (data: StepInput, { container }) => {
const service = container.resolve<ICartModuleService>(
ModuleRegistrationName.CART
)
const items = await service.listLineItems(data.filters, data.config)
return new StepResponse(items)
}
)
@@ -0,0 +1,59 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import {
ICartModuleService,
UpdateLineItemWithSelectorDTO,
} from "@medusajs/types"
import {
getSelectsAndRelationsFromObjectArray,
promiseAll,
removeUndefined,
} from "@medusajs/utils"
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
export const updateLineItemsStepId = "update-line-items"
export const updateLineItemsStep = createStep(
updateLineItemsStepId,
async (input: UpdateLineItemWithSelectorDTO, { container }) => {
const service = container.resolve<ICartModuleService>(
ModuleRegistrationName.CART
)
const { selects, relations } = getSelectsAndRelationsFromObjectArray([
input.data,
])
const itemsBefore = await service.listLineItems(input.selector, {
select: selects,
relations,
})
const items = await service.updateLineItems(input.selector, input.data)
return new StepResponse(items, itemsBefore)
},
async (itemsBefore, { container }) => {
if (!itemsBefore) {
return
}
const service = container.resolve<ICartModuleService>(
ModuleRegistrationName.CART
)
await promiseAll(
itemsBefore.map(async (i) =>
service.updateLineItems(
i.id,
removeUndefined({
quantity: i.quantity,
title: i.title,
metadata: i.metadata,
unit_price: i.unit_price,
tax_lines: i.tax_lines,
adjustments: i.adjustments,
})
)
)
)
}
)
@@ -0,0 +1,17 @@
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
import { deleteLineItemsStep } from "../steps/delete-line-items"
type WorkflowInput = { ids: string[] }
// TODO: The DeleteLineItemsWorkflow are missing the following steps:
// - Refresh/delete shipping methods (fulfillment module)
// - Refresh line item adjustments (promotion module)
// - Update payment sessions (payment module)
export const deleteLineItemsWorkflowId = "delete-line-items"
export const deleteLineItemsWorkflow = createWorkflow(
deleteLineItemsWorkflowId,
(input: WorkflowData<WorkflowInput>) => {
return deleteLineItemsStep(input.ids)
}
)
@@ -0,0 +1 @@
export * from "./delete-line-items"