feat(core-flows,medusa,types,utils): add rules to promotion endpoints + workflow (#6692)
* feat(core-flows,medusa,types,utils): add rules to promotion endpoints + workflow * chore: fix specs * chore: move input type to types package
This commit is contained in:
1 parent
02e784ce78
commit
640eccd5dd
23 files changed
+777
-179
No files matched your search
@@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/core-flows": patch
|
||||||
|
"@medusajs/medusa": patch
|
||||||
|
"@medusajs/types": patch
|
||||||
|
"@medusajs/utils": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
feat(core-flows,medusa,types,utils): add rules to promotion endpoints + workflow
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import { IPromotionModuleService } from "@medusajs/types"
|
|
||||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
|
import { IPromotionModuleService } from "@medusajs/types"
|
||||||
import { PromotionType } from "@medusajs/utils"
|
import { PromotionType } from "@medusajs/utils"
|
||||||
import { createAdminUser } from "../../../../helpers/create-admin-user"
|
|
||||||
import { medusaIntegrationTestRunner } from "medusa-test-utils"
|
import { medusaIntegrationTestRunner } from "medusa-test-utils"
|
||||||
|
import { createAdminUser } from "../../../../helpers/create-admin-user"
|
||||||
|
|
||||||
jest.setTimeout(50000)
|
jest.setTimeout(50000)
|
||||||
|
|
||||||
@@ -56,15 +56,13 @@ medusaIntegrationTestRunner({
|
|||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
deleted_at: null,
|
deleted_at: null,
|
||||||
|
rules: [],
|
||||||
application_method: expect.objectContaining({
|
application_method: expect.objectContaining({
|
||||||
id: expect.any(String),
|
id: expect.any(String),
|
||||||
value: 100,
|
value: 100,
|
||||||
type: "fixed",
|
type: "fixed",
|
||||||
target_type: "order",
|
target_type: "order",
|
||||||
allocation: null,
|
allocation: null,
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
deleted_at: null,
|
|
||||||
}),
|
}),
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
@@ -84,7 +82,7 @@ medusaIntegrationTestRunner({
|
|||||||
])
|
])
|
||||||
|
|
||||||
const response = await api.get(
|
const response = await api.get(
|
||||||
`/admin/promotions?fields=code,created_at,application_method.id`,
|
`/admin/promotions?fields=code,created_at,application_method.id&expand=application_method`,
|
||||||
adminHeaders
|
adminHeaders
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,347 @@
|
|||||||
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
|
import { IPromotionModuleService } from "@medusajs/types"
|
||||||
|
import { PromotionType } from "@medusajs/utils"
|
||||||
|
import { medusaIntegrationTestRunner } from "medusa-test-utils"
|
||||||
|
import { createAdminUser } from "../../../../helpers/create-admin-user"
|
||||||
|
|
||||||
|
jest.setTimeout(50000)
|
||||||
|
|
||||||
|
const env = { MEDUSA_FF_MEDUSA_V2: true }
|
||||||
|
const adminHeaders = { headers: { "x-medusa-access-token": "test_token" } }
|
||||||
|
|
||||||
|
medusaIntegrationTestRunner({
|
||||||
|
env,
|
||||||
|
testSuite: ({ dbConnection, getContainer, api }) => {
|
||||||
|
describe("Admin: Promotion Rules API", () => {
|
||||||
|
let appContainer
|
||||||
|
let standardPromotion
|
||||||
|
let promotionModule: IPromotionModuleService
|
||||||
|
const promotionRule = {
|
||||||
|
operator: "eq",
|
||||||
|
attribute: "old_attr",
|
||||||
|
values: ["old value"],
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
appContainer = getContainer()
|
||||||
|
promotionModule = appContainer.resolve(ModuleRegistrationName.PROMOTION)
|
||||||
|
})
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await createAdminUser(dbConnection, adminHeaders, appContainer)
|
||||||
|
|
||||||
|
standardPromotion = await promotionModule.create({
|
||||||
|
code: "TEST_ACROSS",
|
||||||
|
type: PromotionType.STANDARD,
|
||||||
|
application_method: {
|
||||||
|
type: "fixed",
|
||||||
|
allocation: "across",
|
||||||
|
target_type: "items",
|
||||||
|
value: 100,
|
||||||
|
target_rules: [promotionRule],
|
||||||
|
},
|
||||||
|
rules: [promotionRule],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("POST /admin/promotions/:id/rules", () => {
|
||||||
|
it("should throw error when required params are missing", async () => {
|
||||||
|
const { response } = await api
|
||||||
|
.post(
|
||||||
|
`/admin/promotions/${standardPromotion.id}/rules`,
|
||||||
|
{
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
operator: "eq",
|
||||||
|
values: ["new value"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
.catch((e) => e)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(400)
|
||||||
|
expect(response.data).toEqual({
|
||||||
|
type: "invalid_data",
|
||||||
|
message:
|
||||||
|
"attribute must be a string, attribute should not be empty",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should throw error when promotion does not exist", async () => {
|
||||||
|
const { response } = await api
|
||||||
|
.post(
|
||||||
|
`/admin/promotions/does-not-exist/rules`,
|
||||||
|
{
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
attribute: "new_attr",
|
||||||
|
operator: "eq",
|
||||||
|
values: ["new value"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
.catch((e) => e)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(404)
|
||||||
|
expect(response.data).toEqual({
|
||||||
|
type: "not_found",
|
||||||
|
message: "Promotion with id: does-not-exist was not found",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should add rules to a promotion successfully", async () => {
|
||||||
|
const response = await api.post(
|
||||||
|
`/admin/promotions/${standardPromotion.id}/rules`,
|
||||||
|
{
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
operator: "eq",
|
||||||
|
attribute: "new_attr",
|
||||||
|
values: ["new value"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.promotion).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: standardPromotion.id,
|
||||||
|
rules: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
operator: "eq",
|
||||||
|
attribute: "old_attr",
|
||||||
|
values: [expect.objectContaining({ value: "old value" })],
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
operator: "eq",
|
||||||
|
attribute: "new_attr",
|
||||||
|
values: [expect.objectContaining({ value: "new value" })],
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("POST /admin/promotions/:id/target-rules", () => {
|
||||||
|
it("should throw error when required params are missing", async () => {
|
||||||
|
const { response } = await api
|
||||||
|
.post(
|
||||||
|
`/admin/promotions/${standardPromotion.id}/target-rules`,
|
||||||
|
{
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
operator: "eq",
|
||||||
|
values: ["new value"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
.catch((e) => e)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(400)
|
||||||
|
expect(response.data).toEqual({
|
||||||
|
type: "invalid_data",
|
||||||
|
message:
|
||||||
|
"attribute must be a string, attribute should not be empty",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should throw error when promotion does not exist", async () => {
|
||||||
|
const { response } = await api
|
||||||
|
.post(
|
||||||
|
`/admin/promotions/does-not-exist/target-rules`,
|
||||||
|
{
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
attribute: "new_attr",
|
||||||
|
operator: "eq",
|
||||||
|
values: ["new value"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
.catch((e) => e)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(404)
|
||||||
|
expect(response.data).toEqual({
|
||||||
|
type: "not_found",
|
||||||
|
message: "Promotion with id: does-not-exist was not found",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should add target rules to a promotion successfully", async () => {
|
||||||
|
const response = await api.post(
|
||||||
|
`/admin/promotions/${standardPromotion.id}/target-rules`,
|
||||||
|
{
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
operator: "eq",
|
||||||
|
attribute: "new_attr",
|
||||||
|
values: ["new value"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.promotion).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: standardPromotion.id,
|
||||||
|
application_method: expect.objectContaining({
|
||||||
|
target_rules: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
operator: "eq",
|
||||||
|
attribute: "old_attr",
|
||||||
|
values: [expect.objectContaining({ value: "old value" })],
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
operator: "eq",
|
||||||
|
attribute: "new_attr",
|
||||||
|
values: [expect.objectContaining({ value: "new value" })],
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("POST /admin/promotions/:id/buy-rules", () => {
|
||||||
|
it("should throw error when required params are missing", async () => {
|
||||||
|
const { response } = await api
|
||||||
|
.post(
|
||||||
|
`/admin/promotions/${standardPromotion.id}/buy-rules`,
|
||||||
|
{
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
operator: "eq",
|
||||||
|
values: ["new value"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
.catch((e) => e)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(400)
|
||||||
|
expect(response.data).toEqual({
|
||||||
|
type: "invalid_data",
|
||||||
|
message:
|
||||||
|
"attribute must be a string, attribute should not be empty",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should throw error when promotion does not exist", async () => {
|
||||||
|
const { response } = await api
|
||||||
|
.post(
|
||||||
|
`/admin/promotions/does-not-exist/buy-rules`,
|
||||||
|
{
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
attribute: "new_attr",
|
||||||
|
operator: "eq",
|
||||||
|
values: ["new value"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
.catch((e) => e)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(404)
|
||||||
|
expect(response.data).toEqual({
|
||||||
|
type: "not_found",
|
||||||
|
message: "Promotion with id: does-not-exist was not found",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should throw an error when trying to add buy rules to a standard promotion", async () => {
|
||||||
|
const { response } = await api
|
||||||
|
.post(
|
||||||
|
`/admin/promotions/${standardPromotion.id}/buy-rules`,
|
||||||
|
{
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
operator: "eq",
|
||||||
|
attribute: "new_attr",
|
||||||
|
values: ["new value"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
.catch((e) => e)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(400)
|
||||||
|
expect(response.data).toEqual({
|
||||||
|
type: "invalid_data",
|
||||||
|
message: "Can't add buy rules to a standard promotion",
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should add buy rules to a buyget promotion successfully", async () => {
|
||||||
|
const buyGetPromotion = await promotionModule.create({
|
||||||
|
code: "TEST_BUYGET",
|
||||||
|
type: PromotionType.BUYGET,
|
||||||
|
application_method: {
|
||||||
|
type: "fixed",
|
||||||
|
target_type: "items",
|
||||||
|
allocation: "across",
|
||||||
|
value: 100,
|
||||||
|
apply_to_quantity: 1,
|
||||||
|
buy_rules_min_quantity: 1,
|
||||||
|
buy_rules: [promotionRule],
|
||||||
|
target_rules: [promotionRule],
|
||||||
|
},
|
||||||
|
rules: [promotionRule],
|
||||||
|
})
|
||||||
|
|
||||||
|
const response = await api.post(
|
||||||
|
`/admin/promotions/${buyGetPromotion.id}/buy-rules`,
|
||||||
|
{
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
operator: "eq",
|
||||||
|
attribute: "new_attr",
|
||||||
|
values: ["new value"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
adminHeaders
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.promotion).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: buyGetPromotion.id,
|
||||||
|
application_method: expect.objectContaining({
|
||||||
|
buy_rules: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
operator: "eq",
|
||||||
|
attribute: "old_attr",
|
||||||
|
values: [expect.objectContaining({ value: "old value" })],
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
operator: "eq",
|
||||||
|
attribute: "new_attr",
|
||||||
|
values: [expect.objectContaining({ value: "new value" })],
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import { IPromotionModuleService } from "@medusajs/types"
|
|
||||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
|
import { IPromotionModuleService } from "@medusajs/types"
|
||||||
import { PromotionType } from "@medusajs/utils"
|
import { PromotionType } from "@medusajs/utils"
|
||||||
import { createAdminUser } from "../../../../helpers/create-admin-user"
|
|
||||||
import { medusaIntegrationTestRunner } from "medusa-test-utils"
|
import { medusaIntegrationTestRunner } from "medusa-test-utils"
|
||||||
|
import { createAdminUser } from "../../../../helpers/create-admin-user"
|
||||||
|
|
||||||
jest.setTimeout(50000)
|
jest.setTimeout(50000)
|
||||||
|
|
||||||
@@ -73,11 +73,7 @@ medusaIntegrationTestRunner({
|
|||||||
value: 100,
|
value: 100,
|
||||||
type: "fixed",
|
type: "fixed",
|
||||||
target_type: "order",
|
target_type: "order",
|
||||||
max_quantity: 0,
|
|
||||||
allocation: null,
|
allocation: null,
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
deleted_at: null,
|
|
||||||
}),
|
}),
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -0,0 +1,76 @@
|
|||||||
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
|
import {
|
||||||
|
AddPromotionRulesWorkflowDTO,
|
||||||
|
IPromotionModuleService,
|
||||||
|
} from "@medusajs/types"
|
||||||
|
import { RuleType } from "@medusajs/utils"
|
||||||
|
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||||
|
|
||||||
|
export const addRulesToPromotionsStepId = "add-rules-to-promotions"
|
||||||
|
export const addRulesToPromotionsStep = createStep(
|
||||||
|
addRulesToPromotionsStepId,
|
||||||
|
async (input: AddPromotionRulesWorkflowDTO, { container }) => {
|
||||||
|
const { data, rule_type: ruleType } = input
|
||||||
|
|
||||||
|
const promotionModule = container.resolve<IPromotionModuleService>(
|
||||||
|
ModuleRegistrationName.PROMOTION
|
||||||
|
)
|
||||||
|
|
||||||
|
const createdPromotionRules =
|
||||||
|
ruleType === RuleType.RULES
|
||||||
|
? await promotionModule.addPromotionRules(data.id, data.rules)
|
||||||
|
: []
|
||||||
|
|
||||||
|
const createdPromotionBuyRules =
|
||||||
|
ruleType === RuleType.BUY_RULES
|
||||||
|
? await promotionModule.addPromotionBuyRules(data.id, data.rules)
|
||||||
|
: []
|
||||||
|
|
||||||
|
const createdPromotionTargetRules =
|
||||||
|
ruleType === RuleType.TARGET_RULES
|
||||||
|
? await promotionModule.addPromotionTargetRules(data.id, data.rules)
|
||||||
|
: []
|
||||||
|
|
||||||
|
const promotionRules = [
|
||||||
|
...createdPromotionRules,
|
||||||
|
...createdPromotionBuyRules,
|
||||||
|
...createdPromotionTargetRules,
|
||||||
|
]
|
||||||
|
|
||||||
|
return new StepResponse(promotionRules, {
|
||||||
|
id: data.id,
|
||||||
|
ruleIds: createdPromotionRules.map((pr) => pr.id),
|
||||||
|
buyRuleIds: createdPromotionBuyRules.map((pr) => pr.id),
|
||||||
|
targetRuleIds: createdPromotionBuyRules.map((pr) => pr.id),
|
||||||
|
})
|
||||||
|
},
|
||||||
|
async (data, { container }) => {
|
||||||
|
if (!data) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const { id, ruleIds = [], buyRuleIds = [], targetRuleIds = [] } = data
|
||||||
|
|
||||||
|
const promotionModule = container.resolve<IPromotionModuleService>(
|
||||||
|
ModuleRegistrationName.PROMOTION
|
||||||
|
)
|
||||||
|
|
||||||
|
ruleIds.length &&
|
||||||
|
(await promotionModule.removePromotionRules(
|
||||||
|
id,
|
||||||
|
ruleIds.map((id) => ({ id }))
|
||||||
|
))
|
||||||
|
|
||||||
|
buyRuleIds.length &&
|
||||||
|
(await promotionModule.removePromotionBuyRules(
|
||||||
|
id,
|
||||||
|
buyRuleIds.map((id) => ({ id }))
|
||||||
|
))
|
||||||
|
|
||||||
|
targetRuleIds.length &&
|
||||||
|
(await promotionModule.removePromotionBuyRules(
|
||||||
|
id,
|
||||||
|
targetRuleIds.map((id) => ({ id }))
|
||||||
|
))
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
export * from "./add-rules-to-promotions"
|
||||||
export * from "./create-campaigns"
|
export * from "./create-campaigns"
|
||||||
export * from "./create-promotions"
|
export * from "./create-promotions"
|
||||||
export * from "./delete-campaigns"
|
export * from "./delete-campaigns"
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
import { AddPromotionRulesWorkflowDTO } from "@medusajs/types"
|
||||||
|
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
||||||
|
import { addRulesToPromotionsStep } from "../steps"
|
||||||
|
|
||||||
|
export const addRulesToPromotionsWorkflowId = "add-rules-to-promotions-workflow"
|
||||||
|
export const addRulesToPromotionsWorkflow = createWorkflow(
|
||||||
|
addRulesToPromotionsWorkflowId,
|
||||||
|
(input: WorkflowData<AddPromotionRulesWorkflowDTO>): WorkflowData<void> => {
|
||||||
|
addRulesToPromotionsStep(input)
|
||||||
|
}
|
||||||
|
)
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
export * from "./add-rules-to-promotions"
|
||||||
export * from "./create-campaigns"
|
export * from "./create-campaigns"
|
||||||
export * from "./create-promotions"
|
export * from "./create-promotions"
|
||||||
export * from "./delete-campaigns"
|
export * from "./delete-campaigns"
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import { addRulesToPromotionsWorkflow } from "@medusajs/core-flows"
|
||||||
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
|
import { IPromotionModuleService } from "@medusajs/types"
|
||||||
|
import { RuleType } from "@medusajs/utils"
|
||||||
|
import {
|
||||||
|
AuthenticatedMedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "../../../../../types/routing"
|
||||||
|
import {
|
||||||
|
defaultAdminPromotionFields,
|
||||||
|
defaultAdminPromotionRelations,
|
||||||
|
} from "../../query-config"
|
||||||
|
import { AdminPostPromotionsPromotionRulesReq } from "../../validators"
|
||||||
|
|
||||||
|
export const POST = async (
|
||||||
|
req: AuthenticatedMedusaRequest<AdminPostPromotionsPromotionRulesReq>,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const id = req.params.id
|
||||||
|
const workflow = addRulesToPromotionsWorkflow(req.scope)
|
||||||
|
const { errors } = await workflow.run({
|
||||||
|
input: {
|
||||||
|
rule_type: RuleType.BUY_RULES,
|
||||||
|
data: {
|
||||||
|
id: req.params.id,
|
||||||
|
...req.validatedBody,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
throwOnError: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (Array.isArray(errors) && errors[0]) {
|
||||||
|
throw errors[0].error
|
||||||
|
}
|
||||||
|
|
||||||
|
const promotionModuleService: IPromotionModuleService = req.scope.resolve(
|
||||||
|
ModuleRegistrationName.PROMOTION
|
||||||
|
)
|
||||||
|
|
||||||
|
const promotion = await promotionModuleService.retrieve(id, {
|
||||||
|
select: defaultAdminPromotionFields,
|
||||||
|
relations: defaultAdminPromotionRelations,
|
||||||
|
})
|
||||||
|
|
||||||
|
res.status(200).json({ promotion })
|
||||||
|
}
|
||||||
@@ -1,16 +1,15 @@
|
|||||||
import {
|
|
||||||
AuthenticatedMedusaRequest,
|
|
||||||
MedusaResponse,
|
|
||||||
} from "../../../../types/routing"
|
|
||||||
import {
|
import {
|
||||||
deletePromotionsWorkflow,
|
deletePromotionsWorkflow,
|
||||||
updatePromotionsWorkflow,
|
updatePromotionsWorkflow,
|
||||||
} from "@medusajs/core-flows"
|
} from "@medusajs/core-flows"
|
||||||
|
import {
|
||||||
|
AuthenticatedMedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "../../../../types/routing"
|
||||||
|
|
||||||
import { AdminPostPromotionsPromotionReq } from "../validators"
|
|
||||||
import { IPromotionModuleService } from "@medusajs/types"
|
|
||||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
import { UpdatePromotionDTO } from "@medusajs/types"
|
import { IPromotionModuleService, UpdatePromotionDTO } from "@medusajs/types"
|
||||||
|
import { AdminPostPromotionsPromotionReq } from "../validators"
|
||||||
|
|
||||||
export const GET = async (
|
export const GET = async (
|
||||||
req: AuthenticatedMedusaRequest,
|
req: AuthenticatedMedusaRequest,
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import { addRulesToPromotionsWorkflow } from "@medusajs/core-flows"
|
||||||
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
|
import { IPromotionModuleService } from "@medusajs/types"
|
||||||
|
import { RuleType } from "@medusajs/utils"
|
||||||
|
import {
|
||||||
|
AuthenticatedMedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "../../../../../types/routing"
|
||||||
|
import {
|
||||||
|
defaultAdminPromotionFields,
|
||||||
|
defaultAdminPromotionRelations,
|
||||||
|
} from "../../query-config"
|
||||||
|
import { AdminPostPromotionsPromotionRulesReq } from "../../validators"
|
||||||
|
|
||||||
|
export const POST = async (
|
||||||
|
req: AuthenticatedMedusaRequest<AdminPostPromotionsPromotionRulesReq>,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const id = req.params.id
|
||||||
|
const workflow = addRulesToPromotionsWorkflow(req.scope)
|
||||||
|
|
||||||
|
const { errors } = await workflow.run({
|
||||||
|
input: {
|
||||||
|
rule_type: RuleType.RULES,
|
||||||
|
data: {
|
||||||
|
id: req.params.id,
|
||||||
|
...req.validatedBody,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
throwOnError: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (Array.isArray(errors) && errors[0]) {
|
||||||
|
throw errors[0].error
|
||||||
|
}
|
||||||
|
|
||||||
|
const promotionModuleService: IPromotionModuleService = req.scope.resolve(
|
||||||
|
ModuleRegistrationName.PROMOTION
|
||||||
|
)
|
||||||
|
|
||||||
|
const promotion = await promotionModuleService.retrieve(id, {
|
||||||
|
select: defaultAdminPromotionFields,
|
||||||
|
relations: defaultAdminPromotionRelations,
|
||||||
|
})
|
||||||
|
|
||||||
|
res.status(200).json({ promotion })
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import { addRulesToPromotionsWorkflow } from "@medusajs/core-flows"
|
||||||
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
|
import { IPromotionModuleService } from "@medusajs/types"
|
||||||
|
import { RuleType } from "@medusajs/utils"
|
||||||
|
import {
|
||||||
|
AuthenticatedMedusaRequest,
|
||||||
|
MedusaResponse,
|
||||||
|
} from "../../../../../types/routing"
|
||||||
|
import {
|
||||||
|
defaultAdminPromotionFields,
|
||||||
|
defaultAdminPromotionRelations,
|
||||||
|
} from "../../query-config"
|
||||||
|
import { AdminPostPromotionsPromotionRulesReq } from "../../validators"
|
||||||
|
|
||||||
|
export const POST = async (
|
||||||
|
req: AuthenticatedMedusaRequest<AdminPostPromotionsPromotionRulesReq>,
|
||||||
|
res: MedusaResponse
|
||||||
|
) => {
|
||||||
|
const id = req.params.id
|
||||||
|
const workflow = addRulesToPromotionsWorkflow(req.scope)
|
||||||
|
const { errors } = await workflow.run({
|
||||||
|
input: {
|
||||||
|
rule_type: RuleType.TARGET_RULES,
|
||||||
|
data: {
|
||||||
|
id: req.params.id,
|
||||||
|
...req.validatedBody,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
throwOnError: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (Array.isArray(errors) && errors[0]) {
|
||||||
|
throw errors[0].error
|
||||||
|
}
|
||||||
|
|
||||||
|
const promotionModuleService: IPromotionModuleService = req.scope.resolve(
|
||||||
|
ModuleRegistrationName.PROMOTION
|
||||||
|
)
|
||||||
|
|
||||||
|
const promotion = await promotionModuleService.retrieve(id, {
|
||||||
|
select: defaultAdminPromotionFields,
|
||||||
|
relations: defaultAdminPromotionRelations,
|
||||||
|
})
|
||||||
|
|
||||||
|
res.status(200).json({ promotion })
|
||||||
|
}
|
||||||
@@ -1,18 +1,14 @@
|
|||||||
import * as QueryConfig from "./query-config"
|
import * as QueryConfig from "./query-config"
|
||||||
|
|
||||||
|
import { transformBody, transformQuery } from "../../../api/middlewares"
|
||||||
import {
|
import {
|
||||||
AdminGetPromotionsParams,
|
AdminGetPromotionsParams,
|
||||||
AdminGetPromotionsPromotionParams,
|
AdminGetPromotionsPromotionParams,
|
||||||
AdminPostPromotionsPromotionReq,
|
AdminPostPromotionsPromotionReq,
|
||||||
|
AdminPostPromotionsPromotionRulesReq,
|
||||||
AdminPostPromotionsReq,
|
AdminPostPromotionsReq,
|
||||||
} from "./validators"
|
} from "./validators"
|
||||||
import {
|
|
||||||
isFeatureFlagEnabled,
|
|
||||||
transformBody,
|
|
||||||
transformQuery,
|
|
||||||
} from "../../../api/middlewares"
|
|
||||||
|
|
||||||
import { MedusaV2Flag } from "@medusajs/utils"
|
|
||||||
import { MiddlewareRoute } from "../../../loaders/helpers/routing/types"
|
import { MiddlewareRoute } from "../../../loaders/helpers/routing/types"
|
||||||
import { authenticate } from "../../../utils/authenticate-middleware"
|
import { authenticate } from "../../../utils/authenticate-middleware"
|
||||||
|
|
||||||
@@ -51,4 +47,19 @@ export const adminPromotionRoutesMiddlewares: MiddlewareRoute[] = [
|
|||||||
matcher: "/admin/promotions/:id",
|
matcher: "/admin/promotions/:id",
|
||||||
middlewares: [transformBody(AdminPostPromotionsPromotionReq)],
|
middlewares: [transformBody(AdminPostPromotionsPromotionReq)],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
method: ["POST"],
|
||||||
|
matcher: "/admin/promotions/:id/rules",
|
||||||
|
middlewares: [transformBody(AdminPostPromotionsPromotionRulesReq)],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["POST"],
|
||||||
|
matcher: "/admin/promotions/:id/target-rules",
|
||||||
|
middlewares: [transformBody(AdminPostPromotionsPromotionRulesReq)],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: ["POST"],
|
||||||
|
matcher: "/admin/promotions/:id/buy-rules",
|
||||||
|
middlewares: [transformBody(AdminPostPromotionsPromotionRulesReq)],
|
||||||
|
},
|
||||||
]
|
]
|
||||||
@@ -1,16 +1,43 @@
|
|||||||
export const defaultAdminPromotionRelations = ["campaign", "application_method"]
|
export const defaultAdminPromotionRelations = [
|
||||||
|
"campaign",
|
||||||
|
"rules",
|
||||||
|
"rules.values",
|
||||||
|
"application_method",
|
||||||
|
"application_method.buy_rules",
|
||||||
|
"application_method.buy_rules.values",
|
||||||
|
"application_method.target_rules",
|
||||||
|
"application_method.target_rules.values",
|
||||||
|
]
|
||||||
export const allowedAdminPromotionRelations = [
|
export const allowedAdminPromotionRelations = [
|
||||||
...defaultAdminPromotionRelations,
|
...defaultAdminPromotionRelations,
|
||||||
]
|
]
|
||||||
export const defaultAdminPromotionFields = [
|
export const defaultAdminPromotionFields = [
|
||||||
"id",
|
"id",
|
||||||
"code",
|
"code",
|
||||||
"campaign",
|
|
||||||
"is_automatic",
|
"is_automatic",
|
||||||
"type",
|
"type",
|
||||||
"created_at",
|
"created_at",
|
||||||
"updated_at",
|
"updated_at",
|
||||||
"deleted_at",
|
"deleted_at",
|
||||||
|
"campaign.id",
|
||||||
|
"campaign.name",
|
||||||
|
"application_method.value",
|
||||||
|
"application_method.type",
|
||||||
|
"application_method.max_quantity",
|
||||||
|
"application_method.target_type",
|
||||||
|
"application_method.allocation",
|
||||||
|
"application_method.created_at",
|
||||||
|
"application_method.updated_at",
|
||||||
|
"application_method.deleted_at",
|
||||||
|
"application_method.buy_rules.attribute",
|
||||||
|
"application_method.buy_rules.operator",
|
||||||
|
"application_method.buy_rules.values.value",
|
||||||
|
"application_method.target_rules.attribute",
|
||||||
|
"application_method.target_rules.operator",
|
||||||
|
"application_method.target_rules.values.value",
|
||||||
|
"rules.attribute",
|
||||||
|
"rules.operator",
|
||||||
|
"rules.values.value",
|
||||||
]
|
]
|
||||||
|
|
||||||
export const retrieveTransformQueryConfig = {
|
export const retrieveTransformQueryConfig = {
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
|
import { CreatePromotionDTO, IPromotionModuleService } from "@medusajs/types"
|
||||||
import {
|
import {
|
||||||
AuthenticatedMedusaRequest,
|
AuthenticatedMedusaRequest,
|
||||||
MedusaResponse,
|
MedusaResponse,
|
||||||
} from "../../../types/routing"
|
} from "../../../types/routing"
|
||||||
import { CreatePromotionDTO, IPromotionModuleService } from "@medusajs/types"
|
|
||||||
|
|
||||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
|
||||||
import { createPromotionsWorkflow } from "@medusajs/core-flows"
|
import { createPromotionsWorkflow } from "@medusajs/core-flows"
|
||||||
|
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||||
|
|
||||||
export const GET = async (
|
export const GET = async (
|
||||||
req: AuthenticatedMedusaRequest,
|
req: AuthenticatedMedusaRequest,
|
||||||
|
|||||||
@@ -214,3 +214,10 @@ export class AdminPostPromotionsPromotionReq {
|
|||||||
@Type(() => PromotionRule)
|
@Type(() => PromotionRule)
|
||||||
rules?: PromotionRule[]
|
rules?: PromotionRule[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class AdminPostPromotionsPromotionRulesReq {
|
||||||
|
@IsArray()
|
||||||
|
@ValidateNested({ each: true })
|
||||||
|
@Type(() => PromotionRule)
|
||||||
|
rules: PromotionRule[]
|
||||||
|
}
|
||||||
+61
-75
@@ -1084,8 +1084,8 @@ describe("Promotion Service", () => {
|
|||||||
expect(error.message).toEqual("promotion - id must be defined")
|
expect(error.message).toEqual("promotion - id must be defined")
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should successfully create rules for a promotion", async () => {
|
it("should successfully add rules to a promotion", async () => {
|
||||||
promotion = await service.addPromotionRules(promotion.id, [
|
const promotionRules = await service.addPromotionRules(promotion.id, [
|
||||||
{
|
{
|
||||||
attribute: "customer_group_id",
|
attribute: "customer_group_id",
|
||||||
operator: "in",
|
operator: "in",
|
||||||
@@ -1093,21 +1093,17 @@ describe("Promotion Service", () => {
|
|||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
expect(promotion).toEqual(
|
expect(promotionRules).toEqual([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: promotion.id,
|
id: promotionRules[0].id,
|
||||||
rules: [
|
attribute: "customer_group_id",
|
||||||
expect.objectContaining({
|
operator: "in",
|
||||||
attribute: "customer_group_id",
|
values: expect.arrayContaining([
|
||||||
operator: "in",
|
expect.objectContaining({ value: "VIP" }),
|
||||||
values: [
|
expect.objectContaining({ value: "top100" }),
|
||||||
expect.objectContaining({ value: "VIP" }),
|
]),
|
||||||
expect.objectContaining({ value: "top100" }),
|
}),
|
||||||
],
|
])
|
||||||
}),
|
|
||||||
],
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -1160,31 +1156,28 @@ describe("Promotion Service", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("should successfully create target rules for a promotion", async () => {
|
it("should successfully create target rules for a promotion", async () => {
|
||||||
promotion = await service.addPromotionTargetRules(promotion.id, [
|
const promotionRules = await service.addPromotionTargetRules(
|
||||||
{
|
promotion.id,
|
||||||
|
[
|
||||||
|
{
|
||||||
|
attribute: "customer_group_id",
|
||||||
|
operator: "in",
|
||||||
|
values: ["VIP", "top100"],
|
||||||
|
},
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(promotionRules).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: promotionRules[0].id,
|
||||||
attribute: "customer_group_id",
|
attribute: "customer_group_id",
|
||||||
operator: "in",
|
operator: "in",
|
||||||
values: ["VIP", "top100"],
|
values: expect.arrayContaining([
|
||||||
},
|
expect.objectContaining({ value: "VIP" }),
|
||||||
|
expect.objectContaining({ value: "top100" }),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
])
|
])
|
||||||
|
|
||||||
expect(promotion).toEqual(
|
|
||||||
expect.objectContaining({
|
|
||||||
id: promotion.id,
|
|
||||||
application_method: expect.objectContaining({
|
|
||||||
target_rules: [
|
|
||||||
expect.objectContaining({
|
|
||||||
attribute: "customer_group_id",
|
|
||||||
operator: "in",
|
|
||||||
values: [
|
|
||||||
expect.objectContaining({ value: "VIP" }),
|
|
||||||
expect.objectContaining({ value: "top100" }),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -1250,7 +1243,7 @@ describe("Promotion Service", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it("should successfully create buy rules for a buyget promotion", async () => {
|
it("should successfully create buy rules for a buyget promotion", async () => {
|
||||||
promotion = await service.addPromotionBuyRules(promotion.id, [
|
const promotionRules = await service.addPromotionBuyRules(promotion.id, [
|
||||||
{
|
{
|
||||||
attribute: "product.id",
|
attribute: "product.id",
|
||||||
operator: "in",
|
operator: "in",
|
||||||
@@ -1258,30 +1251,17 @@ describe("Promotion Service", () => {
|
|||||||
},
|
},
|
||||||
])
|
])
|
||||||
|
|
||||||
expect(promotion).toEqual(
|
expect(promotionRules).toEqual([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: promotion.id,
|
id: promotionRules[0].id,
|
||||||
application_method: expect.objectContaining({
|
attribute: "product.id",
|
||||||
buy_rules: expect.arrayContaining([
|
operator: "in",
|
||||||
expect.objectContaining({
|
values: expect.arrayContaining([
|
||||||
attribute: "product_collection.id",
|
expect.objectContaining({ value: "prod_3" }),
|
||||||
operator: "eq",
|
expect.objectContaining({ value: "prod_4" }),
|
||||||
values: expect.arrayContaining([
|
]),
|
||||||
expect.objectContaining({ value: "pcol_towel" }),
|
}),
|
||||||
]),
|
])
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
attribute: "product.id",
|
|
||||||
operator: "in",
|
|
||||||
values: expect.arrayContaining([
|
|
||||||
expect.objectContaining({ value: "prod_3" }),
|
|
||||||
expect.objectContaining({ value: "prod_4" }),
|
|
||||||
]),
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -1337,14 +1317,16 @@ describe("Promotion Service", () => {
|
|||||||
expect(error.message).toEqual("promotion - id must be defined")
|
expect(error.message).toEqual("promotion - id must be defined")
|
||||||
})
|
})
|
||||||
|
|
||||||
it("should successfully create rules for a promotion", async () => {
|
it("should successfully remove rules for a promotion", async () => {
|
||||||
const [ruleId] = promotion.rules.map((rule) => rule.id)
|
const [ruleId] = promotion.rules.map((rule) => rule.id)
|
||||||
|
|
||||||
promotion = await service.removePromotionRules(promotion.id, [
|
await service.removePromotionRules(promotion.id, [{ id: ruleId }])
|
||||||
{ id: ruleId },
|
|
||||||
])
|
|
||||||
|
|
||||||
expect(promotion).toEqual(
|
const updatedPromotion = await service.retrieve(promotion.id, {
|
||||||
|
relations: ["rules", "rules.values"],
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(updatedPromotion).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: promotion.id,
|
id: promotion.id,
|
||||||
rules: [],
|
rules: [],
|
||||||
@@ -1413,11 +1395,13 @@ describe("Promotion Service", () => {
|
|||||||
(rule) => rule.id
|
(rule) => rule.id
|
||||||
)
|
)
|
||||||
|
|
||||||
promotion = await service.removePromotionTargetRules(promotion.id, [
|
await service.removePromotionTargetRules(promotion.id, [{ id: ruleId }])
|
||||||
{ id: ruleId },
|
|
||||||
])
|
|
||||||
|
|
||||||
expect(promotion).toEqual(
|
const updatedPromotion = await service.retrieve(promotion.id, {
|
||||||
|
relations: ["application_method.target_rules.values"],
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(updatedPromotion).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: promotion.id,
|
id: promotion.id,
|
||||||
application_method: expect.objectContaining({
|
application_method: expect.objectContaining({
|
||||||
@@ -1497,11 +1481,13 @@ describe("Promotion Service", () => {
|
|||||||
(rule) => rule.id
|
(rule) => rule.id
|
||||||
)
|
)
|
||||||
|
|
||||||
promotion = await service.removePromotionBuyRules(promotion.id, [
|
await service.removePromotionBuyRules(promotion.id, [{ id: ruleId }])
|
||||||
{ id: ruleId },
|
|
||||||
])
|
|
||||||
|
|
||||||
expect(promotion).toEqual(
|
const updatedPromotion = await service.retrieve(promotion.id, {
|
||||||
|
relations: ["application_method.buy_rules.values"],
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(updatedPromotion).toEqual(
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: promotion.id,
|
id: promotion.id,
|
||||||
application_method: expect.objectContaining({
|
application_method: expect.objectContaining({
|
||||||
|
|||||||
@@ -755,19 +755,19 @@ export default class PromotionModuleService<
|
|||||||
promotionId: string,
|
promotionId: string,
|
||||||
rulesData: PromotionTypes.CreatePromotionRuleDTO[],
|
rulesData: PromotionTypes.CreatePromotionRuleDTO[],
|
||||||
@MedusaContext() sharedContext: Context = {}
|
@MedusaContext() sharedContext: Context = {}
|
||||||
): Promise<PromotionTypes.PromotionDTO> {
|
): Promise<PromotionTypes.PromotionRuleDTO[]> {
|
||||||
const promotion = await this.promotionService_.retrieve(promotionId)
|
const promotion = await this.promotionService_.retrieve(promotionId)
|
||||||
|
|
||||||
await this.createPromotionRulesAndValues_(
|
const createdPromotionRules = await this.createPromotionRulesAndValues_(
|
||||||
rulesData,
|
rulesData,
|
||||||
"promotions",
|
"promotions",
|
||||||
promotion,
|
promotion,
|
||||||
sharedContext
|
sharedContext
|
||||||
)
|
)
|
||||||
|
|
||||||
return await this.retrieve(
|
return this.listPromotionRules(
|
||||||
promotionId,
|
{ id: createdPromotionRules.map((r) => r.id) },
|
||||||
{ relations: ["rules", "rules.values"] },
|
{ relations: ["values"] },
|
||||||
sharedContext
|
sharedContext
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -777,7 +777,7 @@ export default class PromotionModuleService<
|
|||||||
promotionId: string,
|
promotionId: string,
|
||||||
rulesData: PromotionTypes.CreatePromotionRuleDTO[],
|
rulesData: PromotionTypes.CreatePromotionRuleDTO[],
|
||||||
@MedusaContext() sharedContext: Context = {}
|
@MedusaContext() sharedContext: Context = {}
|
||||||
): Promise<PromotionTypes.PromotionDTO> {
|
): Promise<PromotionTypes.PromotionRuleDTO[]> {
|
||||||
const promotion = await this.promotionService_.retrieve(promotionId, {
|
const promotion = await this.promotionService_.retrieve(promotionId, {
|
||||||
relations: ["application_method"],
|
relations: ["application_method"],
|
||||||
})
|
})
|
||||||
@@ -791,24 +791,16 @@ export default class PromotionModuleService<
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.createPromotionRulesAndValues_(
|
const createdPromotionRules = await this.createPromotionRulesAndValues_(
|
||||||
rulesData,
|
rulesData,
|
||||||
"method_target_rules",
|
"method_target_rules",
|
||||||
applicationMethod,
|
applicationMethod,
|
||||||
sharedContext
|
sharedContext
|
||||||
)
|
)
|
||||||
|
|
||||||
return await this.retrieve(
|
return await this.listPromotionRules(
|
||||||
promotionId,
|
{ id: createdPromotionRules.map((pr) => pr.id) },
|
||||||
{
|
{ relations: ["values"] },
|
||||||
relations: [
|
|
||||||
"rules",
|
|
||||||
"rules.values",
|
|
||||||
"application_method",
|
|
||||||
"application_method.target_rules",
|
|
||||||
"application_method.target_rules.values",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
sharedContext
|
sharedContext
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -818,7 +810,7 @@ export default class PromotionModuleService<
|
|||||||
promotionId: string,
|
promotionId: string,
|
||||||
rulesData: PromotionTypes.CreatePromotionRuleDTO[],
|
rulesData: PromotionTypes.CreatePromotionRuleDTO[],
|
||||||
@MedusaContext() sharedContext: Context = {}
|
@MedusaContext() sharedContext: Context = {}
|
||||||
): Promise<PromotionTypes.PromotionDTO> {
|
): Promise<PromotionTypes.PromotionRuleDTO[]> {
|
||||||
const promotion = await this.promotionService_.retrieve(promotionId, {
|
const promotion = await this.promotionService_.retrieve(promotionId, {
|
||||||
relations: ["application_method"],
|
relations: ["application_method"],
|
||||||
})
|
})
|
||||||
@@ -832,24 +824,16 @@ export default class PromotionModuleService<
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.createPromotionRulesAndValues_(
|
const createdPromotionRules = await this.createPromotionRulesAndValues_(
|
||||||
rulesData,
|
rulesData,
|
||||||
"method_buy_rules",
|
"method_buy_rules",
|
||||||
applicationMethod,
|
applicationMethod,
|
||||||
sharedContext
|
sharedContext
|
||||||
)
|
)
|
||||||
|
|
||||||
return await this.retrieve(
|
return await this.listPromotionRules(
|
||||||
promotionId,
|
{ id: createdPromotionRules.map((pr) => pr.id) },
|
||||||
{
|
{ relations: ["values"] },
|
||||||
relations: [
|
|
||||||
"rules",
|
|
||||||
"rules.values",
|
|
||||||
"application_method",
|
|
||||||
"application_method.buy_rules",
|
|
||||||
"application_method.buy_rules.values",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
sharedContext
|
sharedContext
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -860,7 +844,25 @@ export default class PromotionModuleService<
|
|||||||
relationName: "promotions" | "method_target_rules" | "method_buy_rules",
|
relationName: "promotions" | "method_target_rules" | "method_buy_rules",
|
||||||
relation: Promotion | ApplicationMethod,
|
relation: Promotion | ApplicationMethod,
|
||||||
@MedusaContext() sharedContext: Context = {}
|
@MedusaContext() sharedContext: Context = {}
|
||||||
) {
|
): Promise<TPromotionRule[]> {
|
||||||
|
const createdPromotionRules: TPromotionRule[] = []
|
||||||
|
const promotion =
|
||||||
|
relation instanceof ApplicationMethod ? relation.promotion : relation
|
||||||
|
|
||||||
|
if (!rulesData.length) {
|
||||||
|
return []
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
relationName === "method_buy_rules" &&
|
||||||
|
promotion.type === PromotionType.STANDARD
|
||||||
|
) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
`Can't add buy rules to a ${PromotionType.STANDARD} promotion`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
validatePromotionRuleAttributes(rulesData)
|
validatePromotionRuleAttributes(rulesData)
|
||||||
|
|
||||||
for (const ruleData of rulesData) {
|
for (const ruleData of rulesData) {
|
||||||
@@ -875,6 +877,8 @@ export default class PromotionModuleService<
|
|||||||
sharedContext
|
sharedContext
|
||||||
)
|
)
|
||||||
|
|
||||||
|
createdPromotionRules.push(createdPromotionRule)
|
||||||
|
|
||||||
const ruleValues = Array.isArray(values) ? values : [values]
|
const ruleValues = Array.isArray(values) ? values : [values]
|
||||||
const promotionRuleValuesData = ruleValues.map((ruleValue) => ({
|
const promotionRuleValuesData = ruleValues.map((ruleValue) => ({
|
||||||
value: ruleValue,
|
value: ruleValue,
|
||||||
@@ -886,6 +890,8 @@ export default class PromotionModuleService<
|
|||||||
sharedContext
|
sharedContext
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return createdPromotionRules
|
||||||
}
|
}
|
||||||
|
|
||||||
@InjectManager("baseRepository_")
|
@InjectManager("baseRepository_")
|
||||||
@@ -893,14 +899,8 @@ export default class PromotionModuleService<
|
|||||||
promotionId: string,
|
promotionId: string,
|
||||||
rulesData: PromotionTypes.RemovePromotionRuleDTO[],
|
rulesData: PromotionTypes.RemovePromotionRuleDTO[],
|
||||||
@MedusaContext() sharedContext: Context = {}
|
@MedusaContext() sharedContext: Context = {}
|
||||||
): Promise<PromotionTypes.PromotionDTO> {
|
): Promise<void> {
|
||||||
await this.removePromotionRules_(promotionId, rulesData, sharedContext)
|
await this.removePromotionRules_(promotionId, rulesData, sharedContext)
|
||||||
|
|
||||||
return await this.retrieve(
|
|
||||||
promotionId,
|
|
||||||
{ relations: ["rules", "rules.values"] },
|
|
||||||
sharedContext
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@InjectTransactionManager("baseRepository_")
|
@InjectTransactionManager("baseRepository_")
|
||||||
@@ -932,27 +932,13 @@ export default class PromotionModuleService<
|
|||||||
promotionId: string,
|
promotionId: string,
|
||||||
rulesData: PromotionTypes.RemovePromotionRuleDTO[],
|
rulesData: PromotionTypes.RemovePromotionRuleDTO[],
|
||||||
@MedusaContext() sharedContext: Context = {}
|
@MedusaContext() sharedContext: Context = {}
|
||||||
): Promise<PromotionTypes.PromotionDTO> {
|
): Promise<void> {
|
||||||
await this.removeApplicationMethodRules_(
|
await this.removeApplicationMethodRules_(
|
||||||
promotionId,
|
promotionId,
|
||||||
rulesData,
|
rulesData,
|
||||||
ApplicationMethodRuleTypes.TARGET_RULES,
|
ApplicationMethodRuleTypes.TARGET_RULES,
|
||||||
sharedContext
|
sharedContext
|
||||||
)
|
)
|
||||||
|
|
||||||
return await this.retrieve(
|
|
||||||
promotionId,
|
|
||||||
{
|
|
||||||
relations: [
|
|
||||||
"rules",
|
|
||||||
"rules.values",
|
|
||||||
"application_method",
|
|
||||||
"application_method.target_rules",
|
|
||||||
"application_method.target_rules.values",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
sharedContext
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@InjectManager("baseRepository_")
|
@InjectManager("baseRepository_")
|
||||||
@@ -960,27 +946,13 @@ export default class PromotionModuleService<
|
|||||||
promotionId: string,
|
promotionId: string,
|
||||||
rulesData: PromotionTypes.RemovePromotionRuleDTO[],
|
rulesData: PromotionTypes.RemovePromotionRuleDTO[],
|
||||||
@MedusaContext() sharedContext: Context = {}
|
@MedusaContext() sharedContext: Context = {}
|
||||||
): Promise<PromotionTypes.PromotionDTO> {
|
): Promise<void> {
|
||||||
await this.removeApplicationMethodRules_(
|
await this.removeApplicationMethodRules_(
|
||||||
promotionId,
|
promotionId,
|
||||||
rulesData,
|
rulesData,
|
||||||
ApplicationMethodRuleTypes.BUY_RULES,
|
ApplicationMethodRuleTypes.BUY_RULES,
|
||||||
sharedContext
|
sharedContext
|
||||||
)
|
)
|
||||||
|
|
||||||
return await this.retrieve(
|
|
||||||
promotionId,
|
|
||||||
{
|
|
||||||
relations: [
|
|
||||||
"rules",
|
|
||||||
"rules.values",
|
|
||||||
"application_method",
|
|
||||||
"application_method.buy_rules",
|
|
||||||
"application_method.buy_rules.values",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
sharedContext
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@InjectTransactionManager("baseRepository_")
|
@InjectTransactionManager("baseRepository_")
|
||||||
|
|||||||
@@ -38,3 +38,5 @@ export interface FilterablePromotionRuleProps
|
|||||||
id?: string[]
|
id?: string[]
|
||||||
code?: string[]
|
code?: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type PromotionRuleTypes = "buy_rules" | "target_rules" | "rules"
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
export * from "./common"
|
export * from "./common"
|
||||||
export * from "./mutations"
|
export * from "./mutations"
|
||||||
export * from "./service"
|
export * from "./service"
|
||||||
|
export * from "./workflows"
|
||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
FilterableCampaignProps,
|
FilterableCampaignProps,
|
||||||
FilterablePromotionProps,
|
FilterablePromotionProps,
|
||||||
PromotionDTO,
|
PromotionDTO,
|
||||||
|
PromotionRuleDTO,
|
||||||
RemovePromotionRuleDTO,
|
RemovePromotionRuleDTO,
|
||||||
UpdatePromotionDTO,
|
UpdatePromotionDTO,
|
||||||
} from "./common"
|
} from "./common"
|
||||||
@@ -82,37 +83,37 @@ export interface IPromotionModuleService extends IModuleService {
|
|||||||
promotionId: string,
|
promotionId: string,
|
||||||
rulesData: CreatePromotionRuleDTO[],
|
rulesData: CreatePromotionRuleDTO[],
|
||||||
sharedContext?: Context
|
sharedContext?: Context
|
||||||
): Promise<PromotionDTO>
|
): Promise<PromotionRuleDTO[]>
|
||||||
|
|
||||||
addPromotionTargetRules(
|
addPromotionTargetRules(
|
||||||
promotionId: string,
|
promotionId: string,
|
||||||
rulesData: CreatePromotionRuleDTO[],
|
rulesData: CreatePromotionRuleDTO[],
|
||||||
sharedContext?: Context
|
sharedContext?: Context
|
||||||
): Promise<PromotionDTO>
|
): Promise<PromotionRuleDTO[]>
|
||||||
|
|
||||||
addPromotionBuyRules(
|
addPromotionBuyRules(
|
||||||
promotionId: string,
|
promotionId: string,
|
||||||
rulesData: CreatePromotionRuleDTO[],
|
rulesData: CreatePromotionRuleDTO[],
|
||||||
sharedContext?: Context
|
sharedContext?: Context
|
||||||
): Promise<PromotionDTO>
|
): Promise<PromotionRuleDTO[]>
|
||||||
|
|
||||||
removePromotionRules(
|
removePromotionRules(
|
||||||
promotionId: string,
|
promotionId: string,
|
||||||
rulesData: RemovePromotionRuleDTO[],
|
rulesData: RemovePromotionRuleDTO[],
|
||||||
sharedContext?: Context
|
sharedContext?: Context
|
||||||
): Promise<PromotionDTO>
|
): Promise<void>
|
||||||
|
|
||||||
removePromotionTargetRules(
|
removePromotionTargetRules(
|
||||||
promotionId: string,
|
promotionId: string,
|
||||||
rulesData: RemovePromotionRuleDTO[],
|
rulesData: RemovePromotionRuleDTO[],
|
||||||
sharedContext?: Context
|
sharedContext?: Context
|
||||||
): Promise<PromotionDTO>
|
): Promise<void>
|
||||||
|
|
||||||
removePromotionBuyRules(
|
removePromotionBuyRules(
|
||||||
promotionId: string,
|
promotionId: string,
|
||||||
rulesData: RemovePromotionRuleDTO[],
|
rulesData: RemovePromotionRuleDTO[],
|
||||||
sharedContext?: Context
|
sharedContext?: Context
|
||||||
): Promise<PromotionDTO>
|
): Promise<void>
|
||||||
|
|
||||||
createCampaigns(
|
createCampaigns(
|
||||||
data: CreateCampaignDTO,
|
data: CreateCampaignDTO,
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import { CreatePromotionRuleDTO, PromotionRuleTypes } from "./common"
|
||||||
|
|
||||||
|
export type AddPromotionRulesWorkflowDTO = {
|
||||||
|
rule_type: PromotionRuleTypes
|
||||||
|
data: {
|
||||||
|
id: string
|
||||||
|
rules: CreatePromotionRuleDTO[]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -47,3 +47,9 @@ export enum PromotionActions {
|
|||||||
REMOVE = "remove",
|
REMOVE = "remove",
|
||||||
REPLACE = "replace",
|
REPLACE = "replace",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum RuleType {
|
||||||
|
RULES = "rules",
|
||||||
|
TARGET_RULES = "target_rules",
|
||||||
|
BUY_RULES = "buy_rules",
|
||||||
|
}
|
||||||
Reference in new issue
Block a user