feat: Add currency module and remove currency models from region and pricing modules (#6536)

What:
- Creates a new currency module
- Removes currency model from the pricing module
- Removes currency model from region module
This commit is contained in:
Stevche Radevski
2024-02-29 16:09:59 +01:00
committed by GitHub
parent 06f706a51a
commit dc025302a1
102 changed files with 1502 additions and 2128 deletions
@@ -42,7 +42,7 @@ describe("API Keys - Admin", () => {
await createAdminUser(dbConnection, adminHeaders)
// Used for testing cross-module authentication checks
await regionService.createDefaultCountriesAndCurrencies()
await regionService.createDefaultCountries()
})
afterEach(async () => {
@@ -63,7 +63,7 @@ describe("Carts workflows", () => {
beforeEach(async () => {
await adminSeeder(dbConnection)
await regionModuleService.createDefaultCountriesAndCurrencies()
await regionModuleService.createDefaultCountries()
// Here, so we don't have to create a region for each test
defaultRegion = await regionModuleService.create({
@@ -59,7 +59,7 @@ describe("Store Carts API", () => {
beforeEach(async () => {
await adminSeeder(dbConnection)
await regionModuleService.createDefaultCountriesAndCurrencies()
await regionModuleService.createDefaultCountries()
// Here, so we don't have to create a region for each test
defaultRegion = await regionModuleService.create({
@@ -0,0 +1,67 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { ICurrencyModuleService } from "@medusajs/types"
import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import { useApi } from "../../../../environment-helpers/use-api"
import { getContainer } from "../../../../environment-helpers/use-container"
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { DataSource } from "typeorm"
import { createAdminUser } from "../../../helpers/create-admin-user"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}
describe("Currency - Admin", () => {
let dbConnection: DataSource
let appContainer
let shutdownServer
let service: ICurrencyModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
service = appContainer.resolve(ModuleRegistrationName.CURRENCY)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should correctly retrieve and list currencies", async () => {
const api = useApi() as any
const listResp = await api.get("/admin/currencies", adminHeaders)
expect(listResp.data.currencies).toEqual(
expect.arrayContaining([
expect.objectContaining({
code: "aud",
}),
expect.objectContaining({
code: "cad",
}),
])
)
const retrieveResp = await api.get(`/admin/currencies/aud`, adminHeaders)
expect(retrieveResp.data.currency).toEqual(
listResp.data.currencies.find((c) => c.code === "aud")
)
})
})
@@ -0,0 +1,62 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { ICurrencyModuleService } from "@medusajs/types"
import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import { useApi } from "../../../../environment-helpers/use-api"
import { getContainer } from "../../../../environment-helpers/use-container"
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { DataSource } from "typeorm"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const storeHeaders = {
headers: {},
}
describe("Currency - Store", () => {
let dbConnection: DataSource
let appContainer
let shutdownServer
let service: ICurrencyModuleService
beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
service = appContainer.resolve(ModuleRegistrationName.CURRENCY)
})
afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})
afterEach(async () => {
const db = useDb()
await db.teardown()
})
it("should correctly retrieve and list currencies", async () => {
const api = useApi() as any
const listResp = await api.get("/store/currencies", storeHeaders)
expect(listResp.data.currencies).toEqual(
expect.arrayContaining([
expect.objectContaining({
code: "aud",
}),
expect.objectContaining({
code: "cad",
}),
])
)
const retrieveResp = await api.get(`/store/currencies/aud`, storeHeaders)
expect(retrieveResp.data.currency).toEqual(
listResp.data.currencies.find((c) => c.code === "aud")
)
})
})
@@ -45,7 +45,7 @@ describe("Cart links", () => {
beforeEach(async () => {
// @ts-ignore
await regionModule.createDefaultCountriesAndCurrencies()
await regionModule.createDefaultCountries()
})
afterEach(async () => {
@@ -35,7 +35,7 @@ describe("Link: Cart Region", () => {
beforeEach(async () => {
// @ts-ignore
await regionModule.createDefaultCountriesAndCurrencies()
await regionModule.createDefaultCountries()
})
afterEach(async () => {
@@ -38,7 +38,7 @@ describe("Regions - Admin", () => {
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders)
await service.createDefaultCountriesAndCurrencies()
await service.createDefaultCountries()
})
afterEach(async () => {
@@ -127,25 +127,6 @@ describe("Regions - Admin", () => {
)
})
it("should throw on unknown currency in create", async () => {
const api = useApi() as any
const error = await api
.post(
`/admin/regions`,
{
currency_code: "foo",
name: "Test Region",
},
adminHeaders
)
.catch((e) => e)
expect(error.response.status).toEqual(400)
expect(error.response.data.message).toEqual(
'Currencies with codes: "foo" were not found'
)
})
it("should throw on unknown properties in create", async () => {
const api = useApi() as any
const error = await api
@@ -128,5 +128,10 @@ module.exports = {
resources: "shared",
resolve: "@medusajs/tax",
},
[Modules.CURRENCY]: {
scope: "internal",
resources: "shared",
resolve: "@medusajs/currency",
},
},
}
+1
View File
@@ -12,6 +12,7 @@
"@medusajs/api-key": "workspace:^",
"@medusajs/auth": "workspace:*",
"@medusajs/cache-inmemory": "workspace:*",
"@medusajs/currency": "workspace:^",
"@medusajs/customer": "workspace:^",
"@medusajs/event-bus-local": "workspace:*",
"@medusajs/inventory": "workspace:^",
+6
View File
@@ -0,0 +1,6 @@
/dist
node_modules
.DS_store
.env*
.env
*.sql
+1
View File
@@ -0,0 +1 @@
# Currency Module
@@ -0,0 +1,199 @@
import { Modules } from "@medusajs/modules-sdk"
import { ICurrencyModuleService } from "@medusajs/types"
import { moduleIntegrationTestRunner, SuiteOptions } from "medusa-test-utils"
jest.setTimeout(100000)
moduleIntegrationTestRunner({
moduleName: Modules.CURRENCY,
testSuite: ({
MikroOrmWrapper,
service,
}: SuiteOptions<ICurrencyModuleService>) => {
describe("Currency Module Service", () => {
describe("list", () => {
it("list currencies", async () => {
const currenciesResult = await service.list({}, { take: null })
expect(currenciesResult).toEqual(
expect.arrayContaining([
expect.objectContaining({
code: "cad",
name: "Canadian Dollar",
}),
expect.objectContaining({
code: "usd",
name: "US Dollar",
}),
])
)
})
it("list currencies by code", async () => {
const currenciesResult = await service.list(
{ code: ["usd"] },
{ take: null }
)
expect(currenciesResult).toEqual([
expect.objectContaining({
code: "usd",
name: "US Dollar",
}),
])
})
it("list currencies by code regardless of case-sensitivity", async () => {
const currenciesResult = await service.list(
{ code: ["Usd"] },
{ take: null }
)
expect(currenciesResult).toEqual([
expect.objectContaining({
code: "usd",
name: "US Dollar",
}),
])
})
})
describe("listAndCount", () => {
it("should return currencies and count", async () => {
const [currenciesResult, count] = await service.listAndCount(
{},
{ take: null }
)
expect(count).toEqual(120)
expect(currenciesResult).toEqual(
expect.arrayContaining([
expect.objectContaining({
code: "cad",
name: "Canadian Dollar",
}),
expect.objectContaining({
code: "usd",
name: "US Dollar",
}),
])
)
})
it("should return currencies and count when filtered", async () => {
const [currenciesResult, count] = await service.listAndCount(
{
code: ["usd"],
},
{ take: null }
)
expect(count).toEqual(1)
expect(currenciesResult).toEqual([
expect.objectContaining({
code: "usd",
name: "US Dollar",
}),
])
})
it("should return currencies and count when using skip and take", async () => {
const [currenciesResult, count] = await service.listAndCount(
{},
{ skip: 5, take: 1 }
)
expect(count).toEqual(120)
expect(currenciesResult).toEqual([
expect.objectContaining({
code: "aud",
name: "Australian Dollar",
}),
])
})
it("should return requested fields", async () => {
const [currenciesResult, count] = await service.listAndCount(
{},
{
take: 1,
select: ["code"],
}
)
const serialized = JSON.parse(JSON.stringify(currenciesResult))
expect(count).toEqual(120)
expect(serialized).toEqual([
{
code: "aed",
},
])
})
})
describe("retrieve", () => {
const code = "usd"
const name = "US Dollar"
it("should return currency for the given code", async () => {
const currency = await service.retrieve(code)
expect(currency).toEqual(
expect.objectContaining({
code,
})
)
})
it("should return currency for the given code in a case-insensitive manner", async () => {
const currency = await service.retrieve(code.toUpperCase())
expect(currency).toEqual(
expect.objectContaining({
code,
})
)
})
it("should throw an error when currency with code does not exist", async () => {
let error
try {
await service.retrieve("does-not-exist")
} catch (e) {
error = e
}
expect(error.message).toEqual(
"Currency with code: does-not-exist was not found"
)
})
it("should throw an error when a code is not provided", async () => {
let error
try {
await service.retrieve(undefined as unknown as string)
} catch (e) {
error = e
}
expect(error.message).toEqual("currency - code must be defined")
})
it("should return currency based on config select param", async () => {
const currency = await service.retrieve(code, {
select: ["code", "name"],
})
const serialized = JSON.parse(JSON.stringify(currency))
expect(serialized).toEqual({
code,
name,
})
})
})
})
},
})
+20
View File
@@ -0,0 +1,20 @@
module.exports = {
moduleNameMapper: {
"^@models": "<rootDir>/src/models",
"^@services": "<rootDir>/src/services",
"^@repositories": "<rootDir>/src/repositories",
"^@types": "<rootDir>/src/types",
},
transform: {
"^.+\\.[jt]s?$": [
"ts-jest",
{
tsConfig: "tsconfig.spec.json",
isolatedModules: true,
},
],
},
testEnvironment: `node`,
moduleFileExtensions: [`js`, `ts`],
modulePathIgnorePatterns: ["dist/"],
}
@@ -0,0 +1,8 @@
import * as entities from "./src/models"
module.exports = {
entities: Object.values(entities),
schema: "public",
clientUrl: "postgres://postgres@localhost/medusa-currency",
type: "postgresql",
}
+61
View File
@@ -0,0 +1,61 @@
{
"name": "@medusajs/currency",
"version": "0.1.0",
"description": "Medusa Currency module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"files": [
"dist"
],
"engines": {
"node": ">=16"
},
"bin": {
"medusa-currency-seed": "dist/scripts/bin/run-seed.js"
},
"repository": {
"type": "git",
"url": "https://github.com/medusajs/medusa",
"directory": "packages/currency"
},
"publishConfig": {
"access": "public"
},
"author": "Medusa",
"license": "MIT",
"scripts": {
"watch": "tsc --build --watch",
"watch:test": "tsc --build tsconfig.spec.json --watch",
"prepublishOnly": "cross-env NODE_ENV=production tsc --build && tsc-alias -p tsconfig.json",
"build": "rimraf dist && tsc --build && tsc-alias -p tsconfig.json",
"test": "jest --runInBand --bail --forceExit -- src/**/__tests__/**/*.ts",
"test:integration": "jest --runInBand --forceExit -- integration-tests/**/__tests__/**/*.ts",
"migration:generate": " MIKRO_ORM_CLI=./mikro-orm.config.dev.ts mikro-orm migration:generate",
"migration:initial": " MIKRO_ORM_CLI=./mikro-orm.config.dev.ts mikro-orm migration:create --initial",
"migration:create": " MIKRO_ORM_CLI=./mikro-orm.config.dev.ts mikro-orm migration:create",
"migration:up": " MIKRO_ORM_CLI=./mikro-orm.config.dev.ts mikro-orm migration:up",
"orm:cache:clear": " MIKRO_ORM_CLI=./mikro-orm.config.dev.ts mikro-orm cache:clear"
},
"devDependencies": {
"@mikro-orm/cli": "5.9.7",
"cross-env": "^5.2.1",
"jest": "^29.6.3",
"medusa-test-utils": "workspace:^",
"rimraf": "^3.0.2",
"ts-jest": "^29.1.1",
"ts-node": "^10.9.1",
"tsc-alias": "^1.8.6",
"typescript": "^5.1.6"
},
"dependencies": {
"@medusajs/modules-sdk": "^1.12.4",
"@medusajs/types": "^1.11.8",
"@medusajs/utils": "^1.11.1",
"@mikro-orm/core": "5.9.7",
"@mikro-orm/migrations": "5.9.7",
"@mikro-orm/postgresql": "5.9.7",
"awilix": "^8.0.0",
"dotenv": "^16.1.4",
"knex": "2.4.2"
}
}
+14
View File
@@ -0,0 +1,14 @@
import { moduleDefinition } from "./module-definition"
import { initializeFactory, Modules } from "@medusajs/modules-sdk"
export * from "./types"
export * from "./models"
export * from "./services"
export const initialize = initializeFactory({
moduleName: Modules.CURRENCY,
moduleDefinition,
})
export const runMigrations = moduleDefinition.runMigrations
export const revertMigration = moduleDefinition.revertMigration
export default moduleDefinition
+29
View File
@@ -0,0 +1,29 @@
import { Modules } from "@medusajs/modules-sdk"
import { ModuleJoinerConfig } from "@medusajs/types"
import { MapToConfig } from "@medusajs/utils"
import Currency from "./models/currency"
export const LinkableKeys: Record<string, string> = {}
const entityLinkableKeysMap: MapToConfig = {}
Object.entries(LinkableKeys).forEach(([key, value]) => {
entityLinkableKeysMap[value] ??= []
entityLinkableKeysMap[value].push({
mapTo: key,
valueFrom: key.split("_").pop()!,
})
})
export const entityNameToLinkableKeysMap: MapToConfig = entityLinkableKeysMap
export const joinerConfig: ModuleJoinerConfig = {
serviceName: Modules.CURRENCY,
primaryKeys: ["code"],
linkableKeys: LinkableKeys,
alias: [
{
name: ["currency", "currencies"],
args: { entity: Currency.name },
},
],
} as ModuleJoinerConfig
@@ -0,0 +1,30 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { ModulesSdkTypes, LoaderOptions } from "@medusajs/types"
import { defaultCurrencies } from "@medusajs/utils"
import { Currency } from "@models"
export default async ({
container,
options,
}: LoaderOptions<
| ModulesSdkTypes.ModuleServiceInitializeOptions
| ModulesSdkTypes.ModuleServiceInitializeCustomDataLayerOptions
>): Promise<void> => {
try {
const {
currencyService_,
}: { currencyService_: ModulesSdkTypes.InternalModuleService<Currency> } =
container.resolve(ModuleRegistrationName.CURRENCY)
const normalizedCurrencies = Object.values(defaultCurrencies).map((c) => ({
...c,
code: c.code.toLowerCase(),
}))
const resp = await currencyService_.upsert(normalizedCurrencies)
console.log(`Loaded ${resp.length} currencies`)
} catch (error) {
console.error(
`Failed to load currencies, skipping loader. Original error: ${error.message}`
)
}
}
@@ -0,0 +1,63 @@
{
"namespaces": [
"public"
],
"name": "public",
"tables": [
{
"columns": {
"code": {
"name": "code",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "text"
},
"symbol": {
"name": "symbol",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "text"
},
"symbol_native": {
"name": "symbol_native",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "text"
},
"name": {
"name": "name",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "text"
}
},
"name": "currency",
"schema": "public",
"indexes": [
{
"keyName": "currency_pkey",
"columnNames": [
"code"
],
"composite": false,
"primary": true,
"unique": true
}
],
"checks": [],
"foreignKeys": {}
}
]
}
@@ -0,0 +1,9 @@
import { Migration } from "@mikro-orm/migrations"
export class InitialSetup20240228133303 extends Migration {
async up(): Promise<void> {
this.addSql(`create table if not exists "currency"
("code" text not null, "symbol" text not null, "symbol_native" text not null, "name" text not null,
constraint "currency_pkey" primary key ("code"));`)
}
}
+1
View File
@@ -0,0 +1 @@
export { default as Currency } from "./currency"
@@ -0,0 +1,45 @@
import { ModuleExports } from "@medusajs/types"
import * as ModuleServices from "@services"
import { CurrencyModuleService } from "@services"
import { Modules } from "@medusajs/modules-sdk"
import * as Models from "@models"
import * as ModuleModels from "@models"
import { ModulesSdkUtils } from "@medusajs/utils"
import * as ModuleRepositories from "@repositories"
import initialDataLoader from "./loaders/initial-data"
const migrationScriptOptions = {
moduleName: Modules.CURRENCY,
models: Models,
pathToMigrations: __dirname + "/migrations",
}
const runMigrations = ModulesSdkUtils.buildMigrationScript(
migrationScriptOptions
)
const revertMigration = ModulesSdkUtils.buildRevertMigrationScript(
migrationScriptOptions
)
const containerLoader = ModulesSdkUtils.moduleContainerLoaderFactory({
moduleModels: ModuleModels,
moduleRepositories: ModuleRepositories,
moduleServices: ModuleServices,
})
const connectionLoader = ModulesSdkUtils.mikroOrmConnectionLoaderFactory({
moduleName: Modules.CURRENCY,
moduleModels: Object.values(Models),
migrationsPath: __dirname + "/migrations",
})
const service = CurrencyModuleService
const loaders = [containerLoader, connectionLoader, initialDataLoader] as any
export const moduleDefinition: ModuleExports = {
service,
loaders,
revertMigration,
runMigrations,
}
@@ -0,0 +1 @@
export { MikroOrmBaseRepository as BaseRepository } from "@medusajs/utils"
@@ -0,0 +1,29 @@
#!/usr/bin/env node
import { ModulesSdkUtils } from "@medusajs/utils"
import { Modules } from "@medusajs/modules-sdk"
import * as Models from "@models"
import { EOL } from "os"
const args = process.argv
const path = args.pop() as string
export default (async () => {
const { config } = await import("dotenv")
config()
if (!path) {
throw new Error(
`filePath is required.${EOL}Example: medusa-currency-seed <filePath>`
)
}
const run = ModulesSdkUtils.buildSeedScript({
moduleName: Modules.CURRENCY,
models: Models,
pathToMigrations: __dirname + "/../../migrations",
seedHandler: async ({ manager, data }) => {
// TODO: Add seed logic
},
})
await run({ path })
})()
@@ -0,0 +1,5 @@
describe("noop", function () {
it("should run", function () {
expect(true).toBe(true)
})
})
@@ -0,0 +1,131 @@
import {
DAL,
InternalModuleDeclaration,
ModuleJoinerConfig,
ModulesSdkTypes,
ICurrencyModuleService,
CurrencyTypes,
Context,
FindConfig,
FilterableCurrencyProps,
BaseFilterable,
} from "@medusajs/types"
import { ModulesSdkUtils } from "@medusajs/utils"
import { Currency } from "@models"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config"
const generateMethodForModels = []
type InjectedDependencies = {
baseRepository: DAL.RepositoryService
currencyService: ModulesSdkTypes.InternalModuleService<any>
}
export default class CurrencyModuleService<TEntity extends Currency = Currency>
extends ModulesSdkUtils.abstractModuleServiceFactory<
InjectedDependencies,
CurrencyTypes.CurrencyDTO,
{
Currency: { dto: CurrencyTypes.CurrencyDTO }
}
>(Currency, generateMethodForModels, entityNameToLinkableKeysMap)
implements ICurrencyModuleService
{
protected baseRepository_: DAL.RepositoryService
protected readonly currencyService_: ModulesSdkTypes.InternalModuleService<TEntity>
constructor(
{ baseRepository, currencyService }: InjectedDependencies,
protected readonly moduleDeclaration: InternalModuleDeclaration
) {
// @ts-ignore
super(...arguments)
this.baseRepository_ = baseRepository
this.currencyService_ = currencyService
}
__joinerConfig(): ModuleJoinerConfig {
return joinerConfig
}
retrieve(
code: string,
config?: FindConfig<CurrencyTypes.CurrencyDTO>,
sharedContext?: Context
): Promise<CurrencyTypes.CurrencyDTO> {
return this.currencyService_.retrieve(
code?.toLowerCase(),
config,
sharedContext
)
}
list(
filters?: FilterableCurrencyProps,
config?: FindConfig<CurrencyTypes.CurrencyDTO>,
sharedContext?: Context
): Promise<CurrencyTypes.CurrencyDTO[]> {
return this.currencyService_.list(
CurrencyModuleService.normalizeFilters(filters),
config,
sharedContext
)
}
listAndCount(
filters?: FilterableCurrencyProps,
config?: FindConfig<CurrencyTypes.CurrencyDTO>,
sharedContext?: Context
): Promise<[CurrencyTypes.CurrencyDTO[], number]> {
return this.currencyService_.listAndCount(
CurrencyModuleService.normalizeFilters(filters),
config,
sharedContext
)
}
protected static normalizeFilters(
filters: FilterableCurrencyProps | undefined
): FilterableCurrencyProps | undefined {
return normalizeFilterable<
CurrencyTypes.CurrencyDTO,
FilterableCurrencyProps
>(filters, (fieldName, value) => {
if (fieldName === "code" && !!value) {
return value.toLowerCase()
}
return value
})
}
}
// TODO: Move normalizer support to `buildQuery` so we don't even need to override the list/retrieve methods just for normalization
const normalizeFilterable = <TModel, TFilter extends BaseFilterable<TFilter>>(
filters: TFilter | undefined,
normalizer: (fieldName: keyof TModel, value: any) => any
): TFilter | undefined => {
if (!filters) {
return filters
}
const normalizedFilters = {} as TFilter
for (const key in filters) {
if (key === "$and" || key === "$or") {
normalizedFilters[key] = (filters[key] as any).map((filter) =>
normalizeFilterable(filter, normalizer)
)
} else if (filters[key] !== undefined) {
if (Array.isArray(filters[key])) {
normalizedFilters[key] = (filters[key] as any).map((val) =>
normalizer(key as any, val)
)
} else {
normalizedFilters[key] = normalizer(key as any, filters[key])
}
}
}
return normalizedFilters
}
+1
View File
@@ -0,0 +1 @@
export { default as CurrencyModuleService } from "./currency-module-service"
+6
View File
@@ -0,0 +1,6 @@
import { IEventBusModuleService, Logger } from "@medusajs/types"
export type InitializeModuleInjectableDependencies = {
logger?: Logger
eventBusService?: IEventBusModuleService
}
+37
View File
@@ -0,0 +1,37 @@
{
"compilerOptions": {
"lib": ["es2020"],
"target": "es2020",
"outDir": "./dist",
"esModuleInterop": true,
"declaration": true,
"module": "commonjs",
"moduleResolution": "node",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"sourceMap": false,
"noImplicitReturns": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"noImplicitThis": true,
"allowJs": true,
"skipLibCheck": true,
"downlevelIteration": true, // to use ES5 specific tooling
"baseUrl": ".",
"resolveJsonModule": true,
"paths": {
"@models": ["./src/models"],
"@services": ["./src/services"],
"@repositories": ["./src/repositories"],
"@types": ["./src/types"]
}
},
"include": ["src"],
"exclude": [
"dist",
"./src/**/__tests__",
"./src/**/__mocks__",
"./src/**/__fixtures__",
"node_modules"
]
}
+8
View File
@@ -0,0 +1,8 @@
{
"extends": "./tsconfig.json",
"include": ["src", "integration-tests"],
"exclude": ["node_modules", "dist"],
"compilerOptions": {
"sourceMap": true
}
}
@@ -0,0 +1,18 @@
import { remoteQueryObjectFromString } from "@medusajs/utils"
import { MedusaRequest, MedusaResponse } from "../../../../types/routing"
import { defaultAdminCurrencyFields } from "../query-config"
export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
const remoteQuery = req.scope.resolve("remoteQuery")
const variables = { code: req.params.code }
const queryObject = remoteQueryObjectFromString({
entryPoint: "currency",
variables,
fields: defaultAdminCurrencyFields,
})
const [currency] = await remoteQuery(queryObject)
res.status(200).json({ currency })
}
@@ -0,0 +1,36 @@
import { transformQuery } from "../../../api/middlewares"
import { MiddlewareRoute } from "../../../loaders/helpers/routing/types"
import { authenticate } from "../../../utils/authenticate-middleware"
import * as QueryConfig from "./query-config"
import {
AdminGetCurrenciesCurrencyParams,
AdminGetCurrenciesParams,
} from "./validators"
export const adminCurrencyRoutesMiddlewares: MiddlewareRoute[] = [
{
method: ["ALL"],
matcher: "/admin/currencies*",
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
},
{
method: ["GET"],
matcher: "/admin/currencies",
middlewares: [
transformQuery(
AdminGetCurrenciesParams,
QueryConfig.listTransformQueryConfig
),
],
},
{
method: ["GET"],
matcher: "/admin/currencies/:code",
middlewares: [
transformQuery(
AdminGetCurrenciesCurrencyParams,
QueryConfig.retrieveTransformQueryConfig
),
],
},
]
@@ -0,0 +1,20 @@
export const defaultAdminCurrencyRelations = []
export const allowedAdminCurrencyRelations = []
export const defaultAdminCurrencyFields = [
"code",
"name",
"symbol",
"symbol_native",
]
export const retrieveTransformQueryConfig = {
defaultFields: defaultAdminCurrencyFields,
defaultRelations: defaultAdminCurrencyRelations,
allowedRelations: allowedAdminCurrencyRelations,
isList: false,
}
export const listTransformQueryConfig = {
defaultLimit: 50,
isList: true,
}
@@ -0,0 +1,27 @@
import { remoteQueryObjectFromString } from "@medusajs/utils"
import { MedusaRequest, MedusaResponse } from "../../../types/routing"
import { defaultAdminCurrencyFields } from "./query-config"
export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
const remoteQuery = req.scope.resolve("remoteQuery")
const queryObject = remoteQueryObjectFromString({
entryPoint: "currency",
variables: {
filters: req.filterableFields,
order: req.listConfig.order,
skip: req.listConfig.skip,
take: req.listConfig.take,
},
fields: defaultAdminCurrencyFields,
})
const { rows: currencies, metadata } = await remoteQuery(queryObject)
res.json({
currencies,
count: metadata.count,
offset: metadata.skip,
limit: metadata.take,
})
}
@@ -0,0 +1,30 @@
import { Type } from "class-transformer"
import { IsOptional, IsString, ValidateNested } from "class-validator"
import { FindParams, extendedFindParamsMixin } from "../../../types/common"
export class AdminGetCurrenciesCurrencyParams extends FindParams {}
/**
* Parameters used to filter and configure the pagination of the retrieved currencies.
*/
export class AdminGetCurrenciesParams extends extendedFindParamsMixin({
limit: 50,
offset: 0,
}) {
/**
* Search parameter for currencies.
*/
@IsString({ each: true })
@IsOptional()
code?: string | string[]
// Additional filters from BaseFilterable
@IsOptional()
@ValidateNested({ each: true })
@Type(() => AdminGetCurrenciesParams)
$and?: AdminGetCurrenciesParams[]
@IsOptional()
@ValidateNested({ each: true })
@Type(() => AdminGetCurrenciesParams)
$or?: AdminGetCurrenciesParams[]
}
@@ -1,5 +1,5 @@
export const defaultAdminRegionRelations = ["countries", "currency"]
export const allowedAdminRegionRelations = ["countries", "currency"]
export const defaultAdminRegionRelations = ["countries"]
export const allowedAdminRegionRelations = ["countries"]
export const defaultAdminRegionFields = [
"id",
"name",
@@ -13,10 +13,6 @@ export const defaultAdminRegionFields = [
"countries.iso_3",
"countries.num_code",
"countries.name",
"currency.code",
"currency.symbol",
"currency.symbol_native",
"currency.name",
]
export const retrieveTransformQueryConfig = {
@@ -16,6 +16,8 @@ import { storeCartRoutesMiddlewares } from "./store/carts/middlewares"
import { storeCustomerRoutesMiddlewares } from "./store/customers/middlewares"
import { storeRegionRoutesMiddlewares } from "./store/regions/middlewares"
import { hooksRoutesMiddlewares } from "./hooks/middlewares"
import { adminCurrencyRoutesMiddlewares } from "./admin/currencies/middlewares"
import { storeCurrencyRoutesMiddlewares } from "./store/currencies/middlewares"
export const config: MiddlewaresConfig = {
routes: [
@@ -37,5 +39,7 @@ export const config: MiddlewaresConfig = {
...adminApiKeyRoutesMiddlewares,
...hooksRoutesMiddlewares,
...adminStoreRoutesMiddlewares,
...adminCurrencyRoutesMiddlewares,
...storeCurrencyRoutesMiddlewares,
],
}
@@ -0,0 +1,18 @@
import { remoteQueryObjectFromString } from "@medusajs/utils"
import { MedusaRequest, MedusaResponse } from "../../../../types/routing"
import { defaultStoreCurrencyFields } from "../query-config"
export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
const remoteQuery = req.scope.resolve("remoteQuery")
const variables = { code: req.params.code }
const queryObject = remoteQueryObjectFromString({
entryPoint: "currency",
variables,
fields: defaultStoreCurrencyFields,
})
const [currency] = await remoteQuery(queryObject)
res.status(200).json({ currency })
}
@@ -0,0 +1,31 @@
import { transformQuery } from "../../../api/middlewares"
import { MiddlewareRoute } from "../../../loaders/helpers/routing/types"
import { authenticate } from "../../../utils/authenticate-middleware"
import * as QueryConfig from "./query-config"
import {
StoreGetCurrenciesCurrencyParams,
StoreGetCurrenciesParams,
} from "./validators"
export const storeCurrencyRoutesMiddlewares: MiddlewareRoute[] = [
{
method: ["GET"],
matcher: "/store/currencies",
middlewares: [
transformQuery(
StoreGetCurrenciesParams,
QueryConfig.listTransformQueryConfig
),
],
},
{
method: ["GET"],
matcher: "/store/currencies/:code",
middlewares: [
transformQuery(
StoreGetCurrenciesCurrencyParams,
QueryConfig.retrieveTransformQueryConfig
),
],
},
]
@@ -0,0 +1,20 @@
export const defaultStoreCurrencyRelations = []
export const allowedStoreCurrencyRelations = []
export const defaultStoreCurrencyFields = [
"code",
"name",
"symbol",
"symbol_native",
]
export const retrieveTransformQueryConfig = {
defaultFields: defaultStoreCurrencyFields,
defaultRelations: defaultStoreCurrencyRelations,
allowedRelations: allowedStoreCurrencyRelations,
isList: false,
}
export const listTransformQueryConfig = {
defaultLimit: 20,
isList: true,
}
@@ -0,0 +1,27 @@
import { remoteQueryObjectFromString } from "@medusajs/utils"
import { MedusaRequest, MedusaResponse } from "../../../types/routing"
import { defaultStoreCurrencyFields } from "./query-config"
export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
const remoteQuery = req.scope.resolve("remoteQuery")
const queryObject = remoteQueryObjectFromString({
entryPoint: "currency",
variables: {
filters: req.filterableFields,
order: req.listConfig.order,
skip: req.listConfig.skip,
take: req.listConfig.take,
},
fields: defaultStoreCurrencyFields,
})
const { rows: currencies, metadata } = await remoteQuery(queryObject)
res.json({
currencies,
count: metadata.count,
offset: metadata.skip,
limit: metadata.take,
})
}
@@ -0,0 +1,30 @@
import { Type } from "class-transformer"
import { IsOptional, IsString, ValidateNested } from "class-validator"
import { FindParams, extendedFindParamsMixin } from "../../../types/common"
export class StoreGetCurrenciesCurrencyParams extends FindParams {}
/**
* Parameters used to filter and configure the pagination of the retrieved currencies.
*/
export class StoreGetCurrenciesParams extends extendedFindParamsMixin({
limit: 50,
offset: 0,
}) {
/**
* Search parameter for currencies.
*/
@IsString({ each: true })
@IsOptional()
code?: string | string[]
// Additional filters from BaseFilterable
@IsOptional()
@ValidateNested({ each: true })
@Type(() => StoreGetCurrenciesParams)
$and?: StoreGetCurrenciesParams[]
@IsOptional()
@ValidateNested({ each: true })
@Type(() => StoreGetCurrenciesParams)
$or?: StoreGetCurrenciesParams[]
}
@@ -176,33 +176,6 @@ const migratePriceLists = async (container: AwilixContainer) => {
}
}
const ensureCurrencies = async (container: AwilixContainer) => {
const currenciesService: CurrencyService =
container.resolve("currencyService")
const pricingModuleService: IPricingModuleService = container.resolve(
"pricingModuleService"
)
const [coreCurrencies, totalCurrencies] =
await currenciesService.listAndCount({}, {})
const moduleCurrencies = await pricingModuleService.listCurrencies(
{},
{ take: 100000 }
)
const moduleCurrenciesSet = new Set(moduleCurrencies.map(({ code }) => code))
const currenciesToCreate = coreCurrencies
.filter(({ code }) => {
return !moduleCurrenciesSet.has(code)
})
.map(({ includes_tax, ...currency }) => currency)
await pricingModuleService.createCurrencies(currenciesToCreate)
}
const migrate = async function ({ directory }) {
const app = express()
@@ -212,11 +185,6 @@ const migrate = async function ({ directory }) {
isTest: false,
})
Logger.info("-----------------------------------------------")
Logger.info("------------- Creating currencies -------------")
Logger.info("-----------------------------------------------")
await ensureCurrencies(container)
Logger.info("-----------------------------------------------")
Logger.info("--------- Creating default rule types ---------")
Logger.info("-----------------------------------------------")
+16
View File
@@ -28,6 +28,7 @@ export enum Modules {
ORDER = "order",
API_KEY = "apiKey",
STORE = "store",
CURRENCY = "currency",
}
export enum ModuleRegistrationName {
@@ -51,6 +52,7 @@ export enum ModuleRegistrationName {
ORDER = "orderModuleService",
API_KEY = "apiKeyModuleService",
STORE = "storeModuleService",
CURRENCY = "currencyModuleService",
}
export const MODULE_PACKAGE_NAMES = {
@@ -75,6 +77,7 @@ export const MODULE_PACKAGE_NAMES = {
[Modules.ORDER]: "@medusajs/order",
[Modules.API_KEY]: "@medusajs/api-key",
[Modules.STORE]: "@medusajs/store",
[Modules.CURRENCY]: "@medusajs/currency",
}
export const ModulesDefinition: { [key: string | Modules]: ModuleDefinition } =
@@ -340,6 +343,19 @@ export const ModulesDefinition: { [key: string | Modules]: ModuleDefinition } =
resources: MODULE_RESOURCE_TYPE.SHARED,
},
},
[Modules.CURRENCY]: {
key: Modules.CURRENCY,
registrationName: ModuleRegistrationName.CURRENCY,
defaultPackage: false,
label: upperCaseFirst(ModuleRegistrationName.CURRENCY),
isRequired: false,
isQueryable: true,
dependencies: ["logger"],
defaultModuleDeclaration: {
scope: MODULE_SCOPE.INTERNAL,
resources: MODULE_RESOURCE_TYPE.SHARED,
},
},
}
export const MODULE_DEFINITIONS: ModuleDefinition[] =
@@ -1,20 +0,0 @@
export const defaultCurrencyData = [
{
symbol: "$",
name: "US Dollar",
symbol_native: "$",
code: "USD",
},
{
symbol: "CA$",
name: "Canadian Dollar",
symbol_native: "$",
code: "CAD",
},
{
symbol: "€",
name: "Euro",
symbol_native: "€",
code: "EUR",
},
]
@@ -1,22 +0,0 @@
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { Currency } from "@models"
import { defaultCurrencyData } from "./data"
export * from "./data"
export async function createCurrencies(
manager: SqlEntityManager,
currencyData: any[] = defaultCurrencyData
): Promise<Currency[]> {
const currencies: Currency[] = []
for (let curr of currencyData) {
const currency = manager.create(Currency, curr)
currencies.push(currency)
}
await manager.persistAndFlush(currencies)
return currencies
}
@@ -1,6 +1,5 @@
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { createCurrencies, defaultCurrencyData } from "./currency"
import { createMoneyAmounts, defaultMoneyAmountsData } from "./money-amount"
import { createPriceRules, defaultPriceRuleData } from "./price-rule"
import { createPriceSets, defaultPriceSetsData } from "./price-set"
@@ -21,14 +20,12 @@ export async function seedPriceData(
{
moneyAmountsData = defaultMoneyAmountsData,
priceSetsData = defaultPriceSetsData,
currencyData = defaultCurrencyData,
priceRuleData = defaultPriceRuleData,
priceSetMoneyAmountsData = defaultPriceSetMoneyAmountsData,
priceSetMoneyAmountRulesData = defaultPriceSetMoneyAmountRulesData,
ruleTypesData = defaultRuleTypesData,
} = {}
) {
await createCurrencies(testManager, currencyData)
await createMoneyAmounts(testManager, moneyAmountsData)
await createPriceSets(testManager, priceSetsData)
await createPriceSetMoneyAmounts(testManager, priceSetMoneyAmountsData)
@@ -1,278 +0,0 @@
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { Currency } from "@models"
import { createCurrencies } from "../../../__fixtures__/currency"
import { MikroOrmWrapper } from "../../../utils"
import { createMedusaContainer } from "@medusajs/utils"
import { asValue } from "awilix"
import ContainerLoader from "../../../../src/loaders/container"
import { ModulesSdkTypes } from "@medusajs/types"
jest.setTimeout(30000)
describe("Currency Service", () => {
let service: ModulesSdkTypes.InternalModuleService<any>
let testManager: SqlEntityManager
let repositoryManager: SqlEntityManager
let data!: Currency[]
const currencyData = [
{
symbol: "$",
name: "US Dollar",
symbol_native: "$",
code: "USD",
},
{
symbol: "CA$",
name: "Canadian Dollar",
symbol_native: "$",
code: "CAD",
},
]
beforeEach(async () => {
await MikroOrmWrapper.setupDatabase()
repositoryManager = await MikroOrmWrapper.forkManager()
const container = createMedusaContainer()
container.register("manager", asValue(repositoryManager))
await ContainerLoader({ container })
service = container.resolve("currencyService")
testManager = await MikroOrmWrapper.forkManager()
data = await createCurrencies(testManager, currencyData)
})
afterEach(async () => {
await MikroOrmWrapper.clearDatabase()
})
describe("list", () => {
it("list currencies", async () => {
const currenciesResult = await service.list()
expect(currenciesResult).toEqual([
expect.objectContaining({
code: "CAD",
name: "Canadian Dollar",
}),
expect.objectContaining({
code: "USD",
name: "US Dollar",
}),
])
})
it("list currencies by code", async () => {
const currenciesResult = await service.list({ code: ["USD"] })
expect(currenciesResult).toEqual([
expect.objectContaining({
code: "USD",
name: "US Dollar",
}),
])
})
})
describe("listAndCount", () => {
it("should return currencies and count", async () => {
const [currenciesResult, count] = await service.listAndCount()
expect(count).toEqual(2)
expect(currenciesResult).toEqual([
expect.objectContaining({
code: "CAD",
name: "Canadian Dollar",
}),
expect.objectContaining({
code: "USD",
name: "US Dollar",
}),
])
})
it("should return currencies and count when filtered", async () => {
const [currenciesResult, count] = await service.listAndCount({
code: ["USD"],
})
expect(count).toEqual(1)
expect(currenciesResult).toEqual([
expect.objectContaining({
code: "USD",
name: "US Dollar",
}),
])
})
it("should return currencies and count when using skip and take", async () => {
const [currenciesResult, count] = await service.listAndCount(
{},
{ skip: 1, take: 1 }
)
expect(count).toEqual(2)
expect(currenciesResult).toEqual([
expect.objectContaining({
code: "USD",
name: "US Dollar",
}),
])
})
it("should return requested fields", async () => {
const [currenciesResult, count] = await service.listAndCount(
{},
{
take: 1,
select: ["code"],
}
)
const serialized = JSON.parse(JSON.stringify(currenciesResult))
expect(count).toEqual(2)
expect(serialized).toEqual([
{
code: "CAD",
},
])
})
})
describe("retrieve", () => {
const code = "USD"
const name = "US Dollar"
it("should return currency for the given code", async () => {
const currency = await service.retrieve(code)
expect(currency).toEqual(
expect.objectContaining({
code,
})
)
})
it("should throw an error when currency with code does not exist", async () => {
let error
try {
await service.retrieve("does-not-exist")
} catch (e) {
error = e
}
expect(error.message).toEqual(
"Currency with code: does-not-exist was not found"
)
})
it("should throw an error when a code is not provided", async () => {
let error
try {
await service.retrieve(undefined as unknown as string)
} catch (e) {
error = e
}
expect(error.message).toEqual("currency - code must be defined")
})
it("should return currency based on config select param", async () => {
const currency = await service.retrieve(code, {
select: ["code", "name"],
})
const serialized = JSON.parse(JSON.stringify(currency))
expect(serialized).toEqual({
code,
name,
})
})
})
describe("delete", () => {
const code = "USD"
it("should delete the currencies given an code successfully", async () => {
await service.delete([code])
const currencies = await service.list({
code: [code],
})
expect(currencies).toHaveLength(0)
})
})
describe("update", () => {
const code = "USD"
it("should update the name of the currency successfully", async () => {
await service.update([
{
code,
name: "United States Pounds",
},
])
const currency = await service.retrieve(code)
expect(currency.name).toEqual("United States Pounds")
})
it("should throw an error when a code does not exist", async () => {
let error
try {
await service.update([
{
code: "does-not-exist",
name: "UK",
},
])
} catch (e) {
error = e
}
expect(error.message).toEqual(
'Currency with code "does-not-exist" not found'
)
})
})
describe("create", () => {
it("should create a currency successfully", async () => {
await service.create([
{
code: "TES",
name: "Test Dollars",
symbol: "TES1",
symbol_native: "TES2",
},
])
const [currency] = await service.list({
code: ["TES"],
})
expect(currency).toEqual(
expect.objectContaining({
code: "TES",
name: "Test Dollars",
symbol: "TES1",
symbol_native: "TES2",
})
)
})
})
})
@@ -3,7 +3,6 @@ import { SqlEntityManager } from "@mikro-orm/postgresql"
import { Currency, MoneyAmount } from "@models"
import { MoneyAmountService } from "@services"
import { createCurrencies } from "../../../__fixtures__/currency"
import { createMoneyAmounts } from "../../../__fixtures__/money-amount"
import { MikroOrmWrapper } from "../../../utils"
import { createMedusaContainer } from "@medusajs/utils"
@@ -17,7 +16,6 @@ describe("MoneyAmount Service", () => {
let testManager: SqlEntityManager
let repositoryManager: SqlEntityManager
let data!: MoneyAmount[]
let currencyData!: Currency[]
beforeEach(async () => {
await MikroOrmWrapper.setupDatabase()
@@ -31,7 +29,6 @@ describe("MoneyAmount Service", () => {
service = container.resolve("moneyAmountService")
testManager = await MikroOrmWrapper.forkManager()
currencyData = await createCurrencies(testManager)
data = await createMoneyAmounts(testManager)
})
@@ -79,8 +76,7 @@ describe("MoneyAmount Service", () => {
id: ["money-amount-USD"],
},
{
select: ["id", "min_quantity", "currency.code", "amount"],
relations: ["currency"],
select: ["id", "min_quantity", "currency_code", "amount"],
}
)
@@ -92,9 +88,6 @@ describe("MoneyAmount Service", () => {
amount: 500,
min_quantity: "1",
currency_code: "USD",
currency: {
code: "USD",
},
},
])
})
@@ -105,8 +98,7 @@ describe("MoneyAmount Service", () => {
currency_code: ["USD"],
},
{
select: ["id", "min_quantity", "currency.code", "amount"],
relations: ["currency"],
select: ["id", "min_quantity", "currency_code", "amount"],
}
)
@@ -118,9 +110,6 @@ describe("MoneyAmount Service", () => {
min_quantity: "1",
currency_code: "USD",
amount: 500,
currency: {
code: "USD",
},
},
])
})
@@ -165,8 +154,7 @@ describe("MoneyAmount Service", () => {
id: ["money-amount-USD"],
},
{
select: ["id", "min_quantity", "currency.code", "amount"],
relations: ["currency"],
select: ["id", "min_quantity", "currency_code", "amount"],
}
)
@@ -179,9 +167,6 @@ describe("MoneyAmount Service", () => {
amount: 500,
min_quantity: "1",
currency_code: "USD",
currency: {
code: "USD",
},
},
])
})
@@ -316,7 +301,6 @@ describe("MoneyAmount Service", () => {
const moneyAmount = await service.retrieve(id)
expect(moneyAmount.currency_code).toEqual("EUR")
expect(moneyAmount.currency?.code).toEqual("EUR")
})
it("should throw an error when a id does not exist", async () => {
@@ -3,7 +3,6 @@ import { PriceSetMoneyAmount } from "@models"
import { CreatePriceRuleDTO } from "@medusajs/types"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { PriceRuleService } from "@services"
import { createCurrencies } from "../../../__fixtures__/currency"
import { createMoneyAmounts } from "../../../__fixtures__/money-amount"
import { createPriceRules } from "../../../__fixtures__/price-rule"
import { createPriceSets } from "../../../__fixtures__/price-set"
@@ -34,7 +33,6 @@ describe("PriceRule Service", () => {
service = container.resolve("priceRuleService")
await createCurrencies(testManager)
await createMoneyAmounts(testManager)
await createPriceSets(testManager)
await createRuleTypes(testManager)
@@ -3,7 +3,6 @@ import { SqlEntityManager } from "@mikro-orm/postgresql"
import { MoneyAmount, PriceSet } from "@models"
import { PriceSetService } from "@services"
import { createCurrencies } from "../../../__fixtures__/currency"
import { createMoneyAmounts } from "../../../__fixtures__/money-amount"
import { createPriceSets } from "../../../__fixtures__/price-set"
import { MikroOrmWrapper } from "../../../utils"
@@ -63,8 +62,6 @@ describe("PriceSet Service", () => {
service = container.resolve("priceSetService")
await createCurrencies(testManager)
moneyAmountsData = await createMoneyAmounts(
testManager,
moneyAmountsInputData
@@ -85,21 +85,6 @@ describe("PricingModule Service - Calculate Price", () => {
describe("calculatePrices", () => {
beforeEach(async () => {
const currencyData = [
{
symbol: "zł",
name: "Polish Zloty",
symbol_native: "zł",
code: "PLN",
},
{
symbol: "€",
name: "Euro",
symbol_native: "€",
code: "EUR",
},
]
const moneyAmountsData = [
{
id: "money-amount-PLN",
@@ -373,7 +358,6 @@ describe("PricingModule Service - Calculate Price", () => {
] as unknown as CreatePriceRuleDTO[]
await seedPriceData(MikroOrmWrapper.forkManager(), {
currencyData,
moneyAmountsData,
priceSetsData,
priceSetMoneyAmountsData,
@@ -1,277 +0,0 @@
import { IPricingModuleService } from "@medusajs/types"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { Currency } from "@models"
import { createCurrencies } from "../../../__fixtures__/currency"
import { MikroOrmWrapper } from "../../../utils"
import { getInitModuleConfig } from "../../../utils/get-init-module-config"
import { Modules } from "@medusajs/modules-sdk"
import { initModules } from "medusa-test-utils"
describe("PricingModule Service - Currency", () => {
let service: IPricingModuleService
let testManager: SqlEntityManager
let repositoryManager: SqlEntityManager
let data!: Currency[]
let shutdownFunc: () => Promise<void>
beforeAll(async () => {
const initModulesConfig = getInitModuleConfig()
const { medusaApp, shutdown } = await initModules(initModulesConfig)
service = medusaApp.modules[Modules.PRICING]
shutdownFunc = shutdown
})
afterAll(async () => {
await shutdownFunc()
})
beforeEach(async () => {
await MikroOrmWrapper.setupDatabase()
repositoryManager = MikroOrmWrapper.forkManager()
testManager = MikroOrmWrapper.forkManager()
data = await createCurrencies(testManager)
})
afterEach(async () => {
await MikroOrmWrapper.clearDatabase()
})
describe("listCurrencies", () => {
it("list currencies", async () => {
const currenciesResult = await service.listCurrencies()
expect(currenciesResult).toEqual([
expect.objectContaining({
code: "CAD",
name: "Canadian Dollar",
}),
expect.objectContaining({
code: "EUR",
name: "Euro",
}),
expect.objectContaining({
code: "USD",
name: "US Dollar",
}),
])
})
it("list currencies by code", async () => {
const currenciesResult = await service.listCurrencies({ code: ["USD"] })
expect(currenciesResult).toEqual([
expect.objectContaining({
code: "USD",
name: "US Dollar",
}),
])
})
})
describe("listAndCountCurrencies", () => {
it("should return currencies and count", async () => {
const [currenciesResult, count] = await service.listAndCountCurrencies()
expect(count).toEqual(3)
expect(currenciesResult).toEqual([
expect.objectContaining({
code: "CAD",
name: "Canadian Dollar",
}),
expect.objectContaining({
code: "EUR",
name: "Euro",
}),
expect.objectContaining({
code: "USD",
name: "US Dollar",
}),
])
})
it("should return currencies and count when filtered", async () => {
const [currenciesResult, count] = await service.listAndCountCurrencies({
code: ["USD"],
})
expect(count).toEqual(1)
expect(currenciesResult).toEqual([
expect.objectContaining({
code: "USD",
name: "US Dollar",
}),
])
})
it("should return currencies and count when using skip and take", async () => {
const [currenciesResult, count] = await service.listAndCountCurrencies(
{},
{ skip: 1, take: 1 }
)
expect(count).toEqual(3)
expect(currenciesResult).toEqual([
expect.objectContaining({
code: "EUR",
name: "Euro",
symbol: "€",
symbol_native: "€",
}),
])
})
it("should return requested fields", async () => {
const [currenciesResult, count] = await service.listAndCountCurrencies(
{},
{
take: 1,
select: ["code"],
}
)
const serialized = JSON.parse(JSON.stringify(currenciesResult))
expect(count).toEqual(3)
expect(serialized).toEqual([
{
code: "CAD",
},
])
})
})
describe("retrieveCurrency", () => {
const code = "USD"
const name = "US Dollar"
it("should return currency for the given code", async () => {
const currency = await service.retrieveCurrency(code)
expect(currency).toEqual(
expect.objectContaining({
code,
})
)
})
it("should throw an error when currency with code does not exist", async () => {
let error
try {
await service.retrieveCurrency("does-not-exist")
} catch (e) {
error = e
}
expect(error.message).toEqual(
"Currency with code: does-not-exist was not found"
)
})
it("should throw an error when a code is not provided", async () => {
let error
try {
await service.retrieveCurrency(undefined as unknown as string)
} catch (e) {
error = e
}
expect(error.message).toEqual("currency - code must be defined")
})
it("should return currency based on config select param", async () => {
const currency = await service.retrieveCurrency(code, {
select: ["code", "name"],
})
const serialized = JSON.parse(JSON.stringify(currency))
expect(serialized).toEqual({
code,
name,
})
})
})
describe("deleteCurrencies", () => {
const code = "USD"
it("should delete the currencies given an code successfully", async () => {
await service.deleteCurrencies([code])
const currencies = await service.listCurrencies({
code: [code],
})
expect(currencies).toHaveLength(0)
})
})
describe("updateCurrencies", () => {
const code = "USD"
it("should update the name of the currency successfully", async () => {
await service.updateCurrencies([
{
code,
name: "United States Pounds",
},
])
const currency = await service.retrieveCurrency(code)
expect(currency.name).toEqual("United States Pounds")
})
it("should throw an error when a code does not exist", async () => {
let error
try {
await service.updateCurrencies([
{
code: "does-not-exist",
name: "UK",
},
])
} catch (e) {
error = e
}
expect(error.message).toEqual(
'Currency with code "does-not-exist" not found'
)
})
})
describe("createCurrencies", () => {
it("should create a currency successfully", async () => {
await service.createCurrencies([
{
code: "TES",
name: "Test Dollars",
symbol: "TES1",
symbol_native: "TES2",
},
])
const [currency] = await service.listCurrencies({
code: ["TES"],
})
expect(currency).toEqual(
expect.objectContaining({
code: "TES",
name: "Test Dollars",
symbol: "TES1",
symbol_native: "TES2",
})
)
})
})
})
@@ -1,7 +1,6 @@
import { IPricingModuleService } from "@medusajs/types"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { Currency, MoneyAmount } from "@models"
import { createCurrencies } from "../../../__fixtures__/currency"
import { MoneyAmount } from "@models"
import { createMoneyAmounts } from "../../../__fixtures__/money-amount"
import { MikroOrmWrapper } from "../../../utils"
import { createPriceSetMoneyAmounts } from "../../../__fixtures__/price-set-money-amount"
@@ -20,7 +19,6 @@ describe("PricingModule Service - MoneyAmount", () => {
let testManager: SqlEntityManager
let repositoryManager: SqlEntityManager
let data!: MoneyAmount[]
let currencyData!: Currency[]
let shutdownFunc: () => Promise<void>
beforeAll(async () => {
@@ -42,7 +40,6 @@ describe("PricingModule Service - MoneyAmount", () => {
repositoryManager = MikroOrmWrapper.forkManager()
testManager = MikroOrmWrapper.forkManager()
currencyData = await createCurrencies(testManager)
data = await createMoneyAmounts(testManager)
})
@@ -90,8 +87,7 @@ describe("PricingModule Service - MoneyAmount", () => {
id: ["money-amount-USD"],
},
{
select: ["id", "min_quantity", "currency.code"],
relations: ["currency"],
select: ["id", "min_quantity", "currency_code"],
}
)
@@ -103,9 +99,6 @@ describe("PricingModule Service - MoneyAmount", () => {
amount: null,
min_quantity: "1",
currency_code: "USD",
currency: {
code: "USD",
},
},
])
})
@@ -153,8 +146,7 @@ describe("PricingModule Service - MoneyAmount", () => {
id: ["money-amount-USD"],
},
{
select: ["id", "min_quantity", "currency.code", "amount"],
relations: ["currency"],
select: ["id", "min_quantity", "currency_code", "amount"],
}
)
@@ -167,9 +159,6 @@ describe("PricingModule Service - MoneyAmount", () => {
amount: 500,
min_quantity: "1",
currency_code: "USD",
currency: {
code: "USD",
},
},
])
})
@@ -392,12 +381,9 @@ describe("PricingModule Service - MoneyAmount", () => {
},
])
const moneyAmount = await service.retrieveMoneyAmount(id, {
relations: ["currency"],
})
const moneyAmount = await service.retrieveMoneyAmount(id, {})
expect(moneyAmount.currency_code).toEqual("EUR")
expect(moneyAmount.currency?.code).toEqual("EUR")
})
it("should throw an error when a id does not exist", async () => {
@@ -2,7 +2,6 @@ import { MikroOrmWrapper } from "../../../utils"
import { IPricingModuleService } from "@medusajs/types"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { createCurrencies } from "../../../__fixtures__/currency"
import { createPriceLists } from "../../../__fixtures__/price-list"
import { createPriceSets } from "../../../__fixtures__/price-set"
import { Modules } from "@medusajs/modules-sdk"
@@ -35,7 +34,6 @@ describe("PriceList Service", () => {
await MikroOrmWrapper.forkManager()
testManager = await MikroOrmWrapper.forkManager()
await createCurrencies(testManager)
await createPriceSets(testManager)
await createPriceLists(testManager)
await service.createRuleTypes([
@@ -2,7 +2,6 @@ import { CreatePriceRuleDTO, IPricingModuleService } from "@medusajs/types"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { PriceSetMoneyAmount } from "../../../../src"
import { createCurrencies } from "../../../__fixtures__/currency"
import { createMoneyAmounts } from "../../../__fixtures__/money-amount"
import { createPriceRules } from "../../../__fixtures__/price-rule"
import { createPriceSets } from "../../../__fixtures__/price-set"
@@ -39,7 +38,6 @@ describe("PricingModule Service - PriceRule", () => {
await MikroOrmWrapper.setupDatabase()
testManager = MikroOrmWrapper.forkManager()
await createCurrencies(testManager)
await createMoneyAmounts(testManager)
await createPriceSets(testManager)
await createRuleTypes(testManager)
@@ -1,6 +1,5 @@
import { IPricingModuleService } from "@medusajs/types"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { createCurrencies } from "../../../__fixtures__/currency"
import { createMoneyAmounts } from "../../../__fixtures__/money-amount"
import { createPriceSets } from "../../../__fixtures__/price-set"
import { createPriceSetMoneyAmounts } from "../../../__fixtures__/price-set-money-amount"
@@ -38,7 +37,6 @@ describe("PricingModule Service - PriceSetMoneyAmountRules", () => {
repositoryManager = await MikroOrmWrapper.forkManager()
testManager = await MikroOrmWrapper.forkManager()
await createCurrencies(testManager)
await createMoneyAmounts(testManager)
await createPriceSets(testManager)
await createRuleTypes(testManager)
+1 -15
View File
@@ -1,18 +1,11 @@
import { Modules } from "@medusajs/modules-sdk"
import { ModuleJoinerConfig } from "@medusajs/types"
import { MapToConfig } from "@medusajs/utils"
import {
Currency,
MoneyAmount,
PriceList,
PriceSet,
PriceSetMoneyAmount,
} from "@models"
import { MoneyAmount, PriceList, PriceSet, PriceSetMoneyAmount } from "@models"
import schema from "./schema"
export const LinkableKeys = {
money_amount_id: MoneyAmount.name,
currency_code: Currency.name,
price_set_id: PriceSet.name,
price_list_id: PriceList.name,
price_set_money_amount_id: PriceSetMoneyAmount.name,
@@ -48,13 +41,6 @@ export const joinerConfig: ModuleJoinerConfig = {
entity: "MoneyAmount",
},
},
{
name: ["currency", "currencies"],
args: {
methodSuffix: "Currencies",
entity: "Currency",
},
},
{
name: ["price_list", "price_lists"],
args: {
@@ -4,61 +4,6 @@
],
"name": "public",
"tables": [
{
"columns": {
"code": {
"name": "code",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "text"
},
"symbol": {
"name": "symbol",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "text"
},
"symbol_native": {
"name": "symbol_native",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "text"
},
"name": {
"name": "name",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "text"
}
},
"name": "currency",
"schema": "public",
"indexes": [
{
"keyName": "currency_pkey",
"columnNames": [
"code"
],
"composite": false,
"primary": true,
"unique": true
}
],
"checks": [],
"foreignKeys": {}
},
{
"columns": {
"id": {
@@ -172,19 +117,6 @@
],
"checks": [],
"foreignKeys": {
"money_amount_currency_code_foreign": {
"constraintName": "money_amount_currency_code_foreign",
"columnNames": [
"currency_code"
],
"localTableName": "public.money_amount",
"referencedColumnNames": [
"code"
],
"referencedTableName": "public.currency",
"deleteRule": "set null",
"updateRule": "cascade"
}
}
},
{
@@ -2,10 +2,6 @@ import { Migration } from "@mikro-orm/migrations"
export class Migration20230929122253 extends Migration {
async up(): Promise<void> {
this.addSql(
'create table if not exists "currency" ("code" text not null, "symbol" text not null, "symbol_native" text not null, "name" text not null, constraint "currency_pkey" primary key ("code"));'
)
this.addSql(
'create table if not exists "money_amount" ("id" text not null, "currency_code" text null, "amount" numeric null, "min_quantity" numeric null, "max_quantity" numeric null, constraint "money_amount_pkey" primary key ("id"));'
)
@@ -67,10 +63,6 @@ export class Migration20230929122253 extends Migration {
'create index "IDX_price_rule_price_set_money_amount_id" on "price_rule" ("price_set_money_amount_id");'
)
this.addSql(
'alter table "money_amount" add constraint "money_amount_currency_code_foreign" foreign key ("currency_code") references "currency" ("code") on update cascade on delete set null;'
)
this.addSql(
'alter table "price_set_money_amount" add constraint "price_set_money_amount_price_set_id_foreign" foreign key ("price_set_id") references "price_set" ("id") on update cascade on delete cascade;'
)
-1
View File
@@ -1,4 +1,3 @@
export { default as Currency } from "./currency"
export { default as MoneyAmount } from "./money-amount"
export { default as PriceList } from "./price-list"
export { default as PriceListRule } from "./price-list-rule"
@@ -14,7 +14,6 @@ import {
Property,
} from "@mikro-orm/core"
import Currency from "./currency"
import { PriceSetMoneyAmount } from "./index"
import PriceSet from "./price-set"
@@ -47,13 +46,6 @@ class MoneyAmount {
})
price_set_money_amount: PriceSetMoneyAmount
@ManyToOne(() => Currency, {
nullable: true,
index: "IDX_money_amount_currency_code",
fieldName: "currency_code",
})
currency: Currency
@Property({
columnType: "numeric",
nullable: true,
-1
View File
@@ -7,7 +7,6 @@ type PriceSet {
type MoneyAmount {
id: String!
currency_code: String
currency: Currency
amount: Float
min_quantity: Float
max_quantity: Float
+8 -26
View File
@@ -22,17 +22,13 @@ export async function run({
logger.info(`Loading seed data from ${path}...`)
const {
currenciesData,
moneyAmountsData,
priceSetsData,
priceSetMoneyAmountsData,
} = await import(resolve(process.cwd(), path)).catch((e) => {
logger?.error(
`Failed to load seed data from ${path}. Please, provide a relative path and check that you export the following: priceSetsData, currenciesData, moneyAmountsData and priceSetMoneyAmountsData.${EOL}${e}`
)
throw e
})
const { moneyAmountsData, priceSetsData, priceSetMoneyAmountsData } =
await import(resolve(process.cwd(), path)).catch((e) => {
logger?.error(
`Failed to load seed data from ${path}. Please, provide a relative path and check that you export the following: priceSetsData, moneyAmountsData and priceSetMoneyAmountsData.${EOL}${e}`
)
throw e
})
const dbData = ModulesSdkUtils.loadDatabaseConfig("pricing", options)!
const entities = Object.values(PricingModels) as unknown as EntitySchema[]
@@ -47,9 +43,8 @@ export async function run({
const manager = orm.em.fork()
try {
logger.info("Inserting price_sets, currencies & money_amounts")
logger.info("Inserting price_sets & money_amounts")
await createCurrencies(manager as any, currenciesData)
await createMoneyAmounts(manager as any, moneyAmountsData)
await createPriceSets(manager as any, priceSetsData)
await createPriceSetMoneyAmounts(manager as any, priceSetMoneyAmountsData)
@@ -62,19 +57,6 @@ export async function run({
await orm.close(true)
}
async function createCurrencies(
manager: SqlEntityManager<PostgreSqlDriver>,
data: RequiredEntityData<PricingModels.Currency>[]
) {
const currencies = data.map((currencyData) => {
return manager.create(PricingModels.Currency, currencyData)
})
await manager.persistAndFlush(currencies)
return currencies
}
async function createMoneyAmounts(
manager: SqlEntityManager<PostgreSqlDriver>,
data: RequiredEntityData<PricingModels.MoneyAmount>[]
@@ -1,24 +0,0 @@
import { Currency } from "@models"
import { asValue } from "awilix"
;(Currency as any).meta = {
/**
* Need to mock the Currency model as well to expose the primary keys when it is different than `id`
*/
primaryKeys: ["code"],
}
export const nonExistingCurrencyCode = "non-existing-code"
export const currencyRepositoryMock = {
currencyRepository: asValue({
find: jest.fn().mockImplementation(async ({ where: { code } }) => {
if (code === nonExistingCurrencyCode) {
return []
}
return [{}]
}),
findAndCount: jest.fn().mockResolvedValue([[], 0]),
getFreshManager: jest.fn().mockResolvedValue({}),
}),
}
@@ -1,228 +0,0 @@
import {
currencyRepositoryMock,
nonExistingCurrencyCode,
} from "../__fixtures__/currency"
import { createMedusaContainer } from "@medusajs/utils"
import { asValue } from "awilix"
import ContainerLoader from "../../loaders/container"
import { MedusaContainer } from "@medusajs/types"
const code = "existing-currency"
describe("Currency service", function () {
let container: MedusaContainer
beforeEach(async function () {
jest.clearAllMocks()
container = createMedusaContainer()
container.register("manager", asValue({}))
await ContainerLoader({ container })
container.register(currencyRepositoryMock)
})
it("should retrieve a currency", async function () {
const currencyService = container.resolve("currencyService")
const currencyRepository = container.resolve("currencyRepository")
await currencyService.retrieve(code)
expect(currencyRepository.find).toHaveBeenCalledWith(
{
where: {
code,
},
options: {
fields: undefined,
limit: 15,
offset: 0,
populate: [],
},
},
expect.any(Object)
)
})
it("should fail to retrieve a currency", async function () {
const currencyService = container.resolve("currencyService")
const currencyRepository = container.resolve("currencyRepository")
const err = await currencyService
.retrieve(nonExistingCurrencyCode)
.catch((e) => e)
expect(currencyRepository.find).toHaveBeenCalledWith(
{
where: {
code: nonExistingCurrencyCode,
},
options: {
fields: undefined,
limit: 15,
offset: 0,
populate: [],
withDeleted: undefined,
},
},
expect.any(Object)
)
expect(err.message).toBe(
`Currency with code: ${nonExistingCurrencyCode} was not found`
)
})
it("should list currencys", async function () {
const currencyService = container.resolve("currencyService")
const currencyRepository = container.resolve("currencyRepository")
const filters = {}
const config = {
relations: [],
}
await currencyService.list(filters, config)
expect(currencyRepository.find).toHaveBeenCalledWith(
{
where: {},
options: {
fields: undefined,
limit: 15,
offset: 0,
orderBy: {
code: "ASC",
},
populate: [],
withDeleted: undefined,
},
},
expect.any(Object)
)
})
it("should list currencys with filters", async function () {
const currencyService = container.resolve("currencyService")
const currencyRepository = container.resolve("currencyRepository")
const filters = {
tags: {
value: {
$in: ["test"],
},
},
}
const config = {
relations: [],
}
await currencyService.list(filters, config)
expect(currencyRepository.find).toHaveBeenCalledWith(
{
where: {
tags: {
value: {
$in: ["test"],
},
},
},
options: {
fields: undefined,
limit: 15,
offset: 0,
orderBy: {
code: "ASC",
},
populate: [],
withDeleted: undefined,
},
},
expect.any(Object)
)
})
it("should list currencys with filters and relations", async function () {
const currencyService = container.resolve("currencyService")
const currencyRepository = container.resolve("currencyRepository")
const filters = {
tags: {
value: {
$in: ["test"],
},
},
}
const config = {
relations: ["tags"],
}
await currencyService.list(filters, config)
expect(currencyRepository.find).toHaveBeenCalledWith(
{
where: {
tags: {
value: {
$in: ["test"],
},
},
},
options: {
fields: undefined,
limit: 15,
offset: 0,
orderBy: {
code: "ASC",
},
withDeleted: undefined,
populate: ["tags"],
},
},
expect.any(Object)
)
})
it("should list and count the currencies with filters and relations", async function () {
const currencyService = container.resolve("currencyService")
const currencyRepository = container.resolve("currencyRepository")
const filters = {
tags: {
value: {
$in: ["test"],
},
},
}
const config = {
relations: ["tags"],
}
await currencyService.listAndCount(filters, config)
expect(currencyRepository.findAndCount).toHaveBeenCalledWith(
{
where: {
tags: {
value: {
$in: ["test"],
},
},
},
options: {
fields: undefined,
limit: 15,
offset: 0,
orderBy: {
code: "ASC",
},
withDeleted: undefined,
populate: ["tags"],
},
},
expect.any(Object)
)
})
})
@@ -0,0 +1,6 @@
describe("Noop test", () => {
it("noop check", async () => {
expect(true).toBe(true)
})
})
@@ -28,7 +28,6 @@ import {
} from "@medusajs/utils"
import {
Currency,
MoneyAmount,
PriceList,
PriceListRule,
@@ -55,7 +54,6 @@ import { ServiceTypes } from "@types"
type InjectedDependencies = {
baseRepository: DAL.RepositoryService
pricingRepository: PricingRepositoryService
currencyService: ModulesSdkTypes.InternalModuleService<any>
moneyAmountService: ModulesSdkTypes.InternalModuleService<any>
priceSetService: ModulesSdkTypes.InternalModuleService<any>
priceSetMoneyAmountRulesService: ModulesSdkTypes.InternalModuleService<any>
@@ -69,7 +67,6 @@ type InjectedDependencies = {
}
const generateMethodForModels = [
Currency,
MoneyAmount,
PriceList,
PriceListRule,
@@ -84,7 +81,6 @@ const generateMethodForModels = [
export default class PricingModuleService<
TPriceSet extends PriceSet = PriceSet,
TMoneyAmount extends MoneyAmount = MoneyAmount,
TCurrency extends Currency = Currency,
TRuleType extends RuleType = RuleType,
TPriceSetMoneyAmountRules extends PriceSetMoneyAmountRules = PriceSetMoneyAmountRules,
TPriceRule extends PriceRule = PriceRule,
@@ -98,7 +94,6 @@ export default class PricingModuleService<
InjectedDependencies,
PricingTypes.PriceSetDTO,
{
Currency: { dto: PricingTypes.CurrencyDTO }
MoneyAmount: { dto: PricingTypes.MoneyAmountDTO }
PriceSetMoneyAmount: { dto: PricingTypes.PriceSetMoneyAmountDTO }
PriceSetMoneyAmountRules: {
@@ -114,7 +109,6 @@ export default class PricingModuleService<
{
protected baseRepository_: DAL.RepositoryService
protected readonly pricingRepository_: PricingRepositoryService
protected readonly currencyService_: ModulesSdkTypes.InternalModuleService<TCurrency>
protected readonly moneyAmountService_: ModulesSdkTypes.InternalModuleService<TMoneyAmount>
protected readonly ruleTypeService_: RuleTypeService<TRuleType>
protected readonly priceSetService_: ModulesSdkTypes.InternalModuleService<TPriceSet>
@@ -131,7 +125,6 @@ export default class PricingModuleService<
baseRepository,
pricingRepository,
moneyAmountService,
currencyService,
ruleTypeService,
priceSetService,
priceSetMoneyAmountRulesService,
@@ -149,7 +142,6 @@ export default class PricingModuleService<
this.baseRepository_ = baseRepository
this.pricingRepository_ = pricingRepository
this.currencyService_ = currencyService
this.moneyAmountService_ = moneyAmountService
this.ruleTypeService_ = ruleTypeService
this.priceSetService_ = priceSetService
@@ -749,36 +741,6 @@ export default class PricingModuleService<
)
}
@InjectTransactionManager("baseRepository_")
async createCurrencies(
data: PricingTypes.CreateCurrencyDTO[],
@MedusaContext() sharedContext: Context = {}
) {
const currencies = await this.currencyService_.create(data, sharedContext)
return await this.baseRepository_.serialize<PricingTypes.CurrencyDTO[]>(
currencies,
{
populate: true,
}
)
}
@InjectTransactionManager("baseRepository_")
async updateCurrencies(
data: PricingTypes.UpdateCurrencyDTO[],
@MedusaContext() sharedContext: Context = {}
) {
const currencies = await this.currencyService_.update(data, sharedContext)
return await this.baseRepository_.serialize<PricingTypes.CurrencyDTO[]>(
currencies,
{
populate: true,
}
)
}
@InjectTransactionManager("baseRepository_")
async createRuleTypes(
data: PricingTypes.CreateRuleTypeDTO[],
@@ -1,13 +0,0 @@
export interface CreateCurrencyDTO {
code: string
symbol: string
symbol_native: string
name: string
}
export interface UpdateCurrencyDTO {
code: string
symbol?: string
symbol_native?: string
name?: string
}
@@ -1,4 +1,3 @@
export * from "./currency"
export * from "./money-amount"
export * from "./price-list-rule-value"
export * from "./price-list-rule"
@@ -1,9 +1,6 @@
import { Currency } from "@models"
export interface CreateMoneyAmountDTO {
id?: string
currency_code: string
currency?: Currency
amount: number
min_quantity?: number | null
max_quantity?: number | null
@@ -1,27 +0,0 @@
import { BaseFilterable } from "@medusajs/types"
export interface CreateCurrencyDTO {
code: string
symbol: string
symbol_native: string
name: string
}
export interface UpdateCurrencyDTO {
code: string
symbol?: string
symbol_native?: string
name?: string
}
export interface FilterableCurrencyProps
extends BaseFilterable<FilterableCurrencyProps> {
code?: string[]
}
export interface CurrencyDTO {
code: string
symbol?: string
symbol_native?: string
name?: string
}
+1 -2
View File
@@ -1,4 +1,3 @@
export * from "./currency"
export * from "./money-amount"
export * from "./price-list-rule-value"
export * from "./price-list-rule"
@@ -9,4 +8,4 @@ export * from "./price-set-money-amount"
export * from "./price-set-rule-type"
export * from "./price-set"
export * from "./pricing"
export * from "./rule-type"
export * from "./rule-type"
@@ -1,14 +1,8 @@
import {
BaseFilterable,
CreateCurrencyDTO,
CurrencyDTO,
PriceSetMoneyAmountDTO,
} from "@medusajs/types"
import { BaseFilterable, PriceSetMoneyAmountDTO } from "@medusajs/types"
export interface CreateMoneyAmountDTO {
id?: string
currency_code: string
currency?: CreateCurrencyDTO
amount: number
min_quantity?: number | null
max_quantity?: number | null
@@ -25,7 +19,6 @@ export interface UpdateMoneyAmountDTO {
export interface MoneyAmountDTO {
id: string
currency_code?: string
currency?: CurrencyDTO
amount?: number
min_quantity?: number
max_quantity?: number
@@ -26,12 +26,9 @@ describe("Region Module Service", () => {
await shutdownFunc()
})
it("should create countries and currencies on application start", async () => {
it("should create countries on application start", async () => {
const countries = await service.listCountries()
const currencies = await service.listCurrencies()
expect(countries.length).toBeGreaterThan(0)
expect(currencies.length).toBeGreaterThan(0)
})
it("should create countries added to default ones", async () => {
@@ -47,7 +44,7 @@ describe("Region Module Service", () => {
numeric: "420",
})
await service.createDefaultCountriesAndCurrencies()
await service.createDefaultCountries()
const [, newCount] = await service.listAndCountCountries()
expect(newCount).toEqual(initialCountries + 1)
@@ -69,7 +66,7 @@ describe("Region Module Service", () => {
)
const region = await service.retrieve(createdRegion.id, {
relations: ["currency", "countries"],
relations: ["countries"],
})
expect(region).toEqual(
@@ -77,10 +74,6 @@ describe("Region Module Service", () => {
id: region.id,
name: "Europe",
currency_code: "eur",
currency: expect.objectContaining({
code: "eur",
name: "Euro",
}),
countries: [],
})
)
@@ -94,7 +87,7 @@ describe("Region Module Service", () => {
})
const region = await service.retrieve(createdRegion.id, {
relations: ["countries", "currency"],
relations: ["countries"],
})
expect(region).toEqual(
@@ -102,10 +95,6 @@ describe("Region Module Service", () => {
id: region.id,
name: "North America",
currency_code: "usd",
currency: expect.objectContaining({
code: "usd",
name: "US Dollar",
}),
countries: [
expect.objectContaining({
display_name: "Canada",
@@ -182,7 +171,7 @@ describe("Region Module Service", () => {
})
const latestRegion = await service.retrieve(createdRegion.id, {
relations: ["currency", "countries"],
relations: ["countries"],
})
expect(latestRegion).toMatchObject({
@@ -243,7 +232,7 @@ describe("Region Module Service", () => {
})
const latestRegion = await service.retrieve(createdRegion.id, {
relations: ["currency", "countries"],
relations: ["countries"],
})
expect(latestRegion).toMatchObject({
@@ -268,7 +257,7 @@ describe("Region Module Service", () => {
})
const updatedRegion = await service.retrieve(createdRegion.id, {
relations: ["currency", "countries"],
relations: ["countries"],
})
expect(updatedRegion).toMatchObject({
@@ -294,7 +283,7 @@ describe("Region Module Service", () => {
})
const updatedRegion = await service.retrieve(createdRegion.id, {
relations: ["currency", "countries"],
relations: ["countries"],
})
expect(updatedRegion).toMatchObject({
@@ -306,23 +295,6 @@ describe("Region Module Service", () => {
expect(updatedRegion.countries).toHaveLength(0)
})
it("should fail updating the region currency to a non-existent one", async () => {
const createdRegion = await service.create({
name: "North America",
currency_code: "USD",
countries: ["us", "ca"],
})
await expect(
service.update(
{ id: createdRegion.id },
{
currency_code: "DOGECOIN",
}
)
).rejects.toThrowError('Currencies with codes: "dogecoin" were not found')
})
it("should fail updating the region countries to non-existent ones", async () => {
const createdRegion = await service.create({
name: "North America",
@@ -384,13 +356,4 @@ describe("Region Module Service", () => {
'Countries with codes: "mx" are already assigned to a region'
)
})
it("should fail when currency does not exist", async () => {
await expect(
service.create({
name: "Europe",
currency_code: "DOGECOIN",
})
).rejects.toThrowError('Currencies with codes: "dogecoin" were not found')
})
})
+1 -6
View File
@@ -1,11 +1,10 @@
import { Modules } from "@medusajs/modules-sdk"
import { ModuleJoinerConfig } from "@medusajs/types"
import { MapToConfig } from "@medusajs/utils"
import { Country, Currency, Region } from "@models"
import { Country, Region } from "@models"
export const LinkableKeys = {
region_id: Region.name,
currency_code: Country.name,
country_id: Region.name,
}
@@ -29,10 +28,6 @@ export const joinerConfig: ModuleJoinerConfig = {
name: ["region", "regions"],
args: { entity: Region.name },
},
{
name: ["currency", "currencies"],
args: { entity: Currency.name },
},
{
name: ["country", "countries"],
args: { entity: Country.name },
+1 -1
View File
@@ -8,6 +8,6 @@ export default async ({ container }: LoaderOptions): Promise<void> => {
// TODO: Remove when legacy modules have been migrated
if (!!process.env.MEDUSA_FF_MEDUSA_V2) {
await service.createDefaultCountriesAndCurrencies()
await service.createDefaultCountries()
}
}
@@ -1,64 +1,7 @@
{
"namespaces": [
"public"
],
"namespaces": ["public"],
"name": "public",
"tables": [
{
"columns": {
"code": {
"name": "code",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "text"
},
"symbol": {
"name": "symbol",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "text"
},
"symbol_native": {
"name": "symbol_native",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "text"
},
"name": {
"name": "name",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "text"
}
},
"name": "region_currency",
"schema": "public",
"indexes": [
{
"keyName": "region_currency_pkey",
"columnNames": [
"code"
],
"composite": false,
"primary": true,
"unique": true
}
],
"checks": [],
"foreignKeys": {}
},
{
"columns": {
"id": {
@@ -134,18 +77,7 @@
"schema": "public",
"indexes": [
{
"columnNames": [
"currency_code"
],
"composite": false,
"keyName": "IDX_region_currency_code",
"primary": false,
"unique": false
},
{
"columnNames": [
"deleted_at"
],
"columnNames": ["deleted_at"],
"composite": false,
"keyName": "IDX_region_deleted_at",
"primary": false,
@@ -153,30 +85,14 @@
},
{
"keyName": "region_pkey",
"columnNames": [
"id"
],
"columnNames": ["id"],
"composite": false,
"primary": true,
"unique": true
}
],
"checks": [],
"foreignKeys": {
"region_currency_code_foreign": {
"constraintName": "region_currency_code_foreign",
"columnNames": [
"currency_code"
],
"localTableName": "public.region",
"referencedColumnNames": [
"code"
],
"referencedTableName": "public.region_currency",
"deleteRule": "set null",
"updateRule": "cascade"
}
}
"foreignKeys": {}
},
{
"columns": {
@@ -249,9 +165,7 @@
"indexes": [
{
"keyName": "region_country_pkey",
"columnNames": [
"id"
],
"columnNames": ["id"],
"composite": false,
"primary": true,
"unique": true
@@ -261,13 +175,9 @@
"foreignKeys": {
"region_country_region_id_foreign": {
"constraintName": "region_country_region_id_foreign",
"columnNames": [
"region_id"
],
"columnNames": ["region_id"],
"localTableName": "public.region_country",
"referencedColumnNames": [
"id"
],
"referencedColumnNames": ["id"],
"referencedTableName": "public.region",
"deleteRule": "set null",
"updateRule": "cascade"
@@ -16,15 +16,6 @@ CREATE TABLE IF NOT EXISTS "region" (
CONSTRAINT "region_pkey" PRIMARY KEY ("id")
);
-- Create or update "region_currency" table
CREATE TABLE IF NOT EXISTS "region_currency" (
"code" text NOT NULL,
"symbol" text NOT NULL,
"symbol_native" text NOT NULL,
"name" text NOT NULL,
CONSTRAINT "region_currency_pkey" PRIMARY KEY ("code")
);
-- Adjust "region" table
ALTER TABLE "region" DROP CONSTRAINT IF EXISTS "FK_3bdd5896ec93be2f1c62a3309a5";
ALTER TABLE "region" DROP CONSTRAINT IF EXISTS "FK_91f88052197680f9790272aaf5b";
@@ -35,9 +26,6 @@ ${generatePostgresAlterColummnIfExistStatement(
"DROP NOT NULL"
)}
ALTER TABLE "region" ADD CONSTRAINT "region_currency_code_foreign" FOREIGN KEY ("currency_code") REFERENCES "region_currency" ("code") ON UPDATE CASCADE;
CREATE INDEX IF NOT EXISTS "IDX_region_currency_code" ON "region" ("currency_code");
CREATE INDEX IF NOT EXISTS "IDX_region_deleted_at" ON "region" ("deleted_at") WHERE "deleted_at" IS NOT NULL;
-- Create or update "region_country" table
-16
View File
@@ -1,16 +0,0 @@
import { Entity, PrimaryKey, Property } from "@mikro-orm/core"
@Entity({ tableName: "region_currency" })
export default class Currency {
@PrimaryKey({ columnType: "text" })
code: string
@Property({ columnType: "text" })
symbol: string
@Property({ columnType: "text" })
symbol_native: string
@Property({ columnType: "text" })
name: string
}
-2
View File
@@ -1,4 +1,2 @@
export { default as Country } from "./country"
export { default as Currency } from "./currency"
export { default as Region } from "./region"
+1 -12
View File
@@ -14,12 +14,8 @@ import {
Property,
} from "@mikro-orm/core"
import Country from "./country"
import Currency from "./currency"
type RegionOptionalProps =
| "currency"
| "countries"
| DAL.SoftDeletableEntityDateColumns
type RegionOptionalProps = "countries" | DAL.SoftDeletableEntityDateColumns
@Entity({ tableName: "region" })
@Filter(DALUtils.mikroOrmSoftDeletableFilterOptions)
@@ -35,13 +31,6 @@ export default class Region {
@Property({ columnType: "text" })
currency_code: string
@ManyToOne({
entity: () => Currency,
index: "IDX_region_currency_code",
nullable: true,
})
currency?: Currency
@OneToMany(() => Country, (country) => country.region)
countries = new Collection<Country>(this)
+9 -95
View File
@@ -8,7 +8,6 @@ import {
ModuleJoinerConfig,
ModulesSdkTypes,
RegionCountryDTO,
RegionCurrencyDTO,
RegionDTO,
UpdateRegionDTO,
UpsertRegionDTO,
@@ -27,9 +26,9 @@ import {
getDuplicates,
} from "@medusajs/utils"
import { Country, Currency, Region } from "@models"
import { Country, Region } from "@models"
import { CreateCountryDTO, CreateCurrencyDTO, UpdateRegionInput } from "@types"
import { CreateCountryDTO, UpdateRegionInput } from "@types"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config"
const COUNTRIES_LIMIT = 1000
@@ -38,15 +37,13 @@ type InjectedDependencies = {
baseRepository: DAL.RepositoryService
regionService: ModulesSdkTypes.InternalModuleService<any>
countryService: ModulesSdkTypes.InternalModuleService<any>
currencyService: ModulesSdkTypes.InternalModuleService<any>
}
const generateMethodForModels = [Country, Currency]
const generateMethodForModels = [Country]
export default class RegionModuleService<
TRegion extends Region = Region,
TCountry extends Country = Country,
TCurrency extends Currency = Currency
TCountry extends Country = Country
>
extends ModulesSdkUtils.abstractModuleServiceFactory<
InjectedDependencies,
@@ -55,9 +52,6 @@ export default class RegionModuleService<
Country: {
dto: RegionCountryDTO
}
Currency: {
dto: RegionCurrencyDTO
}
}
>(Region, generateMethodForModels, entityNameToLinkableKeysMap)
implements IRegionModuleService
@@ -65,15 +59,9 @@ export default class RegionModuleService<
protected baseRepository_: DAL.RepositoryService
protected readonly regionService_: ModulesSdkTypes.InternalModuleService<TRegion>
protected readonly countryService_: ModulesSdkTypes.InternalModuleService<TCountry>
protected readonly currencyService_: ModulesSdkTypes.InternalModuleService<TCurrency>
constructor(
{
baseRepository,
regionService,
countryService,
currencyService,
}: InjectedDependencies,
{ baseRepository, regionService, countryService }: InjectedDependencies,
protected readonly moduleDeclaration: InternalModuleDeclaration
) {
// @ts-ignore
@@ -81,7 +69,6 @@ export default class RegionModuleService<
this.baseRepository_ = baseRepository
this.regionService_ = regionService
this.countryService_ = countryService
this.currencyService_ = currencyService
}
__joinerConfig(): ModuleJoinerConfig {
@@ -118,10 +105,6 @@ export default class RegionModuleService<
let normalizedInput = RegionModuleService.normalizeInput(data)
const validations = [
this.validateCurrencies(
normalizedInput.map((r) => r.currency_code),
sharedContext
),
this.validateCountries(
normalizedInput.map((r) => r.countries ?? []).flat(),
sharedContext
@@ -129,7 +112,7 @@ export default class RegionModuleService<
] as const
// Assign the full country object so the ORM updates the relationship
const [, dbCountries] = await promiseAll(validations)
const [dbCountries] = await promiseAll(validations)
const dbCountriesMap = new Map(dbCountries.map((d) => [d.iso_2, d]))
let normalizedDbRegions = normalizedInput.map((region) =>
removeUndefined({
@@ -246,10 +229,6 @@ export default class RegionModuleService<
}
const validations = [
this.validateCurrencies(
normalizedInput.map((d) => d.currency_code),
sharedContext
),
this.validateCountries(
normalizedInput.map((d) => d.countries ?? []).flat(),
sharedContext
@@ -257,7 +236,7 @@ export default class RegionModuleService<
] as const
// Assign the full country object so the ORM updates the relationship
const [, dbCountries] = await promiseAll(validations)
const [dbCountries] = await promiseAll(validations)
const dbCountriesMap = new Map(dbCountries.map((d) => [d.iso_2, d]))
let normalizedDbRegions = normalizedInput.map((region) =>
removeUndefined({
@@ -280,41 +259,6 @@ export default class RegionModuleService<
)
}
private async validateCurrencies(
currencyCodes: (string | undefined)[] | undefined,
sharedContext: Context
): Promise<void> {
const normalizedCurrencyCodes = currencyCodes
?.filter((c) => c !== undefined)
.map((c) => c!.toLowerCase())
if (!normalizedCurrencyCodes?.length) {
return
}
const uniqueCurrencyCodes = Array.from(new Set(normalizedCurrencyCodes))
const dbCurrencies = await this.currencyService_.list(
{ code: uniqueCurrencyCodes },
{},
sharedContext
)
const dbCurrencyCodes = dbCurrencies.map((c) => c.code.toLowerCase())
if (uniqueCurrencyCodes.length !== dbCurrencyCodes.length) {
const missingCurrencies = arrayDifference(
uniqueCurrencyCodes,
dbCurrencyCodes
)
throw new MedusaError(
MedusaError.Types.INVALID_DATA,
`Currencies with codes: "${missingCurrencies.join(
", "
)}" were not found`
)
}
}
private async validateCountries(
countries: string[] | undefined,
sharedContext: Context
@@ -369,13 +313,10 @@ export default class RegionModuleService<
}
@InjectManager("baseRepository_")
public async createDefaultCountriesAndCurrencies(
public async createDefaultCountries(
@MedusaContext() sharedContext: Context = {}
): Promise<void> {
await promiseAll([
await this.maybeCreateCountries(sharedContext),
await this.maybeCreateCurrencies(sharedContext),
])
await this.maybeCreateCountries(sharedContext)
}
@InjectTransactionManager("baseRepository_")
@@ -409,31 +350,4 @@ export default class RegionModuleService<
await this.countryService_.create(countsToCreate, sharedContext)
}
}
@InjectTransactionManager("baseRepository_")
private async maybeCreateCurrencies(
@MedusaContext() sharedContext: Context
): Promise<void> {
const [currency] = await this.currencyService_.list(
{},
{ select: ["code"], take: 1 },
sharedContext
)
let currsToCreate: CreateCurrencyDTO[] = []
if (!currency) {
currsToCreate = Object.entries(DefaultsUtils.defaultCurrencies).map(
([code, currency]) => ({
code: code.toLowerCase(),
symbol: currency.symbol,
symbol_native: currency.symbol_native,
name: currency.name,
})
)
}
if (currsToCreate.length) {
await this.currencyService_.create(currsToCreate, sharedContext)
}
}
}
-7
View File
@@ -10,13 +10,6 @@ export type UpdateCountryRegion = {
region_id: string
}
export type CreateCurrencyDTO = {
code: string
symbol: string
name: string
symbol_native: string
}
export type CreateCountryDTO = {
iso_2: string
iso_3: string
+1
View File
@@ -24,3 +24,4 @@ export * as UserTypes from "./user"
export * as WorkflowTypes from "./workflow"
export * as ApiKeyTypes from "./api-key"
export * as StoreTypes from "./store"
export * as CurrencyTypes from "./currency"
@@ -0,0 +1,38 @@
import { BaseFilterable } from "../../dal"
/**
* @interface
*
* A currency's data.
*/
export interface CurrencyDTO {
/**
* The ISO 3 code of the currency.
*/
code: string
/**
* The symbol of the currency.
*/
symbol: string
/**
* The symbol of the currecy in its native form. This is typically the symbol used when displaying a price.
*/
symbol_native: string
/**
* The name of the currency.
*/
name: string
}
/**
* @interface
*
* Filters to apply on a currency.
*/
export interface FilterableCurrencyProps
extends BaseFilterable<FilterableCurrencyProps> {
/**
* The codes to filter the currencies by.
*/
code?: string[]
}
@@ -0,0 +1 @@
export * from "./currency"
+2
View File
@@ -0,0 +1,2 @@
export * from "./common"
export * from "./service"
+238
View File
@@ -0,0 +1,238 @@
import { FindConfig } from "../common"
import { RestoreReturn, SoftDeleteReturn } from "../dal"
import { IModuleService } from "../modules-sdk"
import { Context } from "../shared-context"
import { FilterableCurrencyProps, CurrencyDTO } from "./common"
/**
* The main service interface for the currency module.
*/
export interface ICurrencyModuleService extends IModuleService {
/**
* This method retrieves a currency by its code and and optionally based on the provided configurations.
*
* @param {string} code - The code of the currency to retrieve.
* @param {FindConfig<CurrencyDTO>} config -
* The configurations determining how the currency is retrieved. Its properties, such as `select` or `relations`, accept the
* attributes or relations associated with a currency.
* @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<CurrencyDTO>} The retrieved currency.
*
* @example
* A simple example that retrieves a currency by its code:
*
* ```ts
* import {
* initialize as initializeCurrencyModule,
* } from "@medusajs/currency"
*
* async function retrieveCurrency (code: string) {
* const currencyModule = await initializeCurrencyModule()
*
* const currency = await currencyModule.retrieve(
* code
* )
*
* // do something with the currency or return it
* }
* ```
*
* To specify attributes that should be retrieved:
*
* ```ts
* import {
* initialize as initializeCurrencyModule,
* } from "@medusajs/currency"
*
* async function retrieveCurrency (code: string) {
* const currencyModule = await initializeCurrencyModule()
*
* const currency = await currencyModule.retrieve(
* code,
* {
* select: ["symbol_native"]
* }
* )
*
* // do something with the currency or return it
* }
* ```
*/
retrieve(
code: string,
config?: FindConfig<CurrencyDTO>,
sharedContext?: Context
): Promise<CurrencyDTO>
/**
* This method is used to retrieve a paginated list of currencies based on optional filters and configuration.
*
* @param {FilterableCurrencyProps} filters - The filters to apply on the retrieved currencies.
* @param {FindConfig<CurrencyDTO>} config -
* The configurations determining how the currencies are retrieved. Its properties, such as `select` or `relations`, accept the
* attributes or relations associated with a currency.
* @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<CurrencyDTO[]>} The list of currencies.
*
* @example
*
* To retrieve a list of currencies using their codes:
*
* ```ts
* import {
* initialize as initializeCurrencyModule,
* } from "@medusajs/currency"
*
* async function retrieveCurrencies (codes: string[]) {
* const currencyModule = await initializeCurrencyModule()
*
* const currencies = await currencyModule.list(
* {
* code: codes
* },
* )
*
* // do something with the currencies or return them
* }
* ```
*
* To specify attributes that should be retrieved within the money amounts:
*
* ```ts
* import {
* initialize as initializeCurrencyModule,
* } from "@medusajs/currency"
*
* async function retrieveCurrencies (codes: string[]) {
* const currencyModule = await initializeCurrencyModule()
*
* const currencies = await currencyModule.list(
* {
* code: codes
* },
* {
* select: ["symbol_native"]
* }
* )
*
* // do something with the currencies or return them
* }
* ```
*
* By default, only the first `15` records are retrieved. You can control pagination by specifying the `skip` and `take` properties of the `config` parameter:
*
* ```ts
* import {
* initialize as initializeCurrencyModule,
* } from "@medusajs/currency"
*
* async function retrieveCurrencies (codes: string[], skip: number, take: number) {
* const currencyModule = await initializeCurrencyModule()
*
* const currencies = await currencyModule.list(
* {
* code: codes
* },
* {
* select: ["symbol_native"],
* skip,
* take
* }
* )
*
* // do something with the currencies or return them
* }
* ```
*/
list(
filters?: FilterableCurrencyProps,
config?: FindConfig<CurrencyDTO>,
sharedContext?: Context
): Promise<CurrencyDTO[]>
/**
* This method is used to retrieve a paginated list of currencies along with the total count of available currencies satisfying the provided filters.
*
* @param {FilterableCurrencyProps} filters - The filters to apply on the retrieved currencies.
* @param {FindConfig<CurrencyDTO>} config -
* The configurations determining how the currencies are retrieved. Its properties, such as `select` or `relations`, accept the
* attributes or relations associated with a currency.
* @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<[CurrencyDTO[], number]>} The list of currencies along with the total count.
*
* @example
*
* To retrieve a list of currencies using their codes:
*
* ```ts
* import {
* initialize as initializeCurrencyModule,
* } from "@medusajs/currency"
*
* async function retrieveCurrencies (codes: string[]) {
* const currencyModule = await initializeCurrencyModule()
*
* const [currencies, count] = await currencyModule.listAndCount(
* {
* code: codes
* },
* )
*
* // do something with the currencies or return them
* }
* ```
*
* To specify attributes that should be retrieved within the money amounts:
*
* ```ts
* import {
* initialize as initializeCurrencyModule,
* } from "@medusajs/currency"
*
* async function retrieveCurrencies (codes: string[]) {
* const currencyModule = await initializeCurrencyModule()
*
* const [currencies, count] = await currencyModule.listAndCount(
* {
* code: codes
* },
* {
* select: ["symbol_native"]
* }
* )
*
* // do something with the currencies or return them
* }
* ```
*
* By default, only the first `15` records are retrieved. You can control pagination by specifying the `skip` and `take` properties of the `config` parameter:
*
* ```ts
* import {
* initialize as initializeCurrencyModule,
* } from "@medusajs/currency"
*
* async function retrieveCurrencies (codes: string[], skip: number, take: number) {
* const currencyModule = await initializeCurrencyModule()
*
* const [currencies, count] = await currencyModule.listAndCount(
* {
* code: codes
* },
* {
* select: ["symbol_native"],
* skip,
* take
* }
* )
*
* // do something with the currencies or return them
* }
* ```
*/
listAndCount(
filters?: FilterableCurrencyProps,
config?: FindConfig<CurrencyDTO>,
sharedContext?: Context
): Promise<[CurrencyDTO[], number]>
}
+1
View File
@@ -34,3 +34,4 @@ export * from "./totals"
export * from "./transaction-base"
export * from "./user"
export * from "./workflow"
export * from "./currency"
@@ -1,86 +0,0 @@
import { BaseFilterable } from "../../dal"
/**
* @interface
*
* A currency's data.
*/
export interface CurrencyDTO {
/**
* The code of the currency.
*/
code: string
/**
* The symbol of the currency.
*/
symbol?: string
/**
* The symbol of the currecy in its native form. This is typically the symbol used when displaying a price.
*/
symbol_native?: string
/**
* The name of the currency.
*/
name?: string
}
/**
* @interface
*
* A currency to create.
*/
export interface CreateCurrencyDTO {
/**
* The code of the currency.
*/
code: string
/**
* The symbol of the currency.
*/
symbol: string
/**
* The symbol of the currecy in its native form. This is typically the symbol used when displaying a price.
*/
symbol_native: string
/**
* The name of the currency.
*/
name: string
}
/**
* @interface
*
* The data to update in a currency. The `code` is used to identify which currency to update.
*/
export interface UpdateCurrencyDTO {
/**
* The code of the currency to update.
*/
code: string
/**
* The symbol of the currency.
*/
symbol?: string
/**
* The symbol of the currecy in its native form. This is typically the symbol used when displaying a price.
*/
symbol_native?: string
/**
* The name of the currency.
*/
name?: string
}
/**
* @interface
*
* Filters to apply on a currency.
*/
export interface FilterableCurrencyProps
extends BaseFilterable<FilterableCurrencyProps> {
/**
* The codes to filter the currencies by.
*/
code?: string[]
}
@@ -1,4 +1,3 @@
export * from "./currency"
export * from "./money-amount"
export * from "./price-rule"
export * from "./price-set"
@@ -1,6 +1,5 @@
import { BaseFilterable } from "../../dal";
import { CreateCurrencyDTO, CurrencyDTO } from "./currency";
import { PriceSetMoneyAmountDTO } from "./price-set-money-amount";
import { BaseFilterable } from "../../dal"
import { PriceSetMoneyAmountDTO } from "./price-set-money-amount"
/**
* @interface
@@ -16,12 +15,6 @@ export interface MoneyAmountDTO {
* The currency code of this money amount.
*/
currency_code?: string
/**
* The money amount's currency.
*
* @expandable
*/
currency?: CurrencyDTO
/**
* The price of this money amount.
*/
@@ -66,10 +59,6 @@ export interface CreateMoneyAmountDTO {
* The currency code of this money amount.
*/
currency_code: string
/**
* The currency of this money amount.
*/
currency?: CreateCurrencyDTO
/**
* The amount of this money amount.
*/
@@ -1,6 +1,5 @@
import { BaseFilterable } from "../../dal"
import { PriceSetDTO } from "./price-set"
import { PriceSetMoneyAmountDTO } from "./price-set-money-amount"
import { RuleTypeDTO } from "./rule-type"
export interface PriceSetRuleTypeDTO {
+7 -325
View File
@@ -3,7 +3,6 @@ import {
AddPricesDTO,
AddRulesDTO,
CalculatedPriceSet,
CreateCurrencyDTO,
CreateMoneyAmountDTO,
CreatePriceListDTO,
CreatePriceListRuleDTO,
@@ -11,8 +10,6 @@ import {
CreatePriceSetDTO,
CreatePriceSetMoneyAmountRulesDTO,
CreateRuleTypeDTO,
CurrencyDTO,
FilterableCurrencyProps,
FilterableMoneyAmountProps,
FilterablePriceListProps,
FilterablePriceListRuleProps,
@@ -34,7 +31,6 @@ import {
RemovePriceSetRulesDTO,
RuleTypeDTO,
SetPriceListRulesDTO,
UpdateCurrencyDTO,
UpdateMoneyAmountDTO,
UpdatePriceListDTO,
UpdatePriceListRuleDTO,
@@ -935,7 +931,7 @@ export interface IPricingModuleService extends IModuleService {
* const moneyAmount = await pricingService.retrieveMoneyAmount(
* moneyAmountId,
* {
* relations: ["currency"]
* relations: ["price_set_money_amount"]
* }
* )
*
@@ -996,7 +992,7 @@ export interface IPricingModuleService extends IModuleService {
* id: moneyAmountIds
* },
* {
* relations: ["currency"]
* relations: ["price_set_money_amount"]
* }
* )
*
@@ -1019,7 +1015,7 @@ export interface IPricingModuleService extends IModuleService {
* id: moneyAmountIds
* },
* {
* relations: ["currency"],
* relations: ["price_set_money_amount"],
* skip,
* take
* }
@@ -1051,7 +1047,7 @@ export interface IPricingModuleService extends IModuleService {
* ]
* },
* {
* relations: ["currency"],
* relations: ["price_set_money_amount"],
* skip,
* take
* }
@@ -1114,7 +1110,7 @@ export interface IPricingModuleService extends IModuleService {
* id: moneyAmountIds
* },
* {
* relations: ["currency"]
* relations: ["price_set_money_amount"]
* }
* )
*
@@ -1137,7 +1133,7 @@ export interface IPricingModuleService extends IModuleService {
* id: moneyAmountIds
* },
* {
* relations: ["currency"],
* relations: ["price_set_money_amount"],
* skip,
* take
* }
@@ -1169,7 +1165,7 @@ export interface IPricingModuleService extends IModuleService {
* ]
* },
* {
* relations: ["currency"],
* relations: ["price_set_money_amount"],
* skip,
* take
* }
@@ -1333,320 +1329,6 @@ export interface IPricingModuleService extends IModuleService {
sharedContext?: Context
): Promise<Record<string, string[]> | void>
/**
* This method retrieves a currency by its code and and optionally based on the provided configurations.
*
* @param {string} code - The code of the currency to retrieve.
* @param {FindConfig<CurrencyDTO>} config -
* The configurations determining how the currency is retrieved. Its properties, such as `select` or `relations`, accept the
* attributes or relations associated with a currency.
* @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<CurrencyDTO>} The retrieved currency.
*
* @example
* A simple example that retrieves a currency by its code:
*
* ```ts
* import {
* initialize as initializePricingModule,
* } from "@medusajs/pricing"
*
* async function retrieveCurrency (code: string) {
* const pricingService = await initializePricingModule()
*
* const currency = await pricingService.retrieveCurrency(
* code
* )
*
* // do something with the currency or return it
* }
* ```
*
* To specify attributes that should be retrieved:
*
* ```ts
* import {
* initialize as initializePricingModule,
* } from "@medusajs/pricing"
*
* async function retrieveCurrency (code: string) {
* const pricingService = await initializePricingModule()
*
* const currency = await pricingService.retrieveCurrency(
* code,
* {
* select: ["symbol_native"]
* }
* )
*
* // do something with the currency or return it
* }
* ```
*/
retrieveCurrency(
code: string,
config?: FindConfig<CurrencyDTO>,
sharedContext?: Context
): Promise<CurrencyDTO>
/**
* This method is used to retrieve a paginated list of currencies based on optional filters and configuration.
*
* @param {FilterableCurrencyProps} filters - The filters to apply on the retrieved currencies.
* @param {FindConfig<CurrencyDTO>} config -
* The configurations determining how the currencies are retrieved. Its properties, such as `select` or `relations`, accept the
* attributes or relations associated with a currency.
* @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<CurrencyDTO[]>} The list of currencies.
*
* @example
*
* To retrieve a list of currencies using their codes:
*
* ```ts
* import {
* initialize as initializePricingModule,
* } from "@medusajs/pricing"
*
* async function retrieveCurrencies (codes: string[]) {
* const pricingService = await initializePricingModule()
*
* const currencies = await pricingService.listCurrencies(
* {
* code: codes
* },
* )
*
* // do something with the currencies or return them
* }
* ```
*
* To specify attributes that should be retrieved within the money amounts:
*
* ```ts
* import {
* initialize as initializePricingModule,
* } from "@medusajs/pricing"
*
* async function retrieveCurrencies (codes: string[]) {
* const pricingService = await initializePricingModule()
*
* const currencies = await pricingService.listCurrencies(
* {
* code: codes
* },
* {
* select: ["symbol_native"]
* }
* )
*
* // do something with the currencies or return them
* }
* ```
*
* By default, only the first `15` records are retrieved. You can control pagination by specifying the `skip` and `take` properties of the `config` parameter:
*
* ```ts
* import {
* initialize as initializePricingModule,
* } from "@medusajs/pricing"
*
* async function retrieveCurrencies (codes: string[], skip: number, take: number) {
* const pricingService = await initializePricingModule()
*
* const currencies = await pricingService.listCurrencies(
* {
* code: codes
* },
* {
* select: ["symbol_native"],
* skip,
* take
* }
* )
*
* // do something with the currencies or return them
* }
* ```
*/
listCurrencies(
filters?: FilterableCurrencyProps,
config?: FindConfig<CurrencyDTO>,
sharedContext?: Context
): Promise<CurrencyDTO[]>
/**
* This method is used to retrieve a paginated list of currencies along with the total count of available currencies satisfying the provided filters.
*
* @param {FilterableCurrencyProps} filters - The filters to apply on the retrieved currencies.
* @param {FindConfig<CurrencyDTO>} config -
* The configurations determining how the currencies are retrieved. Its properties, such as `select` or `relations`, accept the
* attributes or relations associated with a currency.
* @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<[CurrencyDTO[], number]>} The list of currencies along with the total count.
*
* @example
*
* To retrieve a list of currencies using their codes:
*
* ```ts
* import {
* initialize as initializePricingModule,
* } from "@medusajs/pricing"
*
* async function retrieveCurrencies (codes: string[]) {
* const pricingService = await initializePricingModule()
*
* const [currencies, count] = await pricingService.listAndCountCurrencies(
* {
* code: codes
* },
* )
*
* // do something with the currencies or return them
* }
* ```
*
* To specify attributes that should be retrieved within the money amounts:
*
* ```ts
* import {
* initialize as initializePricingModule,
* } from "@medusajs/pricing"
*
* async function retrieveCurrencies (codes: string[]) {
* const pricingService = await initializePricingModule()
*
* const [currencies, count] = await pricingService.listAndCountCurrencies(
* {
* code: codes
* },
* {
* select: ["symbol_native"]
* }
* )
*
* // do something with the currencies or return them
* }
* ```
*
* By default, only the first `15` records are retrieved. You can control pagination by specifying the `skip` and `take` properties of the `config` parameter:
*
* ```ts
* import {
* initialize as initializePricingModule,
* } from "@medusajs/pricing"
*
* async function retrieveCurrencies (codes: string[], skip: number, take: number) {
* const pricingService = await initializePricingModule()
*
* const [currencies, count] = await pricingService.listAndCountCurrencies(
* {
* code: codes
* },
* {
* select: ["symbol_native"],
* skip,
* take
* }
* )
*
* // do something with the currencies or return them
* }
* ```
*/
listAndCountCurrencies(
filters?: FilterableCurrencyProps,
config?: FindConfig<CurrencyDTO>,
sharedContext?: Context
): Promise<[CurrencyDTO[], number]>
/**
* This method is used to create new currencies.
*
* @param {CreateCurrencyDTO[]} data - The currencies to create.
* @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<CurrencyDTO[]>} The list of created currencies.
*
* @example
* import {
* initialize as initializePricingModule,
* } from "@medusajs/pricing"
*
* async function createCurrencies () {
* const pricingService = await initializePricingModule()
*
* const currencies = await pricingService.createCurrencies([
* {
* code: "USD",
* symbol: "$",
* symbol_native: "$",
* name: "US Dollar",
* }
* ])
*
* // do something with the currencies or return them
* }
*/
createCurrencies(
data: CreateCurrencyDTO[],
sharedContext?: Context
): Promise<CurrencyDTO[]>
/**
* This method is used to update existing currencies with the provided data. In each currency object, the currency code must be provided to identify which currency to update.
*
* @param {UpdateCurrencyDTO[]} data - The currencies to update, each having the attributes that should be updated in a currency.
* @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<CurrencyDTO[]>} The list of updated currencies.
*
* @example
* import {
* initialize as initializePricingModule,
* } from "@medusajs/pricing"
*
* async function updateCurrencies () {
* const pricingService = await initializePricingModule()
*
* const currencies = await pricingService.updateCurrencies([
* {
* code: "USD",
* symbol: "$",
* }
* ])
*
* // do something with the currencies or return them
* }
*/
updateCurrencies(
data: UpdateCurrencyDTO[],
sharedContext?: Context
): Promise<CurrencyDTO[]>
/**
* This method is used to delete currencies based on their currency code.
*
* @param {string[]} currencyCodes - Currency codes of the currencies to delete.
* @param {Context} sharedContext - A context used to share resources, such as transaction manager, between the application and the module.
* @returns {Promise<void>} Resolves once the currencies are deleted.
*
* @example
* import {
* initialize as initializePricingModule,
* } from "@medusajs/pricing"
*
* async function deleteCurrencies () {
* const pricingService = await initializePricingModule()
*
* await pricingService.deleteCurrencies(["USD"])
*
* }
*/
deleteCurrencies(
currencyCodes: string[],
sharedContext?: Context
): Promise<void>
/**
* This method is used to retrieve a rule type by its ID and and optionally based on the provided configurations.
*
+2 -98
View File
@@ -19,15 +19,10 @@ export interface RegionDTO {
*/
currency_code: string
/**
* The associated region currency.
*/
currency: RegionCurrencyDTO
/**
* The countries of the region.
*/
countries: CountryDTO[]
countries: RegionCountryDTO[]
metadata?: Record<string, any>
created_at: string
updated_at: string
@@ -36,7 +31,7 @@ export interface RegionDTO {
/**
* The country details.
*/
export interface CountryDTO {
export interface RegionCountryDTO {
/**
* The ID of the country.
*/
@@ -99,97 +94,6 @@ export interface FilterableRegionProps
updated_at?: OperatorMap<string>
}
/**
* The details of a region's country.
*/
export interface RegionCountryDTO {
/**
* The ID of the country.
*/
id: string
/**
* The ISO 2 code of the country.
*/
iso_2: string
/**
* The ISO 3 code of the country.
*/
iso_3: string
/**
* The code number of the country.
*/
num_code: number
/**
* The name of the country.
*/
name: string
/**
* The display name of the country.
*/
display_name: string
}
/**
* The details of a region's currency
*/
export interface RegionCurrencyDTO {
/**
* The code of the currency.
*/
code: string
/**
* The symbol of the currency.
*/
symbol: string
/**
* The name of the currency.
*/
name: string
/**
* The symbol native of the currency.
*/
symbol_native: string
}
/**
* The filters to apply on the retrieved region's currencies.
*/
export interface FilterableRegionCurrencyProps
extends BaseFilterable<FilterableRegionCurrencyProps> {
/**
* The IDs to filter the currencies by.
*/
id?: string[] | string
/**
* Filter currencies by their code.
*/
code?: string[] | string
/**
* Filter currencies by their symbol.
*/
symbol?: string[] | string
/**
* Filter currencies by their name.
*/
name?: string[] | string
/**
* Filter currencies by their native symbol.
*/
symbol_native?: string[] | string
}
/**
* The filters to apply on the retrieved region's countries.
*/
-2
View File
@@ -1,5 +1,3 @@
import { RegionCurrencyDTO } from "./common"
/**
* The region to be created.
*/

Some files were not shown because too many files have changed in this diff Show More