feat(core-flows,link-modules,modules-sdk): add cart <> promotion link as source of truth (#6561)
what: - adds promotion cart link - update steps to create and remove links
This commit is contained in:
+16
-42
@@ -1,15 +1,9 @@
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import { LinkModuleUtils, ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import { CartDTO, IPromotionModuleService } from "@medusajs/types"
|
||||
import { PromotionActions, deduplicate, isString } from "@medusajs/utils"
|
||||
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||
|
||||
interface StepInput {
|
||||
cart: CartDTO
|
||||
promoCodes?: string[]
|
||||
action:
|
||||
| PromotionActions.ADD
|
||||
| PromotionActions.REMOVE
|
||||
| PromotionActions.REPLACE
|
||||
}
|
||||
|
||||
export const getActionsToComputeFromPromotionsStepId =
|
||||
@@ -17,46 +11,26 @@ export const getActionsToComputeFromPromotionsStepId =
|
||||
export const getActionsToComputeFromPromotionsStep = createStep(
|
||||
getActionsToComputeFromPromotionsStepId,
|
||||
async (data: StepInput, { container }) => {
|
||||
const promotionModuleService: IPromotionModuleService = container.resolve(
|
||||
const { cart } = data
|
||||
const remoteQuery = container.resolve(LinkModuleUtils.REMOTE_QUERY)
|
||||
const promotionService = container.resolve<IPromotionModuleService>(
|
||||
ModuleRegistrationName.PROMOTION
|
||||
)
|
||||
|
||||
const { action = PromotionActions.ADD, promoCodes, cart } = data
|
||||
const existingCartPromotionLinks = await remoteQuery({
|
||||
cart_promotion: {
|
||||
__args: { cart_id: [cart.id] },
|
||||
fields: ["id", "cart_id", "promotion_id", "deleted_at"],
|
||||
},
|
||||
})
|
||||
|
||||
if (!Array.isArray(promoCodes)) {
|
||||
return new StepResponse([])
|
||||
}
|
||||
const existingPromotions = await promotionService.list(
|
||||
{ id: existingCartPromotionLinks.map((l) => l.promotion_id) },
|
||||
{ take: null, select: ["code"] }
|
||||
)
|
||||
|
||||
const appliedItemPromoCodes = cart.items
|
||||
?.map((item) => item.adjustments?.map((adjustment) => adjustment.code))
|
||||
.flat(1)
|
||||
.filter(isString) as string[]
|
||||
|
||||
const appliedShippingMethodPromoCodes = cart.shipping_methods
|
||||
?.map((shippingMethod) =>
|
||||
shippingMethod.adjustments?.map((adjustment) => adjustment.code)
|
||||
)
|
||||
.flat(1)
|
||||
.filter(isString) as string[]
|
||||
|
||||
let promotionCodesToApply = deduplicate([
|
||||
...promoCodes,
|
||||
...appliedItemPromoCodes,
|
||||
...appliedShippingMethodPromoCodes,
|
||||
])
|
||||
|
||||
if (action === PromotionActions.REMOVE) {
|
||||
promotionCodesToApply = promotionCodesToApply.filter(
|
||||
(code) => !promoCodes.includes(code)
|
||||
)
|
||||
}
|
||||
|
||||
if (action === PromotionActions.REPLACE) {
|
||||
promotionCodesToApply = promoCodes
|
||||
}
|
||||
|
||||
const actionsToCompute = await promotionModuleService.computeActions(
|
||||
promotionCodesToApply,
|
||||
const actionsToCompute = await promotionService.computeActions(
|
||||
existingPromotions.map((p) => p.code!),
|
||||
cart as any
|
||||
)
|
||||
|
||||
|
||||
@@ -12,5 +12,6 @@ export * from "./prepare-adjustments-from-promotion-actions"
|
||||
export * from "./remove-line-item-adjustments"
|
||||
export * from "./remove-shipping-method-adjustments"
|
||||
export * from "./retrieve-cart"
|
||||
export * from "./update-cart-promotions"
|
||||
export * from "./update-carts"
|
||||
export * from "./validate-variants-existence"
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
import {
|
||||
LinkModuleUtils,
|
||||
ModuleRegistrationName,
|
||||
Modules,
|
||||
} from "@medusajs/modules-sdk"
|
||||
import { IPromotionModuleService } from "@medusajs/types"
|
||||
import { PromotionActions } from "@medusajs/utils"
|
||||
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||
|
||||
interface StepInput {
|
||||
id: string
|
||||
promo_codes?: string[]
|
||||
action?:
|
||||
| PromotionActions.ADD
|
||||
| PromotionActions.REMOVE
|
||||
| PromotionActions.REPLACE
|
||||
}
|
||||
|
||||
export const updateCartPromotionsStepId = "update-cart-promotions"
|
||||
export const updateCartPromotionsStep = createStep(
|
||||
updateCartPromotionsStepId,
|
||||
async (data: StepInput, { container }) => {
|
||||
const { promo_codes = [], id, action = PromotionActions.ADD } = data
|
||||
|
||||
const remoteLink = container.resolve(LinkModuleUtils.REMOTE_LINK)
|
||||
const remoteQuery = container.resolve(LinkModuleUtils.REMOTE_QUERY)
|
||||
const promotionService = container.resolve<IPromotionModuleService>(
|
||||
ModuleRegistrationName.PROMOTION
|
||||
)
|
||||
|
||||
const existingCartPromotionLinks = await remoteQuery({
|
||||
cart_promotion: {
|
||||
__args: { cart_id: [id] },
|
||||
fields: ["cart_id", "promotion_id"],
|
||||
},
|
||||
})
|
||||
|
||||
const promotionLinkMap = new Map<string, any>(
|
||||
existingCartPromotionLinks.map((link) => [link.promotion_id, link])
|
||||
)
|
||||
|
||||
const promotions = await promotionService.list(
|
||||
{ code: promo_codes },
|
||||
{ select: ["id"] }
|
||||
)
|
||||
|
||||
const linksToCreate: any[] = []
|
||||
const linksToDismiss: any[] = []
|
||||
|
||||
for (const promotion of promotions) {
|
||||
const linkObject = {
|
||||
[Modules.CART]: { cart_id: id },
|
||||
[Modules.PROMOTION]: { promotion_id: promotion.id },
|
||||
}
|
||||
|
||||
if ([PromotionActions.ADD, PromotionActions.REPLACE].includes(action)) {
|
||||
linksToCreate.push(linkObject)
|
||||
}
|
||||
|
||||
if (action === PromotionActions.REMOVE) {
|
||||
const link = promotionLinkMap.get(promotion.id)
|
||||
|
||||
if (link) {
|
||||
linksToDismiss.push(linkObject)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (action === PromotionActions.REPLACE) {
|
||||
for (const link of existingCartPromotionLinks) {
|
||||
linksToDismiss.push({
|
||||
[Modules.CART]: { cart_id: link.cart_id },
|
||||
[Modules.PROMOTION]: { promotion_id: link.promotion_id },
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const linksToDismissPromise = linksToDismiss.length
|
||||
? remoteLink.dismiss(linksToDismiss)
|
||||
: []
|
||||
|
||||
const linksToCreatePromise = linksToCreate.length
|
||||
? remoteLink.create(linksToCreate)
|
||||
: []
|
||||
|
||||
const [_, createdLinks] = await Promise.all([
|
||||
linksToDismissPromise,
|
||||
linksToCreatePromise,
|
||||
])
|
||||
|
||||
return new StepResponse(null, {
|
||||
createdLinkIds: createdLinks.map((link) => link.id),
|
||||
dismissedLinks: linksToDismiss,
|
||||
})
|
||||
},
|
||||
async (revertData, { container }) => {
|
||||
const remoteLink = container.resolve(LinkModuleUtils.REMOTE_LINK)
|
||||
|
||||
if (revertData?.dismissedLinks?.length) {
|
||||
await remoteLink.create(revertData.dismissedLinks)
|
||||
}
|
||||
|
||||
if (revertData?.createdLinkIds?.length) {
|
||||
await remoteLink.delete(revertData.createdLinkIds)
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -19,7 +19,6 @@ import { prepareLineItemData } from "../utils/prepare-line-item-data"
|
||||
// TODO: The AddToCartWorkflow are missing the following steps:
|
||||
// - Confirm inventory exists (inventory module)
|
||||
// - Refresh/delete shipping methods (fulfillment module)
|
||||
// - Create line item adjustments (promotion module)
|
||||
// - Update payment sessions (payment module)
|
||||
|
||||
export const addToCartWorkflowId = "add-to-cart"
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
removeLineItemAdjustmentsStep,
|
||||
removeShippingMethodAdjustmentsStep,
|
||||
retrieveCartStep,
|
||||
updateCartPromotionsStep,
|
||||
} from "../steps"
|
||||
|
||||
type WorkflowInput = {
|
||||
@@ -39,11 +40,15 @@ export const updateCartPromotionsWorkflow = createWorkflow(
|
||||
},
|
||||
}
|
||||
|
||||
updateCartPromotionsStep({
|
||||
id: input.cartId,
|
||||
promo_codes: input.promoCodes,
|
||||
action: input.action || PromotionActions.ADD,
|
||||
})
|
||||
|
||||
const cart = retrieveCartStep(retrieveCartInput)
|
||||
const actions = getActionsToComputeFromPromotionsStep({
|
||||
cart,
|
||||
promoCodes: input.promoCodes,
|
||||
action: input.action || PromotionActions.ADD,
|
||||
})
|
||||
|
||||
const {
|
||||
|
||||
Reference in New Issue
Block a user