Adds admin discount routes / endpoints (#34)

This commit is contained in:
Oliver Windall Juhl
2020-04-12 17:18:07 +02:00
committed by GitHub
parent 42fdd14e42
commit 20735de62d
21 changed files with 640 additions and 0 deletions

View File

@@ -0,0 +1,42 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { DiscountServiceMock } from "../../../../../services/__mocks__/discount"
describe("POST /admin/discounts/:discount_id/regions/:region_id", () => {
describe("successful addition", () => {
let subject
beforeAll(async () => {
subject = await request(
"POST",
`/admin/discounts/${IdMap.getId("total10")}/regions/${IdMap.getId(
"region-france"
)}`,
{
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
}
)
})
it("returns 200", () => {
expect(subject.status).toEqual(200)
})
it("calls service retrieve", () => {
expect(DiscountServiceMock.retrieve).toHaveBeenCalledTimes(1)
expect(DiscountServiceMock.retrieve).toHaveBeenCalledWith(
IdMap.getId("total10")
)
expect(DiscountServiceMock.addRegion).toHaveBeenCalledTimes(1)
expect(DiscountServiceMock.addRegion).toHaveBeenCalledWith(
IdMap.getId("total10"),
IdMap.getId("region-france")
)
})
})
})

View File

@@ -0,0 +1,42 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { DiscountServiceMock } from "../../../../../services/__mocks__/discount"
describe("POST /admin/discounts/:discount_id/variants/:variant_id", () => {
describe("successful addition", () => {
let subject
beforeAll(async () => {
subject = await request(
"POST",
`/admin/discounts/${IdMap.getId("total10")}/variants/${IdMap.getId(
"testVariant"
)}`,
{
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
}
)
})
it("returns 200", () => {
expect(subject.status).toEqual(200)
})
it("calls service retrieve", () => {
expect(DiscountServiceMock.retrieve).toHaveBeenCalledTimes(1)
expect(DiscountServiceMock.retrieve).toHaveBeenCalledWith(
IdMap.getId("total10")
)
expect(DiscountServiceMock.addValidVariant).toHaveBeenCalledTimes(1)
expect(DiscountServiceMock.addValidVariant).toHaveBeenCalledWith(
IdMap.getId("total10"),
IdMap.getId("testVariant")
)
})
})
})

View File

@@ -0,0 +1,74 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { DiscountServiceMock } from "../../../../../services/__mocks__/discount"
describe("POST /admin/discounts", () => {
describe("successful creation", () => {
let subject
beforeAll(async () => {
subject = await request("POST", "/admin/discounts", {
payload: {
code: "TEST",
discount_rule: {
type: "fixed",
value: 10,
allocation: "total",
},
},
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
})
})
it("returns 200", () => {
expect(subject.status).toEqual(200)
})
it("calls service create", () => {
expect(DiscountServiceMock.create).toHaveBeenCalledTimes(1)
expect(DiscountServiceMock.create).toHaveBeenCalledWith({
code: "TEST",
discount_rule: {
type: "fixed",
value: 10,
allocation: "total",
},
})
})
})
describe("fails on invalid data", () => {
let subject
beforeAll(async () => {
subject = await request("POST", "/admin/discounts", {
payload: {
code: "10%OFF",
discount_rule: {
value: 10,
allocation: "total",
},
},
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
})
})
it("returns 400", () => {
expect(subject.status).toEqual(400)
})
it("returns error", () => {
expect(subject.body.message[0].message).toEqual(
`"discount_rule.type" is required`
)
})
})
})

View File

@@ -0,0 +1,42 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { DiscountServiceMock } from "../../../../../services/__mocks__/discount"
describe("DELETE /admin/discounts/discount_id", () => {
describe("successful deletion", () => {
let subject
beforeAll(async () => {
subject = await request(
"DELETE",
`/admin/discounts/${IdMap.getId("total10")}`,
{
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
}
)
})
it("returns 200", () => {
expect(subject.status).toEqual(200)
})
it("calls service delete", () => {
expect(DiscountServiceMock.delete).toHaveBeenCalledTimes(1)
expect(DiscountServiceMock.delete).toHaveBeenCalledWith(
IdMap.getId("total10")
)
})
it("returns correct delete object", () => {
expect(subject.body).toEqual({
id: IdMap.getId("total10"),
object: "discount",
deleted: true,
})
})
})
})

View File

@@ -0,0 +1,34 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { DiscountServiceMock } from "../../../../../services/__mocks__/discount"
describe("GET /admin/discounts/:discount_id", () => {
describe("successful retrieval", () => {
let subject
beforeAll(async () => {
subject = await request(
"GET",
`/admin/discounts/${IdMap.getId("total10")}`,
{
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
}
)
})
it("returns 200", () => {
expect(subject.status).toEqual(200)
})
it("calls service retrieve", () => {
expect(DiscountServiceMock.retrieve).toHaveBeenCalledTimes(1)
expect(DiscountServiceMock.retrieve).toHaveBeenCalledWith(
IdMap.getId("total10")
)
})
})
})

View File

@@ -0,0 +1,28 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { DiscountServiceMock } from "../../../../../services/__mocks__/discount"
describe("GET /admin/discounts", () => {
describe("successful retrieval", () => {
let subject
beforeAll(async () => {
subject = await request("GET", `/admin/discounts`, {
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
})
})
it("returns 200", () => {
expect(subject.status).toEqual(200)
})
it("calls service retrieve", () => {
expect(DiscountServiceMock.list).toHaveBeenCalledTimes(1)
expect(DiscountServiceMock.list).toHaveBeenCalledWith()
})
})
})

View File

@@ -0,0 +1,42 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { DiscountServiceMock } from "../../../../../services/__mocks__/discount"
describe("DELETE /admin/discounts/:discount_id/regions/region_id", () => {
describe("successful removal", () => {
let subject
beforeAll(async () => {
subject = await request(
"DELETE",
`/admin/discounts/${IdMap.getId("total10")}/regions/${IdMap.getId(
"region-france"
)}`,
{
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
}
)
})
it("returns 200", () => {
expect(subject.status).toEqual(200)
})
it("calls service retrieve", () => {
expect(DiscountServiceMock.retrieve).toHaveBeenCalledTimes(1)
expect(DiscountServiceMock.retrieve).toHaveBeenCalledWith(
IdMap.getId("total10")
)
expect(DiscountServiceMock.removeRegion).toHaveBeenCalledTimes(1)
expect(DiscountServiceMock.removeRegion).toHaveBeenCalledWith(
IdMap.getId("total10"),
IdMap.getId("region-france")
)
})
})
})

View File

@@ -0,0 +1,42 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { DiscountServiceMock } from "../../../../../services/__mocks__/discount"
describe("DELETE /admin/discounts/:discount_id/variants/:variant_id", () => {
describe("successful addition", () => {
let subject
beforeAll(async () => {
subject = await request(
"DELETE",
`/admin/discounts/${IdMap.getId("total10")}/variants/${IdMap.getId(
"testVariant"
)}`,
{
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
}
)
})
it("returns 200", () => {
expect(subject.status).toEqual(200)
})
it("calls service retrieve", () => {
expect(DiscountServiceMock.retrieve).toHaveBeenCalledTimes(1)
expect(DiscountServiceMock.retrieve).toHaveBeenCalledWith(
IdMap.getId("total10")
)
expect(DiscountServiceMock.removeValidVariant).toHaveBeenCalledTimes(1)
expect(DiscountServiceMock.removeValidVariant).toHaveBeenCalledWith(
IdMap.getId("total10"),
IdMap.getId("testVariant")
)
})
})
})

View File

@@ -0,0 +1,50 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { DiscountServiceMock } from "../../../../../services/__mocks__/discount"
describe("POST /admin/discounts", () => {
describe("successful update", () => {
let subject
beforeAll(async () => {
subject = await request(
"POST",
`/admin/discounts/${IdMap.getId("total10")}`,
{
payload: {
code: "10TOTALOFF",
discount_rule: {
type: "fixed",
value: 10,
allocation: "total",
},
},
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
}
)
})
it("returns 200", () => {
expect(subject.status).toEqual(200)
})
it("calls service method", () => {
expect(DiscountServiceMock.update).toHaveBeenCalledTimes(1)
expect(DiscountServiceMock.update).toHaveBeenCalledWith(
IdMap.getId("total10"),
{
code: "10TOTALOFF",
discount_rule: {
type: "fixed",
value: 10,
allocation: "total",
},
}
)
})
})
})

View File

@@ -0,0 +1,15 @@
import { MedusaError, Validator } from "medusa-core-utils"
export default async (req, res) => {
const { discount_id, region_id } = req.params
try {
const discountService = req.scope.resolve("discountService")
await discountService.addRegion(discount_id, region_id)
const data = discountService.retrieve(discount_id)
res.status(200).json(data)
} catch (err) {
throw err
}
}

View File

@@ -0,0 +1,15 @@
import { MedusaError, Validator } from "medusa-core-utils"
export default async (req, res) => {
const { discount_id, variant_id } = req.params
try {
const discountService = req.scope.resolve("discountService")
await discountService.addValidVariant(discount_id, variant_id)
const data = discountService.retrieve(discount_id)
res.status(200).json(data)
} catch (err) {
throw err
}
}

View File

@@ -0,0 +1,39 @@
import { MedusaError, Validator } from "medusa-core-utils"
export default async (req, res) => {
const schema = Validator.object().keys({
code: Validator.string().required(),
discount_rule: Validator.object()
.keys({
description: Validator.string().optional(),
type: Validator.string().required(),
value: Validator.number().required(),
allocation: Validator.string().required(),
valid_for: Validator.array().items(Validator.string()),
usage_limit: Validator.number().optional(),
})
.required(),
usage_count: Validator.number().optional(),
disabled: Validator.boolean().optional(),
starts_at: Validator.date().optional(),
ends_at: Validator.date().optional(),
regions: Validator.array()
.items(Validator.string())
.optional(),
metadata: Validator.object().optional(),
})
const { value, error } = schema.validate(req.body)
if (error) {
throw new MedusaError(MedusaError.Types.INVALID_DATA, error.details)
}
try {
const discountService = req.scope.resolve("discountService")
const data = await discountService.create(value)
res.status(200).json(data)
} catch (err) {
throw err
}
}

View File

@@ -0,0 +1,15 @@
export default async (req, res) => {
const { discount_id } = req.params
try {
const discountService = req.scope.resolve("discountService")
await discountService.delete(discount_id)
res.json({
id: discount_id,
object: "discount",
deleted: true,
})
} catch (err) {
throw err
}
}

View File

@@ -0,0 +1,11 @@
export default async (req, res) => {
const { discount_id } = req.params
try {
const discountService = req.scope.resolve("discountService")
const data = await discountService.retrieve(discount_id)
res.status(200).json(data)
} catch (err) {
throw err
}
}

View File

@@ -0,0 +1,46 @@
import { Router } from "express"
import middlewares from "../../../middlewares"
const route = Router()
export default app => {
app.use("/discounts", route)
route.get("/", middlewares.wrap(require("./list-discounts").default))
route.post("/", middlewares.wrap(require("./create-discount").default))
route.get(
"/:discount_id",
middlewares.wrap(require("./get-discount").default)
)
route.post(
"/:discount_id",
middlewares.wrap(require("./update-discount").default)
)
route.delete(
"/:discount_id",
middlewares.wrap(require("./delete-discount").default)
)
// Discount valid variants management
route.post(
"/:discount_id/variants/:variant_id",
middlewares.wrap(require("./add-valid-variant").default)
)
route.delete(
"/:discount_id/variants/:variant_id",
middlewares.wrap(require("./remove-valid-variant").default)
)
// Discount region management
route.post(
"/:discount_id/regions/:region_id",
middlewares.wrap(require("./add-region").default)
)
route.delete(
"/:discount_id/regions/:region_id",
middlewares.wrap(require("./remove-region").default)
)
return app
}

View File

@@ -0,0 +1,10 @@
export default async (req, res) => {
try {
const discountService = req.scope.resolve("discountService")
const data = await discountService.list()
res.status(200).json(data)
} catch (err) {
throw err
}
}

View File

@@ -0,0 +1,14 @@
export default async (req, res) => {
const { discount_id, region_id } = req.params
try {
const discountService = req.scope.resolve("discountService")
await discountService.removeRegion(discount_id, region_id)
const data = discountService.retrieve(discount_id)
res.status(200).json(data)
} catch (err) {
throw err
}
}

View File

@@ -0,0 +1,14 @@
export default async (req, res) => {
const { discount_id, variant_id } = req.params
try {
const discountService = req.scope.resolve("discountService")
await discountService.removeValidVariant(discount_id, variant_id)
const data = discountService.retrieve(discount_id)
res.status(200).json(data)
} catch (err) {
throw err
}
}

View File

@@ -0,0 +1,43 @@
import { MedusaError, Validator } from "medusa-core-utils"
export default async (req, res) => {
const { discount_id } = req.params
const schema = Validator.object().keys({
code: Validator.string().required(),
discount_rule: Validator.object()
.keys({
description: Validator.string().optional(),
type: Validator.string().required(),
value: Validator.number().required(),
allocation: Validator.string().required(),
valid_for: Validator.array().items(Validator.string()),
usage_limit: Validator.number().optional(),
})
.required(),
usage_count: Validator.number().optional(),
disabled: Validator.boolean().optional(),
starts_at: Validator.date().optional(),
ends_at: Validator.date().optional(),
regions: Validator.array()
.items(Validator.string())
.optional(),
metadata: Validator.object().optional(),
})
const { value, error } = schema.validate(req.body)
if (error) {
throw new MedusaError(MedusaError.Types.INVALID_DATA, error.details)
}
try {
const discountService = req.scope.resolve("discountService")
await discountService.update(discount_id, value)
const data = await discountService.retrieve(discount_id)
res.status(200).json(data)
} catch (err) {
throw err
}
}

View File

@@ -6,6 +6,7 @@ import productVariantRoutes from "./product-variants"
import regionRoutes from "./regions"
import shippingOptionRoutes from "./shipping-options"
import shippingProfileRoutes from "./shipping-profiles"
import discountRoutes from "./discounts"
const route = Router()
@@ -22,6 +23,7 @@ export default app => {
regionRoutes(route)
shippingOptionRoutes(route)
shippingProfileRoutes(route)
discountRoutes(route)
// productVariantRoutes(route)
return app

View File

@@ -2,6 +2,9 @@ import { IdMap } from "medusa-test-utils"
import { discounts } from "../../models/__mocks__/discount"
export const DiscountServiceMock = {
create: jest.fn().mockImplementation(data => {
return Promise.resolve(data)
}),
retrieveByCode: jest.fn().mockImplementation(data => {
if (data === "10%OFF") {
return Promise.resolve(discounts.total10Percent)
@@ -26,6 +29,23 @@ export const DiscountServiceMock = {
}
return Promise.resolve(undefined)
}),
update: jest.fn().mockImplementation(data => {
return Promise.resolve()
}),
delete: jest.fn().mockImplementation(data => {
return Promise.resolve({
_id: IdMap.getId("total10"),
object: "discount",
deleted: true,
})
}),
list: jest.fn().mockImplementation(data => {
return Promise.resolve([])
}),
addRegion: jest.fn().mockReturnValue(Promise.resolve()),
removeRegion: jest.fn().mockReturnValue(Promise.resolve()),
addValidVariant: jest.fn().mockReturnValue(Promise.resolve()),
removeValidVariant: jest.fn().mockReturnValue(Promise.resolve()),
}
const mock = jest.fn().mockImplementation(() => {