import { Context, DAL, FindConfig, InternalModuleDeclaration, ModuleJoinerConfig, PricingContext, PricingFilters, PricingTypes, } from "@medusajs/types" import { Currency, MoneyAmount, PriceSet, RuleType } from "@models" import { CurrencyService, MoneyAmountService, PriceSetService, RuleTypeService, } from "@services" import { InjectManager, InjectTransactionManager, MedusaContext, shouldForceTransaction, } from "@medusajs/utils" import { joinerConfig } from "../joiner-config" type InjectedDependencies = { baseRepository: DAL.RepositoryService currencyService: CurrencyService moneyAmountService: MoneyAmountService ruleTypeService: RuleTypeService priceSetService: PriceSetService } export default class PricingModuleService< TPriceSet extends PriceSet = PriceSet, TMoneyAmount extends MoneyAmount = MoneyAmount, TCurrency extends Currency = Currency, TRuleType extends RuleType = RuleType > implements PricingTypes.IPricingModuleService { protected baseRepository_: DAL.RepositoryService protected readonly currencyService_: CurrencyService protected readonly moneyAmountService_: MoneyAmountService protected readonly ruleTypeService_: RuleTypeService protected readonly priceSetService_: PriceSetService constructor( { baseRepository, moneyAmountService, currencyService, ruleTypeService, priceSetService, }: InjectedDependencies, protected readonly moduleDeclaration: InternalModuleDeclaration ) { this.baseRepository_ = baseRepository this.currencyService_ = currencyService this.moneyAmountService_ = moneyAmountService this.ruleTypeService_ = ruleTypeService this.priceSetService_ = priceSetService } __joinerConfig(): ModuleJoinerConfig { return joinerConfig } @InjectManager("baseRepository_") async calculatePrices( pricingFilters: PricingFilters, pricingContext: PricingContext = { context: {} }, @MedusaContext() sharedContext: Context = {} ): Promise { // 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 context = pricingContext.context || {} const priceSetFilters: PricingTypes.FilterablePriceSetProps = { id: pricingFilters.id, } 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) => context.currency_code && ma.currency_code === context.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 = {}, @MedusaContext() sharedContext: Context = {} ): Promise { const priceSet = await this.priceSetService_.retrieve( id, config, sharedContext ) return this.baseRepository_.serialize(priceSet, { populate: true, }) } @InjectManager("baseRepository_") async list( filters: PricingTypes.FilterablePriceSetProps = {}, config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise { const priceSets = await this.priceSetService_.list( filters, config, sharedContext ) return this.baseRepository_.serialize( priceSets, { populate: true, } ) } @InjectManager("baseRepository_") async listAndCount( filters: PricingTypes.FilterablePriceSetProps = {}, config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise<[PricingTypes.PriceSetDTO[], number]> { const [priceSets, count] = await this.priceSetService_.listAndCount( filters, config, sharedContext ) return [ await this.baseRepository_.serialize( 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( 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( priceSets, { populate: true, } ) } @InjectTransactionManager(shouldForceTransaction, "baseRepository_") async delete( ids: string[], @MedusaContext() sharedContext: Context = {} ): Promise { await this.priceSetService_.delete(ids, sharedContext) } @InjectManager("baseRepository_") async retrieveMoneyAmount( id: string, config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise { const moneyAmount = await this.moneyAmountService_.retrieve( id, config, sharedContext ) return this.baseRepository_.serialize( moneyAmount, { populate: true, } ) } @InjectManager("baseRepository_") async listMoneyAmounts( filters: PricingTypes.FilterableMoneyAmountProps = {}, config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise { const moneyAmounts = await this.moneyAmountService_.list( filters, config, sharedContext ) return this.baseRepository_.serialize( moneyAmounts, { populate: true, } ) } @InjectManager("baseRepository_") async listAndCountMoneyAmounts( filters: PricingTypes.FilterableMoneyAmountProps = {}, config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise<[PricingTypes.MoneyAmountDTO[], number]> { const [moneyAmounts, count] = await this.moneyAmountService_.listAndCount( filters, config, sharedContext ) return [ await this.baseRepository_.serialize( moneyAmounts, { populate: true, } ), count, ] } @InjectTransactionManager(shouldForceTransaction, "baseRepository_") async createMoneyAmounts( data: PricingTypes.CreateMoneyAmountDTO[], @MedusaContext() sharedContext: Context = {} ) { const moneyAmounts = await this.moneyAmountService_.create( data, sharedContext ) return this.baseRepository_.serialize( moneyAmounts, { populate: true, } ) } @InjectTransactionManager(shouldForceTransaction, "baseRepository_") async updateMoneyAmounts( data: PricingTypes.UpdateMoneyAmountDTO[], @MedusaContext() sharedContext: Context = {} ) { const moneyAmounts = await this.moneyAmountService_.update( data, sharedContext ) return this.baseRepository_.serialize( moneyAmounts, { populate: true, } ) } @InjectTransactionManager(shouldForceTransaction, "baseRepository_") async deleteMoneyAmounts( ids: string[], @MedusaContext() sharedContext: Context = {} ): Promise { await this.moneyAmountService_.delete(ids, sharedContext) } @InjectManager("baseRepository_") async retrieveCurrency( code: string, config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise { const currency = await this.currencyService_.retrieve( code, config, sharedContext ) return this.baseRepository_.serialize(currency, { populate: true, }) } @InjectManager("baseRepository_") async listCurrencies( filters: PricingTypes.FilterableCurrencyProps = {}, config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise { const currencies = await this.currencyService_.list( filters, config, sharedContext ) return this.baseRepository_.serialize( currencies, { populate: true, } ) } @InjectManager("baseRepository_") async listAndCountCurrencies( filters: PricingTypes.FilterableCurrencyProps = {}, config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise<[PricingTypes.CurrencyDTO[], number]> { const [currencies, count] = await this.currencyService_.listAndCount( filters, config, sharedContext ) return [ await this.baseRepository_.serialize( currencies, { populate: true, } ), count, ] } @InjectTransactionManager(shouldForceTransaction, "baseRepository_") async createCurrencies( data: PricingTypes.CreateCurrencyDTO[], @MedusaContext() sharedContext: Context = {} ) { const currencies = await this.currencyService_.create(data, sharedContext) return this.baseRepository_.serialize( currencies, { populate: true, } ) } @InjectTransactionManager(shouldForceTransaction, "baseRepository_") async updateCurrencies( data: PricingTypes.UpdateCurrencyDTO[], @MedusaContext() sharedContext: Context = {} ) { const currencies = await this.currencyService_.update(data, sharedContext) return this.baseRepository_.serialize( currencies, { populate: true, } ) } @InjectTransactionManager(shouldForceTransaction, "baseRepository_") async deleteCurrencies( currencyCodes: string[], @MedusaContext() sharedContext: Context = {} ): Promise { await this.currencyService_.delete(currencyCodes, sharedContext) } @InjectManager("baseRepository_") async retrieveRuleType( id: string, config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise { const ruleType = await this.ruleTypeService_.retrieve( id, config, sharedContext ) return this.baseRepository_.serialize(ruleType, { populate: true, }) } @InjectManager("baseRepository_") async listRuleTypes( filters: PricingTypes.FilterableRuleTypeProps = {}, config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise { const ruleTypes = await this.ruleTypeService_.list( filters, config, sharedContext ) return this.baseRepository_.serialize( ruleTypes, { populate: true, } ) } @InjectManager("baseRepository_") async listAndCountRuleTypes( filters: PricingTypes.FilterableRuleTypeProps = {}, config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise<[PricingTypes.RuleTypeDTO[], number]> { const [ruleTypes, count] = await this.ruleTypeService_.listAndCount( filters, config, sharedContext ) return [ await this.baseRepository_.serialize( ruleTypes, { populate: true, } ), count, ] } @InjectTransactionManager(shouldForceTransaction, "baseRepository_") async createRuleTypes( data: PricingTypes.CreateRuleTypeDTO[], @MedusaContext() sharedContext: Context = {} ): Promise { const ruleTypes = await this.ruleTypeService_.create(data, sharedContext) return this.baseRepository_.serialize( ruleTypes, { populate: true, } ) } @InjectTransactionManager(shouldForceTransaction, "baseRepository_") async updateRuleTypes( data: PricingTypes.UpdateRuleTypeDTO[], @MedusaContext() sharedContext: Context = {} ): Promise { const ruleTypes = await this.ruleTypeService_.update(data, sharedContext) return this.baseRepository_.serialize( ruleTypes, { populate: true, } ) } @InjectTransactionManager(shouldForceTransaction, "baseRepository_") async deleteRuleTypes( ruleTypes: string[], @MedusaContext() sharedContext: Context = {} ): Promise { await this.ruleTypeService_.delete(ruleTypes, sharedContext) } }