feat(pricing, types): PriceSets as entry point to pricing module (#4978)
What: - Adds PriceSet, PriceSetMoneyAmount, updates schema - Adds service/repo for PriceSet - Shifts entry point to use PriceSet - Updates link/joiner config RESOLVES CORE-1495
This commit is contained in:
@@ -1,16 +1,22 @@
|
||||
import { Modules } from "@medusajs/modules-sdk"
|
||||
import { ModuleJoinerConfig } from "@medusajs/types"
|
||||
import { MapToConfig } from "@medusajs/utils"
|
||||
import { Currency, MoneyAmount } from "@models"
|
||||
import * as Models from "@models"
|
||||
|
||||
export enum LinkableKeys {
|
||||
MONEY_AMOUNT_ID = "money_amount_id",
|
||||
CURRENCY_CODE = "currency_code",
|
||||
PRICE_SET_ID = "price_set_id",
|
||||
}
|
||||
|
||||
export const entityNameToLinkableKeysMap: MapToConfig = {
|
||||
[Currency.name]: [{ mapTo: LinkableKeys.CURRENCY_CODE, valueFrom: "code" }],
|
||||
[MoneyAmount.name]: [
|
||||
[Models.PriceSet.name]: [
|
||||
{ mapTo: LinkableKeys.PRICE_SET_ID, valueFrom: "id" },
|
||||
],
|
||||
[Models.Currency.name]: [
|
||||
{ mapTo: LinkableKeys.CURRENCY_CODE, valueFrom: "code" },
|
||||
],
|
||||
[Models.MoneyAmount.name]: [
|
||||
{ mapTo: LinkableKeys.MONEY_AMOUNT_ID, valueFrom: "id" },
|
||||
],
|
||||
}
|
||||
@@ -20,11 +26,23 @@ export const joinerConfig: ModuleJoinerConfig = {
|
||||
primaryKeys: ["id", "currency_code"],
|
||||
linkableKeys: Object.values(LinkableKeys),
|
||||
alias: [
|
||||
{
|
||||
name: "price_set",
|
||||
},
|
||||
{
|
||||
name: "price_sets",
|
||||
},
|
||||
{
|
||||
name: "money_amount",
|
||||
args: {
|
||||
methodSuffix: "MoneyAmounts",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "money_amounts",
|
||||
args: {
|
||||
methodSuffix: "MoneyAmounts",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "currency",
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
import { ModulesSdkTypes } from "@medusajs/types"
|
||||
import * as defaultRepositories from "@repositories"
|
||||
import {
|
||||
BaseRepository,
|
||||
CurrencyRepository,
|
||||
MoneyAmountRepository,
|
||||
} from "@repositories"
|
||||
import { CurrencyService, MoneyAmountService } from "@services"
|
||||
import * as defaultServices from "@services"
|
||||
|
||||
import { LoaderOptions } from "@medusajs/modules-sdk"
|
||||
import { loadCustomRepositories } from "@medusajs/utils"
|
||||
@@ -23,8 +18,9 @@ export default async ({
|
||||
)?.repositories
|
||||
|
||||
container.register({
|
||||
currencyService: asClass(CurrencyService).singleton(),
|
||||
moneyAmountService: asClass(MoneyAmountService).singleton(),
|
||||
currencyService: asClass(defaultServices.CurrencyService).singleton(),
|
||||
moneyAmountService: asClass(defaultServices.MoneyAmountService).singleton(),
|
||||
priceSetService: asClass(defaultServices.PriceSetService).singleton(),
|
||||
})
|
||||
|
||||
if (customRepositories) {
|
||||
@@ -40,8 +36,15 @@ export default async ({
|
||||
|
||||
function loadDefaultRepositories({ container }) {
|
||||
container.register({
|
||||
baseRepository: asClass(BaseRepository).singleton(),
|
||||
currencyRepository: asClass(CurrencyRepository).singleton(),
|
||||
moneyAmountRepository: asClass(MoneyAmountRepository).singleton(),
|
||||
baseRepository: asClass(defaultRepositories.BaseRepository).singleton(),
|
||||
currencyRepository: asClass(
|
||||
defaultRepositories.CurrencyRepository
|
||||
).singleton(),
|
||||
moneyAmountRepository: asClass(
|
||||
defaultRepositories.MoneyAmountRepository
|
||||
).singleton(),
|
||||
priceSetRepository: asClass(
|
||||
defaultRepositories.PriceSetRepository
|
||||
).singleton(),
|
||||
})
|
||||
}
|
||||
|
||||
260
packages/pricing/src/migrations/.snapshot-medusa-pricing.json
Normal file
260
packages/pricing/src/migrations/.snapshot-medusa-pricing.json
Normal file
@@ -0,0 +1,260 @@
|
||||
{
|
||||
"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": {}
|
||||
},
|
||||
{
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"currency_code": {
|
||||
"name": "currency_code",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"amount": {
|
||||
"name": "amount",
|
||||
"type": "numeric",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"mappedType": "decimal"
|
||||
},
|
||||
"min_quantity": {
|
||||
"name": "min_quantity",
|
||||
"type": "numeric",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"mappedType": "decimal"
|
||||
},
|
||||
"max_quantity": {
|
||||
"name": "max_quantity",
|
||||
"type": "numeric",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"mappedType": "decimal"
|
||||
}
|
||||
},
|
||||
"name": "money_amount",
|
||||
"schema": "public",
|
||||
"indexes": [
|
||||
{
|
||||
"columnNames": [
|
||||
"currency_code"
|
||||
],
|
||||
"composite": false,
|
||||
"keyName": "IDX_money_amount_currency_code",
|
||||
"primary": false,
|
||||
"unique": false
|
||||
},
|
||||
{
|
||||
"keyName": "money_amount_pkey",
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"composite": false,
|
||||
"primary": true,
|
||||
"unique": true
|
||||
}
|
||||
],
|
||||
"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"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
}
|
||||
},
|
||||
"name": "price_set",
|
||||
"schema": "public",
|
||||
"indexes": [
|
||||
{
|
||||
"keyName": "price_set_pkey",
|
||||
"columnNames": [
|
||||
"id"
|
||||
],
|
||||
"composite": false,
|
||||
"primary": true,
|
||||
"unique": true
|
||||
}
|
||||
],
|
||||
"checks": [],
|
||||
"foreignKeys": {}
|
||||
},
|
||||
{
|
||||
"columns": {
|
||||
"id": {
|
||||
"name": "id",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"price_set_id": {
|
||||
"name": "price_set_id",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"money_amount_id": {
|
||||
"name": "money_amount_id",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": true,
|
||||
"mappedType": "text"
|
||||
},
|
||||
"title": {
|
||||
"name": "title",
|
||||
"type": "text",
|
||||
"unsigned": false,
|
||||
"autoincrement": false,
|
||||
"primary": false,
|
||||
"nullable": false,
|
||||
"mappedType": "text"
|
||||
}
|
||||
},
|
||||
"name": "price_set_money_amount",
|
||||
"schema": "public",
|
||||
"indexes": [
|
||||
{
|
||||
"keyName": "price_set_money_amount_pkey",
|
||||
"columnNames": [
|
||||
"id",
|
||||
"price_set_id",
|
||||
"money_amount_id"
|
||||
],
|
||||
"composite": true,
|
||||
"primary": true,
|
||||
"unique": true
|
||||
}
|
||||
],
|
||||
"checks": [],
|
||||
"foreignKeys": {
|
||||
"price_set_money_amount_price_set_id_foreign": {
|
||||
"constraintName": "price_set_money_amount_price_set_id_foreign",
|
||||
"columnNames": [
|
||||
"price_set_id"
|
||||
],
|
||||
"localTableName": "public.price_set_money_amount",
|
||||
"referencedColumnNames": [
|
||||
"id"
|
||||
],
|
||||
"referencedTableName": "public.price_set",
|
||||
"updateRule": "cascade"
|
||||
},
|
||||
"price_set_money_amount_money_amount_id_foreign": {
|
||||
"constraintName": "price_set_money_amount_money_amount_id_foreign",
|
||||
"columnNames": [
|
||||
"money_amount_id"
|
||||
],
|
||||
"localTableName": "public.price_set_money_amount",
|
||||
"referencedColumnNames": [
|
||||
"id"
|
||||
],
|
||||
"referencedTableName": "public.money_amount",
|
||||
"updateRule": "cascade"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
import { Migration } from '@mikro-orm/migrations';
|
||||
|
||||
export class Migration20230830085850 extends Migration {
|
||||
|
||||
async up(): Promise<void> {
|
||||
this.addSql('create table "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 "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"));');
|
||||
this.addSql('create index "IDX_money_amount_currency_code" on "money_amount" ("currency_code");');
|
||||
|
||||
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;');
|
||||
}
|
||||
|
||||
}
|
||||
36
packages/pricing/src/migrations/Migration20230907144224.ts
Normal file
36
packages/pricing/src/migrations/Migration20230907144224.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import { Migration } from "@mikro-orm/migrations"
|
||||
|
||||
export class Migration20230907144224 extends Migration {
|
||||
async up(): Promise<void> {
|
||||
this.addSql(
|
||||
'create table "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 "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"));'
|
||||
)
|
||||
this.addSql(
|
||||
'create index "IDX_money_amount_currency_code" on "money_amount" ("currency_code");'
|
||||
)
|
||||
|
||||
this.addSql(
|
||||
'create table "price_set" ("id" text not null, constraint "price_set_pkey" primary key ("id"));'
|
||||
)
|
||||
|
||||
this.addSql(
|
||||
'create table "price_set_money_amount" ("id" text not null, "price_set_id" text null, "money_amount_id" text null, "title" text not null, constraint "price_set_money_amount_pkey" primary key ("id", "price_set_id", "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;'
|
||||
)
|
||||
|
||||
this.addSql(
|
||||
'alter table "price_set_money_amount" add constraint "price_set_money_amount_money_amount_id_foreign" foreign key ("money_amount_id") references "money_amount" ("id") on update cascade;'
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,2 +1,4 @@
|
||||
export { default as Currency } from "./currency"
|
||||
export { default as MoneyAmount } from "./money-amount"
|
||||
export { default as PriceSet } from "./price-set"
|
||||
export { default as PriceSetMoneyAmount } from "./price-set-money-amount"
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
import { generateEntityId } from "@medusajs/utils"
|
||||
import {
|
||||
BeforeCreate,
|
||||
Collection,
|
||||
Entity,
|
||||
ManyToMany,
|
||||
ManyToOne,
|
||||
PrimaryKey,
|
||||
Property,
|
||||
} from "@mikro-orm/core"
|
||||
|
||||
import Currency from "./currency"
|
||||
import PriceSet from "./price-set"
|
||||
|
||||
@Entity()
|
||||
class MoneyAmount {
|
||||
@@ -17,6 +20,12 @@ class MoneyAmount {
|
||||
@Property({ columnType: "text", nullable: true })
|
||||
currency_code?: string
|
||||
|
||||
@ManyToMany({
|
||||
entity: () => PriceSet,
|
||||
mappedBy: (ps) => ps.money_amounts,
|
||||
})
|
||||
price_sets = new Collection<PriceSet>(this)
|
||||
|
||||
@ManyToOne(() => Currency, {
|
||||
nullable: true,
|
||||
index: "IDX_money_amount_currency_code",
|
||||
|
||||
39
packages/pricing/src/models/price-set-money-amount.ts
Normal file
39
packages/pricing/src/models/price-set-money-amount.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import { generateEntityId } from "@medusajs/utils"
|
||||
import {
|
||||
BeforeCreate,
|
||||
Entity,
|
||||
ManyToOne,
|
||||
PrimaryKey,
|
||||
PrimaryKeyType,
|
||||
Property,
|
||||
} from "@mikro-orm/core"
|
||||
|
||||
import MoneyAmount from "./money-amount"
|
||||
import PriceSet from "./price-set"
|
||||
|
||||
@Entity()
|
||||
export default class PriceSetMoneyAmount {
|
||||
@PrimaryKey({ columnType: "text" })
|
||||
id!: string
|
||||
|
||||
@Property({ columnType: "text" })
|
||||
title!: string
|
||||
|
||||
@ManyToOne(() => PriceSet, { onDelete: "cascade" })
|
||||
price_set?: PriceSet
|
||||
|
||||
@ManyToOne(() => MoneyAmount, {})
|
||||
money_amount?: MoneyAmount
|
||||
|
||||
@BeforeCreate()
|
||||
onCreate() {
|
||||
this.id = generateEntityId(this.id, "psma")
|
||||
}
|
||||
|
||||
[PrimaryKeyType]?: [string, string]
|
||||
|
||||
constructor(money_amount: MoneyAmount, price_set: PriceSet) {
|
||||
this.money_amount = money_amount
|
||||
this.price_set = price_set
|
||||
}
|
||||
}
|
||||
28
packages/pricing/src/models/price-set.ts
Normal file
28
packages/pricing/src/models/price-set.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
import { generateEntityId } from "@medusajs/utils"
|
||||
import {
|
||||
BeforeCreate,
|
||||
Collection,
|
||||
Entity,
|
||||
ManyToMany,
|
||||
PrimaryKey,
|
||||
} from "@mikro-orm/core"
|
||||
|
||||
import MoneyAmount from "./money-amount"
|
||||
import PriceSetMoneyAmount from "./price-set-money-amount"
|
||||
|
||||
@Entity()
|
||||
export default class PriceSet {
|
||||
@PrimaryKey({ columnType: "text" })
|
||||
id!: string
|
||||
|
||||
@ManyToMany({
|
||||
entity: () => MoneyAmount,
|
||||
pivotEntity: () => PriceSetMoneyAmount,
|
||||
})
|
||||
money_amounts = new Collection<MoneyAmount>(this)
|
||||
|
||||
@BeforeCreate()
|
||||
onCreate() {
|
||||
this.id = generateEntityId(this.id, "pset")
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
export { MikroOrmBaseRepository as BaseRepository } from "@medusajs/utils"
|
||||
export { CurrencyRepository } from "./currency"
|
||||
export { MoneyAmountRepository } from "./money-amount"
|
||||
export { PriceSetRepository } from "./price-set"
|
||||
|
||||
127
packages/pricing/src/repositories/price-set.ts
Normal file
127
packages/pricing/src/repositories/price-set.ts
Normal file
@@ -0,0 +1,127 @@
|
||||
import {
|
||||
Context,
|
||||
CreatePriceSetDTO,
|
||||
DAL,
|
||||
UpdatePriceSetDTO,
|
||||
} from "@medusajs/types"
|
||||
import { DALUtils, MedusaError } from "@medusajs/utils"
|
||||
import {
|
||||
LoadStrategy,
|
||||
FilterQuery as MikroFilterQuery,
|
||||
FindOptions as MikroOptions,
|
||||
} from "@mikro-orm/core"
|
||||
import { SqlEntityManager } from "@mikro-orm/postgresql"
|
||||
import { PriceSet } from "@models"
|
||||
|
||||
export class PriceSetRepository extends DALUtils.MikroOrmBaseRepository {
|
||||
protected readonly manager_: SqlEntityManager
|
||||
|
||||
constructor({ manager }: { manager: SqlEntityManager }) {
|
||||
// @ts-ignore
|
||||
// eslint-disable-next-line prefer-rest-params
|
||||
super(...arguments)
|
||||
this.manager_ = manager
|
||||
}
|
||||
|
||||
async find(
|
||||
findOptions: DAL.FindOptions<PriceSet> = { where: {} },
|
||||
context: Context = {}
|
||||
): Promise<PriceSet[]> {
|
||||
const manager = this.getActiveManager<SqlEntityManager>(context)
|
||||
|
||||
const findOptions_ = { ...findOptions }
|
||||
findOptions_.options ??= {}
|
||||
|
||||
Object.assign(findOptions_.options, {
|
||||
strategy: LoadStrategy.SELECT_IN,
|
||||
})
|
||||
|
||||
return await manager.find(
|
||||
PriceSet,
|
||||
findOptions_.where as MikroFilterQuery<PriceSet>,
|
||||
findOptions_.options as MikroOptions<PriceSet>
|
||||
)
|
||||
}
|
||||
|
||||
async findAndCount(
|
||||
findOptions: DAL.FindOptions<PriceSet> = { where: {} },
|
||||
context: Context = {}
|
||||
): Promise<[PriceSet[], number]> {
|
||||
const manager = this.getActiveManager<SqlEntityManager>(context)
|
||||
|
||||
const findOptions_ = { ...findOptions }
|
||||
findOptions_.options ??= {}
|
||||
|
||||
Object.assign(findOptions_.options, {
|
||||
strategy: LoadStrategy.SELECT_IN,
|
||||
})
|
||||
|
||||
return await manager.findAndCount(
|
||||
PriceSet,
|
||||
findOptions_.where as MikroFilterQuery<PriceSet>,
|
||||
findOptions_.options as MikroOptions<PriceSet>
|
||||
)
|
||||
}
|
||||
|
||||
async delete(ids: string[], context: Context = {}): Promise<void> {
|
||||
const manager = this.getActiveManager<SqlEntityManager>(context)
|
||||
await manager.nativeDelete(PriceSet, { id: { $in: ids } }, {})
|
||||
}
|
||||
|
||||
async create(
|
||||
data: CreatePriceSetDTO[],
|
||||
context: Context = {}
|
||||
): Promise<PriceSet[]> {
|
||||
const manager = this.getActiveManager<SqlEntityManager>(context)
|
||||
|
||||
const priceSets = data.map((priceSetData) => {
|
||||
return manager.create(PriceSet, priceSetData)
|
||||
})
|
||||
|
||||
manager.persist(priceSets)
|
||||
|
||||
return priceSets
|
||||
}
|
||||
|
||||
async update(
|
||||
data: UpdatePriceSetDTO[],
|
||||
context: Context = {}
|
||||
): Promise<PriceSet[]> {
|
||||
const manager = this.getActiveManager<SqlEntityManager>(context)
|
||||
const priceSetIds = data.map((priceSetData) => priceSetData.id)
|
||||
const existingPriceSets = await this.find(
|
||||
{
|
||||
where: {
|
||||
id: {
|
||||
$in: priceSetIds,
|
||||
},
|
||||
},
|
||||
},
|
||||
context
|
||||
)
|
||||
|
||||
const existingPriceSetMap = new Map(
|
||||
existingPriceSets.map<[string, PriceSet]>((priceSet) => [
|
||||
priceSet.id,
|
||||
priceSet,
|
||||
])
|
||||
)
|
||||
|
||||
const priceSets = data.map((priceSetData) => {
|
||||
const existingPriceSet = existingPriceSetMap.get(priceSetData.id)
|
||||
|
||||
if (!existingPriceSet) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_FOUND,
|
||||
`PriceSet with id "${priceSetData.id}" not found`
|
||||
)
|
||||
}
|
||||
|
||||
return manager.assign(existingPriceSet, priceSetData)
|
||||
})
|
||||
|
||||
manager.persist(priceSets)
|
||||
|
||||
return priceSets
|
||||
}
|
||||
}
|
||||
@@ -22,11 +22,14 @@ export async function run({
|
||||
|
||||
logger.info(`Loading seed data from ${path}...`)
|
||||
|
||||
const { currenciesData, moneyAmountsData } = await import(
|
||||
resolve(process.cwd(), path)
|
||||
).catch((e) => {
|
||||
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: currenciesData, moneyAmountsData.${EOL}${e}`
|
||||
`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
|
||||
})
|
||||
@@ -44,10 +47,12 @@ export async function run({
|
||||
const manager = orm.em.fork()
|
||||
|
||||
try {
|
||||
logger.info("Inserting currencies & money_amounts")
|
||||
logger.info("Inserting price_sets, currencies & money_amounts")
|
||||
|
||||
await createCurrencies(manager, currenciesData)
|
||||
await createMoneyAmounts(manager, moneyAmountsData)
|
||||
await createPriceSets(manager, priceSetsData)
|
||||
await createPriceSetMoneyAmounts(manager, priceSetMoneyAmountsData)
|
||||
} catch (e) {
|
||||
logger.error(
|
||||
`Failed to insert the seed data in the PostgreSQL database ${dbData.clientUrl}.${EOL}${e}`
|
||||
@@ -82,3 +87,32 @@ async function createMoneyAmounts(
|
||||
|
||||
return moneyAmounts
|
||||
}
|
||||
|
||||
async function createPriceSets(
|
||||
manager: SqlEntityManager,
|
||||
data: RequiredEntityData<PricingModels.PriceSet>[]
|
||||
) {
|
||||
const priceSets = data.map((priceSetData) => {
|
||||
return manager.create(PricingModels.PriceSet, priceSetData)
|
||||
})
|
||||
|
||||
await manager.persistAndFlush(priceSets)
|
||||
|
||||
return priceSets
|
||||
}
|
||||
|
||||
async function createPriceSetMoneyAmounts(
|
||||
manager: SqlEntityManager,
|
||||
data: RequiredEntityData<PricingModels.PriceSetMoneyAmount>[]
|
||||
) {
|
||||
const priceSetMoneyAmounts = data.map((priceSetMoneyAmountData) => {
|
||||
return manager.create(
|
||||
PricingModels.PriceSetMoneyAmount,
|
||||
priceSetMoneyAmountData
|
||||
)
|
||||
})
|
||||
|
||||
await manager.persistAndFlush(priceSetMoneyAmounts)
|
||||
|
||||
return priceSetMoneyAmounts
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export { default as CurrencyService } from "./currency"
|
||||
export { default as MoneyAmountService } from "./money-amount"
|
||||
export { default as PriceSetService } from "./price-set"
|
||||
export { default as PricingModuleService } from "./pricing-module"
|
||||
|
||||
106
packages/pricing/src/services/price-set.ts
Normal file
106
packages/pricing/src/services/price-set.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import { Context, DAL, FindConfig, PricingTypes } from "@medusajs/types"
|
||||
import {
|
||||
InjectManager,
|
||||
InjectTransactionManager,
|
||||
MedusaContext,
|
||||
ModulesSdkUtils,
|
||||
doNotForceTransaction,
|
||||
retrieveEntity,
|
||||
shouldForceTransaction,
|
||||
} from "@medusajs/utils"
|
||||
import { PriceSet } from "@models"
|
||||
import { PriceSetRepository } from "@repositories"
|
||||
|
||||
type InjectedDependencies = {
|
||||
priceSetRepository: DAL.RepositoryService
|
||||
}
|
||||
|
||||
export default class PriceSetService<TEntity extends PriceSet = PriceSet> {
|
||||
protected readonly priceSetRepository_: DAL.RepositoryService
|
||||
|
||||
constructor({ priceSetRepository }: InjectedDependencies) {
|
||||
this.priceSetRepository_ = priceSetRepository
|
||||
}
|
||||
|
||||
@InjectManager("priceSetRepository_")
|
||||
async retrieve(
|
||||
priceSetId: string,
|
||||
config: FindConfig<PricingTypes.PriceSetDTO> = {},
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<TEntity> {
|
||||
return (await retrieveEntity<PriceSet, PricingTypes.PriceSetDTO>({
|
||||
id: priceSetId,
|
||||
entityName: PriceSet.name,
|
||||
repository: this.priceSetRepository_,
|
||||
config,
|
||||
sharedContext,
|
||||
})) as TEntity
|
||||
}
|
||||
|
||||
@InjectManager("priceSetRepository_")
|
||||
async list(
|
||||
filters: PricingTypes.FilterablePriceSetProps = {},
|
||||
config: FindConfig<PricingTypes.PriceSetDTO> = {},
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<TEntity[]> {
|
||||
return (await this.priceSetRepository_.find(
|
||||
this.buildQueryForList(filters, config),
|
||||
sharedContext
|
||||
)) as TEntity[]
|
||||
}
|
||||
|
||||
@InjectManager("priceSetRepository_")
|
||||
async listAndCount(
|
||||
filters: PricingTypes.FilterablePriceSetProps = {},
|
||||
config: FindConfig<PricingTypes.PriceSetDTO> = {},
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<[TEntity[], number]> {
|
||||
return (await this.priceSetRepository_.findAndCount(
|
||||
this.buildQueryForList(filters, config),
|
||||
sharedContext
|
||||
)) as [TEntity[], number]
|
||||
}
|
||||
|
||||
private buildQueryForList(
|
||||
filters: PricingTypes.FilterablePriceSetProps = {},
|
||||
config: FindConfig<PricingTypes.PriceSetDTO> = {}
|
||||
) {
|
||||
const queryOptions = ModulesSdkUtils.buildQuery<PriceSet>(filters, config)
|
||||
|
||||
if (filters.id) {
|
||||
queryOptions.where.id = { $in: filters.id }
|
||||
}
|
||||
|
||||
return queryOptions
|
||||
}
|
||||
|
||||
@InjectTransactionManager(shouldForceTransaction, "priceSetRepository_")
|
||||
async create(
|
||||
data: PricingTypes.CreatePriceSetDTO[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<TEntity[]> {
|
||||
return (await (this.priceSetRepository_ as PriceSetRepository).create(
|
||||
data,
|
||||
sharedContext
|
||||
)) as TEntity[]
|
||||
}
|
||||
|
||||
@InjectTransactionManager(shouldForceTransaction, "priceSetRepository_")
|
||||
async update(
|
||||
data: PricingTypes.UpdatePriceSetDTO[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<TEntity[]> {
|
||||
return (await (this.priceSetRepository_ as PriceSetRepository).update(
|
||||
data,
|
||||
sharedContext
|
||||
)) as TEntity[]
|
||||
}
|
||||
|
||||
@InjectTransactionManager(doNotForceTransaction, "priceSetRepository_")
|
||||
async delete(
|
||||
ids: string[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<void> {
|
||||
await this.priceSetRepository_.delete(ids, sharedContext)
|
||||
}
|
||||
}
|
||||
@@ -6,8 +6,8 @@ import {
|
||||
ModuleJoinerConfig,
|
||||
PricingTypes,
|
||||
} from "@medusajs/types"
|
||||
import { Currency, MoneyAmount } from "@models"
|
||||
import { CurrencyService, MoneyAmountService } from "@services"
|
||||
import { Currency, MoneyAmount, PriceSet } from "@models"
|
||||
import { CurrencyService, MoneyAmountService, PriceSetService } from "@services"
|
||||
|
||||
import {
|
||||
InjectManager,
|
||||
@@ -22,9 +22,15 @@ type InjectedDependencies = {
|
||||
baseRepository: DAL.RepositoryService
|
||||
currencyService: CurrencyService<any>
|
||||
moneyAmountService: MoneyAmountService<any>
|
||||
priceSetService: PriceSetService<any>
|
||||
}
|
||||
|
||||
type PricingContext = {
|
||||
currency_code?: string
|
||||
}
|
||||
|
||||
export default class PricingModuleService<
|
||||
TPriceSet extends PriceSet = PriceSet,
|
||||
TMoneyAmount extends MoneyAmount = MoneyAmount,
|
||||
TCurrency extends Currency = Currency
|
||||
> implements PricingTypes.IPricingModuleService
|
||||
@@ -32,26 +38,180 @@ export default class PricingModuleService<
|
||||
protected baseRepository_: DAL.RepositoryService
|
||||
protected readonly currencyService_: CurrencyService<TCurrency>
|
||||
protected readonly moneyAmountService_: MoneyAmountService<TMoneyAmount>
|
||||
protected readonly priceSetService_: PriceSetService<TPriceSet>
|
||||
|
||||
constructor(
|
||||
{
|
||||
baseRepository,
|
||||
moneyAmountService,
|
||||
currencyService,
|
||||
priceSetService,
|
||||
}: InjectedDependencies,
|
||||
protected readonly moduleDeclaration: InternalModuleDeclaration
|
||||
) {
|
||||
this.baseRepository_ = baseRepository
|
||||
this.currencyService_ = currencyService
|
||||
this.moneyAmountService_ = moneyAmountService
|
||||
this.priceSetService_ = priceSetService
|
||||
}
|
||||
|
||||
__joinerConfig(): ModuleJoinerConfig {
|
||||
return joinerConfig
|
||||
}
|
||||
|
||||
@InjectManager("baseRepository_")
|
||||
async calculatePrices(
|
||||
priceSetIds: string[],
|
||||
pricingContext: PricingContext,
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<PricingTypes.CalculatedPriceSetDTO> {
|
||||
// Keeping this whole logic raw in here for now as they will undergo
|
||||
// some changes, will abstract them out once we have a final version
|
||||
const priceSetFilters: PricingTypes.FilterablePriceSetProps = {
|
||||
id: priceSetIds,
|
||||
}
|
||||
|
||||
const priceSets = await this.list(
|
||||
priceSetFilters,
|
||||
{
|
||||
select: [
|
||||
"id",
|
||||
"money_amounts.id",
|
||||
"money_amounts.currency_code",
|
||||
"money_amounts.amount",
|
||||
"money_amounts.min_quantity",
|
||||
"money_amounts.max_quantity",
|
||||
],
|
||||
relations: ["money_amounts"],
|
||||
},
|
||||
sharedContext
|
||||
)
|
||||
|
||||
const calculatedPrices = priceSets.map(
|
||||
(priceSet): PricingTypes.CalculatedPriceSetDTO => {
|
||||
// TODO: This will change with the rules engine selection,
|
||||
// making a DB query directly instead
|
||||
// This should look for a default price when no rules apply
|
||||
// When no price is set, return null values for all cases
|
||||
const selectedMoneyAmount = priceSet.money_amounts?.find(
|
||||
(ma) =>
|
||||
pricingContext.currency_code &&
|
||||
ma.currency_code === pricingContext.currency_code
|
||||
)
|
||||
|
||||
return {
|
||||
id: priceSet.id,
|
||||
amount: selectedMoneyAmount?.amount || null,
|
||||
currency_code: selectedMoneyAmount?.currency_code || null,
|
||||
min_quantity: selectedMoneyAmount?.min_quantity || null,
|
||||
max_quantity: selectedMoneyAmount?.max_quantity || null,
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
return JSON.parse(JSON.stringify(calculatedPrices))
|
||||
}
|
||||
|
||||
@InjectManager("baseRepository_")
|
||||
async retrieve(
|
||||
id: string,
|
||||
config: FindConfig<PricingTypes.PriceSetDTO> = {},
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<PricingTypes.PriceSetDTO> {
|
||||
const priceSet = await this.priceSetService_.retrieve(
|
||||
id,
|
||||
config,
|
||||
sharedContext
|
||||
)
|
||||
|
||||
return this.baseRepository_.serialize<PricingTypes.PriceSetDTO>(priceSet, {
|
||||
populate: true,
|
||||
})
|
||||
}
|
||||
|
||||
@InjectManager("baseRepository_")
|
||||
async list(
|
||||
filters: PricingTypes.FilterablePriceSetProps = {},
|
||||
config: FindConfig<PricingTypes.PriceSetDTO> = {},
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<PricingTypes.PriceSetDTO[]> {
|
||||
const priceSets = await this.priceSetService_.list(
|
||||
filters,
|
||||
config,
|
||||
sharedContext
|
||||
)
|
||||
|
||||
return this.baseRepository_.serialize<PricingTypes.PriceSetDTO[]>(
|
||||
priceSets,
|
||||
{
|
||||
populate: true,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@InjectManager("baseRepository_")
|
||||
async listAndCount(
|
||||
filters: PricingTypes.FilterablePriceSetProps = {},
|
||||
config: FindConfig<PricingTypes.PriceSetDTO> = {},
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<[PricingTypes.PriceSetDTO[], number]> {
|
||||
const [priceSets, count] = await this.priceSetService_.listAndCount(
|
||||
filters,
|
||||
config,
|
||||
sharedContext
|
||||
)
|
||||
|
||||
return [
|
||||
await this.baseRepository_.serialize<PricingTypes.PriceSetDTO[]>(
|
||||
priceSets,
|
||||
{
|
||||
populate: true,
|
||||
}
|
||||
),
|
||||
count,
|
||||
]
|
||||
}
|
||||
|
||||
@InjectTransactionManager(shouldForceTransaction, "baseRepository_")
|
||||
async create(
|
||||
data: PricingTypes.CreatePriceSetDTO[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
) {
|
||||
const priceSets = await this.priceSetService_.create(data, sharedContext)
|
||||
|
||||
return this.baseRepository_.serialize<PricingTypes.PriceSetDTO[]>(
|
||||
priceSets,
|
||||
{
|
||||
populate: true,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@InjectTransactionManager(shouldForceTransaction, "baseRepository_")
|
||||
async update(
|
||||
data: PricingTypes.UpdatePriceSetDTO[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
) {
|
||||
const priceSets = await this.priceSetService_.update(data, sharedContext)
|
||||
|
||||
return this.baseRepository_.serialize<PricingTypes.PriceSetDTO[]>(
|
||||
priceSets,
|
||||
{
|
||||
populate: true,
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@InjectTransactionManager(shouldForceTransaction, "baseRepository_")
|
||||
async delete(
|
||||
ids: string[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<void> {
|
||||
await this.priceSetService_.delete(ids, sharedContext)
|
||||
}
|
||||
|
||||
@InjectManager("baseRepository_")
|
||||
async retrieveMoneyAmount(
|
||||
id: string,
|
||||
config: FindConfig<PricingTypes.MoneyAmountDTO> = {},
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
@@ -71,7 +231,7 @@ export default class PricingModuleService<
|
||||
}
|
||||
|
||||
@InjectManager("baseRepository_")
|
||||
async list(
|
||||
async listMoneyAmounts(
|
||||
filters: PricingTypes.FilterableMoneyAmountProps = {},
|
||||
config: FindConfig<PricingTypes.MoneyAmountDTO> = {},
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
@@ -91,7 +251,7 @@ export default class PricingModuleService<
|
||||
}
|
||||
|
||||
@InjectManager("baseRepository_")
|
||||
async listAndCount(
|
||||
async listAndCountMoneyAmounts(
|
||||
filters: PricingTypes.FilterableMoneyAmountProps = {},
|
||||
config: FindConfig<PricingTypes.MoneyAmountDTO> = {},
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
@@ -114,7 +274,7 @@ export default class PricingModuleService<
|
||||
}
|
||||
|
||||
@InjectTransactionManager(shouldForceTransaction, "baseRepository_")
|
||||
async create(
|
||||
async createMoneyAmounts(
|
||||
data: PricingTypes.CreateMoneyAmountDTO[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
) {
|
||||
@@ -132,7 +292,7 @@ export default class PricingModuleService<
|
||||
}
|
||||
|
||||
@InjectTransactionManager(shouldForceTransaction, "baseRepository_")
|
||||
async update(
|
||||
async updateMoneyAmounts(
|
||||
data: PricingTypes.UpdateMoneyAmountDTO[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
) {
|
||||
@@ -150,7 +310,7 @@ export default class PricingModuleService<
|
||||
}
|
||||
|
||||
@InjectTransactionManager(shouldForceTransaction, "baseRepository_")
|
||||
async delete(
|
||||
async deleteMoneyAmounts(
|
||||
ids: string[],
|
||||
@MedusaContext() sharedContext: Context = {}
|
||||
): Promise<void> {
|
||||
|
||||
Reference in New Issue
Block a user