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:
1 parent
effee5c8bb
commit
5eab9e7399
35 files changed
+1208
-1743
No files matched your search
@@ -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,
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
ApplicationMethodTargetTypeValues,
|
||||
ApplicationMethodTypeValues,
|
||||
PromotionRuleOperatorValues,
|
||||
PromotionStatusValues,
|
||||
PromotionTypeValues,
|
||||
} from "../../../promotion"
|
||||
import { AdminCreateCampaign } from "../../campaign"
|
||||
@@ -64,6 +65,7 @@ export interface AdminUpdatePromotion {
|
||||
code?: string
|
||||
is_automatic?: boolean
|
||||
type?: PromotionTypeValues
|
||||
status?: PromotionStatusValues
|
||||
campaign_id?: string | null
|
||||
campaign?: AdminCreateCampaign
|
||||
application_method?: AdminUpdateApplicationMethod
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
ApplicationMethodTargetTypeValues,
|
||||
ApplicationMethodTypeValues,
|
||||
PromotionRuleOperatorValues,
|
||||
PromotionStatusValues,
|
||||
PromotionTypeValues,
|
||||
} from "../../promotion"
|
||||
import { AdminCampaign } from "../campaign"
|
||||
@@ -37,6 +38,7 @@ export interface BasePromotion {
|
||||
is_automatic?: boolean
|
||||
application_method?: BaseApplicationMethod
|
||||
rules?: BasePromotionRule[]
|
||||
status?: PromotionStatusValues
|
||||
campaign_id?: string
|
||||
campaign?: AdminCampaign
|
||||
created_at: string
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
CreateApplicationMethodDTO,
|
||||
UpdateApplicationMethodDTO,
|
||||
} from "./application-method"
|
||||
import { CampaignDTO } from "./campaign"
|
||||
import { CampaignDTO, FilterableCampaignProps } from "./campaign"
|
||||
import { CreatePromotionRuleDTO, PromotionRuleDTO } from "./promotion-rule"
|
||||
|
||||
/**
|
||||
@@ -13,6 +13,11 @@ import { CreatePromotionRuleDTO, PromotionRuleDTO } from "./promotion-rule"
|
||||
*/
|
||||
export type PromotionTypeValues = "standard" | "buyget"
|
||||
|
||||
/**
|
||||
* The promotion's possible types.
|
||||
*/
|
||||
export type PromotionStatusValues = "draft" | "active" | "inactive"
|
||||
|
||||
/**
|
||||
* The promotion's possible rule types.
|
||||
*/
|
||||
@@ -41,6 +46,15 @@ export interface PromotionDTO {
|
||||
*/
|
||||
type?: PromotionTypeValues
|
||||
|
||||
/**
|
||||
* The status of the promotion:
|
||||
*
|
||||
* - `active` promotion is available for user to consume
|
||||
* - `inactive` promotion is no longer available to the user
|
||||
* - `draft` promotion is currently being prepared
|
||||
*/
|
||||
status?: PromotionStatusValues
|
||||
|
||||
/**
|
||||
* Whether the promotion is applied automatically.
|
||||
*/
|
||||
@@ -85,6 +99,15 @@ export interface CreatePromotionDTO {
|
||||
*/
|
||||
type: PromotionTypeValues
|
||||
|
||||
/**
|
||||
* The status of the promotion:
|
||||
*
|
||||
* - `draft` indicates that a promotion is currently being prepared
|
||||
* - `active` indicates that a promotion is active
|
||||
* - `inactive` indicates that a promotion is no longer active
|
||||
*/
|
||||
status: PromotionStatusValues
|
||||
|
||||
/**
|
||||
* Whether the promotion is applied automatically.
|
||||
*/
|
||||
@@ -135,6 +158,15 @@ export interface UpdatePromotionDTO {
|
||||
*/
|
||||
type?: PromotionTypeValues
|
||||
|
||||
/**
|
||||
* The status of the promotion:
|
||||
*
|
||||
* - `draft` indicates that a promotion is currently being prepared
|
||||
* - `active` indicates that a promotion is active
|
||||
* - `inactive` indicates that a promotion is no longer active
|
||||
*/
|
||||
status?: PromotionStatusValues
|
||||
|
||||
/**
|
||||
* The associated application method.
|
||||
*/
|
||||
@@ -180,4 +212,14 @@ export interface FilterablePromotionProps
|
||||
* Filter promotions by their type.
|
||||
*/
|
||||
type?: PromotionTypeValues[]
|
||||
|
||||
/**
|
||||
* Filter promotions by their status.
|
||||
*/
|
||||
status?: PromotionStatusValues[]
|
||||
|
||||
/**
|
||||
* Filter promotions by their campaign
|
||||
*/
|
||||
campaign?: FilterableCampaignProps
|
||||
}
|
||||
@@ -3,6 +3,12 @@ export enum PromotionType {
|
||||
BUYGET = "buyget",
|
||||
}
|
||||
|
||||
export enum PromotionStatus {
|
||||
DRAFT = "draft",
|
||||
ACTIVE = "active",
|
||||
INACTIVE = "inactive",
|
||||
}
|
||||
|
||||
export enum ApplicationMethodType {
|
||||
FIXED = "fixed",
|
||||
PERCENTAGE = "percentage",
|
||||
|
||||
Reference in new issue
Block a user