import { AddPricesDTO, Context, CreateMoneyAmountDTO, CreatePriceListRuleDTO, DAL, FindConfig, InternalModuleDeclaration, ModuleJoinerConfig, MoneyAmountDTO, PriceSetDTO, PricingContext, PricingFilters, PricingRepositoryService, PricingTypes, RestoreReturn, RuleTypeDTO, } from "@medusajs/types" import { InjectManager, InjectTransactionManager, MedusaContext, MedusaError, PriceListType, arrayDifference, deduplicate, groupBy, mapObjectTo, removeNullish, } from "@medusajs/utils" import { Currency, MoneyAmount, PriceList, PriceListRule, PriceListRuleValue, PriceRule, PriceSet, PriceSetMoneyAmount, PriceSetMoneyAmountRules, PriceSetRuleType, RuleType, } from "@models" import { CurrencyService, MoneyAmountService, PriceListRuleService, PriceListRuleValueService, PriceListService, PriceRuleService, PriceSetMoneyAmountRulesService, PriceSetMoneyAmountService, PriceSetRuleTypeService, PriceSetService, RuleTypeService, } from "@services" import { LinkableKeys, entityNameToLinkableKeysMap, joinerConfig, } from "../joiner-config" import { validatePriceListDates } from "@utils" import { ServiceTypes } from "@types" import { CreatePriceListRuleValueDTO } from "src/types/services" type InjectedDependencies = { baseRepository: DAL.RepositoryService pricingRepository: PricingRepositoryService currencyService: CurrencyService moneyAmountService: MoneyAmountService priceSetService: PriceSetService priceSetMoneyAmountRulesService: PriceSetMoneyAmountRulesService ruleTypeService: RuleTypeService priceRuleService: PriceRuleService priceSetRuleTypeService: PriceSetRuleTypeService priceSetMoneyAmountService: PriceSetMoneyAmountService priceListService: PriceListService priceListRuleService: PriceListRuleService priceListRuleValueService: PriceListRuleValueService } 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, TPriceSetRuleType extends PriceSetRuleType = PriceSetRuleType, TPriceSetMoneyAmount extends PriceSetMoneyAmount = PriceSetMoneyAmount, TPriceList extends PriceList = PriceList, TPriceListRule extends PriceListRule = PriceListRule, TPriceListRuleValue extends PriceListRuleValue = PriceListRuleValue > implements PricingTypes.IPricingModuleService { protected baseRepository_: DAL.RepositoryService protected readonly pricingRepository_: PricingRepositoryService protected readonly currencyService_: CurrencyService protected readonly moneyAmountService_: MoneyAmountService protected readonly ruleTypeService_: RuleTypeService protected readonly priceSetService_: PriceSetService protected readonly priceSetMoneyAmountRulesService_: PriceSetMoneyAmountRulesService protected readonly priceRuleService_: PriceRuleService protected readonly priceSetRuleTypeService_: PriceSetRuleTypeService protected readonly priceSetMoneyAmountService_: PriceSetMoneyAmountService protected readonly priceListService_: PriceListService protected readonly priceListRuleService_: PriceListRuleService protected readonly priceListRuleValueService_: PriceListRuleValueService constructor( { baseRepository, pricingRepository, moneyAmountService, currencyService, ruleTypeService, priceSetService, priceSetMoneyAmountRulesService, priceRuleService, priceSetRuleTypeService, priceSetMoneyAmountService, priceListService, priceListRuleService, priceListRuleValueService, }: InjectedDependencies, protected readonly moduleDeclaration: InternalModuleDeclaration ) { this.baseRepository_ = baseRepository this.pricingRepository_ = pricingRepository this.currencyService_ = currencyService this.moneyAmountService_ = moneyAmountService this.ruleTypeService_ = ruleTypeService this.priceSetService_ = priceSetService this.priceSetMoneyAmountRulesService_ = priceSetMoneyAmountRulesService this.ruleTypeService_ = ruleTypeService this.priceRuleService_ = priceRuleService this.priceSetRuleTypeService_ = priceSetRuleTypeService this.priceSetMoneyAmountService_ = priceSetMoneyAmountService this.priceListService_ = priceListService this.priceListRuleService_ = priceListRuleService this.priceListRuleValueService_ = priceListRuleValueService } __joinerConfig(): ModuleJoinerConfig { return joinerConfig } @InjectManager("baseRepository_") async calculatePrices( pricingFilters: PricingFilters, pricingContext: PricingContext = { context: {} }, @MedusaContext() sharedContext: Context = {} ): Promise { const results = await this.pricingRepository_.calculatePrices( pricingFilters, pricingContext, sharedContext ) const pricesSetPricesMap = groupBy(results, "price_set_id") const calculatedPrices: PricingTypes.CalculatedPriceSet[] = pricingFilters.id.map( (priceSetId: string): PricingTypes.CalculatedPriceSet => { // This is where we select prices, for now we just do a first match based on the database results // which is prioritized by rules_count first for exact match and then deafult_priority of the rule_type // inject custom price selection here const prices = pricesSetPricesMap.get(priceSetId) || [] const priceListPrice = prices.find((p) => p.price_list_id) const defaultPrice = prices?.find((p) => !p.price_list_id) let calculatedPrice: PricingTypes.CalculatedPriceSetDTO = defaultPrice let originalPrice: PricingTypes.CalculatedPriceSetDTO = defaultPrice if (priceListPrice) { calculatedPrice = priceListPrice if (priceListPrice.price_list_type === PriceListType.OVERRIDE) { originalPrice = priceListPrice } } return { id: priceSetId, is_calculated_price_price_list: !!calculatedPrice?.price_list_id, calculated_amount: parseInt(calculatedPrice?.amount || "") || null, is_original_price_price_list: !!originalPrice?.price_list_id, original_amount: parseInt(originalPrice?.amount || "") || null, currency_code: calculatedPrice?.currency_code || null, calculated_price: { money_amount_id: calculatedPrice?.id || null, price_list_id: calculatedPrice?.price_list_id || null, price_list_type: calculatedPrice?.price_list_type || null, min_quantity: parseInt(calculatedPrice?.min_quantity || "") || null, max_quantity: parseInt(calculatedPrice?.max_quantity || "") || null, }, original_price: { money_amount_id: originalPrice?.id || null, price_list_id: originalPrice?.price_list_id || null, price_list_type: originalPrice?.price_list_type || null, min_quantity: parseInt(originalPrice?.min_quantity || "") || null, max_quantity: parseInt(originalPrice?.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, ] } async create( data: PricingTypes.CreatePriceSetDTO, sharedContext?: Context ): Promise async create( data: PricingTypes.CreatePriceSetDTO[], sharedContext?: Context ): Promise @InjectManager("baseRepository_") async create( data: PricingTypes.CreatePriceSetDTO | PricingTypes.CreatePriceSetDTO[], @MedusaContext() sharedContext: Context = {} ): Promise { const input = Array.isArray(data) ? data : [data] const priceSets = await this.create_(input, sharedContext) const dbPriceSets = await this.list( { id: priceSets.filter((p) => !!p).map((p) => p!.id) }, { relations: ["rule_types", "money_amounts", "price_rules"], }, sharedContext ) return (Array.isArray(data) ? dbPriceSets : dbPriceSets[0]) as unknown as | PriceSetDTO | PriceSetDTO[] } @InjectTransactionManager("baseRepository_") protected async create_( data: PricingTypes.CreatePriceSetDTO[], @MedusaContext() sharedContext: Context = {} ) { const ruleAttributes = data .map((d) => d.rules?.map((r) => r.rule_attribute) ?? []) .flat() const ruleTypes = await this.ruleTypeService_.list( { rule_attribute: ruleAttributes, }, { take: null }, sharedContext ) const ruleTypeMap = ruleTypes.reduce((acc, curr) => { acc.set(curr.rule_attribute, curr) return acc }, new Map()) const invalidRuleAttributes = ruleAttributes.filter( (r) => !ruleTypeMap.has(r) ) if (invalidRuleAttributes.length > 0) { throw new MedusaError( MedusaError.Types.NOT_FOUND, `Rule types don't exist for: ${invalidRuleAttributes.join(", ")}` ) } const invalidMoneyAmountRule = data .map( (d) => d.prices?.map((ma) => Object.keys(ma?.rules ?? {})).flat() ?? [] ) .flat() .filter((r) => !ruleTypeMap.has(r)) if (invalidMoneyAmountRule.length > 0) { throw new MedusaError( MedusaError.Types.INVALID_DATA, `Rule types don't exist for money amounts with rule attribute: ${invalidMoneyAmountRule.join( ", " )}` ) } // Bulk create price sets const priceSetData = data.map(({ rules, prices, ...rest }) => rest) const createdPriceSets = await this.priceSetService_.create( priceSetData, sharedContext ) // Price set rule types const ruleTypeData = data.flatMap( (item, index) => item.rules?.map((rule) => ({ rule_type: ruleTypeMap.get(rule.rule_attribute), price_set: createdPriceSets[index], })) || [] ) if (ruleTypeData.length > 0) { await this.priceSetRuleTypeService_.create( ruleTypeData as unknown as PricingTypes.CreatePriceSetRuleTypeDTO[], sharedContext ) } // Money amounts const moneyAmountData = data.flatMap((item) => item.prices || []) const createdMoneyAmounts = await this.moneyAmountService_.create( moneyAmountData, sharedContext ) let moneyAmountIndex = 0 const priceSetMoneyAmountData: unknown[] = [] const priceRulesData: unknown[] = [] for (const [index, item] of data.entries()) { for (const ma of item.prices || []) { const cleanRules = ma.rules ? removeNullish(ma.rules) : {} const numberOfRules = Object.entries(cleanRules).length const priceSetMoneyAmount = { price_set: createdPriceSets[index], money_amount: createdMoneyAmounts[moneyAmountIndex++], title: "test", // TODO: accept title rules_count: numberOfRules, } priceSetMoneyAmountData.push(priceSetMoneyAmount) for (const [k, v] of Object.entries(cleanRules)) { priceRulesData.push({ price_set_money_amount: null, // Updated later rule_type: ruleTypeMap.get(k), price_set: createdPriceSets[index], value: v, price_list_id: "test", }) } } } // Bulk create price set money amounts const createdPriceSetMoneyAmounts = await this.priceSetMoneyAmountService_.create( priceSetMoneyAmountData as PricingTypes.CreatePriceSetMoneyAmountDTO[], sharedContext ) // Update price set money amount references for (let i = 0, j = 0; i < priceSetMoneyAmountData.length; i++) { const rulesCount = (priceSetMoneyAmountData[i] as any).rules_count for (let k = 0; k < rulesCount; k++, j++) { ;(priceRulesData[j] as any).price_set_money_amount = createdPriceSetMoneyAmounts[i] } } // Price rules if (priceRulesData.length > 0) { await this.priceRuleService_.create( priceRulesData as ServiceTypes.CreatePriceRuleDTO[], sharedContext ) } return createdPriceSets } async addRules( data: PricingTypes.AddRulesDTO, sharedContext?: Context ): Promise async addRules( data: PricingTypes.AddRulesDTO[], sharedContext?: Context ): Promise @InjectManager("baseRepository_") async addRules( data: PricingTypes.AddRulesDTO | PricingTypes.AddRulesDTO[], @MedusaContext() sharedContext: Context = {} ): Promise { const inputs = Array.isArray(data) ? data : [data] const priceSets = await this.addRules_(inputs, sharedContext) return await this.list( { id: priceSets.map(({ id }) => id) }, { relations: ["rule_types"], } ) } @InjectTransactionManager("baseRepository_") protected async addRules_( inputs: PricingTypes.AddRulesDTO[], @MedusaContext() sharedContext: Context = {} ): Promise { const priceSets = await this.priceSetService_.list( { id: inputs.map((d) => d.priceSetId) }, { relations: ["rule_types"] }, sharedContext ) const priceSetRuleTypeMap: Map> = new Map( priceSets.map((priceSet) => [ priceSet.id, new Map([...priceSet.rule_types].map((rt) => [rt.rule_attribute, rt])), ]) ) const priceSetMap = new Map(priceSets.map((p) => [p.id, p])) const invalidPriceSetInputs = inputs.filter( (d) => !priceSetMap.has(d.priceSetId) ) if (invalidPriceSetInputs.length) { throw new MedusaError( MedusaError.Types.INVALID_DATA, `PriceSets with ids: ${invalidPriceSetInputs .map((d) => d.priceSetId) .join(", ")} was not found` ) } const ruleTypes = await this.ruleTypeService_.list( { rule_attribute: inputs .map((d) => d.rules.map((r) => r.attribute)) .flat(), }, { take: null }, sharedContext ) const ruleTypeMap: Map = new Map( ruleTypes.map((rt) => [rt.rule_attribute, rt]) ) const invalidRuleAttributeInputs = inputs .map((d) => d.rules.map((r) => r.attribute)) .flat() .filter((r) => !ruleTypeMap.has(r)) if (invalidRuleAttributeInputs.length) { throw new MedusaError( MedusaError.Types.INVALID_DATA, `Rule types don't exist for attributes: ${[ ...new Set(invalidRuleAttributeInputs), ].join(", ")}` ) } const priceSetRuleTypesCreate: PricingTypes.CreatePriceSetRuleTypeDTO[] = [] inputs.forEach((d) => { const priceSet = priceSetMap.get(d.priceSetId) for (const r of d.rules) { if (priceSetRuleTypeMap.get(d.priceSetId)!.has(r.attribute)) { continue } priceSetRuleTypesCreate.push({ rule_type: ruleTypeMap.get(r.attribute) as RuleTypeDTO, price_set: priceSet as unknown as PriceSetDTO, }) } }) await this.priceSetRuleTypeService_.create( priceSetRuleTypesCreate as unknown as PricingTypes.CreatePriceSetRuleTypeDTO[], sharedContext ) return priceSets } async addPrices( data: AddPricesDTO, sharedContext?: Context ): Promise async addPrices( data: AddPricesDTO[], sharedContext?: Context ): Promise @InjectManager("baseRepository_") async addPrices( data: AddPricesDTO | AddPricesDTO[], @MedusaContext() sharedContext: Context = {} ): Promise { const input = Array.isArray(data) ? data : [data] await this.addPrices_(input, sharedContext) return (await this.list( { id: input.map((d) => d.priceSetId) }, { relations: ["money_amounts"] }, sharedContext )) as unknown as PricingTypes.PriceSetDTO[] | PricingTypes.PriceSetDTO } @InjectTransactionManager("baseRepository_") protected async addPrices_( input: AddPricesDTO[], @MedusaContext() sharedContext: Context = {} ) { const priceSets = await this.list( { id: input.map((d) => d.priceSetId) }, { relations: ["rule_types"] }, sharedContext ) const priceSetMap = new Map(priceSets.map((p) => [p.id, p])) const ruleTypeMap: Map> = new Map( priceSets.map((priceSet) => [ priceSet.id, new Map( priceSet.rule_types?.map((rt) => [rt.rule_attribute, rt]) ?? [] ), ]) ) input.forEach(({ priceSetId, prices }) => { const priceSet = priceSetMap.get(priceSetId) if (!priceSet) { throw new MedusaError( MedusaError.Types.INVALID_DATA, `Price set with id: ${priceSetId} not found` ) } const ruleAttributes = prices .map((d) => (d.rules ? Object.keys(d.rules) : [])) .flat() const invalidRuleAttributes = ruleAttributes.filter( (r) => !ruleTypeMap.get(priceSetId)!.has(r) ) if (invalidRuleAttributes.length > 0) { throw new MedusaError( MedusaError.Types.NOT_FOUND, `Rule types don't exist for: ${invalidRuleAttributes.join(", ")}` ) } }) // Money amounts const moneyAmountsBulkData = input.flatMap((entry) => entry.prices) const createdMoneyAmounts = await this.moneyAmountService_.create( moneyAmountsBulkData as unknown as CreateMoneyAmountDTO[], sharedContext ) // Price set money amounts let maCursor = 0 const priceSetMoneyAmountsBulkData: unknown[] = input.flatMap(({ priceSetId, prices }) => prices.map(() => { const ma = createdMoneyAmounts[maCursor] const numberOfRules = Object.entries( prices[maCursor]?.rules ?? {} ).length maCursor++ return { price_set: priceSetId, money_amount: ma, title: "test", // TODO: accept title rules_count: numberOfRules, } }) ) const createdPriceSetMoneyAmounts = await this.priceSetMoneyAmountService_.create( priceSetMoneyAmountsBulkData as ServiceTypes.CreatePriceSetMoneyAmountDTO[], sharedContext ) // Price rules let rulesCursor = 0 const priceRulesBulkData = input.flatMap(({ priceSetId, prices }) => prices.flatMap((ma) => { const rules = ma.rules ?? {} const priceSetMoneyAmount = createdPriceSetMoneyAmounts[rulesCursor] rulesCursor++ return Object.entries(rules).map(([k, v]) => ({ price_set_money_amount: priceSetMoneyAmount, rule_type_id: ruleTypeMap.get(priceSetId)!.get(k)!.id, price_set: priceSetId, value: v, })) }) ) if (priceRulesBulkData.length > 0) { await this.priceRuleService_.create(priceRulesBulkData, sharedContext) } } @InjectTransactionManager("baseRepository_") async removeRules( data: PricingTypes.RemovePriceSetRulesDTO[], @MedusaContext() sharedContext: Context = {} ): Promise { const priceSets = await this.priceSetService_.list( { id: data.map((d) => d.id), }, {}, sharedContext ) const priceSetIds = priceSets.map((ps) => ps.id) const ruleTypes = await this.ruleTypeService_.list( { rule_attribute: data.map((d) => d.rules || []).flat(), }, { take: null }, sharedContext ) const ruleTypeIds = ruleTypes.map((rt) => rt.id) const priceSetRuleTypes = await this.priceSetRuleTypeService_.list( { price_set_id: priceSetIds, rule_type_id: ruleTypeIds, }, { take: null }, sharedContext ) const priceRules = await this.priceRuleService_.list( { price_set_id: priceSetIds, rule_type_id: ruleTypeIds, }, { select: ["price_set_money_amount"], take: null, }, sharedContext ) await this.priceSetRuleTypeService_.delete( priceSetRuleTypes.map((psrt) => psrt.id), sharedContext ) await this.priceSetMoneyAmountService_.delete( priceRules.map((pr) => pr.price_set_money_amount.id), sharedContext ) } @InjectTransactionManager("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("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("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("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("baseRepository_") async deleteMoneyAmounts( ids: string[], @MedusaContext() sharedContext: Context = {} ): Promise { await this.moneyAmountService_.delete(ids, sharedContext) } @InjectTransactionManager("baseRepository_") async softDeleteMoneyAmounts( ids: string[], @MedusaContext() sharedContext: Context = {} ): Promise { await this.moneyAmountService_.softDelete(ids, sharedContext) } @InjectTransactionManager("baseRepository_") async restoreDeletedMoneyAmounts< TReturnableLinkableKeys extends string = Lowercase< keyof typeof LinkableKeys > >( ids: string[], { returnLinkableKeys }: RestoreReturn = {}, @MedusaContext() sharedContext: Context = {} ): Promise, string[]> | void> { const [_, cascadedEntitiesMap] = await this.moneyAmountService_.restore( ids, sharedContext ) let mappedCascadedEntitiesMap if (returnLinkableKeys) { mappedCascadedEntitiesMap = mapObjectTo< Record, string[]> >(cascadedEntitiesMap, entityNameToLinkableKeysMap, { pick: returnLinkableKeys, }) } return mappedCascadedEntitiesMap ? mappedCascadedEntitiesMap : void 0 } @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("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("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("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("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("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("baseRepository_") async deleteRuleTypes( ruleTypeIds: string[], @MedusaContext() sharedContext: Context = {} ): Promise { await this.ruleTypeService_.delete(ruleTypeIds, sharedContext) } @InjectManager("baseRepository_") async retrievePriceSetMoneyAmountRules( id: string, config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise { const record = await this.priceSetMoneyAmountRulesService_.retrieve( id, config, sharedContext ) return this.baseRepository_.serialize( record, { populate: true, } ) } @InjectManager("baseRepository_") async listPriceSetMoneyAmountRules( filters: PricingTypes.FilterablePriceSetMoneyAmountRulesProps = {}, config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise { const records = await this.priceSetMoneyAmountRulesService_.list( filters, config, sharedContext ) return this.baseRepository_.serialize< PricingTypes.PriceSetMoneyAmountRulesDTO[] >(records, { populate: true, }) } @InjectManager("baseRepository_") async listAndCountPriceSetMoneyAmountRules( filters: PricingTypes.FilterablePriceSetMoneyAmountRulesProps = {}, config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise<[PricingTypes.PriceSetMoneyAmountRulesDTO[], number]> { const [records, count] = await this.priceSetMoneyAmountRulesService_.listAndCount( filters, config, sharedContext ) return [ await this.baseRepository_.serialize< PricingTypes.PriceSetMoneyAmountRulesDTO[] >(records, { populate: true, }), count, ] } @InjectManager("baseRepository_") async listPriceSetMoneyAmounts( filters: PricingTypes.FilterablePriceSetMoneyAmountProps = {}, config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise { const records = await this.priceSetMoneyAmountService_.list( filters, config, sharedContext ) return this.baseRepository_.serialize< PricingTypes.PriceSetMoneyAmountDTO[] >(records, { populate: true, }) } @InjectManager("baseRepository_") async listAndCountPriceSetMoneyAmounts( filters: PricingTypes.FilterablePriceSetMoneyAmountProps = {}, config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise<[PricingTypes.PriceSetMoneyAmountDTO[], number]> { const [records, count] = await this.priceSetMoneyAmountService_.listAndCount( filters, config, sharedContext ) return [ await this.baseRepository_.serialize< PricingTypes.PriceSetMoneyAmountDTO[] >(records, { populate: true, }), count, ] } @InjectTransactionManager("baseRepository_") async createPriceSetMoneyAmountRules( data: PricingTypes.CreatePriceSetMoneyAmountRulesDTO[], @MedusaContext() sharedContext: Context = {} ): Promise { const records = await this.priceSetMoneyAmountRulesService_.create( data, sharedContext ) return this.baseRepository_.serialize< PricingTypes.PriceSetMoneyAmountRulesDTO[] >(records, { populate: true, }) } @InjectTransactionManager("baseRepository_") async updatePriceSetMoneyAmountRules( data: PricingTypes.UpdatePriceSetMoneyAmountRulesDTO[], @MedusaContext() sharedContext: Context = {} ): Promise { const records = await this.priceSetMoneyAmountRulesService_.update( data, sharedContext ) return this.baseRepository_.serialize< PricingTypes.PriceSetMoneyAmountRulesDTO[] >(records, { populate: true, }) } @InjectTransactionManager("baseRepository_") async deletePriceSetMoneyAmountRules( ids: string[], @MedusaContext() sharedContext: Context = {} ): Promise { await this.priceSetMoneyAmountRulesService_.delete(ids, sharedContext) } @InjectManager("baseRepository_") async retrievePriceRule( id: string, config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise { const priceRule = await this.priceRuleService_.retrieve( id, config, sharedContext ) return this.baseRepository_.serialize( priceRule, { populate: true, } ) } @InjectManager("baseRepository_") async listPriceRules( filters: PricingTypes.FilterablePriceRuleProps = {}, config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise { const priceRules = await this.priceRuleService_.list( filters, config, sharedContext ) return this.baseRepository_.serialize( priceRules, { populate: true, } ) } @InjectManager("baseRepository_") async listAndCountPriceRules( filters: PricingTypes.FilterablePriceRuleProps = {}, config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise<[PricingTypes.PriceRuleDTO[], number]> { const [priceRules, count] = await this.priceRuleService_.listAndCount( filters, config, sharedContext ) return [ await this.baseRepository_.serialize( priceRules, { populate: true, } ), count, ] } @InjectTransactionManager("baseRepository_") async createPriceRules( data: PricingTypes.CreatePriceRuleDTO[], @MedusaContext() sharedContext: Context = {} ): Promise { const priceRules = await this.priceRuleService_.create( data as ServiceTypes.CreatePriceRuleDTO[], sharedContext ) return this.baseRepository_.serialize( priceRules, { populate: true, } ) } @InjectTransactionManager("baseRepository_") async updatePriceRules( data: PricingTypes.UpdatePriceRuleDTO[], @MedusaContext() sharedContext: Context = {} ): Promise { const priceRules = await this.priceRuleService_.update(data, sharedContext) return this.baseRepository_.serialize( priceRules, { populate: true, } ) } @InjectTransactionManager("baseRepository_") async deletePriceRules( priceRuleIds: string[], @MedusaContext() sharedContext: Context = {} ): Promise { await this.priceRuleService_.delete(priceRuleIds, sharedContext) } @InjectManager("baseRepository_") async retrievePriceList( id: string, config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise { const priceList = await this.priceListService_.retrieve( id, config, sharedContext ) return this.baseRepository_.serialize( priceList, { populate: true, } ) } @InjectManager("baseRepository_") async listPriceLists( filters: PricingTypes.FilterablePriceListProps = {}, config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise { const priceLists = await this.priceListService_.list( filters, config, sharedContext ) return this.baseRepository_.serialize( priceLists, { populate: true, } ) } @InjectManager("baseRepository_") async listAndCountPriceLists( filters: PricingTypes.FilterablePriceListProps = {}, config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise<[PricingTypes.PriceListDTO[], number]> { const [priceLists, count] = await this.priceListService_.listAndCount( filters, config, sharedContext ) return [ await this.baseRepository_.serialize( priceLists, { populate: true, } ), count, ] } @InjectManager("baseRepository_") async createPriceLists( data: PricingTypes.CreatePriceListDTO[], @MedusaContext() sharedContext: Context = {} ): Promise { const priceLists = await this.createPriceLists_(data, sharedContext) return this.baseRepository_.serialize( priceLists, { populate: true, } ) } @InjectTransactionManager("baseRepository_") protected async createPriceLists_( data: PricingTypes.CreatePriceListDTO[], @MedusaContext() sharedContext: Context = {} ) { const ruleTypeAttributes: string[] = [] for (const priceListData of data) { const { prices = [], rules: priceListRules = {} } = priceListData ruleTypeAttributes.push(...Object.keys(priceListRules)) for (const price of prices) { const { rules: priceListPriceRules = {} } = price ruleTypeAttributes.push(...Object.keys(priceListPriceRules)) } } const ruleTypes = await this.listRuleTypes( { rule_attribute: ruleTypeAttributes }, { take: null } ) const invalidRuleTypes = arrayDifference( deduplicate(ruleTypeAttributes), ruleTypes.map((ruleType) => ruleType.rule_attribute) ) if (invalidRuleTypes.length) { throw new MedusaError( MedusaError.Types.INVALID_DATA, `Cannot find RuleTypes with rule_attribute - ${invalidRuleTypes.join( ", " )}` ) } const ruleTypeMap: Map = new Map( ruleTypes.map((rt) => [rt.rule_attribute, rt]) ) const priceListsToCreate: PricingTypes.CreatePriceListDTO[] = [] for (const priceListData of data) { const { rules = {}, prices = [], ...priceListOnlyData } = priceListData validatePriceListDates(priceListData) priceListsToCreate.push({ ...priceListOnlyData, rules_count: Object.keys(rules).length, }) } const priceLists = (await this.priceListService_.create( priceListsToCreate )) as unknown as PricingTypes.PriceListDTO[] for (var i = 0; i < data.length; i++) { const { rules = {}, prices = [] } = data[i] const priceList = priceLists[i] for (const [ruleAttribute, ruleValues = []] of Object.entries(rules)) { let ruleType = ruleTypeMap.get(ruleAttribute)! // Create the rule const [priceListRule] = await this.priceListRuleService_.create( [ { price_list: priceList, rule_type: ruleType.id, }, ], sharedContext ) // Create the values for the rule for (const ruleValue of ruleValues as string[]) { await this.priceListRuleValueService_.create( [ { price_list_rule: priceListRule, value: ruleValue, }, ], sharedContext ) } } for (const price of prices) { const { price_set_id: priceSetId, rules: priceRules = {}, ...moneyAmountData } = price const [moneyAmount] = await this.moneyAmountService_.create( [moneyAmountData], sharedContext ) const [priceSetMoneyAmount] = await this.priceSetMoneyAmountService_.create( [ { price_set: priceSetId, price_list: priceList, money_amount: moneyAmount, title: "test", rules_count: Object.keys(priceRules).length, }, ] as unknown as ServiceTypes.CreatePriceSetMoneyAmountDTO[], sharedContext ) await this.createPriceRules( Object.entries(priceRules).map(([ruleAttribute, ruleValue]) => { return { price_set_id: priceSetId, rule_type: ruleTypeMap.get(ruleAttribute)!?.id || ruleTypeMap.get(ruleAttribute)!, value: ruleValue, price_set_money_amount: priceSetMoneyAmount as any, } }), sharedContext ) } } return priceLists } @InjectTransactionManager("baseRepository_") async updatePriceLists( data: PricingTypes.UpdatePriceListDTO[], @MedusaContext() sharedContext: Context = {} ): Promise { const priceLists = await this.updatePriceLists_(data, sharedContext) return this.baseRepository_.serialize( priceLists, { populate: true, } ) } @InjectTransactionManager("baseRepository_") protected async updatePriceLists_( data: PricingTypes.UpdatePriceListDTO[], @MedusaContext() sharedContext: Context = {} ) { const updatedPriceLists: PricingTypes.PriceListDTO[] = [] const ruleAttributes: string[] = [] const priceListIds: string[] = [] for (const priceListData of data) { if (typeof priceListData.rules === "object") { ruleAttributes.push(...Object.keys(priceListData.rules)) priceListIds.push(priceListData.id) } } const existingPriceLists = await this.listPriceLists( { id: priceListIds }, { relations: ["price_list_rules"] }, sharedContext ) const priceListRuleIds = existingPriceLists .map((pl) => (pl.price_list_rules || []).map((plr) => plr.id)) .flat() const existingPriceListRules = await this.listPriceListRules( { id: priceListRuleIds, }, {}, sharedContext ) if (existingPriceListRules.length) { await this.deletePriceListRules( existingPriceListRules.map((plr) => plr.id), sharedContext ) } const ruleTypes = await this.listRuleTypes( { rule_attribute: ruleAttributes, }, { take: null }, sharedContext ) const ruleTypeMap: Map = new Map( ruleTypes.map((rt) => [rt.rule_attribute, rt]) ) for (const priceListData of data) { const { rules, ...priceListOnlyData } = priceListData const updatePriceListData: any = { ...priceListOnlyData, } validatePriceListDates(updatePriceListData) if (typeof rules === "object") { updatePriceListData.rules_count = Object.keys(rules).length } const [updatedPriceList] = (await this.priceListService_.update( [updatePriceListData], sharedContext )) as unknown as PricingTypes.PriceListDTO[] updatedPriceLists.push(updatedPriceList) for (const [ruleAttribute, ruleValues = []] of Object.entries( rules || {} )) { let ruleType = ruleTypeMap.get(ruleAttribute) if (!ruleType) { ;[ruleType] = await this.createRuleTypes( [ { name: ruleAttribute, rule_attribute: ruleAttribute, }, ], sharedContext ) ruleTypeMap.set(ruleAttribute, ruleType) } const [priceListRule] = await this.priceListRuleService_.create( [ { price_list: updatedPriceList, rule_type: ruleType?.id || ruleType, }, ], sharedContext ) for (const ruleValue of ruleValues as string[]) { await this.priceListRuleValueService_.create( [ { price_list_rule: priceListRule, value: ruleValue, }, ], sharedContext ) } } } return updatedPriceLists } @InjectTransactionManager("baseRepository_") async deletePriceLists( priceListIds: string[], @MedusaContext() sharedContext: Context = {} ): Promise { await this.priceListService_.delete(priceListIds, sharedContext) } @InjectManager("baseRepository_") async retrievePriceListRule( id: string, config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise { const priceList = await this.priceListRuleService_.retrieve( id, config, sharedContext ) return this.baseRepository_.serialize( priceList, { populate: true, } ) } @InjectManager("baseRepository_") async listPriceListRules( filters: PricingTypes.FilterablePriceListRuleProps = {}, config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise { const priceLists = await this.priceListRuleService_.list( filters, config, sharedContext ) return this.baseRepository_.serialize( priceLists, { populate: true, } ) } @InjectManager("baseRepository_") async listAndCountPriceListRules( filters: PricingTypes.FilterablePriceListRuleProps = {}, config: FindConfig = {}, @MedusaContext() sharedContext: Context = {} ): Promise<[PricingTypes.PriceListRuleDTO[], number]> { const [priceLists, count] = await this.priceListRuleService_.listAndCount( filters, config, sharedContext ) return [ await this.baseRepository_.serialize( priceLists, { populate: true, } ), count, ] } @InjectManager("baseRepository_") async createPriceListRules( data: PricingTypes.CreatePriceListRuleDTO[], @MedusaContext() sharedContext: Context = {} ): Promise { const priceLists = await this.createPriceListRules_(data, sharedContext) return this.baseRepository_.serialize( priceLists, { populate: true, } ) } @InjectTransactionManager("baseRepository_") async createPriceListRules_( data: PricingTypes.CreatePriceListRuleDTO[], @MedusaContext() sharedContext: Context = {} ) { return await this.priceListRuleService_.create(data, sharedContext) } @InjectTransactionManager("baseRepository_") async updatePriceListRules( data: PricingTypes.UpdatePriceListRuleDTO[], @MedusaContext() sharedContext: Context = {} ): Promise { const priceLists = await this.priceListRuleService_.update( data, sharedContext ) return this.baseRepository_.serialize( priceLists, { populate: true, } ) } @InjectTransactionManager("baseRepository_") async deletePriceListRules( priceListRuleIds: string[], @MedusaContext() sharedContext: Context = {} ): Promise { await this.priceListRuleService_.delete(priceListRuleIds, sharedContext) } @InjectManager("baseRepository_") async addPriceListPrices( data: PricingTypes.AddPriceListPricesDTO[], @MedusaContext() sharedContext: Context = {} ): Promise { return await this.addPriceListPrices_(data, sharedContext) } @InjectTransactionManager("baseRepository_") protected async addPriceListPrices_( data: PricingTypes.AddPriceListPricesDTO[], sharedContext: Context = {} ): Promise { const ruleTypeAttributes: string[] = [] const priceListIds: string[] = [] const priceSetIds: string[] = [] for (const priceListData of data) { priceListIds.push(priceListData.priceListId) for (const price of priceListData.prices) { ruleTypeAttributes.push(...Object.keys(price.rules || {})) priceSetIds.push(price.price_set_id) } } const ruleTypes = await this.listRuleTypes( { rule_attribute: ruleTypeAttributes }, { take: null }, sharedContext ) const priceSets = await this.list( { id: priceSetIds }, { relations: ["rule_types"] }, sharedContext ) const priceSetRuleTypeMap: Map> = priceSets.reduce( (acc, curr) => { const priceSetRuleAttributeSet: Set = acc.get(curr.id) || new Set() for (const rt of curr.rule_types ?? []) { priceSetRuleAttributeSet.add(rt.rule_attribute) } acc.set(curr.id, priceSetRuleAttributeSet) return acc }, new Map() ) const ruleTypeErrors: string[] = [] for (const priceListData of data) { for (const price of priceListData.prices) { for (const rule_attribute of Object.keys(price.rules ?? {})) { if ( !priceSetRuleTypeMap.get(price.price_set_id)?.has(rule_attribute) ) { ruleTypeErrors.push( `rule_attribute "${rule_attribute}" in price set ${price.price_set_id}` ) } } } } if (ruleTypeErrors.length) { throw new MedusaError( MedusaError.Types.INVALID_DATA, `Invalid rule type configuration: Price set rules doesn't exist for ${ruleTypeErrors.join( ", " )}` ) } const ruleTypeMap: Map = new Map( ruleTypes.map((rt) => [rt.rule_attribute, rt]) ) const priceLists = await this.listPriceLists( { id: priceListIds }, {}, sharedContext ) const priceListMap = new Map(priceLists.map((p) => [p.id, p])) for (const { priceListId, prices } of data) { const priceList = priceListMap.get(priceListId) if (!priceList) { throw new MedusaError( MedusaError.Types.INVALID_DATA, `Price list with id: ${priceListId} not found` ) } await Promise.all( prices.map(async (price) => { const priceRules = price.rules || {} const noOfRules = Object.keys(priceRules).length const [moneyAmount] = await this.moneyAmountService_.create( [price] as unknown as CreateMoneyAmountDTO[], sharedContext ) const [psma] = await this.priceSetMoneyAmountService_.create( [ { price_set: price.price_set_id, money_amount: moneyAmount.id, title: "test", price_list: priceList.id, rules_count: noOfRules, }, ], sharedContext ) await this.createPriceRules( Object.entries(priceRules).map(([ruleAttribute, ruleValue]) => { return { price_set_id: price.price_set_id, rule_type: ruleTypeMap.get(ruleAttribute)!?.id || ruleTypeMap.get(ruleAttribute)!, value: ruleValue, price_set_money_amount: psma as any, } }), sharedContext ) return psma }) ) } return priceLists } @InjectManager("baseRepository_") async setPriceListRules( data: PricingTypes.SetPriceListRulesDTO, @MedusaContext() sharedContext: Context = {} ): Promise { const [priceList] = await this.setPriceListRules_([data], sharedContext) return priceList } @InjectTransactionManager("baseRepository_") protected async setPriceListRules_( data: PricingTypes.SetPriceListRulesDTO[], sharedContext: Context = {} ): Promise { const priceLists = await this.priceListService_.list( { id: data.map((d) => d.priceListId) }, { relations: ["price_list_rules", "price_list_rules.rule_type"], }, sharedContext ) const priceListMap = new Map(priceLists.map((p) => [p.id, p])) const ruleTypes = await this.listRuleTypes( { rule_attribute: data.map((d) => Object.keys(d.rules)).flat(), }, { take: null, } ) const ruleTypeMap = new Map(ruleTypes.map((rt) => [rt.rule_attribute, rt])) const ruleIdsToUpdate: string[] = [] const rulesToCreate: CreatePriceListRuleDTO[] = [] const priceRuleValues = new Map>() for (const { priceListId, rules } of data) { const priceList = priceListMap.get(priceListId) if (!priceList) { throw new MedusaError( MedusaError.Types.INVALID_DATA, `Price list with id: ${priceListId} not found` ) } const priceListRulesMap: Map = new Map( priceList.price_list_rules .getItems() .map((p) => [p.rule_type.rule_attribute, p]) ) const priceListRuleValues = new Map() await Promise.all( Object.entries(rules).map(async ([key, value]) => { const ruleType = ruleTypeMap.get(key) if (!ruleType) { throw new MedusaError( MedusaError.Types.INVALID_DATA, `Rule type with attribute: ${key} not found` ) } const rule = priceListRulesMap.get(key) priceListRuleValues.set( ruleType.id, Array.isArray(value) ? value : [value] ) if (!rule) { rulesToCreate.push({ rule_type: ruleType.id, price_list: priceListId, }) } else { ruleIdsToUpdate.push(rule.id) } }) ) priceRuleValues.set(priceListId, priceListRuleValues) } const [createdRules, priceListValuesToDelete] = await Promise.all([ this.priceListRuleService_.create(rulesToCreate), this.priceListRuleValueService_.list( { price_list_rule_id: ruleIdsToUpdate, }, { take: null } ), ]) const priceListRuleValuesToCreate: unknown[] = [] for (const { id, price_list, rule_type } of createdRules) { const ruleValues = priceRuleValues.get( price_list.id ?? (price_list as unknown as string) ) if (!ruleValues) { continue } const values = ruleValues.get( rule_type.id ?? (rule_type as unknown as string) ) if (!values) { continue } values.forEach((v) => { priceListRuleValuesToCreate.push({ price_list_rule: id, value: v, }) }) } await Promise.all([ this.priceListRuleValueService_.delete( priceListValuesToDelete.map((p) => p.id) ), this.priceListRuleValueService_.create( priceListRuleValuesToCreate as CreatePriceListRuleValueDTO[] ), ]) return this.baseRepository_.serialize( priceLists, { populate: true, } ) } @InjectManager("baseRepository_") async removePriceListRules( data: PricingTypes.RemovePriceListRulesDTO, @MedusaContext() sharedContext: Context = {} ): Promise { const [priceList] = await this.removePriceListRules_([data], sharedContext) return priceList } @InjectTransactionManager("baseRepository_") protected async removePriceListRules_( data: PricingTypes.RemovePriceListRulesDTO[], sharedContext: Context = {} ): Promise { const priceLists = await this.priceListService_.list( { id: data.map((d) => d.priceListId) }, { relations: ["price_list_rules", "price_list_rules.rule_type"], }, sharedContext ) const priceListMap = new Map(priceLists.map((p) => [p.id, p])) const idsToDelete: string[] = [] for (const { priceListId, rules } of data) { const priceList = priceListMap.get(priceListId) if (!priceList) { throw new MedusaError( MedusaError.Types.INVALID_DATA, `Price list with id: ${priceListId} not found` ) } const priceListRulesMap: Map = new Map( priceList.price_list_rules .getItems() .map((p) => [p.rule_type.rule_attribute, p]) ) await Promise.all( rules.map(async (rule_attribute) => { const rule = priceListRulesMap.get(rule_attribute) if (rule) { idsToDelete.push(rule.id) } }) ) } await this.priceListRuleService_.delete(idsToDelete) return this.baseRepository_.serialize( priceLists, { populate: true, } ) } }