feat(region): Create region with countries (#6372)

This commit is contained in:
Oli Juhl
2024-02-14 12:48:43 +01:00
committed by GitHub
parent 0c2a460751
commit 7ce15916ca
5 changed files with 154 additions and 8 deletions

View File

@@ -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 () => {
await expect(
service.create({

View File

@@ -30,13 +30,15 @@ export default class Country {
@Property({ columnType: "text" })
display_name: string
@Property({ columnType: "text", nullable: true })
region_id?: string | null = null
@ManyToOne({
entity: () => Region,
fieldName: "region_id",
index: "IDX_country_region_id",
nullable: true,
})
region: Region | null = null
region?: Region | null
@BeforeCreate()
onCreate() {

View File

@@ -23,7 +23,11 @@ import {
import { Country, Currency, Region } from "@models"
import { DefaultsUtils } from "@medusajs/utils"
import { CreateCountryDTO, CreateCurrencyDTO } from "@types"
import {
CreateCountryDTO,
CreateCurrencyDTO,
CreateRegionDTO as InternalCreateRegionDTO,
} from "@types"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config"
const COUNTRIES_LIMIT = 1000
@@ -115,20 +119,70 @@ export default class RegionModuleService<
sharedContext
)
let currencyMap = new Map(currencies.map((c) => [c.code.toLowerCase(), c]))
for (const reg of data) {
const lowerCasedCurrency = reg.currency_code.toLowerCase()
const countriesInDb = await this.countryService_.list(
{ iso_2: data.map((d) => d.countries).flat() },
{ 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)) {
throw new MedusaError(
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
toCreate.push(reg as InternalCreateRegionDTO)
}
const result = await this.regionService_.create(data, sharedContext)
const result = await this.regionService_.create(toCreate, sharedContext)
return result
}

View File

@@ -1,4 +1,5 @@
import { Logger } from "@medusajs/types"
import { Country } from "@models"
export type InitializeModuleInjectableDependencies = {
logger?: Logger
@@ -22,4 +23,10 @@ export type CreateCountryDTO = {
num_code: string
name: string
display_name: string
}
export type CreateRegionDTO = {
name: string
currency_code: string
countries?: Country[]
}

View File

@@ -4,6 +4,7 @@ export interface CreateRegionDTO {
name: string
currency_code: string
currency?: RegionCurrencyDTO
countries?: string[]
tax_code?: string
tax_rate?: number
tax_provider_id?: string
@@ -13,6 +14,7 @@ export interface UpdateRegionDTO {
id: string
currency_code?: string
currency?: RegionCurrencyDTO
countries: string[]
name?: string
tax_code?: string
tax_rate?: number