Add support for tax inclusivity to region and store (#7808)

This also includes rework of the currency model for the Store module.

This change is breaking as existing stores won't have any supported currencies set, so users would need to go to the store settings again and choose the supported currencies there.
This commit is contained in:
Stevche Radevski
2024-06-24 17:25:44 +02:00
committed by GitHub
parent 79d90fadc4
commit e8d6025374
45 changed files with 580 additions and 408 deletions
@@ -8,6 +8,7 @@ import {
StoreTypes,
} from "@medusajs/types"
import {
getDuplicates,
InjectManager,
InjectTransactionManager,
isString,
@@ -18,7 +19,7 @@ import {
removeUndefined,
} from "@medusajs/utils"
import { Store } from "@models"
import { Store, StoreCurrency } from "@models"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config"
import { UpdateStoreInput } from "@types"
@@ -30,7 +31,8 @@ type InjectedDependencies = {
export default class StoreModuleService
extends MedusaService<{
Store: { dto: StoreTypes.StoreDTO }
}>({ Store }, entityNameToLinkableKeysMap)
StoreCurrency: { dto: StoreTypes.StoreCurrencyDTO }
}>({ Store, StoreCurrency }, entityNameToLinkableKeysMap)
implements IStoreModuleService
{
protected baseRepository_: DAL.RepositoryService
@@ -81,7 +83,13 @@ export default class StoreModuleService
let normalizedInput = StoreModuleService.normalizeInput(data)
StoreModuleService.validateCreateRequest(normalizedInput)
return await this.storeService_.create(normalizedInput, sharedContext)
return (
await this.storeService_.upsertWithReplace(
normalizedInput,
{ relations: ["supported_currencies"] },
sharedContext
)
).entities
}
async upsertStores(
@@ -168,8 +176,15 @@ export default class StoreModuleService
@MedusaContext() sharedContext: Context = {}
): Promise<Store[]> {
const normalizedInput = StoreModuleService.normalizeInput(data)
await this.validateUpdateRequest(normalizedInput)
return await this.storeService_.update(normalizedInput, sharedContext)
StoreModuleService.validateUpdateRequest(normalizedInput)
return (
await this.storeService_.upsertWithReplace(
normalizedInput,
{ relations: ["supported_currencies"] },
sharedContext
)
).entities
}
private static normalizeInput<T extends StoreTypes.UpdateStoreDTO>(
@@ -178,6 +193,10 @@ export default class StoreModuleService
return stores.map((store) =>
removeUndefined({
...store,
supported_currencies: store.supported_currencies?.map((c) => ({
...c,
currency_code: c.currency_code.toLowerCase(),
})),
name: store.name?.trim(),
})
)
@@ -185,77 +204,42 @@ export default class StoreModuleService
private static validateCreateRequest(stores: StoreTypes.CreateStoreDTO[]) {
for (const store of stores) {
// If we are setting the default currency code on creating, make sure it is supported
if (store.default_currency_code) {
if (
!store.supported_currency_codes?.includes(
store.default_currency_code ?? ""
)
) {
if (store.supported_currencies?.length) {
const duplicates = getDuplicates(
store.supported_currencies?.map((c) => c.currency_code)
)
if (duplicates.length) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Store does not have currency: ${store.default_currency_code}`
`Duplicate currency codes: ${duplicates.join(", ")}`
)
}
let seenDefault = false
store.supported_currencies?.forEach((c) => {
if (c.is_default) {
if (seenDefault) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Only one default currency is allowed`
)
}
seenDefault = true
}
})
if (!seenDefault) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`There should be a default currency set for the store`
)
}
}
}
}
private async validateUpdateRequest(stores: UpdateStoreInput[]) {
const dbStores = await this.storeService_.list(
{ id: stores.map((s) => s.id) },
{ take: null }
)
const dbStoresMap = new Map<string, Store>(
dbStores.map((dbStore) => [dbStore.id, dbStore])
)
for (const store of stores) {
const dbStore = dbStoresMap.get(store.id)
// If it is updating both the supported currency codes and the default one, look in that list
if (store.supported_currency_codes && store.default_currency_code) {
if (
!store.supported_currency_codes.includes(
store.default_currency_code ?? ""
)
) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Store does not have currency: ${store.default_currency_code}`
)
}
return
}
// If it is updating only the default currency code, look in the db store
if (store.default_currency_code) {
if (
!dbStore?.supported_currency_codes?.includes(
store.default_currency_code
)
) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Store does not have currency: ${store.default_currency_code}`
)
}
}
// If it is updating only the supported currency codes, make sure one of them is not set as a default one
if (store.supported_currency_codes) {
if (
!store.supported_currency_codes.includes(
dbStore?.default_currency_code ?? ""
)
) {
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
"You are not allowed to remove default currency from store currencies without replacing it as well"
)
}
}
}
private static validateUpdateRequest(stores: UpdateStoreInput[]) {
StoreModuleService.validateCreateRequest(stores)
}
}