fix(medusa): Normalize discount code before querying DB (#2224)

**What**
Normalize discount code before querying DB

Fixes CORE-567
This commit is contained in:
Oliver Windall Juhl authored and GitHub committed 2022-09-16 12:01:36 +00:00
1 parent f7177c9033
commit 3f73170288
7 files changed
+143 -20

No files matched your search

+5
View File
@@ -0,0 +1,5 @@
---
"@medusajs/medusa": patch
---
Normalize discount code before querying DB in `DiscountService.retrieveByCode`
@@ -403,7 +403,7 @@ describe("/admin/discounts", () => {
expect.objectContaining({ expect.objectContaining({
id: "dynamic-discount", id: "dynamic-discount",
code: "Dyn100", code: "Dyn100",
}) }),
]) ])
) )
}) })
@@ -2365,4 +2365,120 @@ describe("/admin/discounts", () => {
} }
}) })
}) })
describe("GET /admin/discounts/code/:code", () => {
beforeEach(async () => {
const manager = dbConnection.manager
await adminSeeder(dbConnection)
await manager.insert(DiscountRule, {
id: "test-discount-rule-fixed",
description: "Test discount rule",
type: "fixed",
value: 10,
allocation: "total",
})
await simpleDiscountFactory(dbConnection, {
id: "test-discount",
code: "TEST",
rule: {
type: "percentage",
value: "10",
allocation: "total",
},
})
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should retrieve discount using uppercase code", async () => {
const api = useApi()
const response = await api
.get("/admin/discounts/code/TEST", {
headers: {
Authorization: "Bearer test_token",
},
})
.catch((err) => {
console.log(err)
})
const disc = response.data.discount
expect(response.status).toEqual(200)
expect(disc).toEqual(
expect.objectContaining({
id: "test-discount",
code: "TEST",
})
)
})
it("should retrieve discount using lowercase code", async () => {
const api = useApi()
const response = await api
.get("/admin/discounts/code/test", {
headers: {
Authorization: "Bearer test_token",
},
})
.catch((err) => {
console.log(err)
})
const disc = response.data.discount
expect(response.status).toEqual(200)
expect(disc).toEqual(
expect.objectContaining({
id: "test-discount",
code: "TEST",
})
)
})
it("should retrieve discount using mixed casing code", async () => {
const api = useApi()
const response = await api
.get("/admin/discounts/code/TesT", {
headers: {
Authorization: "Bearer test_token",
},
})
.catch((err) => {
console.log(err)
})
const disc = response.data.discount
expect(response.status).toEqual(200)
expect(disc).toEqual(
expect.objectContaining({
id: "test-discount",
code: "TEST",
})
)
})
it("should respond with 404 on non-existing code", async () => {
const api = useApi()
try {
await api.get("/admin/discounts/code/non-existing", {
headers: {
Authorization: "Bearer test_token",
},
})
} catch (error) {
expect(error.response.status).toEqual(404)
expect(error.response.data.message).toBe(
"Discount with code non-existing was not found"
)
}
})
})
}) })
@@ -420,7 +420,7 @@ describe("/admin/draft-orders", () => {
code: "TEST", code: "TEST",
}), }),
expect.objectContaining({ expect.objectContaining({
code: "free-shipping", code: "FREE-SHIPPING",
}), }),
]) ])
) )
@@ -2,13 +2,13 @@ import {
AllocationType, AllocationType,
Discount, Discount,
DiscountRule, DiscountRule,
DiscountRuleType, DiscountRuleType
} from "@medusajs/medusa" } from "@medusajs/medusa"
import faker from "faker" import faker from "faker"
import { Connection } from "typeorm" import { Connection } from "typeorm"
import { import {
DiscountConditionFactoryData, DiscountConditionFactoryData,
simpleDiscountConditionFactory, simpleDiscountConditionFactory
} from "./simple-discount-condition-factory" } from "./simple-discount-condition-factory"
export type DiscountRuleFactoryData = { export type DiscountRuleFactoryData = {
@@ -137,7 +137,7 @@ module.exports = async (connection, data = {}) => {
const freeShippingDiscount = manager.create(Discount, { const freeShippingDiscount = manager.create(Discount, {
id: "free-shipping-discount", id: "free-shipping-discount",
code: "free-shipping", code: "FREE-SHIPPING",
is_dynamic: false, is_dynamic: false,
is_disabled: false, is_disabled: false,
rule_id: "free-shipping-rule", rule_id: "free-shipping-rule",
+4 -4
View File
@@ -6,14 +6,14 @@ import {
JoinColumn, JoinColumn,
JoinTable, JoinTable,
ManyToMany, ManyToMany,
ManyToOne, ManyToOne
} from "typeorm" } from "typeorm"
import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column" import { DbAwareColumn, resolveDbType } from "../utils/db-aware-column"
import { DiscountRule } from "./discount-rule"
import { Region } from "./region"
import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity" import { SoftDeletableEntity } from "../interfaces/models/soft-deletable-entity"
import { generateEntityId } from "../utils/generate-entity-id" import { generateEntityId } from "../utils/generate-entity-id"
import { DiscountRule } from "./discount-rule"
import { Region } from "./region"
@Entity() @Entity()
export class Discount extends SoftDeletableEntity { export class Discount extends SoftDeletableEntity {
@@ -79,10 +79,10 @@ export class Discount extends SoftDeletableEntity {
@BeforeInsert() @BeforeInsert()
private upperCaseCode(): void { private upperCaseCode(): void {
this.code = this.code.toUpperCase()
if (this.id) return if (this.id) return
this.id = generateEntityId(this.id, "disc") this.id = generateEntityId(this.id, "disc")
this.code = this.code.toUpperCase()
} }
} }
+13 -11
View File
@@ -6,19 +6,21 @@ import {
DeepPartial, DeepPartial,
EntityManager, EntityManager,
ILike, ILike,
SelectQueryBuilder, SelectQueryBuilder
} from "typeorm" } from "typeorm"
import { import {
EventBusService, EventBusService,
ProductService, ProductService,
RegionService, RegionService,
TotalsService, TotalsService
} from "." } from "."
import { TransactionBaseService } from "../interfaces"
import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing"
import { Cart, Discount, LineItem, Region } from "../models" import { Cart, Discount, LineItem, Region } from "../models"
import { import {
AllocationType as DiscountAllocation, AllocationType as DiscountAllocation,
DiscountRule, DiscountRule,
DiscountRuleType, DiscountRuleType
} from "../models/discount-rule" } from "../models/discount-rule"
import { DiscountRepository } from "../repositories/discount" import { DiscountRepository } from "../repositories/discount"
import { DiscountConditionRepository } from "../repositories/discount-condition" import { DiscountConditionRepository } from "../repositories/discount-condition"
@@ -31,16 +33,14 @@ import {
CreateDynamicDiscountInput, CreateDynamicDiscountInput,
FilterableDiscountProps, FilterableDiscountProps,
UpdateDiscountInput, UpdateDiscountInput,
UpdateDiscountRuleInput, UpdateDiscountRuleInput
} from "../types/discount" } from "../types/discount"
import { buildQuery, setMetadata } from "../utils"
import { isFuture, isPast } from "../utils/date-helpers" import { isFuture, isPast } from "../utils/date-helpers"
import { formatException } from "../utils/exception-formatter" import { formatException } from "../utils/exception-formatter"
import DiscountConditionService from "./discount-condition"
import CustomerService from "./customer"
import { TransactionBaseService } from "../interfaces"
import { buildQuery, setMetadata } from "../utils"
import { FlagRouter } from "../utils/flag-router" import { FlagRouter } from "../utils/flag-router"
import TaxInclusivePricingFeatureFlag from "../loaders/feature-flags/tax-inclusive-pricing" import CustomerService from "./customer"
import DiscountConditionService from "./discount-condition"
/** /**
* Provides layer to manipulate discounts. * Provides layer to manipulate discounts.
@@ -276,11 +276,13 @@ class DiscountService extends TransactionBaseService {
const manager = this.manager_ const manager = this.manager_
const discountRepo = manager.getCustomRepository(this.discountRepository_) const discountRepo = manager.getCustomRepository(this.discountRepository_)
let query = buildQuery({ code: discountCode, is_dynamic: false }, config) const normalizedCode = discountCode.toUpperCase()
let query = buildQuery({ code: normalizedCode, is_dynamic: false }, config)
let discount = await discountRepo.findOne(query) let discount = await discountRepo.findOne(query)
if (!discount) { if (!discount) {
query = buildQuery({ code: discountCode, is_dynamic: true }, config) query = buildQuery({ code: normalizedCode, is_dynamic: true }, config)
discount = await discountRepo.findOne(query) discount = await discountRepo.findOne(query)
if (!discount) { if (!discount) {