Adds Regions (#33)

Regions are a collection of countries that share some common functionality, e.g., currency, available fulfillment and shipping providers and a taxrate. The store operator can have as many Regions as needed.
This commit is contained in:
Sebastian Rindom authored and GitHub committed 2020-04-08 09:44:41 +02:00
1 parent ea4185eddd
commit b7557db9f9
31 files changed
+2686 -9

No files matched your search

@@ -3,6 +3,7 @@ import middlewares from "../../middlewares"
import authRoutes from "./auth"
import productRoutes from "./products"
import productVariantRoutes from "./product-variants"
import regionRoutes from "./regions"
import shippingOptionRoutes from "./shipping-options"
import shippingProfileRoutes from "./shipping-profiles"
@@ -18,6 +19,7 @@ export default app => {
route.use(middlewares.authenticate())
productRoutes(route)
regionRoutes(route)
shippingOptionRoutes(route)
shippingProfileRoutes(route)
// productVariantRoutes(route)
@@ -0,0 +1,35 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { RegionServiceMock } from "../../../../../services/__mocks__/region"
describe("POST /admin/regions/:region_id/countries", () => {
describe("successful creation", () => {
let subject
beforeAll(async () => {
const id = IdMap.getId("region")
subject = await request("POST", `/admin/regions/${id}/countries`, {
payload: {
country_code: "se",
},
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
})
})
it("returns 200", () => {
expect(subject.status).toEqual(200)
})
it("calls service addCountry", () => {
expect(RegionServiceMock.addCountry).toHaveBeenCalledTimes(1)
expect(RegionServiceMock.addCountry).toHaveBeenCalledWith(
IdMap.getId("region"),
"se"
)
})
})
})
@@ -0,0 +1,39 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { RegionServiceMock } from "../../../../../services/__mocks__/region"
describe("POST /admin/regions/:region_id/fulfillment-providers", () => {
describe("successful creation", () => {
let subject
beforeAll(async () => {
const id = IdMap.getId("region")
subject = await request(
"POST",
`/admin/regions/${id}/fulfillment-providers`,
{
payload: {
provider_id: "default_provider",
},
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
}
)
})
it("returns 200", () => {
expect(subject.status).toEqual(200)
})
it("calls service addCountry", () => {
expect(RegionServiceMock.addFulfillmentProvider).toHaveBeenCalledTimes(1)
expect(RegionServiceMock.addFulfillmentProvider).toHaveBeenCalledWith(
IdMap.getId("region"),
"default_provider"
)
})
})
})
@@ -0,0 +1,39 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { RegionServiceMock } from "../../../../../services/__mocks__/region"
describe("POST /admin/regions/:region_id/payment-providers", () => {
describe("successful creation", () => {
let subject
beforeAll(async () => {
const id = IdMap.getId("region")
subject = await request(
"POST",
`/admin/regions/${id}/payment-providers`,
{
payload: {
provider_id: "default_provider",
},
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
}
)
})
it("returns 200", () => {
expect(subject.status).toEqual(200)
})
it("calls service addCountry", () => {
expect(RegionServiceMock.addPaymentProvider).toHaveBeenCalledTimes(1)
expect(RegionServiceMock.addPaymentProvider).toHaveBeenCalledWith(
IdMap.getId("region"),
"default_provider"
)
})
})
})
@@ -0,0 +1,43 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { RegionServiceMock } from "../../../../../services/__mocks__/region"
describe("POST /admin/regions", () => {
describe("successful creation", () => {
let subject
beforeAll(async () => {
subject = await request("POST", "/admin/regions", {
payload: {
name: "New Region",
currency_code: "dkk",
countries: ["dk"],
tax_rate: 0.3,
payment_providers: ["default_provider"],
fulfillment_providers: ["default_provider"],
},
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
})
})
it("returns 200", () => {
expect(subject.status).toEqual(200)
})
it("calls service create", () => {
expect(RegionServiceMock.create).toHaveBeenCalledTimes(1)
expect(RegionServiceMock.create).toHaveBeenCalledWith({
name: "New Region",
currency_code: "dkk",
countries: ["dk"],
tax_rate: 0.3,
payment_providers: ["default_provider"],
fulfillment_providers: ["default_provider"],
})
})
})
})
@@ -0,0 +1,31 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { RegionServiceMock } from "../../../../../services/__mocks__/region"
describe("DELETE /admin/regions/:region_id", () => {
describe("successful deletion", () => {
let subject
beforeAll(async () => {
const id = IdMap.getId("region")
subject = await request("DELETE", `/admin/regions/${id}`, {
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
})
})
it("returns 200", () => {
expect(subject.status).toEqual(200)
})
it("calls service addCountry", () => {
expect(RegionServiceMock.delete).toHaveBeenCalledTimes(1)
expect(RegionServiceMock.delete).toHaveBeenCalledWith(
IdMap.getId("region")
)
})
})
})
@@ -0,0 +1,31 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { RegionServiceMock } from "../../../../../services/__mocks__/region"
describe("GET /admin/regions/:region_id", () => {
describe("successful creation", () => {
let subject
beforeAll(async () => {
const id = IdMap.getId("region")
subject = await request("GET", `/admin/regions/${id}`, {
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
})
})
it("returns 200", () => {
expect(subject.status).toEqual(200)
})
it("calls service addCountry", () => {
expect(RegionServiceMock.retrieve).toHaveBeenCalledTimes(1)
expect(RegionServiceMock.retrieve).toHaveBeenCalledWith(
IdMap.getId("region")
)
})
})
})
@@ -0,0 +1,28 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { RegionServiceMock } from "../../../../../services/__mocks__/region"
describe("GET /admin/regions", () => {
describe("successful creation", () => {
let subject
beforeAll(async () => {
subject = await request("GET", `/admin/regions`, {
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
})
})
it("returns 200", () => {
expect(subject.status).toEqual(200)
})
it("calls service addCountry", () => {
expect(RegionServiceMock.list).toHaveBeenCalledTimes(1)
expect(RegionServiceMock.list).toHaveBeenCalledWith({})
})
})
})
@@ -0,0 +1,32 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { RegionServiceMock } from "../../../../../services/__mocks__/region"
describe("DELETE /admin/regions/:region_id/countries/:country_code", () => {
describe("successful creation", () => {
let subject
beforeAll(async () => {
const id = IdMap.getId("region")
subject = await request("DELETE", `/admin/regions/${id}/countries/DK`, {
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
})
})
it("returns 200", () => {
expect(subject.status).toEqual(200)
})
it("calls service addCountry", () => {
expect(RegionServiceMock.removeCountry).toHaveBeenCalledTimes(1)
expect(RegionServiceMock.removeCountry).toHaveBeenCalledWith(
IdMap.getId("region"),
"DK"
)
})
})
})
@@ -0,0 +1,38 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { RegionServiceMock } from "../../../../../services/__mocks__/region"
describe("DELETE /admin/regions/:region_id/fulfillment-providers/:provider_id", () => {
describe("successful deletion", () => {
let subject
beforeAll(async () => {
const id = IdMap.getId("region")
subject = await request(
"DELETE",
`/admin/regions/${id}/fulfillment-providers/default_provider`,
{
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
}
)
})
it("returns 200", () => {
expect(subject.status).toEqual(200)
})
it("calls service addCountry", () => {
expect(RegionServiceMock.removeFulfillmentProvider).toHaveBeenCalledTimes(
1
)
expect(RegionServiceMock.removeFulfillmentProvider).toHaveBeenCalledWith(
IdMap.getId("region"),
"default_provider"
)
})
})
})
@@ -0,0 +1,36 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { RegionServiceMock } from "../../../../../services/__mocks__/region"
describe("DELETE /admin/regions/:region_id/payment-providers/:provider_id", () => {
describe("successful deletion", () => {
let subject
beforeAll(async () => {
const id = IdMap.getId("region")
subject = await request(
"DELETE",
`/admin/regions/${id}/payment-providers/default_provider`,
{
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
}
)
})
it("returns 200", () => {
expect(subject.status).toEqual(200)
})
it("calls service addCountry", () => {
expect(RegionServiceMock.removePaymentProvider).toHaveBeenCalledTimes(1)
expect(RegionServiceMock.removePaymentProvider).toHaveBeenCalledWith(
IdMap.getId("region"),
"default_provider"
)
})
})
})
@@ -0,0 +1,47 @@
import { IdMap } from "medusa-test-utils"
import { request } from "../../../../../helpers/test-request"
import { RegionServiceMock } from "../../../../../services/__mocks__/region"
describe("POST /admin/regions/:region_id", () => {
describe("successful deletion", () => {
let subject
beforeAll(async () => {
const id = IdMap.getId("region")
subject = await request("POST", `/admin/regions/${id}`, {
payload: {
name: "Updated Region",
currency_code: "dkk",
countries: ["dk"],
tax_rate: 0.3,
payment_providers: ["default_provider"],
fulfillment_providers: ["default_provider"],
},
adminSession: {
jwt: {
userId: IdMap.getId("admin_user"),
},
},
})
})
it("returns 200", () => {
expect(subject.status).toEqual(200)
})
it("calls service addCountry", () => {
expect(RegionServiceMock.update).toHaveBeenCalledTimes(1)
expect(RegionServiceMock.update).toHaveBeenCalledWith(
IdMap.getId("region"),
{
name: "Updated Region",
currency_code: "dkk",
countries: ["dk"],
tax_rate: 0.3,
payment_providers: ["default_provider"],
fulfillment_providers: ["default_provider"],
}
)
})
})
})
@@ -0,0 +1,23 @@
import { MedusaError, Validator } from "medusa-core-utils"
export default async (req, res) => {
const { region_id } = req.params
const schema = Validator.object().keys({
country_code: Validator.string().required(),
})
const { value, error } = schema.validate(req.body)
if (error) {
throw new MedusaError(MedusaError.Types.INVALID_DATA, error.details)
}
try {
const regionService = req.scope.resolve("regionService")
await regionService.addCountry(region_id, value.country_code)
const data = await regionService.retrieve(region_id)
res.status(200).json(data)
} catch (err) {
throw err
}
}
@@ -0,0 +1,23 @@
import { MedusaError, Validator } from "medusa-core-utils"
export default async (req, res) => {
const { region_id } = req.params
const schema = Validator.object().keys({
provider_id: Validator.string().required(),
})
const { value, error } = schema.validate(req.body)
if (error) {
throw new MedusaError(MedusaError.Types.INVALID_DATA, error.details)
}
try {
const regionService = req.scope.resolve("regionService")
await regionService.addFulfillmentProvider(region_id, value.provider_id)
const data = await regionService.retrieve(region_id)
res.status(200).json(data)
} catch (err) {
throw err
}
}
@@ -0,0 +1,23 @@
import { MedusaError, Validator } from "medusa-core-utils"
export default async (req, res) => {
const { region_id } = req.params
const schema = Validator.object().keys({
provider_id: Validator.string().required(),
})
const { value, error } = schema.validate(req.body)
if (error) {
throw new MedusaError(MedusaError.Types.INVALID_DATA, error.details)
}
try {
const regionService = req.scope.resolve("regionService")
await regionService.addPaymentProvider(region_id, value.provider_id)
const data = await regionService.retrieve(region_id)
res.status(200).json(data)
} catch (err) {
throw err
}
}
@@ -0,0 +1,25 @@
import { MedusaError, Validator } from "medusa-core-utils"
export default async (req, res) => {
const schema = Validator.object().keys({
name: Validator.string().required(),
currency_code: Validator.string().required(),
tax_rate: Validator.number().required(),
payment_providers: Validator.array().items(Validator.string()),
fulfillment_providers: Validator.array().items(Validator.string()),
countries: Validator.array().items(Validator.string()),
})
const { value, error } = schema.validate(req.body)
if (error) {
throw new MedusaError(MedusaError.Types.INVALID_DATA, error.details)
}
try {
const regionService = req.scope.resolve("regionService")
const data = await regionService.create(value)
res.status(200).json(data)
} catch (err) {
throw err
}
}
@@ -0,0 +1,17 @@
import { MedusaError, Validator } from "medusa-core-utils"
export default async (req, res) => {
const { region_id } = req.params
try {
const regionService = req.scope.resolve("regionService")
await regionService.delete(region_id)
res.status(200).json({
id: region_id,
object: "region",
deleted: true,
})
} catch (err) {
throw err
}
}
@@ -0,0 +1,13 @@
import { MedusaError, Validator } from "medusa-core-utils"
export default async (req, res) => {
const { region_id } = req.params
try {
const regionService = req.scope.resolve("regionService")
const data = await regionService.retrieve(region_id)
res.status(200).json(data)
} catch (err) {
throw err
}
}
@@ -0,0 +1,51 @@
import { Router } from "express"
import middlewares from "../../../middlewares"
const route = Router()
export default app => {
app.use("/regions", route)
route.get("/", middlewares.wrap(require("./list-regions").default))
route.get("/:region_id", middlewares.wrap(require("./get-region").default))
route.post("/", middlewares.wrap(require("./create-region").default))
route.post(
"/:region_id",
middlewares.wrap(require("./update-region").default)
)
route.delete(
"/:region_id",
middlewares.wrap(require("./delete-region").default)
)
route.post(
"/:region_id/countries",
middlewares.wrap(require("./add-country").default)
)
route.delete(
"/:region_id/countries/:country_code",
middlewares.wrap(require("./remove-country").default)
)
route.post(
"/:region_id/payment-providers",
middlewares.wrap(require("./add-payment-provider").default)
)
route.delete(
"/:region_id/payment-providers/:provider_id",
middlewares.wrap(require("./remove-payment-provider").default)
)
route.post(
"/:region_id/fulfillment-providers",
middlewares.wrap(require("./add-fulfillment-provider").default)
)
route.delete(
"/:region_id/fulfillment-providers/:provider_id",
middlewares.wrap(require("./remove-fulfillment-provider").default)
)
return app
}
@@ -0,0 +1,12 @@
import { MedusaError, Validator } from "medusa-core-utils"
export default async (req, res) => {
try {
const regionService = req.scope.resolve("regionService")
const data = await regionService.list({})
res.status(200).json(data)
} catch (err) {
throw err
}
}
@@ -0,0 +1,13 @@
import { MedusaError, Validator } from "medusa-core-utils"
export default async (req, res) => {
const { region_id, country_code } = req.params
try {
const regionService = req.scope.resolve("regionService")
await regionService.removeCountry(region_id, country_code)
res.sendStatus(200)
} catch (err) {
throw err
}
}
@@ -0,0 +1,13 @@
import { MedusaError, Validator } from "medusa-core-utils"
export default async (req, res) => {
const { region_id, provider_id } = req.params
try {
const regionService = req.scope.resolve("regionService")
await regionService.removeFulfillmentProvider(region_id, provider_id)
res.sendStatus(200)
} catch (err) {
throw err
}
}
@@ -0,0 +1,13 @@
import { MedusaError, Validator } from "medusa-core-utils"
export default async (req, res) => {
const { region_id, provider_id } = req.params
try {
const regionService = req.scope.resolve("regionService")
await regionService.removePaymentProvider(region_id, provider_id)
res.sendStatus(200)
} catch (err) {
throw err
}
}
@@ -0,0 +1,26 @@
import { MedusaError, Validator } from "medusa-core-utils"
export default async (req, res) => {
const { region_id } = req.params
const schema = Validator.object().keys({
name: Validator.string(),
currency_code: Validator.string(),
tax_rate: Validator.number(),
payment_providers: Validator.array().items(Validator.string()),
fulfillment_providers: Validator.array().items(Validator.string()),
countries: Validator.array().items(Validator.string()),
})
const { value, error } = schema.validate(req.body)
if (error) {
throw new MedusaError(MedusaError.Types.INVALID_DATA, error.details)
}
try {
const regionService = req.scope.resolve("regionService")
const data = await regionService.update(region_id, value)
res.status(200).json(data)
} catch (err) {
throw err
}
}