feat(region): Create region with countries (#6372)
This commit is contained in:
1 parent
0c2a460751
commit
7ce15916ca
5 files changed
+154
-8
No files matched your search
@@ -86,6 +86,87 @@ describe("Region Module Service", () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("should create a region with countries", async () => {
|
||||||
|
const createdRegion = await service.create({
|
||||||
|
name: "North America",
|
||||||
|
currency_code: "USD",
|
||||||
|
countries: ["us", "ca"],
|
||||||
|
})
|
||||||
|
|
||||||
|
const region = await service.retrieve(createdRegion.id, {
|
||||||
|
relations: ["countries", "currency"],
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(region).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
id: region.id,
|
||||||
|
name: "North America",
|
||||||
|
currency_code: "usd",
|
||||||
|
currency: expect.objectContaining({
|
||||||
|
code: "usd",
|
||||||
|
name: "US Dollar",
|
||||||
|
}),
|
||||||
|
countries: [
|
||||||
|
expect.objectContaining({
|
||||||
|
display_name: "Canada",
|
||||||
|
iso_2: "ca",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
display_name: "United States",
|
||||||
|
iso_2: "us",
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should throw when country doesn't exist", async () => {
|
||||||
|
await expect(
|
||||||
|
service.create({
|
||||||
|
name: "North America",
|
||||||
|
currency_code: "USD",
|
||||||
|
countries: ["neverland"],
|
||||||
|
})
|
||||||
|
).rejects.toThrowError("Countries with codes neverland does not exist")
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should throw when country is already assigned to a region", async () => {
|
||||||
|
await service.create({
|
||||||
|
name: "North America",
|
||||||
|
currency_code: "USD",
|
||||||
|
countries: ["us"],
|
||||||
|
})
|
||||||
|
|
||||||
|
await expect(
|
||||||
|
service.create({
|
||||||
|
name: "United States",
|
||||||
|
currency_code: "USD",
|
||||||
|
countries: ["us"],
|
||||||
|
})
|
||||||
|
).rejects.toThrowError(
|
||||||
|
"Country with code us is already assigned to a region"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("should throw when country is being assigned to multiple regions", async () => {
|
||||||
|
await expect(
|
||||||
|
service.create([
|
||||||
|
{
|
||||||
|
name: "United States",
|
||||||
|
currency_code: "USD",
|
||||||
|
countries: ["us"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "North America",
|
||||||
|
currency_code: "USD",
|
||||||
|
countries: ["us"],
|
||||||
|
},
|
||||||
|
])
|
||||||
|
).rejects.toThrowError(
|
||||||
|
"Country with code us is already assigned to a region"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
it("should fail when currency does not exist", async () => {
|
it("should fail when currency does not exist", async () => {
|
||||||
await expect(
|
await expect(
|
||||||
service.create({
|
service.create({
|
||||||
|
|||||||
@@ -30,13 +30,15 @@ export default class Country {
|
|||||||
@Property({ columnType: "text" })
|
@Property({ columnType: "text" })
|
||||||
display_name: string
|
display_name: string
|
||||||
|
|
||||||
|
@Property({ columnType: "text", nullable: true })
|
||||||
|
region_id?: string | null = null
|
||||||
|
|
||||||
@ManyToOne({
|
@ManyToOne({
|
||||||
entity: () => Region,
|
entity: () => Region,
|
||||||
fieldName: "region_id",
|
|
||||||
index: "IDX_country_region_id",
|
index: "IDX_country_region_id",
|
||||||
nullable: true,
|
nullable: true,
|
||||||
})
|
})
|
||||||
region: Region | null = null
|
region?: Region | null
|
||||||
|
|
||||||
@BeforeCreate()
|
@BeforeCreate()
|
||||||
onCreate() {
|
onCreate() {
|
||||||
|
|||||||
@@ -23,7 +23,11 @@ import {
|
|||||||
import { Country, Currency, Region } from "@models"
|
import { Country, Currency, Region } from "@models"
|
||||||
|
|
||||||
import { DefaultsUtils } from "@medusajs/utils"
|
import { DefaultsUtils } from "@medusajs/utils"
|
||||||
import { CreateCountryDTO, CreateCurrencyDTO } from "@types"
|
import {
|
||||||
|
CreateCountryDTO,
|
||||||
|
CreateCurrencyDTO,
|
||||||
|
CreateRegionDTO as InternalCreateRegionDTO,
|
||||||
|
} from "@types"
|
||||||
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config"
|
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config"
|
||||||
|
|
||||||
const COUNTRIES_LIMIT = 1000
|
const COUNTRIES_LIMIT = 1000
|
||||||
@@ -115,20 +119,70 @@ export default class RegionModuleService<
|
|||||||
sharedContext
|
sharedContext
|
||||||
)
|
)
|
||||||
|
|
||||||
let currencyMap = new Map(currencies.map((c) => [c.code.toLowerCase(), c]))
|
const countriesInDb = await this.countryService_.list(
|
||||||
for (const reg of data) {
|
{ iso_2: data.map((d) => d.countries).flat() },
|
||||||
const lowerCasedCurrency = reg.currency_code.toLowerCase()
|
{ select: ["iso_2", "region_id"] },
|
||||||
|
sharedContext
|
||||||
|
)
|
||||||
|
|
||||||
|
const countriesInDbMap = new Map<string, Country>(
|
||||||
|
countriesInDb.map((c) => [c.iso_2, c])
|
||||||
|
)
|
||||||
|
|
||||||
|
const currencyMap = new Map(
|
||||||
|
currencies.map((c) => [c.code.toLowerCase(), c])
|
||||||
|
)
|
||||||
|
|
||||||
|
const toCreate: InternalCreateRegionDTO[] = []
|
||||||
|
const seenCountries = new Set<string>()
|
||||||
|
for (const region of data) {
|
||||||
|
const reg = { ...region } as InternalCreateRegionDTO
|
||||||
|
const countriesToAdd = region.countries || []
|
||||||
|
|
||||||
|
if (countriesToAdd) {
|
||||||
|
const notInDb = countriesToAdd.filter(
|
||||||
|
(c) => !countriesInDbMap.has(c.toLowerCase())
|
||||||
|
)
|
||||||
|
|
||||||
|
if (notInDb.length) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
`Countries with codes ${countriesToAdd.join(", ")} does not exist`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const regionCountries = countriesToAdd.map((code) => {
|
||||||
|
const country = countriesInDbMap.get(code.toLowerCase())
|
||||||
|
|
||||||
|
if (country?.region_id || seenCountries.has(code.toLowerCase())) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
`Country with code ${code} is already assigned to a region`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
seenCountries.add(code.toLowerCase())
|
||||||
|
|
||||||
|
return country
|
||||||
|
}) as unknown as TCountry[]
|
||||||
|
|
||||||
|
reg.countries = regionCountries
|
||||||
|
}
|
||||||
|
|
||||||
|
const lowerCasedCurrency = region.currency_code.toLowerCase()
|
||||||
if (!currencyMap.has(lowerCasedCurrency)) {
|
if (!currencyMap.has(lowerCasedCurrency)) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
MedusaError.Types.INVALID_DATA,
|
MedusaError.Types.INVALID_DATA,
|
||||||
`Currency with code: ${reg.currency_code} was not found`
|
`Currency with code: ${region.currency_code} was not found`
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
reg.currency_code = lowerCasedCurrency
|
reg.currency_code = lowerCasedCurrency
|
||||||
|
|
||||||
|
toCreate.push(reg as InternalCreateRegionDTO)
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await this.regionService_.create(data, sharedContext)
|
const result = await this.regionService_.create(toCreate, sharedContext)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { Logger } from "@medusajs/types"
|
import { Logger } from "@medusajs/types"
|
||||||
|
import { Country } from "@models"
|
||||||
|
|
||||||
export type InitializeModuleInjectableDependencies = {
|
export type InitializeModuleInjectableDependencies = {
|
||||||
logger?: Logger
|
logger?: Logger
|
||||||
@@ -23,3 +24,9 @@ export type CreateCountryDTO = {
|
|||||||
name: string
|
name: string
|
||||||
display_name: string
|
display_name: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CreateRegionDTO = {
|
||||||
|
name: string
|
||||||
|
currency_code: string
|
||||||
|
countries?: Country[]
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ export interface CreateRegionDTO {
|
|||||||
name: string
|
name: string
|
||||||
currency_code: string
|
currency_code: string
|
||||||
currency?: RegionCurrencyDTO
|
currency?: RegionCurrencyDTO
|
||||||
|
countries?: string[]
|
||||||
tax_code?: string
|
tax_code?: string
|
||||||
tax_rate?: number
|
tax_rate?: number
|
||||||
tax_provider_id?: string
|
tax_provider_id?: string
|
||||||
@@ -13,6 +14,7 @@ export interface UpdateRegionDTO {
|
|||||||
id: string
|
id: string
|
||||||
currency_code?: string
|
currency_code?: string
|
||||||
currency?: RegionCurrencyDTO
|
currency?: RegionCurrencyDTO
|
||||||
|
countries: string[]
|
||||||
name?: string
|
name?: string
|
||||||
tax_code?: string
|
tax_code?: string
|
||||||
tax_rate?: number
|
tax_rate?: number
|
||||||
|
|||||||
Reference in new issue
Block a user