Merge branch 'fix/discount-usage' into develop
This commit is contained in:
@@ -38,6 +38,8 @@ describe("POST /admin/discounts/:discount_id/regions/:region_id", () => {
|
||||
"is_disabled",
|
||||
"rule_id",
|
||||
"parent_discount_id",
|
||||
"usage_limit",
|
||||
"usage_count",
|
||||
"starts_at",
|
||||
"ends_at",
|
||||
"created_at",
|
||||
|
||||
@@ -38,6 +38,8 @@ describe("POST /admin/discounts/:discount_id/variants/:variant_id", () => {
|
||||
"is_disabled",
|
||||
"rule_id",
|
||||
"parent_discount_id",
|
||||
"usage_limit",
|
||||
"usage_count",
|
||||
"starts_at",
|
||||
"ends_at",
|
||||
"created_at",
|
||||
|
||||
@@ -11,6 +11,7 @@ describe("POST /admin/discounts", () => {
|
||||
payload: {
|
||||
code: "TEST",
|
||||
rule: {
|
||||
description: "Test",
|
||||
type: "fixed",
|
||||
value: 10,
|
||||
allocation: "total",
|
||||
@@ -33,6 +34,7 @@ describe("POST /admin/discounts", () => {
|
||||
expect(DiscountServiceMock.create).toHaveBeenCalledWith({
|
||||
code: "TEST",
|
||||
rule: {
|
||||
description: "Test",
|
||||
type: "fixed",
|
||||
value: 10,
|
||||
allocation: "total",
|
||||
@@ -51,6 +53,7 @@ describe("POST /admin/discounts", () => {
|
||||
payload: {
|
||||
code: "10%OFF",
|
||||
rule: {
|
||||
description: "Test",
|
||||
value: 10,
|
||||
allocation: "total",
|
||||
},
|
||||
|
||||
@@ -9,6 +9,8 @@ const defaultFields = [
|
||||
"is_disabled",
|
||||
"rule_id",
|
||||
"parent_discount_id",
|
||||
"usage_limit",
|
||||
"usage_count",
|
||||
"starts_at",
|
||||
"ends_at",
|
||||
"created_at",
|
||||
|
||||
@@ -9,6 +9,8 @@ const defaultFields = [
|
||||
"is_disabled",
|
||||
"rule_id",
|
||||
"parent_discount_id",
|
||||
"usage_limit",
|
||||
"usage_count",
|
||||
"starts_at",
|
||||
"ends_at",
|
||||
"created_at",
|
||||
|
||||
@@ -9,6 +9,8 @@ const defaultFields = [
|
||||
"is_disabled",
|
||||
"rule_id",
|
||||
"parent_discount_id",
|
||||
"usage_limit",
|
||||
"usage_count",
|
||||
"starts_at",
|
||||
"ends_at",
|
||||
"created_at",
|
||||
|
||||
@@ -36,6 +36,9 @@ import { MedusaError, Validator } from "medusa-core-utils"
|
||||
* type: array
|
||||
* items:
|
||||
* type: string
|
||||
* usage_limit:
|
||||
* type: number
|
||||
* description: Maximum times the discount can be used
|
||||
* metadata:
|
||||
* description: An optional set of key-value pairs to hold additional information.
|
||||
* type: object
|
||||
@@ -64,14 +67,14 @@ export default async (req, res) => {
|
||||
.required(),
|
||||
allocation: Validator.string().required(),
|
||||
valid_for: Validator.array().items(Validator.string()),
|
||||
usage_limit: Validator.number()
|
||||
.positive()
|
||||
.optional(),
|
||||
})
|
||||
.required(),
|
||||
is_disabled: Validator.boolean().default(false),
|
||||
starts_at: Validator.date().optional(),
|
||||
ends_at: Validator.date().optional(),
|
||||
usage_limit: Validator.number()
|
||||
.positive()
|
||||
.optional(),
|
||||
regions: Validator.array()
|
||||
.items(Validator.string())
|
||||
.optional(),
|
||||
|
||||
@@ -26,6 +26,7 @@ export default async (req, res) => {
|
||||
|
||||
const schema = Validator.object().keys({
|
||||
code: Validator.string().required(),
|
||||
usage_limit: Validator.number().default(1),
|
||||
metadata: Validator.object().optional(),
|
||||
})
|
||||
|
||||
|
||||
@@ -62,6 +62,8 @@ export const defaultFields = [
|
||||
"is_disabled",
|
||||
"rule_id",
|
||||
"parent_discount_id",
|
||||
"usage_limit",
|
||||
"usage_count",
|
||||
"starts_at",
|
||||
"ends_at",
|
||||
"created_at",
|
||||
|
||||
@@ -64,14 +64,14 @@ export default async (req, res) => {
|
||||
value: Validator.number().required(),
|
||||
allocation: Validator.string().required(),
|
||||
valid_for: Validator.array().items(Validator.string()),
|
||||
usage_limit: Validator.number()
|
||||
.positive()
|
||||
.optional(),
|
||||
})
|
||||
.optional(),
|
||||
is_disabled: Validator.boolean().optional(),
|
||||
starts_at: Validator.date().optional(),
|
||||
ends_at: Validator.date().optional(),
|
||||
usage_limit: Validator.number()
|
||||
.positive()
|
||||
.optional(),
|
||||
regions: Validator.array()
|
||||
.items(Validator.string())
|
||||
.optional(),
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm"
|
||||
|
||||
export class discountUsage1617002207608 implements MigrationInterface {
|
||||
name = "discountUsage1617002207608"
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "discount_rule" DROP COLUMN "usage_limit"`
|
||||
)
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "discount_rule" DROP COLUMN "usage_count"`
|
||||
)
|
||||
await queryRunner.query(`ALTER TABLE "discount" ADD "usage_limit" integer`)
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "discount" ADD "usage_count" integer NOT NULL DEFAULT '0'`
|
||||
)
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "discount_rule" ALTER COLUMN "description" DROP NOT NULL`
|
||||
)
|
||||
await queryRunner.query(
|
||||
`COMMENT ON COLUMN "discount_rule"."description" IS NULL`
|
||||
)
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "discount" DROP COLUMN "usage_count"`)
|
||||
await queryRunner.query(`ALTER TABLE "discount" DROP COLUMN "usage_limit"`)
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "discount_rule" ADD "usage_count" integer NOT NULL DEFAULT '0'`
|
||||
)
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "discount_rule" ADD "usage_limit" integer`
|
||||
)
|
||||
await queryRunner.query(
|
||||
`COMMENT ON COLUMN "discount_rule"."description" IS NULL`
|
||||
)
|
||||
await queryRunner.query(
|
||||
`ALTER TABLE "discount_rule" ALTER COLUMN "description" SET NOT NULL`
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ export class DiscountRule {
|
||||
@PrimaryColumn()
|
||||
id: string
|
||||
|
||||
@Column()
|
||||
@Column({ nullable: true })
|
||||
description: string
|
||||
|
||||
@Column({
|
||||
@@ -63,12 +63,6 @@ export class DiscountRule {
|
||||
})
|
||||
valid_for: Product[]
|
||||
|
||||
@Column({ nullable: true })
|
||||
usage_limit: number
|
||||
|
||||
@Column({ default: 0 })
|
||||
usage_count: number
|
||||
|
||||
@CreateDateColumn({ type: "timestamptz" })
|
||||
created_at: Date
|
||||
|
||||
@@ -121,12 +115,6 @@ export class DiscountRule {
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: "#/components/schemas/product"
|
||||
* usage_limit:
|
||||
* description: "The maximum number of times that a discount can be used."
|
||||
* type: integer
|
||||
* usage_count:
|
||||
* description: "The number of times a discount has been used."
|
||||
* type: integer
|
||||
* created_at:
|
||||
* description: "The date with timezone at which the resource was created."
|
||||
* type: string
|
||||
|
||||
@@ -68,6 +68,12 @@ export class Discount {
|
||||
})
|
||||
regions: Region[]
|
||||
|
||||
@Column({ nullable: true })
|
||||
usage_limit: number
|
||||
|
||||
@Column({ default: 0 })
|
||||
usage_count: number
|
||||
|
||||
@CreateDateColumn({ type: "timestamptz" })
|
||||
created_at: Date
|
||||
|
||||
@@ -127,6 +133,12 @@ export class Discount {
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: "#/components/schemas/region"
|
||||
* usage_limit:
|
||||
* description: "The maximum number of times that a discount can be used."
|
||||
* type: integer
|
||||
* usage_count:
|
||||
* description: "The number of times a discount has been used."
|
||||
* type: integer
|
||||
* created_at:
|
||||
* description: "The date with timezone at which the resource was created."
|
||||
* type: string
|
||||
|
||||
@@ -1467,10 +1467,9 @@ describe("CartService", () => {
|
||||
id: IdMap.getId("limit-reached"),
|
||||
code: "limit-reached",
|
||||
regions: [{ id: IdMap.getId("good") }],
|
||||
rule: {
|
||||
usage_count: 2,
|
||||
usage_limit: 2,
|
||||
},
|
||||
rule: {},
|
||||
usage_count: 2,
|
||||
usage_limit: 2,
|
||||
})
|
||||
}
|
||||
if (code === "null-count") {
|
||||
@@ -1478,10 +1477,9 @@ describe("CartService", () => {
|
||||
id: IdMap.getId("null-count"),
|
||||
code: "null-count",
|
||||
regions: [{ id: IdMap.getId("good") }],
|
||||
rule: {
|
||||
usage_count: null,
|
||||
usage_limit: 2,
|
||||
},
|
||||
rule: {},
|
||||
usage_count: null,
|
||||
usage_limit: 2,
|
||||
})
|
||||
}
|
||||
if (code === "FREESHIPPING") {
|
||||
@@ -1630,10 +1628,9 @@ describe("CartService", () => {
|
||||
id: IdMap.getId("null-count"),
|
||||
code: "null-count",
|
||||
regions: [{ id: IdMap.getId("good") }],
|
||||
rule: {
|
||||
usage_count: 0,
|
||||
usage_limit: 2,
|
||||
},
|
||||
usage_count: 0,
|
||||
usage_limit: 2,
|
||||
rule: {},
|
||||
},
|
||||
],
|
||||
discount_total: 0,
|
||||
|
||||
@@ -814,10 +814,10 @@ class CartService extends BaseService {
|
||||
const rule = discount.rule
|
||||
|
||||
// if limit is set and reached, we make an early exit
|
||||
if (rule?.usage_limit) {
|
||||
rule.usage_count = rule.usage_count || 0
|
||||
if (discount.usage_limit) {
|
||||
discount.usage_count = discount.usage_count || 0
|
||||
|
||||
if (rule.usage_limit === rule.usage_count)
|
||||
if (discount.usage_limit === discount.usage_count)
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_ALLOWED,
|
||||
"Discount has been used maximum allowed times"
|
||||
|
||||
@@ -83,13 +83,6 @@ class DiscountService extends BaseService {
|
||||
.required(),
|
||||
allocation: Validator.string().required(),
|
||||
valid_for: Validator.array().optional(),
|
||||
usage_limit: Validator.number()
|
||||
.positive()
|
||||
.allow(null)
|
||||
.optional(),
|
||||
usage_count: Validator.number()
|
||||
.positive()
|
||||
.optional(),
|
||||
created_at: Validator.date().optional(),
|
||||
updated_at: Validator.date()
|
||||
.allow(null)
|
||||
@@ -337,6 +330,7 @@ class DiscountService extends BaseService {
|
||||
is_disabled: false,
|
||||
code: data.code.toUpperCase(),
|
||||
parent_discount_id: discount.id,
|
||||
usage_limit: discount.usage_limit,
|
||||
}
|
||||
|
||||
const created = await discountRepo.create(toCreate)
|
||||
|
||||
@@ -48,12 +48,9 @@ class OrderSubscriber {
|
||||
|
||||
await Promise.all(
|
||||
order.discounts.map(async d => {
|
||||
const usageCount = d.rule?.usage_count || 0
|
||||
const usageCount = d?.usage_count || 0
|
||||
return this.discountService_.update(d.id, {
|
||||
rule: {
|
||||
...d.rule,
|
||||
usage_count: usageCount + 1,
|
||||
},
|
||||
usage_count: usageCount + 1,
|
||||
})
|
||||
})
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user