feat(types): promotion delete / update / retrieve / add/remove-rules (#5988)
This commit is contained in:
1 parent
7d650771d1
commit
dc46ee1189
13 files changed
+1014
-49
No files matched your search
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/types": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
feat(types): promotion delete / update / retrieve
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { CreatePromotionDTO } from "@medusajs/types"
|
||||||
import { SqlEntityManager } from "@mikro-orm/postgresql"
|
import { SqlEntityManager } from "@mikro-orm/postgresql"
|
||||||
import { Promotion } from "@models"
|
import { Promotion } from "@models"
|
||||||
import { defaultPromotionsData } from "./data"
|
import { defaultPromotionsData } from "./data"
|
||||||
@@ -6,9 +7,9 @@ export * from "./data"
|
|||||||
|
|
||||||
export async function createPromotions(
|
export async function createPromotions(
|
||||||
manager: SqlEntityManager,
|
manager: SqlEntityManager,
|
||||||
promotionsData = defaultPromotionsData
|
promotionsData: CreatePromotionDTO[] = defaultPromotionsData
|
||||||
): Promise<Promotion[]> {
|
): Promise<Promotion[]> {
|
||||||
const promotion: Promotion[] = []
|
const promotions: Promotion[] = []
|
||||||
|
|
||||||
for (let promotionData of promotionsData) {
|
for (let promotionData of promotionsData) {
|
||||||
let promotion = manager.create(Promotion, promotionData)
|
let promotion = manager.create(Promotion, promotionData)
|
||||||
@@ -18,5 +19,5 @@ export async function createPromotions(
|
|||||||
await manager.flush()
|
await manager.flush()
|
||||||
}
|
}
|
||||||
|
|
||||||
return promotion
|
return promotions
|
||||||
}
|
}
|
||||||
+542
-4
@@ -2,6 +2,7 @@ import { IPromotionModuleService } from "@medusajs/types"
|
|||||||
import { PromotionType } from "@medusajs/utils"
|
import { PromotionType } from "@medusajs/utils"
|
||||||
import { SqlEntityManager } from "@mikro-orm/postgresql"
|
import { SqlEntityManager } from "@mikro-orm/postgresql"
|
||||||
import { initialize } from "../../../../src"
|
import { initialize } from "../../../../src"
|
||||||
|
import { createPromotions } from "../../../__fixtures__/promotion"
|
||||||
import { DB_URL, MikroOrmWrapper } from "../../../utils"
|
import { DB_URL, MikroOrmWrapper } from "../../../utils"
|
||||||
|
|
||||||
jest.setTimeout(30000)
|
jest.setTimeout(30000)
|
||||||
@@ -70,7 +71,7 @@ describe("Promotion Service", () => {
|
|||||||
application_method: {
|
application_method: {
|
||||||
type: "fixed",
|
type: "fixed",
|
||||||
target_type: "order",
|
target_type: "order",
|
||||||
value: 100,
|
value: "100",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
@@ -106,7 +107,7 @@ describe("Promotion Service", () => {
|
|||||||
application_method: {
|
application_method: {
|
||||||
type: "fixed",
|
type: "fixed",
|
||||||
target_type: "order",
|
target_type: "order",
|
||||||
value: 100,
|
value: "100",
|
||||||
target_rules: [
|
target_rules: [
|
||||||
{
|
{
|
||||||
attribute: "product_id",
|
attribute: "product_id",
|
||||||
@@ -164,7 +165,7 @@ describe("Promotion Service", () => {
|
|||||||
application_method: {
|
application_method: {
|
||||||
type: "fixed",
|
type: "fixed",
|
||||||
target_type: "item",
|
target_type: "item",
|
||||||
value: 100,
|
value: "100",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
@@ -185,7 +186,7 @@ describe("Promotion Service", () => {
|
|||||||
type: "fixed",
|
type: "fixed",
|
||||||
allocation: "each",
|
allocation: "each",
|
||||||
target_type: "shipping",
|
target_type: "shipping",
|
||||||
value: 100,
|
value: "100",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
@@ -347,4 +348,541 @@ describe("Promotion Service", () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("update", () => {
|
||||||
|
it("should throw an error when required params are not passed", async () => {
|
||||||
|
const error = await service
|
||||||
|
.update([
|
||||||
|
{
|
||||||
|
type: PromotionType.STANDARD,
|
||||||
|
} as any,
|
||||||
|
])
|
||||||
|
.catch((e) => e)
|
||||||
|
|
||||||
|
expect(error.message).toContain('Promotion with id "undefined" not found')
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should update the attributes of a promotion successfully", async () => {
|
||||||
|
await createPromotions(repositoryManager)
|
||||||
|
|
||||||
|
const [updatedPromotion] = await service.update([
|
||||||
|
{
|
||||||
|
id: "promotion-id-1",
|
||||||
|
is_automatic: true,
|
||||||
|
code: "TEST",
|
||||||
|
type: PromotionType.BUYGET,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
expect(updatedPromotion).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
is_automatic: true,
|
||||||
|
code: "TEST",
|
||||||
|
type: PromotionType.BUYGET,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should update the attributes of a application method successfully", async () => {
|
||||||
|
const [createdPromotion] = await service.create([
|
||||||
|
{
|
||||||
|
code: "TEST",
|
||||||
|
type: PromotionType.STANDARD,
|
||||||
|
application_method: {
|
||||||
|
type: "fixed",
|
||||||
|
target_type: "item",
|
||||||
|
allocation: "across",
|
||||||
|
value: "100",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
const applicationMethod = createdPromotion.application_method
|
||||||
|
|
||||||
|
const [updatedPromotion] = await service.update([
|
||||||
|
{
|
||||||
|
id: createdPromotion.id,
|
||||||
|
application_method: {
|
||||||
|
id: applicationMethod?.id as string,
|
||||||
|
value: "200",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
expect(updatedPromotion).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
application_method: expect.objectContaining({
|
||||||
|
value: 200,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should change max_quantity to 0 when target_type is changed to order", async () => {
|
||||||
|
const [createdPromotion] = await service.create([
|
||||||
|
{
|
||||||
|
code: "TEST",
|
||||||
|
type: PromotionType.STANDARD,
|
||||||
|
application_method: {
|
||||||
|
type: "fixed",
|
||||||
|
target_type: "item",
|
||||||
|
allocation: "each",
|
||||||
|
value: "100",
|
||||||
|
max_quantity: 500,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
const applicationMethod = createdPromotion.application_method
|
||||||
|
|
||||||
|
const [updatedPromotion] = await service.update([
|
||||||
|
{
|
||||||
|
id: createdPromotion.id,
|
||||||
|
application_method: {
|
||||||
|
id: applicationMethod?.id as string,
|
||||||
|
target_type: "order",
|
||||||
|
allocation: "across",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
expect(updatedPromotion).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
application_method: expect.objectContaining({
|
||||||
|
target_type: "order",
|
||||||
|
allocation: "across",
|
||||||
|
max_quantity: 0,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should validate the attributes of a application method successfully", async () => {
|
||||||
|
const [createdPromotion] = await service.create([
|
||||||
|
{
|
||||||
|
code: "TEST",
|
||||||
|
type: PromotionType.STANDARD,
|
||||||
|
application_method: {
|
||||||
|
type: "fixed",
|
||||||
|
target_type: "order",
|
||||||
|
allocation: "across",
|
||||||
|
value: "100",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
const applicationMethod = createdPromotion.application_method
|
||||||
|
|
||||||
|
let error = await service
|
||||||
|
.update([
|
||||||
|
{
|
||||||
|
id: createdPromotion.id,
|
||||||
|
application_method: {
|
||||||
|
id: applicationMethod?.id as string,
|
||||||
|
target_type: "should-error",
|
||||||
|
} as any,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
.catch((e) => e)
|
||||||
|
|
||||||
|
expect(error.message).toContain(
|
||||||
|
`application_method.target_type should be one of order, shipping, item`
|
||||||
|
)
|
||||||
|
|
||||||
|
error = await service
|
||||||
|
.update([
|
||||||
|
{
|
||||||
|
id: createdPromotion.id,
|
||||||
|
application_method: {
|
||||||
|
id: applicationMethod?.id as string,
|
||||||
|
allocation: "should-error",
|
||||||
|
} as any,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
.catch((e) => e)
|
||||||
|
|
||||||
|
expect(error.message).toContain(
|
||||||
|
`application_method.allocation should be one of each, across`
|
||||||
|
)
|
||||||
|
|
||||||
|
error = await service
|
||||||
|
.update([
|
||||||
|
{
|
||||||
|
id: createdPromotion.id,
|
||||||
|
application_method: {
|
||||||
|
id: applicationMethod?.id as string,
|
||||||
|
type: "should-error",
|
||||||
|
} as any,
|
||||||
|
},
|
||||||
|
])
|
||||||
|
.catch((e) => e)
|
||||||
|
|
||||||
|
expect(error.message).toContain(
|
||||||
|
`application_method.type should be one of fixed, percentage`
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("retrieve", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await createPromotions(repositoryManager)
|
||||||
|
})
|
||||||
|
|
||||||
|
const id = "promotion-id-1"
|
||||||
|
|
||||||
|
it("should return promotion for the given id", async () => {
|
||||||
|
const promotion = await service.retrieve(id)
|
||||||
|
|
||||||
|
expect(promotion).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should throw an error when promotion with id does not exist", async () => {
|
||||||
|
let error
|
||||||
|
|
||||||
|
try {
|
||||||
|
await service.retrieve("does-not-exist")
|
||||||
|
} catch (e) {
|
||||||
|
error = e
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error.message).toEqual(
|
||||||
|
"Promotion with id: does-not-exist was not found"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should throw an error when a id is not provided", async () => {
|
||||||
|
let error
|
||||||
|
|
||||||
|
try {
|
||||||
|
await service.retrieve(undefined as unknown as string)
|
||||||
|
} catch (e) {
|
||||||
|
error = e
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error.message).toEqual('"promotionId" must be defined')
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should return promotion based on config select param", async () => {
|
||||||
|
const promotion = await service.retrieve(id, {
|
||||||
|
select: ["id"],
|
||||||
|
})
|
||||||
|
|
||||||
|
const serialized = JSON.parse(JSON.stringify(promotion))
|
||||||
|
|
||||||
|
expect(serialized).toEqual({
|
||||||
|
id,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("delete", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await createPromotions(repositoryManager)
|
||||||
|
})
|
||||||
|
|
||||||
|
const id = "promotion-id-1"
|
||||||
|
|
||||||
|
it("should delete the promotions given an id successfully", async () => {
|
||||||
|
await service.delete([id])
|
||||||
|
|
||||||
|
const promotions = await service.list({
|
||||||
|
id: [id],
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(promotions).toHaveLength(0)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("addPromotionRules", () => {
|
||||||
|
let promotion
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
;[promotion] = await service.create([
|
||||||
|
{
|
||||||
|
code: "TEST",
|
||||||
|
type: PromotionType.STANDARD,
|
||||||
|
application_method: {
|
||||||
|
type: "fixed",
|
||||||
|
target_type: "item",
|
||||||
|
allocation: "each",
|
||||||
|
value: "100",
|
||||||
|
max_quantity: 500,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should throw an error when promotion with id does not exist", async () => {
|
||||||
|
let error
|
||||||
|
|
||||||
|
try {
|
||||||
|
await service.addPromotionRules("does-not-exist", [])
|
||||||
|
} catch (e) {
|
||||||
|
error = e
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error.message).toEqual(
|
||||||
|
"Promotion with id: does-not-exist was not found"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should throw an error when a id is not provided", async () => {
|
||||||
|
let error
|
||||||
|
|
||||||
|
try {
|
||||||
|
await service.addPromotionRules(undefined as unknown as string, [])
|
||||||
|
} catch (e) {
|
||||||
|
error = e
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error.message).toEqual('"promotionId" must be defined')
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should successfully create rules for a promotion", async () => {
|
||||||
|
promotion = await service.addPromotionRules(promotion.id, [
|
||||||
|
{
|
||||||
|
attribute: "customer_group_id",
|
||||||
|
operator: "in",
|
||||||
|
values: ["VIP", "top100"],
|
||||||
|
},
|
||||||
|
])
|
||||||
|
|
||||||
|
expect(promotion).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: promotion.id,
|
||||||
|
rules: [
|
||||||
|
expect.objectContaining({
|
||||||
|
attribute: "customer_group_id",
|
||||||
|
operator: "in",
|
||||||
|
values: [
|
||||||
|
expect.objectContaining({ value: "VIP" }),
|
||||||
|
expect.objectContaining({ value: "top100" }),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("addPromotionTargetRules", () => {
|
||||||
|
let promotion
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
;[promotion] = await service.create([
|
||||||
|
{
|
||||||
|
code: "TEST",
|
||||||
|
type: PromotionType.STANDARD,
|
||||||
|
application_method: {
|
||||||
|
type: "fixed",
|
||||||
|
target_type: "item",
|
||||||
|
allocation: "each",
|
||||||
|
value: "100",
|
||||||
|
max_quantity: 500,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should throw an error when promotion with id does not exist", async () => {
|
||||||
|
let error
|
||||||
|
|
||||||
|
try {
|
||||||
|
await service.addPromotionTargetRules("does-not-exist", [])
|
||||||
|
} catch (e) {
|
||||||
|
error = e
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error.message).toEqual(
|
||||||
|
"Promotion with id: does-not-exist was not found"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should throw an error when a id is not provided", async () => {
|
||||||
|
let error
|
||||||
|
|
||||||
|
try {
|
||||||
|
await service.addPromotionTargetRules(
|
||||||
|
undefined as unknown as string,
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
} catch (e) {
|
||||||
|
error = e
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error.message).toEqual('"promotionId" must be defined')
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should successfully create target rules for a promotion", async () => {
|
||||||
|
promotion = await service.addPromotionTargetRules(promotion.id, [
|
||||||
|
{
|
||||||
|
attribute: "customer_group_id",
|
||||||
|
operator: "in",
|
||||||
|
values: ["VIP", "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" }),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("removePromotionRules", () => {
|
||||||
|
let promotion
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
;[promotion] = await service.create([
|
||||||
|
{
|
||||||
|
code: "TEST",
|
||||||
|
type: PromotionType.STANDARD,
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
attribute: "customer_group_id",
|
||||||
|
operator: "in",
|
||||||
|
values: ["VIP", "top100"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
application_method: {
|
||||||
|
type: "fixed",
|
||||||
|
target_type: "item",
|
||||||
|
allocation: "each",
|
||||||
|
value: "100",
|
||||||
|
max_quantity: 500,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should throw an error when promotion with id does not exist", async () => {
|
||||||
|
let error
|
||||||
|
|
||||||
|
try {
|
||||||
|
await service.removePromotionRules("does-not-exist", [])
|
||||||
|
} catch (e) {
|
||||||
|
error = e
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error.message).toEqual(
|
||||||
|
"Promotion with id: does-not-exist was not found"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should throw an error when a id is not provided", async () => {
|
||||||
|
let error
|
||||||
|
|
||||||
|
try {
|
||||||
|
await service.removePromotionRules(undefined as unknown as string, [])
|
||||||
|
} catch (e) {
|
||||||
|
error = e
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error.message).toEqual('"promotionId" must be defined')
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should successfully create rules for a promotion", async () => {
|
||||||
|
const [ruleId] = promotion.rules.map((rule) => rule.id)
|
||||||
|
|
||||||
|
promotion = await service.removePromotionRules(promotion.id, [
|
||||||
|
{ id: ruleId },
|
||||||
|
])
|
||||||
|
|
||||||
|
expect(promotion).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: promotion.id,
|
||||||
|
rules: [],
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("removePromotionTargetRules", () => {
|
||||||
|
let promotion
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
;[promotion] = await service.create([
|
||||||
|
{
|
||||||
|
code: "TEST",
|
||||||
|
type: PromotionType.STANDARD,
|
||||||
|
application_method: {
|
||||||
|
type: "fixed",
|
||||||
|
target_type: "item",
|
||||||
|
allocation: "each",
|
||||||
|
value: "100",
|
||||||
|
max_quantity: 500,
|
||||||
|
target_rules: [
|
||||||
|
{
|
||||||
|
attribute: "customer_group_id",
|
||||||
|
operator: "in",
|
||||||
|
values: ["VIP", "top100"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should throw an error when promotion with id does not exist", async () => {
|
||||||
|
let error
|
||||||
|
|
||||||
|
try {
|
||||||
|
await service.removePromotionTargetRules("does-not-exist", [])
|
||||||
|
} catch (e) {
|
||||||
|
error = e
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error.message).toEqual(
|
||||||
|
"Promotion with id: does-not-exist was not found"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should throw an error when a id is not provided", async () => {
|
||||||
|
let error
|
||||||
|
|
||||||
|
try {
|
||||||
|
await service.removePromotionTargetRules(
|
||||||
|
undefined as unknown as string,
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
} catch (e) {
|
||||||
|
error = e
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(error.message).toEqual('"promotionId" must be defined')
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should successfully create rules for a promotion", async () => {
|
||||||
|
const [ruleId] = promotion.application_method.target_rules.map(
|
||||||
|
(rule) => rule.id
|
||||||
|
)
|
||||||
|
|
||||||
|
promotion = await service.removePromotionTargetRules(promotion.id, [
|
||||||
|
{ id: ruleId },
|
||||||
|
])
|
||||||
|
|
||||||
|
expect(promotion).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: promotion.id,
|
||||||
|
application_method: expect.objectContaining({
|
||||||
|
target_rules: [],
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
ApplicationMethodAllocation,
|
ApplicationMethodAllocationValues,
|
||||||
ApplicationMethodTargetType,
|
ApplicationMethodTargetTypeValues,
|
||||||
ApplicationMethodType,
|
ApplicationMethodTypeValues,
|
||||||
} from "@medusajs/types"
|
} from "@medusajs/types"
|
||||||
import { PromotionUtils, generateEntityId } from "@medusajs/utils"
|
import { PromotionUtils, generateEntityId } from "@medusajs/utils"
|
||||||
import {
|
import {
|
||||||
@@ -27,6 +27,7 @@ type OptionalFields =
|
|||||||
| "created_at"
|
| "created_at"
|
||||||
| "updated_at"
|
| "updated_at"
|
||||||
| "deleted_at"
|
| "deleted_at"
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export default class ApplicationMethod {
|
export default class ApplicationMethod {
|
||||||
[OptionalProps]?: OptionalFields
|
[OptionalProps]?: OptionalFields
|
||||||
@@ -35,25 +36,25 @@ export default class ApplicationMethod {
|
|||||||
id!: string
|
id!: string
|
||||||
|
|
||||||
@Property({ columnType: "numeric", nullable: true, serializer: Number })
|
@Property({ columnType: "numeric", nullable: true, serializer: Number })
|
||||||
value?: number | null
|
value?: string | null
|
||||||
|
|
||||||
@Property({ columnType: "numeric", nullable: true, serializer: Number })
|
@Property({ columnType: "numeric", nullable: true, serializer: Number })
|
||||||
max_quantity?: number | null
|
max_quantity?: number | null
|
||||||
|
|
||||||
@Index({ name: "IDX_application_method_type" })
|
@Index({ name: "IDX_application_method_type" })
|
||||||
@Enum(() => PromotionUtils.ApplicationMethodType)
|
@Enum(() => PromotionUtils.ApplicationMethodType)
|
||||||
type: ApplicationMethodType
|
type: ApplicationMethodTypeValues
|
||||||
|
|
||||||
@Index({ name: "IDX_application_method_target_type" })
|
@Index({ name: "IDX_application_method_target_type" })
|
||||||
@Enum(() => PromotionUtils.ApplicationMethodTargetType)
|
@Enum(() => PromotionUtils.ApplicationMethodTargetType)
|
||||||
target_type: ApplicationMethodTargetType
|
target_type: ApplicationMethodTargetTypeValues
|
||||||
|
|
||||||
@Index({ name: "IDX_application_method_allocation" })
|
@Index({ name: "IDX_application_method_allocation" })
|
||||||
@Enum({
|
@Enum({
|
||||||
items: () => PromotionUtils.ApplicationMethodAllocation,
|
items: () => PromotionUtils.ApplicationMethodAllocation,
|
||||||
nullable: true,
|
nullable: true,
|
||||||
})
|
})
|
||||||
allocation?: ApplicationMethodAllocation
|
allocation?: ApplicationMethodAllocationValues
|
||||||
|
|
||||||
@OneToOne({
|
@OneToOne({
|
||||||
entity: () => Promotion,
|
entity: () => Promotion,
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ export default class Promotion {
|
|||||||
@OneToOne({
|
@OneToOne({
|
||||||
entity: () => ApplicationMethod,
|
entity: () => ApplicationMethod,
|
||||||
mappedBy: (am) => am.promotion,
|
mappedBy: (am) => am.promotion,
|
||||||
|
cascade: ["soft-remove"] as any,
|
||||||
})
|
})
|
||||||
application_method: ApplicationMethod
|
application_method: ApplicationMethod
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import {
|
|||||||
InjectManager,
|
InjectManager,
|
||||||
InjectTransactionManager,
|
InjectTransactionManager,
|
||||||
MedusaContext,
|
MedusaContext,
|
||||||
|
MedusaError,
|
||||||
} from "@medusajs/utils"
|
} from "@medusajs/utils"
|
||||||
import { ApplicationMethod, Promotion } from "@models"
|
import { ApplicationMethod, Promotion } from "@models"
|
||||||
import {
|
import {
|
||||||
@@ -19,8 +20,14 @@ import {
|
|||||||
PromotionService,
|
PromotionService,
|
||||||
} from "@services"
|
} from "@services"
|
||||||
import { joinerConfig } from "../joiner-config"
|
import { joinerConfig } from "../joiner-config"
|
||||||
import { CreateApplicationMethodDTO, CreatePromotionDTO } from "../types"
|
|
||||||
import {
|
import {
|
||||||
|
CreateApplicationMethodDTO,
|
||||||
|
CreatePromotionDTO,
|
||||||
|
UpdateApplicationMethodDTO,
|
||||||
|
UpdatePromotionDTO,
|
||||||
|
} from "../types"
|
||||||
|
import {
|
||||||
|
allowedAllocationForQuantity,
|
||||||
validateApplicationMethodAttributes,
|
validateApplicationMethodAttributes,
|
||||||
validatePromotionRuleAttributes,
|
validatePromotionRuleAttributes,
|
||||||
} from "../utils"
|
} from "../utils"
|
||||||
@@ -64,6 +71,26 @@ export default class PromotionModuleService<
|
|||||||
return joinerConfig
|
return joinerConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@InjectManager("baseRepository_")
|
||||||
|
async retrieve(
|
||||||
|
id: string,
|
||||||
|
config: FindConfig<PromotionTypes.PromotionDTO> = {},
|
||||||
|
@MedusaContext() sharedContext: Context = {}
|
||||||
|
): Promise<PromotionTypes.PromotionDTO> {
|
||||||
|
const promotion = await this.promotionService_.retrieve(
|
||||||
|
id,
|
||||||
|
config,
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
|
||||||
|
return await this.baseRepository_.serialize<PromotionTypes.PromotionDTO>(
|
||||||
|
promotion,
|
||||||
|
{
|
||||||
|
populate: true,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@InjectManager("baseRepository_")
|
@InjectManager("baseRepository_")
|
||||||
async list(
|
async list(
|
||||||
filters: PromotionTypes.FilterablePromotionProps = {},
|
filters: PromotionTypes.FilterablePromotionProps = {},
|
||||||
@@ -76,7 +103,7 @@ export default class PromotionModuleService<
|
|||||||
sharedContext
|
sharedContext
|
||||||
)
|
)
|
||||||
|
|
||||||
return this.baseRepository_.serialize<PromotionTypes.PromotionDTO[]>(
|
return await this.baseRepository_.serialize<PromotionTypes.PromotionDTO[]>(
|
||||||
promotions,
|
promotions,
|
||||||
{
|
{
|
||||||
populate: true,
|
populate: true,
|
||||||
@@ -94,7 +121,13 @@ export default class PromotionModuleService<
|
|||||||
return await this.list(
|
return await this.list(
|
||||||
{ id: promotions.map((p) => p!.id) },
|
{ id: promotions.map((p) => p!.id) },
|
||||||
{
|
{
|
||||||
relations: ["application_method", "rules", "rules.values"],
|
relations: [
|
||||||
|
"application_method",
|
||||||
|
"application_method.target_rules",
|
||||||
|
"application_method.target_rules.values",
|
||||||
|
"rules",
|
||||||
|
"rules.values",
|
||||||
|
],
|
||||||
},
|
},
|
||||||
sharedContext
|
sharedContext
|
||||||
)
|
)
|
||||||
@@ -195,6 +228,162 @@ export default class PromotionModuleService<
|
|||||||
return createdPromotions
|
return createdPromotions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@InjectManager("baseRepository_")
|
||||||
|
async update(
|
||||||
|
data: PromotionTypes.UpdatePromotionDTO[],
|
||||||
|
@MedusaContext() sharedContext: Context = {}
|
||||||
|
): Promise<PromotionTypes.PromotionDTO[]> {
|
||||||
|
const promotions = await this.update_(data, sharedContext)
|
||||||
|
|
||||||
|
return await this.list(
|
||||||
|
{ id: promotions.map((p) => p!.id) },
|
||||||
|
{
|
||||||
|
relations: [
|
||||||
|
"application_method",
|
||||||
|
"application_method.target_rules",
|
||||||
|
"rules",
|
||||||
|
"rules.values",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@InjectTransactionManager("baseRepository_")
|
||||||
|
protected async update_(
|
||||||
|
data: PromotionTypes.UpdatePromotionDTO[],
|
||||||
|
@MedusaContext() sharedContext: Context = {}
|
||||||
|
) {
|
||||||
|
const promotionIds = data.map((d) => d.id)
|
||||||
|
const existingPromotions = await this.promotionService_.list(
|
||||||
|
{
|
||||||
|
id: promotionIds,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
relations: ["application_method"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
const existingPromotionsMap = new Map<string, Promotion>(
|
||||||
|
existingPromotions.map((promotion) => [promotion.id, promotion])
|
||||||
|
)
|
||||||
|
|
||||||
|
const promotionsData: UpdatePromotionDTO[] = []
|
||||||
|
const applicationMethodsData: UpdateApplicationMethodDTO[] = []
|
||||||
|
|
||||||
|
for (const {
|
||||||
|
application_method: applicationMethodData,
|
||||||
|
...promotionData
|
||||||
|
} of data) {
|
||||||
|
promotionsData.push(promotionData)
|
||||||
|
|
||||||
|
if (!applicationMethodData) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const existingPromotion = existingPromotionsMap.get(promotionData.id)
|
||||||
|
const existingApplicationMethod = existingPromotion?.application_method
|
||||||
|
|
||||||
|
if (!existingApplicationMethod) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
applicationMethodData.allocation &&
|
||||||
|
!allowedAllocationForQuantity.includes(applicationMethodData.allocation)
|
||||||
|
) {
|
||||||
|
applicationMethodData.max_quantity = null
|
||||||
|
}
|
||||||
|
|
||||||
|
validateApplicationMethodAttributes({
|
||||||
|
type: applicationMethodData.type || existingApplicationMethod.type,
|
||||||
|
target_type:
|
||||||
|
applicationMethodData.target_type ||
|
||||||
|
existingApplicationMethod.target_type,
|
||||||
|
allocation:
|
||||||
|
applicationMethodData.allocation ||
|
||||||
|
existingApplicationMethod.allocation,
|
||||||
|
max_quantity:
|
||||||
|
applicationMethodData.max_quantity ||
|
||||||
|
existingApplicationMethod.max_quantity,
|
||||||
|
})
|
||||||
|
|
||||||
|
applicationMethodsData.push(applicationMethodData)
|
||||||
|
}
|
||||||
|
|
||||||
|
const updatedPromotions = this.promotionService_.update(
|
||||||
|
promotionsData,
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
|
||||||
|
if (applicationMethodsData.length) {
|
||||||
|
await this.applicationMethodService_.update(
|
||||||
|
applicationMethodsData,
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return updatedPromotions
|
||||||
|
}
|
||||||
|
|
||||||
|
@InjectManager("baseRepository_")
|
||||||
|
@InjectTransactionManager("baseRepository_")
|
||||||
|
async addPromotionRules(
|
||||||
|
promotionId: string,
|
||||||
|
rulesData: PromotionTypes.CreatePromotionRuleDTO[],
|
||||||
|
@MedusaContext() sharedContext: Context = {}
|
||||||
|
): Promise<PromotionTypes.PromotionDTO> {
|
||||||
|
const promotion = await this.promotionService_.retrieve(promotionId)
|
||||||
|
|
||||||
|
await this.createPromotionRulesAndValues(
|
||||||
|
rulesData,
|
||||||
|
"promotions",
|
||||||
|
promotion,
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
|
||||||
|
return this.retrieve(promotionId, {
|
||||||
|
relations: ["rules", "rules.values"],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@InjectManager("baseRepository_")
|
||||||
|
@InjectTransactionManager("baseRepository_")
|
||||||
|
async addPromotionTargetRules(
|
||||||
|
promotionId: string,
|
||||||
|
rulesData: PromotionTypes.CreatePromotionRuleDTO[],
|
||||||
|
@MedusaContext() sharedContext: Context = {}
|
||||||
|
): Promise<PromotionTypes.PromotionDTO> {
|
||||||
|
const promotion = await this.promotionService_.retrieve(promotionId, {
|
||||||
|
relations: ["application_method"],
|
||||||
|
})
|
||||||
|
|
||||||
|
const applicationMethod = promotion.application_method
|
||||||
|
|
||||||
|
if (!applicationMethod) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
`application_method for promotion not found`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.createPromotionRulesAndValues(
|
||||||
|
rulesData,
|
||||||
|
"application_methods",
|
||||||
|
applicationMethod,
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
|
||||||
|
return this.retrieve(promotionId, {
|
||||||
|
relations: [
|
||||||
|
"rules",
|
||||||
|
"rules.values",
|
||||||
|
"application_method",
|
||||||
|
"application_method.target_rules",
|
||||||
|
"application_method.target_rules.values",
|
||||||
|
],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
protected async createPromotionRulesAndValues(
|
protected async createPromotionRulesAndValues(
|
||||||
rulesData: PromotionTypes.CreatePromotionRuleDTO[],
|
rulesData: PromotionTypes.CreatePromotionRuleDTO[],
|
||||||
relationName: "promotions" | "application_methods",
|
relationName: "promotions" | "application_methods",
|
||||||
@@ -224,4 +413,111 @@ export default class PromotionModuleService<
|
|||||||
await this.promotionRuleValueService_.create(promotionRuleValuesData)
|
await this.promotionRuleValueService_.create(promotionRuleValuesData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@InjectTransactionManager("baseRepository_")
|
||||||
|
async delete(
|
||||||
|
ids: string[],
|
||||||
|
@MedusaContext() sharedContext: Context = {}
|
||||||
|
): Promise<void> {
|
||||||
|
await this.promotionService_.delete(ids, sharedContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
@InjectManager("baseRepository_")
|
||||||
|
async removePromotionRules(
|
||||||
|
promotionId: string,
|
||||||
|
rulesData: PromotionTypes.RemovePromotionRuleDTO[],
|
||||||
|
@MedusaContext() sharedContext: Context = {}
|
||||||
|
): Promise<PromotionTypes.PromotionDTO> {
|
||||||
|
await this.removePromotionRules_(promotionId, rulesData, sharedContext)
|
||||||
|
|
||||||
|
return this.retrieve(
|
||||||
|
promotionId,
|
||||||
|
{ relations: ["rules", "rules.values"] },
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@InjectTransactionManager("baseRepository_")
|
||||||
|
protected async removePromotionRules_(
|
||||||
|
promotionId: string,
|
||||||
|
rulesData: PromotionTypes.RemovePromotionRuleDTO[],
|
||||||
|
@MedusaContext() sharedContext: Context = {}
|
||||||
|
): Promise<void> {
|
||||||
|
const promotionRuleIdsToRemove = rulesData.map((ruleData) => ruleData.id)
|
||||||
|
const promotion = await this.promotionService_.retrieve(
|
||||||
|
promotionId,
|
||||||
|
{ relations: ["rules"] },
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
|
||||||
|
const existingPromotionRuleIds = promotion.rules
|
||||||
|
.toArray()
|
||||||
|
.map((rule) => rule.id)
|
||||||
|
|
||||||
|
const idsToRemove = promotionRuleIdsToRemove.filter((ruleId) =>
|
||||||
|
existingPromotionRuleIds.includes(ruleId)
|
||||||
|
)
|
||||||
|
|
||||||
|
await this.promotionRuleService_.delete(idsToRemove, sharedContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
@InjectManager("baseRepository_")
|
||||||
|
async removePromotionTargetRules(
|
||||||
|
promotionId: string,
|
||||||
|
rulesData: PromotionTypes.RemovePromotionRuleDTO[],
|
||||||
|
@MedusaContext() sharedContext: Context = {}
|
||||||
|
): Promise<PromotionTypes.PromotionDTO> {
|
||||||
|
await this.removePromotionTargetRules_(
|
||||||
|
promotionId,
|
||||||
|
rulesData,
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
|
||||||
|
return this.retrieve(
|
||||||
|
promotionId,
|
||||||
|
{
|
||||||
|
relations: [
|
||||||
|
"rules",
|
||||||
|
"rules.values",
|
||||||
|
"application_method",
|
||||||
|
"application_method.target_rules",
|
||||||
|
"application_method.target_rules.values",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@InjectTransactionManager("baseRepository_")
|
||||||
|
protected async removePromotionTargetRules_(
|
||||||
|
promotionId: string,
|
||||||
|
rulesData: PromotionTypes.RemovePromotionRuleDTO[],
|
||||||
|
@MedusaContext() sharedContext: Context = {}
|
||||||
|
): Promise<void> {
|
||||||
|
const promotionRuleIds = rulesData.map((ruleData) => ruleData.id)
|
||||||
|
const promotion = await this.promotionService_.retrieve(
|
||||||
|
promotionId,
|
||||||
|
{ relations: ["application_method.target_rules"] },
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
|
||||||
|
const applicationMethod = promotion.application_method
|
||||||
|
|
||||||
|
if (!applicationMethod) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
`application_method for promotion not found`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetRuleIdsToRemove = applicationMethod.target_rules
|
||||||
|
.toArray()
|
||||||
|
.filter((rule) => promotionRuleIds.includes(rule.id))
|
||||||
|
.map((rule) => rule.id)
|
||||||
|
|
||||||
|
await this.promotionRuleService_.delete(
|
||||||
|
targetRuleIdsToRemove,
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,19 +1,27 @@
|
|||||||
import {
|
import {
|
||||||
ApplicationMethodAllocation,
|
ApplicationMethodAllocationValues,
|
||||||
ApplicationMethodTargetType,
|
ApplicationMethodTargetTypeValues,
|
||||||
ApplicationMethodType,
|
ApplicationMethodTypeValues,
|
||||||
PromotionDTO,
|
PromotionDTO,
|
||||||
} from "@medusajs/types"
|
} from "@medusajs/types"
|
||||||
|
|
||||||
|
import { Promotion } from "@models"
|
||||||
|
|
||||||
export interface CreateApplicationMethodDTO {
|
export interface CreateApplicationMethodDTO {
|
||||||
type: ApplicationMethodType
|
type: ApplicationMethodTypeValues
|
||||||
target_type: ApplicationMethodTargetType
|
target_type: ApplicationMethodTargetTypeValues
|
||||||
allocation?: ApplicationMethodAllocation
|
allocation?: ApplicationMethodAllocationValues
|
||||||
value?: number
|
value?: string | null
|
||||||
promotion: PromotionDTO | string
|
promotion: Promotion | string | PromotionDTO
|
||||||
max_quantity?: number
|
max_quantity?: number | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdateApplicationMethodDTO {
|
export interface UpdateApplicationMethodDTO {
|
||||||
id: string
|
id: string
|
||||||
|
type?: ApplicationMethodTypeValues
|
||||||
|
target_type?: ApplicationMethodTargetTypeValues
|
||||||
|
allocation?: ApplicationMethodAllocationValues
|
||||||
|
value?: string | null
|
||||||
|
promotion?: Promotion | string | PromotionDTO
|
||||||
|
max_quantity?: number | null
|
||||||
}
|
}
|
||||||
@@ -8,4 +8,8 @@ export interface CreatePromotionDTO {
|
|||||||
|
|
||||||
export interface UpdatePromotionDTO {
|
export interface UpdatePromotionDTO {
|
||||||
id: string
|
id: string
|
||||||
|
code?: string
|
||||||
|
// TODO: add this when buyget is available
|
||||||
|
// type: PromotionType
|
||||||
|
is_automatic?: boolean
|
||||||
}
|
}
|
||||||
@@ -1,44 +1,86 @@
|
|||||||
|
import {
|
||||||
|
ApplicationMethodAllocationValues,
|
||||||
|
ApplicationMethodTargetTypeValues,
|
||||||
|
ApplicationMethodTypeValues,
|
||||||
|
} from "@medusajs/types"
|
||||||
import {
|
import {
|
||||||
ApplicationMethodAllocation,
|
ApplicationMethodAllocation,
|
||||||
ApplicationMethodTargetType,
|
ApplicationMethodTargetType,
|
||||||
|
ApplicationMethodType,
|
||||||
MedusaError,
|
MedusaError,
|
||||||
isDefined,
|
isDefined,
|
||||||
} from "@medusajs/utils"
|
} from "@medusajs/utils"
|
||||||
import { CreateApplicationMethodDTO } from "../../types"
|
|
||||||
|
|
||||||
const allowedTargetTypes: string[] = [
|
export const allowedAllocationTargetTypes: string[] = [
|
||||||
ApplicationMethodTargetType.SHIPPING,
|
ApplicationMethodTargetType.SHIPPING,
|
||||||
ApplicationMethodTargetType.ITEM,
|
ApplicationMethodTargetType.ITEM,
|
||||||
]
|
]
|
||||||
|
|
||||||
const allowedAllocationTypes: string[] = [
|
export const allowedAllocationTypes: string[] = [
|
||||||
ApplicationMethodAllocation.ACROSS,
|
ApplicationMethodAllocation.ACROSS,
|
||||||
ApplicationMethodAllocation.EACH,
|
ApplicationMethodAllocation.EACH,
|
||||||
]
|
]
|
||||||
|
|
||||||
const allowedAllocationForQuantity: string[] = [
|
export const allowedAllocationForQuantity: string[] = [
|
||||||
ApplicationMethodAllocation.EACH,
|
ApplicationMethodAllocation.EACH,
|
||||||
]
|
]
|
||||||
|
|
||||||
export function validateApplicationMethodAttributes(
|
export function validateApplicationMethodAttributes(data: {
|
||||||
data: CreateApplicationMethodDTO
|
type: ApplicationMethodTypeValues
|
||||||
) {
|
target_type: ApplicationMethodTargetTypeValues
|
||||||
|
allocation?: ApplicationMethodAllocationValues
|
||||||
|
max_quantity?: number | null
|
||||||
|
}) {
|
||||||
|
const allTargetTypes: string[] = Object.values(ApplicationMethodTargetType)
|
||||||
|
|
||||||
|
if (!allTargetTypes.includes(data.target_type)) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
`application_method.target_type should be one of ${allTargetTypes.join(
|
||||||
|
", "
|
||||||
|
)}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const allTypes: string[] = Object.values(ApplicationMethodType)
|
||||||
|
|
||||||
|
if (!allTypes.includes(data.type)) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
`application_method.type should be one of ${allTypes.join(", ")}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
allowedTargetTypes.includes(data.target_type) &&
|
allowedAllocationTargetTypes.includes(data.target_type) &&
|
||||||
!allowedAllocationTypes.includes(data.allocation || "")
|
!allowedAllocationTypes.includes(data.allocation || "")
|
||||||
) {
|
) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
MedusaError.Types.INVALID_DATA,
|
MedusaError.Types.INVALID_DATA,
|
||||||
`application_method.allocation should be either '${allowedAllocationTypes.join(
|
`application_method.allocation should be either '${allowedAllocationTypes.join(
|
||||||
" OR "
|
" OR "
|
||||||
)}' when application_method.target_type is either '${allowedTargetTypes.join(
|
)}' when application_method.target_type is either '${allowedAllocationTargetTypes.join(
|
||||||
" OR "
|
" OR "
|
||||||
)}'`
|
)}'`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const allAllocationTypes: string[] = Object.values(
|
||||||
|
ApplicationMethodAllocation
|
||||||
|
)
|
||||||
|
|
||||||
|
if (data.allocation && !allAllocationTypes.includes(data.allocation)) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
`application_method.allocation should be one of ${allAllocationTypes.join(
|
||||||
|
", "
|
||||||
|
)}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
allowedAllocationForQuantity.includes(data.allocation || "") &&
|
data.allocation &&
|
||||||
|
allowedAllocationForQuantity.includes(data.allocation) &&
|
||||||
!isDefined(data.max_quantity)
|
!isDefined(data.max_quantity)
|
||||||
) {
|
) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
|
|||||||
@@ -1,33 +1,46 @@
|
|||||||
import { BaseFilterable } from "../../dal"
|
import { BaseFilterable } from "../../dal"
|
||||||
import { PromotionDTO } from "./promotion"
|
import { PromotionDTO } from "./promotion"
|
||||||
import { CreatePromotionRuleDTO } from "./promotion-rule"
|
import { CreatePromotionRuleDTO, PromotionRuleDTO } from "./promotion-rule"
|
||||||
|
|
||||||
export type ApplicationMethodType = "fixed" | "percentage"
|
export type ApplicationMethodTypeValues = "fixed" | "percentage"
|
||||||
export type ApplicationMethodTargetType = "order" | "shipping" | "item"
|
export type ApplicationMethodTargetTypeValues = "order" | "shipping" | "item"
|
||||||
export type ApplicationMethodAllocation = "each" | "across"
|
export type ApplicationMethodAllocationValues = "each" | "across"
|
||||||
|
|
||||||
export interface ApplicationMethodDTO {
|
export interface ApplicationMethodDTO {
|
||||||
id: string
|
id: string
|
||||||
|
type?: ApplicationMethodTypeValues
|
||||||
|
target_type?: ApplicationMethodTargetTypeValues
|
||||||
|
allocation?: ApplicationMethodAllocationValues
|
||||||
|
value?: string | null
|
||||||
|
max_quantity?: number | null
|
||||||
|
promotion?: PromotionDTO | string
|
||||||
|
target_rules?: PromotionRuleDTO[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreateApplicationMethodDTO {
|
export interface CreateApplicationMethodDTO {
|
||||||
type: ApplicationMethodType
|
type: ApplicationMethodTypeValues
|
||||||
target_type: ApplicationMethodTargetType
|
target_type: ApplicationMethodTargetTypeValues
|
||||||
allocation?: ApplicationMethodAllocation
|
allocation?: ApplicationMethodAllocationValues
|
||||||
value?: number
|
value?: string | null
|
||||||
max_quantity?: number
|
max_quantity?: number | null
|
||||||
promotion?: PromotionDTO | string
|
promotion?: PromotionDTO | string
|
||||||
target_rules?: CreatePromotionRuleDTO[]
|
target_rules?: CreatePromotionRuleDTO[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdateApplicationMethodDTO {
|
export interface UpdateApplicationMethodDTO {
|
||||||
id: string
|
id: string
|
||||||
|
type?: ApplicationMethodTypeValues
|
||||||
|
target_type?: ApplicationMethodTargetTypeValues
|
||||||
|
allocation?: ApplicationMethodAllocationValues
|
||||||
|
value?: string | null
|
||||||
|
max_quantity?: number | null
|
||||||
|
promotion?: PromotionDTO | string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FilterableApplicationMethodProps
|
export interface FilterableApplicationMethodProps
|
||||||
extends BaseFilterable<FilterableApplicationMethodProps> {
|
extends BaseFilterable<FilterableApplicationMethodProps> {
|
||||||
id?: string[]
|
id?: string[]
|
||||||
type?: ApplicationMethodType[]
|
type?: ApplicationMethodTypeValues[]
|
||||||
target_type?: ApplicationMethodTargetType[]
|
target_type?: ApplicationMethodTargetTypeValues[]
|
||||||
allocation?: ApplicationMethodAllocation[]
|
allocation?: ApplicationMethodAllocationValues[]
|
||||||
}
|
}
|
||||||
@@ -24,6 +24,10 @@ export interface UpdatePromotionRuleDTO {
|
|||||||
id: string
|
id: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface RemovePromotionRuleDTO {
|
||||||
|
id: string
|
||||||
|
}
|
||||||
|
|
||||||
export interface FilterablePromotionRuleProps
|
export interface FilterablePromotionRuleProps
|
||||||
extends BaseFilterable<FilterablePromotionRuleProps> {
|
extends BaseFilterable<FilterablePromotionRuleProps> {
|
||||||
id?: string[]
|
id?: string[]
|
||||||
|
|||||||
@@ -1,11 +1,19 @@
|
|||||||
import { BaseFilterable } from "../../dal"
|
import { BaseFilterable } from "../../dal"
|
||||||
import { CreateApplicationMethodDTO } from "./application-method"
|
import {
|
||||||
|
ApplicationMethodDTO,
|
||||||
|
CreateApplicationMethodDTO,
|
||||||
|
UpdateApplicationMethodDTO,
|
||||||
|
} from "./application-method"
|
||||||
import { CreatePromotionRuleDTO } from "./promotion-rule"
|
import { CreatePromotionRuleDTO } from "./promotion-rule"
|
||||||
|
|
||||||
export type PromotionType = "standard" | "buyget"
|
export type PromotionType = "standard" | "buyget"
|
||||||
|
|
||||||
export interface PromotionDTO {
|
export interface PromotionDTO {
|
||||||
id: string
|
id: string
|
||||||
|
code?: string
|
||||||
|
type?: PromotionType
|
||||||
|
is_automatic?: boolean
|
||||||
|
application_method?: ApplicationMethodDTO
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CreatePromotionDTO {
|
export interface CreatePromotionDTO {
|
||||||
@@ -18,6 +26,10 @@ export interface CreatePromotionDTO {
|
|||||||
|
|
||||||
export interface UpdatePromotionDTO {
|
export interface UpdatePromotionDTO {
|
||||||
id: string
|
id: string
|
||||||
|
is_automatic?: boolean
|
||||||
|
code?: string
|
||||||
|
type?: PromotionType
|
||||||
|
application_method?: UpdateApplicationMethodDTO
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FilterablePromotionProps
|
export interface FilterablePromotionProps
|
||||||
|
|||||||
@@ -3,8 +3,11 @@ import { IModuleService } from "../modules-sdk"
|
|||||||
import { Context } from "../shared-context"
|
import { Context } from "../shared-context"
|
||||||
import {
|
import {
|
||||||
CreatePromotionDTO,
|
CreatePromotionDTO,
|
||||||
|
CreatePromotionRuleDTO,
|
||||||
FilterablePromotionProps,
|
FilterablePromotionProps,
|
||||||
PromotionDTO,
|
PromotionDTO,
|
||||||
|
RemovePromotionRuleDTO,
|
||||||
|
UpdatePromotionDTO,
|
||||||
} from "./common"
|
} from "./common"
|
||||||
|
|
||||||
export interface IPromotionModuleService extends IModuleService {
|
export interface IPromotionModuleService extends IModuleService {
|
||||||
@@ -13,9 +16,46 @@ export interface IPromotionModuleService extends IModuleService {
|
|||||||
sharedContext?: Context
|
sharedContext?: Context
|
||||||
): Promise<PromotionDTO[]>
|
): Promise<PromotionDTO[]>
|
||||||
|
|
||||||
|
update(
|
||||||
|
data: UpdatePromotionDTO[],
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<PromotionDTO[]>
|
||||||
|
|
||||||
list(
|
list(
|
||||||
filters?: FilterablePromotionProps,
|
filters?: FilterablePromotionProps,
|
||||||
config?: FindConfig<PromotionDTO>,
|
config?: FindConfig<PromotionDTO>,
|
||||||
sharedContext?: Context
|
sharedContext?: Context
|
||||||
): Promise<PromotionDTO[]>
|
): Promise<PromotionDTO[]>
|
||||||
|
|
||||||
|
retrieve(
|
||||||
|
id: string,
|
||||||
|
config?: FindConfig<PromotionDTO>,
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<PromotionDTO>
|
||||||
|
|
||||||
|
delete(ids: string[], sharedContext?: Context): Promise<void>
|
||||||
|
|
||||||
|
addPromotionRules(
|
||||||
|
promotionId: string,
|
||||||
|
rulesData: CreatePromotionRuleDTO[],
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<PromotionDTO>
|
||||||
|
|
||||||
|
addPromotionTargetRules(
|
||||||
|
promotionId: string,
|
||||||
|
rulesData: CreatePromotionRuleDTO[],
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<PromotionDTO>
|
||||||
|
|
||||||
|
removePromotionRules(
|
||||||
|
promotionId: string,
|
||||||
|
rulesData: RemovePromotionRuleDTO[],
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<PromotionDTO>
|
||||||
|
|
||||||
|
removePromotionTargetRules(
|
||||||
|
promotionId: string,
|
||||||
|
rulesData: RemovePromotionRuleDTO[],
|
||||||
|
sharedContext?: Context
|
||||||
|
): Promise<PromotionDTO>
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user