feat(medusa,core-flows): update cart adjustments on item updates (#6539)
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/core-flows": patch
|
||||||
|
"@medusajs/medusa": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
feat(medusa,core-flows): update cart adjustments on item updates
|
||||||
@@ -134,7 +134,6 @@ describe("Store Carts API: Add promotions to cart", () => {
|
|||||||
id: "item-1",
|
id: "item-1",
|
||||||
adjustments: expect.arrayContaining([
|
adjustments: expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
promotion_id: createdPromotion.id,
|
|
||||||
code: createdPromotion.code,
|
code: createdPromotion.code,
|
||||||
amount: 1000,
|
amount: 1000,
|
||||||
}),
|
}),
|
||||||
@@ -144,7 +143,6 @@ describe("Store Carts API: Add promotions to cart", () => {
|
|||||||
adjustments: expect.arrayContaining([
|
adjustments: expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: expect.not.stringContaining(lineItemAdjustment.id),
|
id: expect.not.stringContaining(lineItemAdjustment.id),
|
||||||
promotion_id: appliedPromotion.id,
|
|
||||||
code: appliedPromotion.code,
|
code: appliedPromotion.code,
|
||||||
amount: 300,
|
amount: 300,
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -557,10 +557,6 @@ describe("Store Carts API", () => {
|
|||||||
|
|
||||||
describe("POST /store/carts/:id/line-items", () => {
|
describe("POST /store/carts/:id/line-items", () => {
|
||||||
it("should add item to cart", async () => {
|
it("should add item to cart", async () => {
|
||||||
const cart = await cartModuleService.create({
|
|
||||||
currency_code: "usd",
|
|
||||||
})
|
|
||||||
|
|
||||||
const [product] = await productModule.create([
|
const [product] = await productModule.create([
|
||||||
{
|
{
|
||||||
title: "Test product",
|
title: "Test product",
|
||||||
@@ -572,6 +568,48 @@ describe("Store Carts API", () => {
|
|||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
|
const cart = await cartModuleService.create({
|
||||||
|
currency_code: "usd",
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: "item-1",
|
||||||
|
unit_price: 2000,
|
||||||
|
quantity: 1,
|
||||||
|
title: "Test item",
|
||||||
|
product_id: "prod_mat",
|
||||||
|
} as any,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
const appliedPromotion = await promotionModule.create({
|
||||||
|
code: "PROMOTION_APPLIED",
|
||||||
|
type: PromotionType.STANDARD,
|
||||||
|
application_method: {
|
||||||
|
type: "fixed",
|
||||||
|
target_type: "items",
|
||||||
|
allocation: "across",
|
||||||
|
value: "300",
|
||||||
|
apply_to_quantity: 2,
|
||||||
|
target_rules: [
|
||||||
|
{
|
||||||
|
attribute: "product_id",
|
||||||
|
operator: "in",
|
||||||
|
values: ["prod_mat", product.id],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const [lineItemAdjustment] =
|
||||||
|
await cartModuleService.addLineItemAdjustments([
|
||||||
|
{
|
||||||
|
code: appliedPromotion.code!,
|
||||||
|
amount: 300,
|
||||||
|
item_id: "item-1",
|
||||||
|
promotion_id: appliedPromotion.id,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
const priceSet = await pricingModule.create({
|
const priceSet = await pricingModule.create({
|
||||||
prices: [
|
prices: [
|
||||||
{
|
{
|
||||||
@@ -608,6 +646,24 @@ describe("Store Carts API", () => {
|
|||||||
unit_price: 3000,
|
unit_price: 3000,
|
||||||
quantity: 1,
|
quantity: 1,
|
||||||
title: "Test variant",
|
title: "Test variant",
|
||||||
|
adjustments: [
|
||||||
|
expect.objectContaining({
|
||||||
|
code: "PROMOTION_APPLIED",
|
||||||
|
amount: 180,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
unit_price: 2000,
|
||||||
|
quantity: 1,
|
||||||
|
title: "Test item",
|
||||||
|
adjustments: [
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.not.stringContaining(lineItemAdjustment.id),
|
||||||
|
code: "PROMOTION_APPLIED",
|
||||||
|
amount: 120,
|
||||||
|
}),
|
||||||
|
],
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -14,4 +14,3 @@ export * from "./remove-shipping-method-adjustments"
|
|||||||
export * from "./retrieve-cart"
|
export * from "./retrieve-cart"
|
||||||
export * from "./update-carts"
|
export * from "./update-carts"
|
||||||
export * from "./validate-variants-existence"
|
export * from "./validate-variants-existence"
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { PromotionActions } from "@medusajs/utils"
|
||||||
|
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||||
|
import { updateCartPromotionsWorkflow } from "../workflows"
|
||||||
|
|
||||||
|
interface StepInput {
|
||||||
|
id: string
|
||||||
|
promo_codes?: string[]
|
||||||
|
action?:
|
||||||
|
| PromotionActions.ADD
|
||||||
|
| PromotionActions.REMOVE
|
||||||
|
| PromotionActions.REPLACE
|
||||||
|
}
|
||||||
|
|
||||||
|
export const refreshCartPromotionsStepId = "refresh-cart-promotions"
|
||||||
|
export const refreshCartPromotionsStep = createStep(
|
||||||
|
refreshCartPromotionsStepId,
|
||||||
|
async (data: StepInput, { container }) => {
|
||||||
|
const { promo_codes = [], id, action = PromotionActions.ADD } = data
|
||||||
|
|
||||||
|
await updateCartPromotionsWorkflow(container).run({
|
||||||
|
input: {
|
||||||
|
action,
|
||||||
|
promoCodes: promo_codes,
|
||||||
|
cartId: id,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return new StepResponse(null)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
getVariantsStep,
|
getVariantsStep,
|
||||||
validateVariantsExistStep,
|
validateVariantsExistStep,
|
||||||
} from "../steps"
|
} from "../steps"
|
||||||
|
import { refreshCartPromotionsStep } from "../steps/refresh-cart-promotions"
|
||||||
import { prepareLineItemData } from "../utils/prepare-line-item-data"
|
import { prepareLineItemData } from "../utils/prepare-line-item-data"
|
||||||
|
|
||||||
// TODO: The AddToCartWorkflow are missing the following steps:
|
// TODO: The AddToCartWorkflow are missing the following steps:
|
||||||
@@ -70,6 +71,8 @@ export const addToCartWorkflow = createWorkflow(
|
|||||||
|
|
||||||
const items = addToCartStep({ items: lineItems })
|
const items = addToCartStep({ items: lineItems })
|
||||||
|
|
||||||
|
refreshCartPromotionsStep({ id: input.cart.id })
|
||||||
|
|
||||||
return items
|
return items
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import { CartDTO } from "@medusajs/types"
|
|
||||||
import { PromotionActions } from "@medusajs/utils"
|
import { PromotionActions } from "@medusajs/utils"
|
||||||
import {
|
import {
|
||||||
WorkflowData,
|
WorkflowData,
|
||||||
@@ -27,7 +26,7 @@ type WorkflowInput = {
|
|||||||
export const updateCartPromotionsWorkflowId = "update-cart-promotions"
|
export const updateCartPromotionsWorkflowId = "update-cart-promotions"
|
||||||
export const updateCartPromotionsWorkflow = createWorkflow(
|
export const updateCartPromotionsWorkflow = createWorkflow(
|
||||||
updateCartPromotionsWorkflowId,
|
updateCartPromotionsWorkflowId,
|
||||||
(input: WorkflowData<WorkflowInput>): WorkflowData<CartDTO> => {
|
(input: WorkflowData<WorkflowInput>): WorkflowData<void> => {
|
||||||
const retrieveCartInput = {
|
const retrieveCartInput = {
|
||||||
id: input.cartId,
|
id: input.cartId,
|
||||||
config: {
|
config: {
|
||||||
@@ -65,9 +64,5 @@ export const updateCartPromotionsWorkflow = createWorkflow(
|
|||||||
createLineItemAdjustmentsStep({ lineItemAdjustmentsToCreate }),
|
createLineItemAdjustmentsStep({ lineItemAdjustmentsToCreate }),
|
||||||
createShippingMethodAdjustmentsStep({ shippingMethodAdjustmentsToCreate })
|
createShippingMethodAdjustmentsStep({ shippingMethodAdjustmentsToCreate })
|
||||||
)
|
)
|
||||||
|
|
||||||
return retrieveCartStep(retrieveCartInput).config({
|
|
||||||
name: "retrieve-cart-result-step",
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -7,35 +7,18 @@ import {
|
|||||||
transform,
|
transform,
|
||||||
} from "@medusajs/workflows-sdk"
|
} from "@medusajs/workflows-sdk"
|
||||||
import {
|
import {
|
||||||
createLineItemAdjustmentsStep,
|
|
||||||
createShippingMethodAdjustmentsStep,
|
|
||||||
findOneOrAnyRegionStep,
|
findOneOrAnyRegionStep,
|
||||||
findOrCreateCustomerStep,
|
findOrCreateCustomerStep,
|
||||||
findSalesChannelStep,
|
findSalesChannelStep,
|
||||||
getActionsToComputeFromPromotionsStep,
|
|
||||||
prepareAdjustmentsFromPromotionActionsStep,
|
|
||||||
removeLineItemAdjustmentsStep,
|
|
||||||
removeShippingMethodAdjustmentsStep,
|
|
||||||
retrieveCartStep,
|
retrieveCartStep,
|
||||||
updateCartsStep,
|
updateCartsStep,
|
||||||
} from "../steps"
|
} from "../steps"
|
||||||
|
import { refreshCartPromotionsStep } from "../steps/refresh-cart-promotions"
|
||||||
|
|
||||||
export const updateCartWorkflowId = "update-cart"
|
export const updateCartWorkflowId = "update-cart"
|
||||||
export const updateCartWorkflow = createWorkflow(
|
export const updateCartWorkflow = createWorkflow(
|
||||||
updateCartWorkflowId,
|
updateCartWorkflowId,
|
||||||
(input: WorkflowData<UpdateCartWorkflowInputDTO>): WorkflowData<CartDTO> => {
|
(input: WorkflowData<UpdateCartWorkflowInputDTO>): WorkflowData<CartDTO> => {
|
||||||
const retrieveCartInput = {
|
|
||||||
id: input.id,
|
|
||||||
config: {
|
|
||||||
relations: [
|
|
||||||
"items",
|
|
||||||
"items.adjustments",
|
|
||||||
"shipping_methods",
|
|
||||||
"shipping_methods.adjustments",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
const [salesChannel, region, customerData] = parallelize(
|
const [salesChannel, region, customerData] = parallelize(
|
||||||
findSalesChannelStep({
|
findSalesChannelStep({
|
||||||
salesChannelId: input.sales_channel_id,
|
salesChannelId: input.sales_channel_id,
|
||||||
@@ -79,34 +62,24 @@ export const updateCartWorkflow = createWorkflow(
|
|||||||
|
|
||||||
updateCartsStep([cartInput])
|
updateCartsStep([cartInput])
|
||||||
|
|
||||||
const cart = retrieveCartStep(retrieveCartInput)
|
refreshCartPromotionsStep({
|
||||||
const actions = getActionsToComputeFromPromotionsStep({
|
id: input.id,
|
||||||
cart,
|
promo_codes: input.promo_codes,
|
||||||
promoCodes: input.promo_codes,
|
|
||||||
action: PromotionActions.REPLACE,
|
action: PromotionActions.REPLACE,
|
||||||
})
|
})
|
||||||
|
|
||||||
const {
|
const retrieveCartInput = {
|
||||||
lineItemAdjustmentsToCreate,
|
id: input.id,
|
||||||
lineItemAdjustmentIdsToRemove,
|
config: {
|
||||||
shippingMethodAdjustmentsToCreate,
|
relations: [
|
||||||
shippingMethodAdjustmentIdsToRemove,
|
"items",
|
||||||
} = prepareAdjustmentsFromPromotionActionsStep({ actions })
|
"items.adjustments",
|
||||||
|
"shipping_methods",
|
||||||
|
"shipping_methods.adjustments",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
parallelize(
|
return retrieveCartStep(retrieveCartInput)
|
||||||
removeLineItemAdjustmentsStep({ lineItemAdjustmentIdsToRemove }),
|
|
||||||
removeShippingMethodAdjustmentsStep({
|
|
||||||
shippingMethodAdjustmentIdsToRemove,
|
|
||||||
})
|
|
||||||
)
|
|
||||||
|
|
||||||
parallelize(
|
|
||||||
createLineItemAdjustmentsStep({ lineItemAdjustmentsToCreate }),
|
|
||||||
createShippingMethodAdjustmentsStep({ shippingMethodAdjustmentsToCreate })
|
|
||||||
)
|
|
||||||
|
|
||||||
return retrieveCartStep(retrieveCartInput).config({
|
|
||||||
name: "retrieve-cart-result-step",
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
} from "@medusajs/workflows-sdk"
|
} from "@medusajs/workflows-sdk"
|
||||||
import { getVariantPriceSetsStep } from ".."
|
import { getVariantPriceSetsStep } from ".."
|
||||||
import { updateLineItemsStep } from "../../line-item/steps"
|
import { updateLineItemsStep } from "../../line-item/steps"
|
||||||
|
import { refreshCartPromotionsStep } from "../steps/refresh-cart-promotions"
|
||||||
|
|
||||||
// TODO: The UpdateLineItemsWorkflow are missing the following steps:
|
// TODO: The UpdateLineItemsWorkflow are missing the following steps:
|
||||||
// - Confirm inventory exists (inventory module)
|
// - Confirm inventory exists (inventory module)
|
||||||
@@ -55,6 +56,8 @@ export const updateLineItemInCartWorkflow = createWorkflow(
|
|||||||
selector: lineItemUpdate.selector,
|
selector: lineItemUpdate.selector,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
refreshCartPromotionsStep({ id: input.cart.id })
|
||||||
|
|
||||||
const updatedItem = transform({ result }, (data) => data.result?.[0])
|
const updatedItem = transform({ result }, (data) => data.result?.[0])
|
||||||
|
|
||||||
return updatedItem
|
return updatedItem
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
import { updateCartPromotionsWorkflow } from "@medusajs/core-flows"
|
import { updateCartPromotionsWorkflow } from "@medusajs/core-flows"
|
||||||
import { PromotionActions } from "@medusajs/utils"
|
import { PromotionActions, remoteQueryObjectFromString } from "@medusajs/utils"
|
||||||
import { MedusaRequest, MedusaResponse } from "../../../../../types/routing"
|
import { MedusaRequest, MedusaResponse } from "../../../../../types/routing"
|
||||||
|
import { defaultStoreCartFields } from "../../query-config"
|
||||||
import { StorePostCartsCartPromotionsReq } from "../../validators"
|
import { StorePostCartsCartPromotionsReq } from "../../validators"
|
||||||
|
|
||||||
export const POST = async (req: MedusaRequest, res: MedusaResponse) => {
|
export const POST = async (req: MedusaRequest, res: MedusaResponse) => {
|
||||||
|
const remoteQuery = req.scope.resolve("remoteQuery")
|
||||||
const workflow = updateCartPromotionsWorkflow(req.scope)
|
const workflow = updateCartPromotionsWorkflow(req.scope)
|
||||||
const payload = req.validatedBody as StorePostCartsCartPromotionsReq
|
const payload = req.validatedBody as StorePostCartsCartPromotionsReq
|
||||||
|
|
||||||
const { result, errors } = await workflow.run({
|
const { errors } = await workflow.run({
|
||||||
input: {
|
input: {
|
||||||
promoCodes: payload.promo_codes,
|
promoCodes: payload.promo_codes,
|
||||||
cartId: req.params.id,
|
cartId: req.params.id,
|
||||||
@@ -20,14 +22,24 @@ export const POST = async (req: MedusaRequest, res: MedusaResponse) => {
|
|||||||
throw errors[0].error
|
throw errors[0].error
|
||||||
}
|
}
|
||||||
|
|
||||||
res.status(200).json({ cart: result })
|
const query = remoteQueryObjectFromString({
|
||||||
|
entryPoint: "cart",
|
||||||
|
fields: defaultStoreCartFields,
|
||||||
|
})
|
||||||
|
|
||||||
|
const [cart] = await remoteQuery(query, {
|
||||||
|
cart: { id: req.params.id },
|
||||||
|
})
|
||||||
|
|
||||||
|
res.status(200).json({ cart })
|
||||||
}
|
}
|
||||||
|
|
||||||
export const DELETE = async (req: MedusaRequest, res: MedusaResponse) => {
|
export const DELETE = async (req: MedusaRequest, res: MedusaResponse) => {
|
||||||
|
const remoteQuery = req.scope.resolve("remoteQuery")
|
||||||
const workflow = updateCartPromotionsWorkflow(req.scope)
|
const workflow = updateCartPromotionsWorkflow(req.scope)
|
||||||
const payload = req.validatedBody as StorePostCartsCartPromotionsReq
|
const payload = req.validatedBody as StorePostCartsCartPromotionsReq
|
||||||
|
|
||||||
const { result, errors } = await workflow.run({
|
const { errors } = await workflow.run({
|
||||||
input: {
|
input: {
|
||||||
promoCodes: payload.promo_codes,
|
promoCodes: payload.promo_codes,
|
||||||
cartId: req.params.id,
|
cartId: req.params.id,
|
||||||
@@ -40,5 +52,14 @@ export const DELETE = async (req: MedusaRequest, res: MedusaResponse) => {
|
|||||||
throw errors[0].error
|
throw errors[0].error
|
||||||
}
|
}
|
||||||
|
|
||||||
res.status(200).json({ cart: result })
|
const query = remoteQueryObjectFromString({
|
||||||
|
entryPoint: "cart",
|
||||||
|
fields: defaultStoreCartFields,
|
||||||
|
})
|
||||||
|
|
||||||
|
const [cart] = await remoteQuery(query, {
|
||||||
|
cart: { id: req.params.id },
|
||||||
|
})
|
||||||
|
|
||||||
|
res.status(200).json({ cart })
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user