feat(promotion,dashboard,types,utils,medusa): Add statuses to promotions (#10950)

what:

- adds a status column to promotion table
- introduce active promotion query
- scope revert, register and compute actions to active promotions
- admin to create and update promotion with statuses

RESOLVES CMRC-845
RESOLVES CMRC-846
RESOLVES CMRC-847
RESOLVES CMRC-848
RESOLVES CMRC-849
RESOLVES CMRC-850
This commit is contained in:
Riqwan Thamir
2025-01-16 19:17:22 +00:00
committed by GitHub
parent effee5c8bb
commit 5eab9e7399
35 changed files with 1208 additions and 1743 deletions
@@ -9,3 +9,4 @@ export * from "./delete-promotions"
export * from "./update-campaigns"
export * from "./update-promotion-rules"
export * from "./update-promotions"
export * from "./update-promotions-status"
@@ -0,0 +1,55 @@
import {
AdditionalData,
PromotionStatusValues,
} from "@medusajs/framework/types"
import { MedusaError, PromotionStatus } from "@medusajs/framework/utils"
import {
WorkflowResponse,
createHook,
createStep,
createWorkflow,
} from "@medusajs/framework/workflows-sdk"
import { updatePromotionsStep } from "../steps"
export type UpdatePromotionsStatusWorkflowInput = {
promotionsData: {
id: string
status: PromotionStatusValues
}[]
} & AdditionalData
export const updatePromotionsValidationStep = createStep(
"update-promotions-validation",
async function ({ promotionsData }: UpdatePromotionsStatusWorkflowInput) {
for (const promotionData of promotionsData) {
const allowedStatuses: PromotionStatusValues[] =
Object.values(PromotionStatus)
if (!allowedStatuses.includes(promotionData.status)) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`promotion's status should be one of - ${allowedStatuses.join(", ")}`
)
}
}
}
)
export const updatePromotionsStatusWorkflowId = "update-promotions-status"
export const updatePromotionsStatusWorkflow = createWorkflow(
updatePromotionsStatusWorkflowId,
(input: UpdatePromotionsStatusWorkflowInput) => {
updatePromotionsValidationStep(input)
const updatedPromotions = updatePromotionsStep(input.promotionsData)
const promotionStatusUpdated = createHook("promotionStatusUpdated", {
promotions: updatedPromotions,
additional_data: input.additional_data,
})
return new WorkflowResponse(updatedPromotions, {
hooks: [promotionStatusUpdated],
})
}
)
@@ -1,11 +1,21 @@
import { AdditionalData, UpdatePromotionDTO } from "@medusajs/framework/types"
import {
WorkflowData,
WorkflowResponse,
AdditionalData,
PromotionDTO,
PromotionStatusValues,
UpdatePromotionDTO,
} from "@medusajs/framework/types"
import { isString } from "@medusajs/framework/utils"
import {
createHook,
createWorkflow,
transform,
when,
WorkflowData,
WorkflowResponse,
} from "@medusajs/framework/workflows-sdk"
import { useRemoteQueryStep } from "../../common"
import { updatePromotionsStep } from "../steps"
import { updatePromotionsStatusWorkflow } from "./update-promotions-status"
/**
* The data to update one or more promotions, along with custom data that's passed to the workflow's hooks.
@@ -20,12 +30,12 @@ export type UpdatePromotionsWorkflowInput = {
export const updatePromotionsWorkflowId = "update-promotions"
/**
* This workflow updates one or more promotions. It's used by the [Update Promotion Admin API Route](https://docs.medusajs.com/api/admin#promotions_postpromotionsid).
*
*
* This workflow has a hook that allows you to perform custom actions on the updated promotion. For example, you can pass under `additional_data` custom data that
* allows you to update custom data models linked to the promotions.
*
*
* You can also use this workflow within your customizations or your own custom workflows, allowing you to wrap custom logic around updating promotions.
*
*
* @example
* const { result } = await updatePromotionsWorkflow(container)
* .run({
@@ -41,17 +51,78 @@ export const updatePromotionsWorkflowId = "update-promotions"
* }
* }
* })
*
*
* @summary
*
*
* Update one or more promotions.
*
*
* @property hooks.promotionsUpdated - This hook is executed after the promotions are updated. You can consume this hook to perform custom actions on the updated promotions.
*/
export const updatePromotionsWorkflow = createWorkflow(
updatePromotionsWorkflowId,
(input: WorkflowData<UpdatePromotionsWorkflowInput>) => {
const updatedPromotions = updatePromotionsStep(input.promotionsData)
const promotionIds = transform({ input }, ({ input }) =>
input.promotionsData.map((pd) => pd.id)
)
const promotions = useRemoteQueryStep({
entry_point: "promotion",
variables: { id: promotionIds },
fields: ["id", "status"],
list: true,
throw_if_key_not_found: true,
}).config({ name: "get-promotions" })
const promotionInputs = transform(
{ promotions, input },
({ promotions, input }) => {
const promotionMap: Record<string, PromotionDTO> = {}
const promotionsUpdateInput: UpdatePromotionsWorkflowInput["promotionsData"] =
[]
const promotionsStatusUpdateInput: {
id: string
status: PromotionStatusValues
}[] = []
for (const promotion of promotions) {
promotionMap[promotion.id] = promotion
}
for (const promotionUpdateData of input.promotionsData) {
const promotion = promotionMap[promotionUpdateData.id]
const { status, ...rest } = promotionUpdateData
promotionsUpdateInput.push(rest)
if (
isString(status) &&
promotionUpdateData.status !== promotion.status
) {
promotionsStatusUpdateInput.push({
id: promotionUpdateData.id,
status,
})
}
}
return { promotionsUpdateInput, promotionsStatusUpdateInput }
}
)
const updatedPromotions = updatePromotionsStep(
promotionInputs.promotionsUpdateInput
)
when({ promotionInputs }, ({ promotionInputs }) => {
return !!promotionInputs.promotionsStatusUpdateInput?.length
}).then(() => {
updatePromotionsStatusWorkflow.runAsStep({
input: {
promotionsData: promotionInputs.promotionsStatusUpdateInput,
},
})
})
const promotionsUpdated = createHook("promotionsUpdated", {
promotions: updatedPromotions,
additional_data: input.additional_data,