feat: Add support for shipping options prices update (#7028)
This commit is contained in:
committed by
GitHub
parent
51acd1da5b
commit
c78915c7c5
@@ -0,0 +1,8 @@
|
||||
---
|
||||
"@medusajs/medusa": patch
|
||||
"@medusajs/core-flows": patch
|
||||
"@medusajs/pricing": patch
|
||||
"@medusajs/types": patch
|
||||
---
|
||||
|
||||
feat(): Add support for shipping options prices update
|
||||
@@ -856,8 +856,14 @@ medusaIntegrationTestRunner({
|
||||
expect(response.data.values.length).toEqual(2)
|
||||
expect(response.data.values).toEqual(
|
||||
expect.arrayContaining([
|
||||
{ label: "Afghanistan", value: "af" },
|
||||
{ label: "Albania", value: "al" },
|
||||
{
|
||||
label: "Andorra",
|
||||
value: "ad",
|
||||
},
|
||||
{
|
||||
label: "United Arab Emirates",
|
||||
value: "ae",
|
||||
},
|
||||
])
|
||||
)
|
||||
|
||||
|
||||
+39
-8
@@ -264,7 +264,7 @@ medusaIntegrationTestRunner({
|
||||
})
|
||||
})
|
||||
|
||||
it("should create a shipping option successfully", async () => {
|
||||
it("should update a shipping option successfully", async () => {
|
||||
const shippingOptionPayload = {
|
||||
name: "Test shipping option",
|
||||
service_zone_id: fulfillmentSet.service_zones[0].id,
|
||||
@@ -295,15 +295,44 @@ medusaIntegrationTestRunner({
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
expect(response.status).toEqual(200)
|
||||
expect(response.data.shipping_option).toEqual(
|
||||
const shippingOptionId = response.data.shipping_option.id
|
||||
|
||||
const eurPrice = response.data.shipping_option.prices.find(
|
||||
(p) => p.currency_code === "eur"
|
||||
)
|
||||
const updateShippingOptionPayload = {
|
||||
id: shippingOptionId,
|
||||
name: "Updated shipping option",
|
||||
provider_id: "manual_test-provider",
|
||||
price_type: "flat",
|
||||
prices: [
|
||||
{
|
||||
currency_code: "dkk",
|
||||
amount: 10,
|
||||
},
|
||||
{
|
||||
id: eurPrice.id,
|
||||
amount: 10000,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const updateResponse = await api.post(
|
||||
`/admin/shipping-options/${shippingOptionId}`,
|
||||
updateShippingOptionPayload,
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
expect(updateResponse.status).toEqual(200)
|
||||
expect(updateResponse.data.shipping_option.prices).toHaveLength(2)
|
||||
expect(updateResponse.data.shipping_option).toEqual(
|
||||
expect.objectContaining({
|
||||
id: expect.any(String),
|
||||
name: shippingOptionPayload.name,
|
||||
name: updateShippingOptionPayload.name,
|
||||
provider: expect.objectContaining({
|
||||
id: shippingOptionPayload.provider_id,
|
||||
}),
|
||||
price_type: shippingOptionPayload.price_type,
|
||||
price_type: updateShippingOptionPayload.price_type,
|
||||
type: expect.objectContaining({
|
||||
id: expect.any(String),
|
||||
label: shippingOptionPayload.type.label,
|
||||
@@ -315,13 +344,15 @@ medusaIntegrationTestRunner({
|
||||
prices: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
id: expect.any(String),
|
||||
currency_code: "usd",
|
||||
amount: 1000,
|
||||
currency_code: "dkk",
|
||||
rules_count: 0,
|
||||
amount: 10,
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: expect.any(String),
|
||||
currency_code: "eur",
|
||||
amount: 1000,
|
||||
rules_count: 1,
|
||||
amount: 10000,
|
||||
}),
|
||||
]),
|
||||
rules: expect.arrayContaining([
|
||||
|
||||
+55
-21
@@ -97,6 +97,10 @@ medusaIntegrationTestRunner({
|
||||
region_id: region.id,
|
||||
amount: 100,
|
||||
},
|
||||
{
|
||||
currency_code: "dkk",
|
||||
amount: 1000,
|
||||
},
|
||||
],
|
||||
rules: [
|
||||
{
|
||||
@@ -111,26 +115,11 @@ medusaIntegrationTestRunner({
|
||||
input: [shippingOptionData],
|
||||
})
|
||||
|
||||
const updateData: UpdateShippingOptionsWorkflowInput = {
|
||||
id: result[0].id,
|
||||
name: "Test shipping option",
|
||||
price_type: "flat",
|
||||
type: {
|
||||
code: "manual-type",
|
||||
label: "Manual Type",
|
||||
description: "Manual Type Description",
|
||||
},
|
||||
}
|
||||
|
||||
await updateShippingOptionsWorkflow(container).run({
|
||||
input: [updateData],
|
||||
})
|
||||
|
||||
const remoteQuery = container.resolve(
|
||||
ContainerRegistrationKeys.REMOTE_QUERY
|
||||
)
|
||||
|
||||
const remoteQueryObject = remoteQueryObjectFromString({
|
||||
let remoteQueryObject = remoteQueryObjectFromString({
|
||||
entryPoint: "shipping_option",
|
||||
variables: {
|
||||
id: result[0].id,
|
||||
@@ -155,10 +144,50 @@ medusaIntegrationTestRunner({
|
||||
|
||||
const [createdShippingOption] = await remoteQuery(remoteQueryObject)
|
||||
|
||||
const prices = createdShippingOption.prices
|
||||
delete createdShippingOption.prices
|
||||
const usdPrice = createdShippingOption.prices.find((price) => {
|
||||
return price.currency_code === "usd"
|
||||
})
|
||||
|
||||
expect(createdShippingOption).toEqual(
|
||||
const dkkPrice = createdShippingOption.prices.find((price) => {
|
||||
return price.currency_code === "dkk"
|
||||
})
|
||||
|
||||
const updateData: UpdateShippingOptionsWorkflowInput = {
|
||||
id: createdShippingOption.id,
|
||||
name: "Test shipping option",
|
||||
price_type: "flat",
|
||||
type: {
|
||||
code: "manual-type",
|
||||
label: "Manual Type",
|
||||
description: "Manual Type Description",
|
||||
},
|
||||
prices: [
|
||||
// We keep the usd price as is
|
||||
// update the dkk price to 100
|
||||
// delete the third price eur
|
||||
// create a new eur one instead
|
||||
usdPrice,
|
||||
{
|
||||
...dkkPrice,
|
||||
amount: 100,
|
||||
},
|
||||
{
|
||||
region_id: region.id,
|
||||
amount: 1000,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
await updateShippingOptionsWorkflow(container).run({
|
||||
input: [updateData],
|
||||
})
|
||||
|
||||
const [updatedShippingOption] = await remoteQuery(remoteQueryObject)
|
||||
|
||||
const prices = updatedShippingOption.prices
|
||||
delete updatedShippingOption.prices
|
||||
|
||||
expect(updatedShippingOption).toEqual(
|
||||
expect.objectContaining({
|
||||
id: result[0].id,
|
||||
name: updateData.name,
|
||||
@@ -178,7 +207,7 @@ medusaIntegrationTestRunner({
|
||||
})
|
||||
)
|
||||
|
||||
expect(prices).toHaveLength(2)
|
||||
expect(prices).toHaveLength(3)
|
||||
expect(prices).toContainEqual(
|
||||
expect.objectContaining({
|
||||
currency_code: "usd",
|
||||
@@ -188,8 +217,13 @@ medusaIntegrationTestRunner({
|
||||
expect(prices).toContainEqual(
|
||||
expect.objectContaining({
|
||||
currency_code: "eur",
|
||||
amount: 1000,
|
||||
})
|
||||
)
|
||||
expect(prices).toContainEqual(
|
||||
expect.objectContaining({
|
||||
currency_code: "dkk",
|
||||
amount: 100,
|
||||
rules_count: 1,
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
@@ -7,3 +7,4 @@ export * from "./delete-service-zones"
|
||||
export * from "./delete-shipping-options"
|
||||
export * from "./create-shipping-profiles"
|
||||
export * from "./remove-rules-from-fulfillment-shipping-option"
|
||||
export * from "./set-shipping-options-prices"
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
import {
|
||||
CreatePriceDTO,
|
||||
CreatePricesDTO,
|
||||
FulfillmentWorkflow,
|
||||
IPricingModuleService,
|
||||
IRegionModuleService,
|
||||
PriceDTO,
|
||||
PriceSetDTO,
|
||||
RemoteQueryFunction,
|
||||
} from "@medusajs/types"
|
||||
import { createStep, StepResponse } from "@medusajs/workflows-sdk"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
isDefined,
|
||||
LINKS,
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
|
||||
interface PriceRegionId {
|
||||
region_id: string
|
||||
amount: number
|
||||
}
|
||||
|
||||
type SetShippingOptionsPricesStepInput = {
|
||||
id: string
|
||||
prices?: FulfillmentWorkflow.UpdateShippingOptionsWorkflowInput["prices"]
|
||||
}[]
|
||||
|
||||
async function getCurrentShippingOptionPrices(
|
||||
shippingOptionIds: string[],
|
||||
{ remoteQuery }: { remoteQuery: RemoteQueryFunction }
|
||||
): Promise<
|
||||
{ shipping_option_id: string; price_set_id: string; prices: PriceDTO[] }[]
|
||||
> {
|
||||
const query = remoteQueryObjectFromString({
|
||||
service: LINKS.ShippingOptionPriceSet,
|
||||
variables: {
|
||||
filters: { shipping_option_id: shippingOptionIds },
|
||||
take: null,
|
||||
},
|
||||
fields: ["shipping_option_id", "price_set_id", "price_set.prices.*"],
|
||||
})
|
||||
|
||||
const shippingOptionPrices = (await remoteQuery(query)) as {
|
||||
shipping_option_id: string
|
||||
price_set_id: string
|
||||
price_set: PriceSetDTO
|
||||
}[]
|
||||
|
||||
return shippingOptionPrices.map((shippingOption) => {
|
||||
const prices = shippingOption.price_set?.prices ?? []
|
||||
const price_set_id = shippingOption.price_set_id
|
||||
return {
|
||||
shipping_option_id: shippingOption.shipping_option_id,
|
||||
price_set_id,
|
||||
prices,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function buildPrices(
|
||||
prices: SetShippingOptionsPricesStepInput[0]["prices"],
|
||||
regionToCurrencyMap: Map<string, string>
|
||||
): CreatePriceDTO[] {
|
||||
if (!prices) {
|
||||
return []
|
||||
}
|
||||
|
||||
const shippingOptionPrices = prices.map((price) => {
|
||||
if ("region_id" in price) {
|
||||
const currency_code = regionToCurrencyMap.get(price.region_id!)!
|
||||
const regionId = price.region_id
|
||||
delete price.region_id
|
||||
return {
|
||||
...price,
|
||||
currency_code: currency_code,
|
||||
amount: price.amount,
|
||||
rules: {
|
||||
region_id: regionId,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return price
|
||||
})
|
||||
|
||||
return shippingOptionPrices as CreatePriceDTO[]
|
||||
}
|
||||
|
||||
export const setShippingOptionsPricesStepId = "set-shipping-options-prices-step"
|
||||
export const setShippingOptionsPricesStep = createStep(
|
||||
setShippingOptionsPricesStepId,
|
||||
async (data: SetShippingOptionsPricesStepInput, { container }) => {
|
||||
if (!data.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const regionIds = data
|
||||
.map((input) => input.prices)
|
||||
.flat()
|
||||
.filter((price): price is PriceRegionId => "region_id" in (price ?? {}))
|
||||
.map((price) => price.region_id)
|
||||
|
||||
let regionToCurrencyMap: Map<string, string> = new Map()
|
||||
|
||||
if (regionIds.length) {
|
||||
const regionService = container.resolve<IRegionModuleService>(
|
||||
ModuleRegistrationName.REGION
|
||||
)
|
||||
const regions = await regionService.list(
|
||||
{
|
||||
id: [...new Set(regionIds)],
|
||||
},
|
||||
{
|
||||
select: ["id", "currency_code"],
|
||||
}
|
||||
)
|
||||
|
||||
regionToCurrencyMap = new Map(
|
||||
regions.map((region) => [region.id, region.currency_code])
|
||||
)
|
||||
}
|
||||
|
||||
const remoteQuery = container.resolve<RemoteQueryFunction>(
|
||||
ContainerRegistrationKeys.REMOTE_QUERY
|
||||
)
|
||||
|
||||
const currentShippingOptionPricesData =
|
||||
await getCurrentShippingOptionPrices(
|
||||
data.map((d) => d.id),
|
||||
{ remoteQuery }
|
||||
)
|
||||
|
||||
const shippingOptionPricesMap = new Map(
|
||||
currentShippingOptionPricesData.map((currentShippingOptionDataItem) => {
|
||||
const shippingOptionData = data.find(
|
||||
(d) => d.id === currentShippingOptionDataItem.shipping_option_id
|
||||
)!
|
||||
const pricesData = shippingOptionData?.prices?.map((priceData) => {
|
||||
return {
|
||||
...priceData,
|
||||
price_set_id: currentShippingOptionDataItem.price_set_id,
|
||||
}
|
||||
})
|
||||
const buildPricesData =
|
||||
pricesData && buildPrices(pricesData, regionToCurrencyMap)
|
||||
return [
|
||||
currentShippingOptionDataItem.shipping_option_id,
|
||||
{
|
||||
price_set_id: currentShippingOptionDataItem.price_set_id,
|
||||
prices: buildPricesData,
|
||||
},
|
||||
]
|
||||
})
|
||||
)
|
||||
|
||||
const pricingService = container.resolve<IPricingModuleService>(
|
||||
ModuleRegistrationName.PRICING
|
||||
)
|
||||
|
||||
for (const data_ of data) {
|
||||
const shippingOptionData = shippingOptionPricesMap.get(data_.id)!
|
||||
|
||||
if (!isDefined(shippingOptionData.prices)) {
|
||||
continue
|
||||
}
|
||||
|
||||
await pricingService.update(shippingOptionData.price_set_id, {
|
||||
prices: shippingOptionData.prices,
|
||||
})
|
||||
}
|
||||
|
||||
return new StepResponse(void 0, currentShippingOptionPricesData)
|
||||
},
|
||||
async (rollbackData, { container }) => {
|
||||
if (!rollbackData?.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const pricingService = container.resolve<IPricingModuleService>(
|
||||
ModuleRegistrationName.PRICING
|
||||
)
|
||||
|
||||
for (const data_ of rollbackData) {
|
||||
const prices = data_.prices as CreatePricesDTO[]
|
||||
if (!isDefined(prices)) {
|
||||
continue
|
||||
}
|
||||
await pricingService.update(data_.price_set_id, { prices })
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -22,9 +22,10 @@ export const createShippingOptionsWorkflow = createWorkflow(
|
||||
): WorkflowData<FulfillmentWorkflow.CreateShippingOptionsWorkflowOutput> => {
|
||||
const data = transform(input, (data) => {
|
||||
const shippingOptionsIndexToPrices = data.map((option, index) => {
|
||||
const prices = option.prices
|
||||
return {
|
||||
shipping_option_index: index,
|
||||
prices: option.prices,
|
||||
prices,
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
@@ -1,10 +1,18 @@
|
||||
import { FulfillmentWorkflow } from "@medusajs/types"
|
||||
import {
|
||||
CreateRuleTypeDTO,
|
||||
FulfillmentWorkflow,
|
||||
RuleTypeDTO,
|
||||
} from "@medusajs/types"
|
||||
import {
|
||||
createWorkflow,
|
||||
transform,
|
||||
WorkflowData,
|
||||
} from "@medusajs/workflows-sdk"
|
||||
import { upsertShippingOptionsStep } from "../steps"
|
||||
import {
|
||||
setShippingOptionsPricesStep,
|
||||
upsertShippingOptionsStep,
|
||||
} from "../steps"
|
||||
import { createPricingRuleTypesStep } from "../../pricing"
|
||||
|
||||
export const updateShippingOptionsWorkflowId =
|
||||
"update-shipping-options-workflow"
|
||||
@@ -17,9 +25,11 @@ export const updateShippingOptionsWorkflow = createWorkflow(
|
||||
): WorkflowData<FulfillmentWorkflow.UpdateShippingOptionsWorkflowOutput> => {
|
||||
const data = transform(input, (data) => {
|
||||
const shippingOptionsIndexToPrices = data.map((option, index) => {
|
||||
const prices = option.prices
|
||||
delete option.prices
|
||||
return {
|
||||
shipping_option_index: index,
|
||||
prices: option.prices,
|
||||
prices,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -33,7 +43,7 @@ export const updateShippingOptionsWorkflow = createWorkflow(
|
||||
data.shippingOptions
|
||||
)
|
||||
|
||||
/*const normalizedShippingOptionsPrices = transform(
|
||||
const normalizedShippingOptionsPrices = transform(
|
||||
{
|
||||
shippingOptions: updatedShippingOptions,
|
||||
shippingOptionsIndexToPrices: data.shippingOptionsIndexToPrices,
|
||||
@@ -60,32 +70,16 @@ export const updateShippingOptionsWorkflow = createWorkflow(
|
||||
|
||||
return {
|
||||
shippingOptionsPrices,
|
||||
ruleTypes: Array.from(ruleTypes) as UpdateRuleTypeDTO[],
|
||||
ruleTypes: Array.from(ruleTypes) as CreateRuleTypeDTO[],
|
||||
}
|
||||
}
|
||||
)*/
|
||||
|
||||
/*updatePricingRuleTypesStep(normalizedShippingOptionsPrices.ruleTypes)*/
|
||||
|
||||
/*const shippingOptionsPriceSetsLinkData = updateShippingOptionsPriceSetsStep(
|
||||
normalizedShippingOptionsPrices.shippingOptionsPrices
|
||||
)
|
||||
|
||||
const normalizedLinkData = transform(
|
||||
{
|
||||
shippingOptionsPriceSetsLinkData,
|
||||
},
|
||||
(data) => {
|
||||
return data.shippingOptionsPriceSetsLinkData.map((item) => {
|
||||
return {
|
||||
id: item.id,
|
||||
price_sets: [item.priceSetId],
|
||||
}
|
||||
})
|
||||
}
|
||||
)*/
|
||||
createPricingRuleTypesStep(normalizedShippingOptionsPrices.ruleTypes)
|
||||
|
||||
/*setShippingOptionsPriceSetsStep(normalizedLinkData)*/
|
||||
setShippingOptionsPricesStep(
|
||||
normalizedShippingOptionsPrices.shippingOptionsPrices
|
||||
)
|
||||
|
||||
return updatedShippingOptions
|
||||
}
|
||||
|
||||
@@ -70,6 +70,23 @@ export const AdminCreateShippingOptionPriceWithRegion = z
|
||||
})
|
||||
.strict()
|
||||
|
||||
export const AdminUpdateShippingOptionPriceWithCurrency =z
|
||||
.object({
|
||||
id: z.string().optional(),
|
||||
currency_code: z.string().optional(),
|
||||
amount: z.number().optional(),
|
||||
})
|
||||
.strict()
|
||||
|
||||
export const AdminUpdateShippingOptionPriceWithRegion =
|
||||
z
|
||||
.object({
|
||||
id: z.string().optional(),
|
||||
region_id: z.string().optional(),
|
||||
amount: z.number().optional(),
|
||||
})
|
||||
.strict()
|
||||
|
||||
export const AdminCreateShippingOption = z
|
||||
.object({
|
||||
name: z.string(),
|
||||
@@ -98,6 +115,11 @@ export const AdminUpdateShippingOption = z
|
||||
price_type: z.nativeEnum(ShippingOptionPriceTypeEnum).optional(),
|
||||
provider_id: z.string().optional(),
|
||||
type: AdminCreateShippingOptionTypeObject.optional(),
|
||||
prices: AdminUpdateShippingOptionPriceWithCurrency.or(
|
||||
AdminUpdateShippingOptionPriceWithRegion
|
||||
)
|
||||
.array()
|
||||
.optional(),
|
||||
})
|
||||
.strict()
|
||||
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
import { getSetDifference, stringToSelectRelationObject } from "@medusajs/utils"
|
||||
import {
|
||||
getSetDifference,
|
||||
isPresent,
|
||||
stringToSelectRelationObject,
|
||||
} from "@medusajs/utils"
|
||||
import { pick } from "lodash"
|
||||
import { MedusaError, isDefined } from "medusa-core-utils"
|
||||
import { isDefined, MedusaError } from "medusa-core-utils"
|
||||
import { BaseEntity } from "../interfaces"
|
||||
import { FindConfig, QueryConfig, RequestQueryFields } from "../types/common"
|
||||
import { featureFlagRouter } from "../loaders/feature-flags"
|
||||
import MedusaV2 from "../loaders/feature-flags/medusa-v2"
|
||||
|
||||
export function pickByConfig<TModel extends BaseEntity>(
|
||||
obj: TModel | TModel[],
|
||||
@@ -24,7 +30,7 @@ export function prepareListQuery<
|
||||
T extends RequestQueryFields,
|
||||
TEntity extends BaseEntity
|
||||
>(validated: T, queryConfig: QueryConfig<TEntity> = {}) {
|
||||
const isMedusaV2 = process.env.MEDUSA_FF_MEDUSA_V2 == "true"
|
||||
const isMedusaV2 = featureFlagRouter.isFeatureEnabled(MedusaV2.key)
|
||||
|
||||
// TODO: this function will be simplified a lot once we drop support for the old api
|
||||
const { order, fields, limit = 50, expand, offset = 0 } = validated
|
||||
@@ -189,13 +195,14 @@ export function prepareListQuery<
|
||||
}
|
||||
}
|
||||
|
||||
const finalOrder = isPresent(orderBy) ? orderBy : undefined
|
||||
return {
|
||||
listConfig: {
|
||||
select: select.length ? select : undefined,
|
||||
relations: Array.from(allRelations),
|
||||
skip: offset,
|
||||
take: limit ?? defaultLimit,
|
||||
order: orderBy,
|
||||
order: finalOrder,
|
||||
},
|
||||
remoteQueryConfig: {
|
||||
// Add starFields that are relations only on which we want all properties with a dedicated format to the remote query
|
||||
@@ -207,7 +214,7 @@ export function prepareListQuery<
|
||||
? {
|
||||
skip: offset,
|
||||
take: limit ?? defaultLimit,
|
||||
order: orderBy,
|
||||
order: finalOrder,
|
||||
}
|
||||
: {},
|
||||
},
|
||||
|
||||
@@ -2,8 +2,8 @@ import {
|
||||
AddPricesDTO,
|
||||
Context,
|
||||
CreatePriceListRuleDTO,
|
||||
CreatePriceSetDTO,
|
||||
CreatePricesDTO,
|
||||
CreatePriceSetDTO,
|
||||
DAL,
|
||||
InternalModuleDeclaration,
|
||||
ModuleJoinerConfig,
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
groupBy,
|
||||
InjectManager,
|
||||
InjectTransactionManager,
|
||||
isDefined,
|
||||
isDefined, isPresent,
|
||||
isString,
|
||||
MedusaContext,
|
||||
MedusaError,
|
||||
@@ -44,12 +44,12 @@ import {
|
||||
RuleType,
|
||||
} from "@models"
|
||||
|
||||
import { PriceListService, RuleTypeService } from "@services"
|
||||
import { validatePriceListDates } from "@utils"
|
||||
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config"
|
||||
import { PriceSetIdPrefix } from "../models/price-set"
|
||||
import { PriceListIdPrefix } from "../models/price-list"
|
||||
import { UpdatePriceSetInput } from "src/types/services"
|
||||
import {PriceListService, RuleTypeService} from "@services"
|
||||
import {validatePriceListDates} from "@utils"
|
||||
import {entityNameToLinkableKeysMap, joinerConfig} from "../joiner-config"
|
||||
import {PriceSetIdPrefix} from "../models/price-set"
|
||||
import {PriceListIdPrefix} from "../models/price-list"
|
||||
import {UpdatePriceSetInput} from "src/types/services"
|
||||
|
||||
type InjectedDependencies = {
|
||||
baseRepository: DAL.RepositoryService
|
||||
@@ -336,6 +336,54 @@ export default class PricingModuleService<
|
||||
return isString(idOrSelector) ? priceSets[0] : priceSets
|
||||
}
|
||||
|
||||
private async normalizeUpdateData(
|
||||
data: UpdatePriceSetInput[],
|
||||
sharedContext
|
||||
) {
|
||||
const ruleAttributes = data
|
||||
.map((d) => d.prices?.map((p) => Object.keys(p.rules ?? [])) ?? [])
|
||||
.flat(Infinity)
|
||||
.filter(Boolean)
|
||||
|
||||
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())
|
||||
|
||||
return data.map((priceSet) => {
|
||||
const prices = priceSet.prices?.map((price) => {
|
||||
const rules = Object.entries(price.rules ?? {}).map(
|
||||
([attribute, value]) => {
|
||||
return {
|
||||
price_set_id: priceSet.id,
|
||||
rule_type_id: ruleTypeMap.get(attribute)!.id,
|
||||
value,
|
||||
}
|
||||
}
|
||||
)
|
||||
const hasRulesInput = isPresent(price.rules)
|
||||
delete price.rules
|
||||
return {
|
||||
...price,
|
||||
price_set_id: priceSet.id,
|
||||
price_rules: hasRulesInput ? rules : undefined,
|
||||
rules_count: hasRulesInput ? rules.length : undefined
|
||||
}
|
||||
})
|
||||
|
||||
return {
|
||||
...priceSet,
|
||||
prices,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@InjectTransactionManager("baseRepository_")
|
||||
protected async update_(
|
||||
data: UpdatePriceSetInput[],
|
||||
@@ -344,8 +392,33 @@ export default class PricingModuleService<
|
||||
// TODO: We are not handling rule types, rules, etc. here, add support after data models are finalized
|
||||
// TODO: Since money IDs are rarely passed, this will delete all previous data and insert new entries.
|
||||
// We can make the `insert` inside upsertWithReplace do an `upsert` instead to avoid this
|
||||
return this.priceSetService_.upsertWithReplace(
|
||||
data,
|
||||
const normalizedData = await this.normalizeUpdateData(data, sharedContext)
|
||||
|
||||
const prices = normalizedData.flatMap((priceSet) => priceSet.prices || [])
|
||||
const upsertedPrices = await this.priceService_.upsertWithReplace(
|
||||
prices,
|
||||
{
|
||||
relations: ["price_rules"],
|
||||
},
|
||||
sharedContext
|
||||
)
|
||||
|
||||
const priceSetsToUpsert = normalizedData.map((priceSet) => {
|
||||
const { prices, ...rest } = priceSet
|
||||
return {
|
||||
...rest,
|
||||
prices: upsertedPrices
|
||||
.filter((p) => p.price_set_id === priceSet.id)
|
||||
.map((price) => {
|
||||
// @ts-ignore
|
||||
delete price.price_rules
|
||||
return price
|
||||
}),
|
||||
}
|
||||
})
|
||||
|
||||
return await this.priceSetService_.upsertWithReplace(
|
||||
priceSetsToUpsert,
|
||||
{ relations: ["prices"] },
|
||||
sharedContext
|
||||
)
|
||||
|
||||
@@ -16,12 +16,14 @@ export interface UpdateShippingOptionsWorkflowInput {
|
||||
}
|
||||
prices?: (
|
||||
| {
|
||||
currency_code: string
|
||||
amount: number
|
||||
id?: string
|
||||
currency_code?: string
|
||||
amount?: number
|
||||
}
|
||||
| {
|
||||
region_id: string
|
||||
amount: number
|
||||
id?: string
|
||||
region_id?: string
|
||||
amount?: number
|
||||
}
|
||||
)[]
|
||||
rules?: {
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
doNotForceTransaction,
|
||||
isDefined,
|
||||
isObject,
|
||||
isPresent,
|
||||
isString,
|
||||
lowerCaseFirst,
|
||||
MedusaError,
|
||||
@@ -85,7 +86,7 @@ export function internalModuleServiceFactory<
|
||||
* @param config
|
||||
*/
|
||||
static applyDefaultOrdering(config: FindConfig<any>) {
|
||||
if (config.order) {
|
||||
if (isPresent(config.order)) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user