feat(core-flows,medusa,types): create/update workflows to create and update PriceList prices (#6711)
what: - create and update workflows for price list prices - update price list endpoint does a "set"
This commit is contained in:
5
.changeset/eight-candles-smoke.md
Normal file
5
.changeset/eight-candles-smoke.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@medusajs/medusa": patch
|
||||
---
|
||||
|
||||
feat(medusa): rework prices add/remove to batch spec
|
||||
7
.changeset/pretty-bugs-smoke.md
Normal file
7
.changeset/pretty-bugs-smoke.md
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@medusajs/core-flows": patch
|
||||
"@medusajs/medusa": patch
|
||||
"@medusajs/types": patch
|
||||
---
|
||||
|
||||
feat(core-flows,medusa,types): split upsert workflow to create and update
|
||||
@@ -259,7 +259,7 @@ medusaIntegrationTestRunner({
|
||||
})
|
||||
|
||||
describe("POST /admin/price-lists", () => {
|
||||
it("should create price list and money amounts", async () => {
|
||||
it("should create price list and prices successfully", async () => {
|
||||
await createVariantPriceSet({
|
||||
container: appContainer,
|
||||
variantId: variant.id,
|
||||
@@ -422,7 +422,7 @@ medusaIntegrationTestRunner({
|
||||
)
|
||||
})
|
||||
|
||||
it("should update price lists successfully", async () => {
|
||||
it("should update price lists and set prices successfully", async () => {
|
||||
await createVariantPriceSet({
|
||||
container: appContainer,
|
||||
variantId: variant.id,
|
||||
@@ -456,7 +456,7 @@ medusaIntegrationTestRunner({
|
||||
],
|
||||
}
|
||||
|
||||
const response = await api.post(
|
||||
let response = await api.post(
|
||||
`admin/price-lists/${priceList.id}`,
|
||||
data,
|
||||
adminHeaders
|
||||
@@ -466,14 +466,8 @@ medusaIntegrationTestRunner({
|
||||
expect(response.data.price_list).toEqual(
|
||||
expect.objectContaining({
|
||||
id: expect.any(String),
|
||||
created_at: expect.any(String),
|
||||
updated_at: expect.any(String),
|
||||
title: "new price list name",
|
||||
description: "new price list description",
|
||||
type: "override",
|
||||
status: "active",
|
||||
starts_at: expect.any(String),
|
||||
ends_at: expect.any(String),
|
||||
rules: {
|
||||
customer_group_id: [customerGroup.id],
|
||||
},
|
||||
@@ -492,11 +486,41 @@ medusaIntegrationTestRunner({
|
||||
],
|
||||
})
|
||||
)
|
||||
|
||||
// Updating prices should remove existing prices and create new ones
|
||||
response = await api.post(
|
||||
`admin/price-lists/${priceList.id}`,
|
||||
{
|
||||
prices: [
|
||||
{
|
||||
amount: 600,
|
||||
variant_id: variant.id,
|
||||
currency_code: "usd",
|
||||
rules: { region_id: region.id },
|
||||
},
|
||||
],
|
||||
},
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
expect(response.data.price_list).toEqual(
|
||||
expect.objectContaining({
|
||||
prices: [
|
||||
expect.objectContaining({
|
||||
id: expect.any(String),
|
||||
currency_code: "usd",
|
||||
amount: 600,
|
||||
variant_id: variant.id,
|
||||
rules: { region_id: region.id },
|
||||
}),
|
||||
],
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
describe("POST /admin/price-lists/:id/prices", () => {
|
||||
it("should upsert price list prices successfully", async () => {
|
||||
describe("POST /admin/price-lists/:id/prices/batch/add", () => {
|
||||
it("should add price list prices successfully", async () => {
|
||||
const priceSet = await createVariantPriceSet({
|
||||
container: appContainer,
|
||||
variantId: variant.id,
|
||||
@@ -527,16 +551,11 @@ medusaIntegrationTestRunner({
|
||||
currency_code: "usd",
|
||||
rules: { region_id: region.id },
|
||||
},
|
||||
{
|
||||
id: "test-price-id",
|
||||
variant_id: variant.id,
|
||||
amount: 200,
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
const response = await api.post(
|
||||
`admin/price-lists/${priceList.id}/prices`,
|
||||
`admin/price-lists/${priceList.id}/prices/batch/add`,
|
||||
data,
|
||||
adminHeaders
|
||||
)
|
||||
@@ -555,7 +574,7 @@ medusaIntegrationTestRunner({
|
||||
expect.objectContaining({
|
||||
id: "test-price-id",
|
||||
currency_code: "usd",
|
||||
amount: 200,
|
||||
amount: 5000,
|
||||
}),
|
||||
]),
|
||||
})
|
||||
@@ -563,8 +582,8 @@ medusaIntegrationTestRunner({
|
||||
})
|
||||
})
|
||||
|
||||
describe("DELETE /admin/price-lists/:id/prices", () => {
|
||||
it("should delete price list prices", async () => {
|
||||
describe("POST /admin/price-lists/:id/prices/batch/remove", () => {
|
||||
it("should remove price list prices successfully", async () => {
|
||||
const priceSet = await createVariantPriceSet({
|
||||
container: appContainer,
|
||||
variantId: variant.id,
|
||||
@@ -577,7 +596,6 @@ medusaIntegrationTestRunner({
|
||||
description: "test",
|
||||
prices: [
|
||||
{
|
||||
id: "test-price-id",
|
||||
amount: 5000,
|
||||
currency_code: "usd",
|
||||
price_set_id: priceSet.id,
|
||||
@@ -589,17 +607,21 @@ medusaIntegrationTestRunner({
|
||||
},
|
||||
])
|
||||
|
||||
let response = await api.delete(
|
||||
`/admin/price-lists/${priceList.id}/prices`,
|
||||
{ ...adminHeaders, data: { ids: ["test-price-id"] } }
|
||||
const psmaIdToDelete = priceList.price_set_money_amounts![0].id
|
||||
|
||||
const response = await api.post(
|
||||
`/admin/price-lists/${priceList.id}/prices/batch/remove`,
|
||||
{ ids: [psmaIdToDelete] },
|
||||
adminHeaders
|
||||
)
|
||||
|
||||
expect(response.status).toEqual(200)
|
||||
expect(response.data).toEqual({
|
||||
ids: ["test-price-id"],
|
||||
object: "price_list_prices",
|
||||
deleted: true,
|
||||
})
|
||||
expect(response.data.price_list).toEqual(
|
||||
expect.objectContaining({
|
||||
id: expect.any(String),
|
||||
prices: [],
|
||||
})
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import {
|
||||
AddPriceListPricesDTO,
|
||||
CreatePriceListPriceDTO,
|
||||
CreatePriceListPricesWorkflowStepDTO,
|
||||
IPricingModuleService,
|
||||
} from "@medusajs/types"
|
||||
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||
|
||||
export const createPriceListPricesStepId = "create-price-list-prices"
|
||||
export const createPriceListPricesStep = createStep(
|
||||
createPriceListPricesStepId,
|
||||
async (stepInput: CreatePriceListPricesWorkflowStepDTO, { container }) => {
|
||||
const { data, variant_price_map: variantPriceSetMap } = stepInput
|
||||
const priceListPricesToCreate: AddPriceListPricesDTO[] = []
|
||||
const pricingModule = container.resolve<IPricingModuleService>(
|
||||
ModuleRegistrationName.PRICING
|
||||
)
|
||||
|
||||
for (const createPriceListPricesData of data) {
|
||||
const { prices = [], id } = createPriceListPricesData
|
||||
const pricesToAdd: CreatePriceListPriceDTO[] = []
|
||||
|
||||
for (const price of prices) {
|
||||
pricesToAdd.push({
|
||||
...price,
|
||||
price_set_id: variantPriceSetMap[price.variant_id!],
|
||||
})
|
||||
}
|
||||
|
||||
if (pricesToAdd.length) {
|
||||
priceListPricesToCreate.push({
|
||||
price_list_id: id,
|
||||
prices: pricesToAdd,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
const createdPrices = await pricingModule.addPriceListPrices(
|
||||
priceListPricesToCreate
|
||||
)
|
||||
|
||||
return new StepResponse(
|
||||
null,
|
||||
createdPrices.map((p) => p.id)
|
||||
)
|
||||
},
|
||||
async (createdIds, { container }) => {
|
||||
if (!createdIds?.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const pricingModule = container.resolve<IPricingModuleService>(
|
||||
ModuleRegistrationName.PRICING
|
||||
)
|
||||
|
||||
if (createdIds.length) {
|
||||
await pricingModule.removePrices(createdIds)
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -1,20 +1,15 @@
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import {
|
||||
CreatePriceListDTO,
|
||||
CreatePriceListWorkflowInputDTO,
|
||||
CreatePriceListsWorkflowStepDTO,
|
||||
IPricingModuleService,
|
||||
} from "@medusajs/types"
|
||||
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||
|
||||
type WorkflowStepInput = {
|
||||
data: CreatePriceListWorkflowInputDTO[]
|
||||
variant_price_map: Record<string, string>
|
||||
}
|
||||
|
||||
export const createPriceListsStepId = "create-price-lists"
|
||||
export const createPriceListsStep = createStep(
|
||||
createPriceListsStepId,
|
||||
async (stepInput: WorkflowStepInput, { container }) => {
|
||||
async (stepInput: CreatePriceListsWorkflowStepDTO, { container }) => {
|
||||
const { data, variant_price_map: variantPriceMap } = stepInput
|
||||
|
||||
const pricingModule = container.resolve<IPricingModuleService>(
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import { IPricingModuleService } from "@medusajs/types"
|
||||
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||
|
||||
export const getExistingPriceListsPriceIdsStepId =
|
||||
"get-existing-price-lists-prices"
|
||||
export const getExistingPriceListsPriceIdsStep = createStep(
|
||||
getExistingPriceListsPriceIdsStepId,
|
||||
async (data: { price_list_ids: string[] }, { container }) => {
|
||||
const { price_list_ids: priceListIds = [] } = data
|
||||
const priceListPriceIdsMap: Record<string, string[]> = {}
|
||||
const pricingModule = container.resolve<IPricingModuleService>(
|
||||
ModuleRegistrationName.PRICING
|
||||
)
|
||||
|
||||
const existingPrices = priceListIds.length
|
||||
? await pricingModule.listPriceSetMoneyAmounts(
|
||||
{ price_list_id: priceListIds },
|
||||
{ relations: ["price_list"] }
|
||||
)
|
||||
: []
|
||||
|
||||
for (const price of existingPrices) {
|
||||
const priceListId = price.price_list!.id
|
||||
const prices = priceListPriceIdsMap[priceListId] || []
|
||||
|
||||
priceListPriceIdsMap[priceListId] = prices.concat(price.id)
|
||||
}
|
||||
|
||||
return new StepResponse(priceListPriceIdsMap)
|
||||
}
|
||||
)
|
||||
@@ -1,6 +1,9 @@
|
||||
export * from "./create-price-list-prices"
|
||||
export * from "./create-price-lists"
|
||||
export * from "./delete-price-lists"
|
||||
export * from "./get-existing-price-lists-price-ids"
|
||||
export * from "./remove-price-list-prices"
|
||||
export * from "./update-price-list-prices"
|
||||
export * from "./update-price-lists"
|
||||
export * from "./upsert-price-list-prices"
|
||||
export * from "./validate-price-lists"
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import {
|
||||
IPricingModuleService,
|
||||
PriceSetMoneyAmountDTO,
|
||||
UpdatePriceListPriceDTO,
|
||||
UpdatePriceListPricesDTO,
|
||||
UpdatePriceListPriceWorkflowStepDTO,
|
||||
} from "@medusajs/types"
|
||||
import { buildPriceSetPricesForModule } from "@medusajs/utils"
|
||||
import { createStep, StepResponse } from "@medusajs/workflows-sdk"
|
||||
|
||||
export const updatePriceListPricesStepId = "update-price-list-prices"
|
||||
export const updatePriceListPricesStep = createStep(
|
||||
updatePriceListPricesStepId,
|
||||
async (stepInput: UpdatePriceListPriceWorkflowStepDTO, { container }) => {
|
||||
const { data = [], variant_price_map: variantPriceSetMap } = stepInput
|
||||
const priceListPricesToUpdate: UpdatePriceListPricesDTO[] = []
|
||||
const priceIds: string[] = []
|
||||
const pricingModule = container.resolve<IPricingModuleService>(
|
||||
ModuleRegistrationName.PRICING
|
||||
)
|
||||
|
||||
for (const priceListData of data) {
|
||||
const pricesToUpdate: UpdatePriceListPriceDTO[] = []
|
||||
const { prices = [], id } = priceListData
|
||||
|
||||
for (const price of prices) {
|
||||
pricesToUpdate.push({
|
||||
...price,
|
||||
price_set_id: variantPriceSetMap[price.variant_id!],
|
||||
})
|
||||
|
||||
if (price.id) {
|
||||
priceIds.push(price.id)
|
||||
}
|
||||
}
|
||||
|
||||
priceListPricesToUpdate.push({
|
||||
price_list_id: id,
|
||||
prices: pricesToUpdate,
|
||||
})
|
||||
}
|
||||
|
||||
const existingPrices = priceIds.length
|
||||
? await pricingModule.listPriceSetMoneyAmounts(
|
||||
{ id: priceIds },
|
||||
{ relations: ["price_list"] }
|
||||
)
|
||||
: []
|
||||
|
||||
const priceListPsmaMap = new Map<string, PriceSetMoneyAmountDTO[]>()
|
||||
const dataBeforePriceUpdate: UpdatePriceListPricesDTO[] = []
|
||||
|
||||
for (const price of existingPrices) {
|
||||
const priceListId = price.price_list!.id
|
||||
const psmas = priceListPsmaMap.get(priceListId) || []
|
||||
|
||||
priceListPsmaMap.set(priceListId, psmas)
|
||||
}
|
||||
|
||||
for (const [priceListId, psmas] of Object.entries(priceListPsmaMap)) {
|
||||
dataBeforePriceUpdate.push({
|
||||
price_list_id: priceListId,
|
||||
prices: buildPriceSetPricesForModule(psmas),
|
||||
})
|
||||
}
|
||||
|
||||
await pricingModule.updatePriceListPrices(priceListPricesToUpdate)
|
||||
|
||||
return new StepResponse(null, dataBeforePriceUpdate)
|
||||
},
|
||||
async (dataBeforePriceUpdate, { container }) => {
|
||||
if (!dataBeforePriceUpdate?.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const pricingModule = container.resolve<IPricingModuleService>(
|
||||
ModuleRegistrationName.PRICING
|
||||
)
|
||||
|
||||
if (dataBeforePriceUpdate.length) {
|
||||
await pricingModule.updatePriceListPrices(dataBeforePriceUpdate)
|
||||
}
|
||||
}
|
||||
)
|
||||
@@ -8,20 +8,15 @@ import {
|
||||
UpdatePriceListPriceDTO,
|
||||
UpdatePriceListPriceWorkflowDTO,
|
||||
UpdatePriceListPricesDTO,
|
||||
UpdatePriceListWorkflowInputDTO,
|
||||
UpsertPriceListPricesWorkflowStepDTO,
|
||||
} from "@medusajs/types"
|
||||
import { buildPriceSetPricesForModule, promiseAll } from "@medusajs/utils"
|
||||
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||
|
||||
type WorkflowStepInput = {
|
||||
data: Pick<UpdatePriceListWorkflowInputDTO, "id" | "prices">[]
|
||||
variant_price_map: Record<string, string>
|
||||
}
|
||||
|
||||
export const upsertPriceListPricesStepId = "upsert-price-list-prices"
|
||||
export const upsertPriceListPricesStep = createStep(
|
||||
upsertPriceListPricesStepId,
|
||||
async (stepInput: WorkflowStepInput, { container }) => {
|
||||
async (stepInput: UpsertPriceListPricesWorkflowStepDTO, { container }) => {
|
||||
const { data, variant_price_map: variantPriceSetMap } = stepInput
|
||||
|
||||
const priceListPricesToUpdate: UpdatePriceListPricesDTO[] = []
|
||||
|
||||
@@ -6,12 +6,13 @@ import {
|
||||
} from "@medusajs/utils"
|
||||
import { StepResponse, createStep } from "@medusajs/workflows-sdk"
|
||||
|
||||
type WorkflowStepInput = Pick<UpdatePriceListWorkflowInputDTO, "prices">[]
|
||||
|
||||
export const validateVariantPriceLinksStepId = "validate-variant-price-links"
|
||||
export const validateVariantPriceLinksStep = createStep(
|
||||
validateVariantPriceLinksStepId,
|
||||
async (data: WorkflowStepInput, { container }) => {
|
||||
async (
|
||||
data: Pick<UpdatePriceListWorkflowInputDTO, "prices">[],
|
||||
{ container }
|
||||
) => {
|
||||
const remoteQuery = container.resolve(
|
||||
ContainerRegistrationKeys.REMOTE_QUERY
|
||||
)
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
import { CreatePriceListPricesWorkflowDTO } from "@medusajs/types"
|
||||
import {
|
||||
WorkflowData,
|
||||
createWorkflow,
|
||||
parallelize,
|
||||
} from "@medusajs/workflows-sdk"
|
||||
import {
|
||||
createPriceListPricesStep,
|
||||
validatePriceListsStep,
|
||||
validateVariantPriceLinksStep,
|
||||
} from "../steps"
|
||||
|
||||
export const createPriceListPricesWorkflowId = "create-price-list-prices"
|
||||
export const createPriceListPricesWorkflow = createWorkflow(
|
||||
createPriceListPricesWorkflowId,
|
||||
(
|
||||
input: WorkflowData<{
|
||||
data: CreatePriceListPricesWorkflowDTO[]
|
||||
}>
|
||||
): WorkflowData<void> => {
|
||||
const [_, variantPriceMap] = parallelize(
|
||||
validatePriceListsStep(input.data),
|
||||
validateVariantPriceLinksStep(input.data)
|
||||
)
|
||||
|
||||
createPriceListPricesStep({
|
||||
data: input.data,
|
||||
variant_price_map: variantPriceMap,
|
||||
})
|
||||
}
|
||||
)
|
||||
@@ -1,12 +1,10 @@
|
||||
import { createWorkflow, WorkflowData } from "@medusajs/workflows-sdk"
|
||||
import { deletePriceListsStep } from "../steps"
|
||||
|
||||
type WorkflowInput = { ids: string[] }
|
||||
|
||||
export const deletePriceListsWorkflowId = "delete-price-lists"
|
||||
export const deletePriceListsWorkflow = createWorkflow(
|
||||
deletePriceListsWorkflowId,
|
||||
(input: WorkflowData<WorkflowInput>): WorkflowData<void> => {
|
||||
(input: WorkflowData<{ ids: string[] }>): WorkflowData<void> => {
|
||||
return deletePriceListsStep(input.ids)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from "./create-price-list-prices"
|
||||
export * from "./create-price-lists"
|
||||
export * from "./delete-price-lists"
|
||||
export * from "./remove-price-list-prices"
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk"
|
||||
import { removePriceListPricesStep } from "../steps"
|
||||
|
||||
type WorkflowInput = { ids: string[] }
|
||||
|
||||
export const removePriceListPricesWorkflowId = "remove-price-list-prices"
|
||||
export const removePriceListPricesWorkflow = createWorkflow(
|
||||
removePriceListPricesWorkflowId,
|
||||
(input: WorkflowData<WorkflowInput>): WorkflowData<void> => {
|
||||
(input: WorkflowData<{ ids: string[] }>): WorkflowData<void> => {
|
||||
removePriceListPricesStep(input.ids)
|
||||
}
|
||||
)
|
||||
|
||||
@@ -6,33 +6,46 @@ import {
|
||||
transform,
|
||||
} from "@medusajs/workflows-sdk"
|
||||
import {
|
||||
createPriceListPricesStep,
|
||||
getExistingPriceListsPriceIdsStep,
|
||||
removePriceListPricesStep,
|
||||
updatePriceListsStep,
|
||||
upsertPriceListPricesStep,
|
||||
validatePriceListsStep,
|
||||
validateVariantPriceLinksStep,
|
||||
} from "../steps"
|
||||
|
||||
type WorkflowInput = { price_lists_data: UpdatePriceListWorkflowInputDTO[] }
|
||||
|
||||
export const updatePriceListsWorkflowId = "update-price-lists"
|
||||
export const updatePriceListsWorkflow = createWorkflow(
|
||||
updatePriceListsWorkflowId,
|
||||
(input: WorkflowData<WorkflowInput>): WorkflowData<void> => {
|
||||
(
|
||||
input: WorkflowData<{ price_lists_data: UpdatePriceListWorkflowInputDTO[] }>
|
||||
): WorkflowData<void> => {
|
||||
const [priceListsMap, variantPriceMap] = parallelize(
|
||||
validatePriceListsStep(input.price_lists_data),
|
||||
validateVariantPriceLinksStep(input.price_lists_data)
|
||||
)
|
||||
|
||||
const updatePricesInput = transform(
|
||||
{ priceListsMap, variantPriceMap, input },
|
||||
(data) => ({
|
||||
data: data.input.price_lists_data,
|
||||
price_lists_map: data.priceListsMap,
|
||||
variant_price_map: data.variantPriceMap,
|
||||
})
|
||||
const getPriceListPricesInput = transform({ priceListsMap }, (data) => ({
|
||||
price_list_ids: Object.keys(data.priceListsMap),
|
||||
}))
|
||||
|
||||
const priceListPriceIdMap = getExistingPriceListsPriceIdsStep(
|
||||
getPriceListPricesInput
|
||||
)
|
||||
|
||||
upsertPriceListPricesStep(updatePricesInput)
|
||||
const removePriceListPricesInput = transform(
|
||||
{ priceListPriceIdMap },
|
||||
(data) => Object.values(data.priceListPriceIdMap).flat(1)
|
||||
)
|
||||
|
||||
removePriceListPricesStep(removePriceListPricesInput)
|
||||
|
||||
const updatePricesInput = transform({ variantPriceMap, input }, (data) => ({
|
||||
data: data.input.price_lists_data,
|
||||
variant_price_map: data.variantPriceMap,
|
||||
}))
|
||||
|
||||
createPriceListPricesStep(updatePricesInput)
|
||||
|
||||
const updatePriceListInput = transform({ input }, (data) => {
|
||||
return data.input.price_lists_data.map((priceListData) => {
|
||||
|
||||
@@ -10,14 +10,14 @@ import {
|
||||
validateVariantPriceLinksStep,
|
||||
} from "../steps"
|
||||
|
||||
type WorkflowInput = {
|
||||
price_lists_data: Pick<UpdatePriceListWorkflowInputDTO, "id" | "prices">[]
|
||||
}
|
||||
|
||||
export const upsertPriceListPricesWorkflowId = "upsert-price-list-prices"
|
||||
export const upsertPriceListPricesWorkflow = createWorkflow(
|
||||
upsertPriceListPricesWorkflowId,
|
||||
(input: WorkflowData<WorkflowInput>): WorkflowData<void> => {
|
||||
(
|
||||
input: WorkflowData<{
|
||||
price_lists_data: Pick<UpdatePriceListWorkflowInputDTO, "id" | "prices">[]
|
||||
}>
|
||||
): WorkflowData<void> => {
|
||||
const [_, variantPriceMap] = parallelize(
|
||||
validatePriceListsStep(input.price_lists_data),
|
||||
validateVariantPriceLinksStep(input.price_lists_data)
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { createPriceListPricesWorkflow } from "@medusajs/core-flows"
|
||||
import {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "../../../../../../../types/routing"
|
||||
import { getPriceList } from "../../../../queries"
|
||||
import {
|
||||
adminPriceListRemoteQueryFields,
|
||||
defaultAdminPriceListFields,
|
||||
} from "../../../../query-config"
|
||||
import { AdminPostPriceListsPriceListPricesBatchAddReq } from "../../../../validators"
|
||||
|
||||
export const POST = async (
|
||||
req: AuthenticatedMedusaRequest<AdminPostPriceListsPriceListPricesBatchAddReq>,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const { prices } = req.validatedBody
|
||||
|
||||
const id = req.params.id
|
||||
const workflow = createPriceListPricesWorkflow(req.scope)
|
||||
const { errors } = await workflow.run({
|
||||
input: { data: [{ id, prices }] },
|
||||
throwOnError: false,
|
||||
})
|
||||
|
||||
if (Array.isArray(errors) && errors[0]) {
|
||||
throw errors[0].error
|
||||
}
|
||||
|
||||
const priceList = await getPriceList({
|
||||
id,
|
||||
container: req.scope,
|
||||
remoteQueryFields: adminPriceListRemoteQueryFields,
|
||||
apiFields: defaultAdminPriceListFields,
|
||||
})
|
||||
|
||||
res.status(200).json({ price_list: priceList })
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { removePriceListPricesWorkflow } from "@medusajs/core-flows"
|
||||
import {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "../../../../../../../types/routing"
|
||||
import { getPriceList } from "../../../../queries"
|
||||
import {
|
||||
adminPriceListRemoteQueryFields,
|
||||
defaultAdminPriceListFields,
|
||||
} from "../../../../query-config"
|
||||
import { AdminPostPriceListsPriceListPricesBatchRemoveReq } from "../../../../validators"
|
||||
|
||||
export const POST = async (
|
||||
req: AuthenticatedMedusaRequest<AdminPostPriceListsPriceListPricesBatchRemoveReq>,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const { ids } = req.validatedBody
|
||||
const id = req.params.id
|
||||
const workflow = removePriceListPricesWorkflow(req.scope)
|
||||
const { errors } = await workflow.run({
|
||||
input: { ids },
|
||||
throwOnError: false,
|
||||
})
|
||||
|
||||
if (Array.isArray(errors) && errors[0]) {
|
||||
throw errors[0].error
|
||||
}
|
||||
|
||||
const priceList = await getPriceList({
|
||||
id,
|
||||
container: req.scope,
|
||||
remoteQueryFields: adminPriceListRemoteQueryFields,
|
||||
apiFields: defaultAdminPriceListFields,
|
||||
})
|
||||
|
||||
res.status(200).json({ price_list: priceList })
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
import {
|
||||
removePriceListPricesWorkflow,
|
||||
upsertPriceListPricesWorkflow,
|
||||
} from "@medusajs/core-flows"
|
||||
import {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "../../../../../types/routing"
|
||||
import { listPriceLists } from "../../queries"
|
||||
import {
|
||||
adminPriceListRemoteQueryFields,
|
||||
defaultAdminPriceListFields,
|
||||
} from "../../query-config"
|
||||
import {
|
||||
AdminDeletePriceListsPriceListPricesReq,
|
||||
AdminPostPriceListsPriceListPricesReq,
|
||||
} from "../../validators"
|
||||
|
||||
export const POST = async (
|
||||
req: AuthenticatedMedusaRequest<AdminPostPriceListsPriceListPricesReq>,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const { prices } = req.validatedBody
|
||||
const id = req.params.id
|
||||
const workflow = upsertPriceListPricesWorkflow(req.scope)
|
||||
const { errors } = await workflow.run({
|
||||
input: {
|
||||
price_lists_data: [{ id, prices }],
|
||||
},
|
||||
throwOnError: false,
|
||||
})
|
||||
|
||||
if (Array.isArray(errors) && errors[0]) {
|
||||
throw errors[0].error
|
||||
}
|
||||
|
||||
const [[priceList]] = await listPriceLists({
|
||||
container: req.scope,
|
||||
remoteQueryFields: adminPriceListRemoteQueryFields,
|
||||
apiFields: defaultAdminPriceListFields,
|
||||
variables: { filters: { id }, skip: 0, take: 1 },
|
||||
})
|
||||
|
||||
res.status(200).json({ price_list: priceList })
|
||||
}
|
||||
|
||||
export const DELETE = async (
|
||||
req: AuthenticatedMedusaRequest<AdminDeletePriceListsPriceListPricesReq>,
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const { ids } = req.validatedBody
|
||||
const workflow = removePriceListPricesWorkflow(req.scope)
|
||||
|
||||
const { errors } = await workflow.run({
|
||||
input: { ids },
|
||||
throwOnError: false,
|
||||
})
|
||||
|
||||
if (Array.isArray(errors) && errors[0]) {
|
||||
throw errors[0].error
|
||||
}
|
||||
|
||||
res.status(200).json({
|
||||
ids,
|
||||
object: "price_list_prices",
|
||||
deleted: true,
|
||||
})
|
||||
}
|
||||
@@ -2,12 +2,11 @@ import {
|
||||
deletePriceListsWorkflow,
|
||||
updatePriceListsWorkflow,
|
||||
} from "@medusajs/core-flows"
|
||||
import { MedusaError } from "@medusajs/utils"
|
||||
import {
|
||||
AuthenticatedMedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "../../../../types/routing"
|
||||
import { listPriceLists } from "../queries"
|
||||
import { getPriceList } from "../queries"
|
||||
import {
|
||||
adminPriceListRemoteQueryFields,
|
||||
defaultAdminPriceListFields,
|
||||
@@ -19,24 +18,13 @@ export const GET = async (
|
||||
res: MedusaResponse
|
||||
) => {
|
||||
const id = req.params.id
|
||||
const [[priceList], count] = await listPriceLists({
|
||||
const priceList = await getPriceList({
|
||||
id,
|
||||
container: req.scope,
|
||||
remoteQueryFields: adminPriceListRemoteQueryFields,
|
||||
apiFields: req.retrieveConfig.select!,
|
||||
variables: {
|
||||
filters: { id },
|
||||
skip: 0,
|
||||
take: 1,
|
||||
},
|
||||
})
|
||||
|
||||
if (count === 0) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_FOUND,
|
||||
`Price list with id: ${id} was not found`
|
||||
)
|
||||
}
|
||||
|
||||
res.status(200).json({ price_list: priceList })
|
||||
}
|
||||
|
||||
@@ -56,11 +44,11 @@ export const POST = async (
|
||||
throw errors[0].error
|
||||
}
|
||||
|
||||
const [[priceList]] = await listPriceLists({
|
||||
const priceList = await getPriceList({
|
||||
id,
|
||||
container: req.scope,
|
||||
remoteQueryFields: adminPriceListRemoteQueryFields,
|
||||
apiFields: defaultAdminPriceListFields,
|
||||
variables: { filters: { id }, skip: 0, take: 1 },
|
||||
})
|
||||
|
||||
res.status(200).json({ price_list: priceList })
|
||||
|
||||
@@ -3,10 +3,10 @@ import { MiddlewareRoute } from "../../../loaders/helpers/routing/types"
|
||||
import { authenticate } from "../../../utils/authenticate-middleware"
|
||||
import * as QueryConfig from "./query-config"
|
||||
import {
|
||||
AdminDeletePriceListsPriceListPricesReq,
|
||||
AdminGetPriceListsParams,
|
||||
AdminGetPriceListsPriceListParams,
|
||||
AdminPostPriceListsPriceListPricesReq,
|
||||
AdminPostPriceListsPriceListPricesBatchAddReq,
|
||||
AdminPostPriceListsPriceListPricesBatchRemoveReq,
|
||||
AdminPostPriceListsPriceListReq,
|
||||
AdminPostPriceListsReq,
|
||||
} from "./validators"
|
||||
@@ -49,12 +49,14 @@ export const adminPriceListsRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
},
|
||||
{
|
||||
method: ["POST"],
|
||||
matcher: "/admin/price-lists/:id/prices",
|
||||
middlewares: [transformBody(AdminPostPriceListsPriceListPricesReq)],
|
||||
matcher: "/admin/price-lists/:id/prices/batch/add",
|
||||
middlewares: [transformBody(AdminPostPriceListsPriceListPricesBatchAddReq)],
|
||||
},
|
||||
{
|
||||
method: ["DELETE"],
|
||||
matcher: "/admin/price-lists/:id/prices",
|
||||
middlewares: [transformBody(AdminDeletePriceListsPriceListPricesReq)],
|
||||
method: ["POST"],
|
||||
matcher: "/admin/price-lists/:id/prices/batch/remove",
|
||||
middlewares: [
|
||||
transformBody(AdminPostPriceListsPriceListPricesBatchRemoveReq),
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
import { MedusaContainer } from "@medusajs/types"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
MedusaError,
|
||||
isPresent,
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
import { AdminPriceListRemoteQueryDTO } from "../types"
|
||||
import { buildPriceListResponse } from "./"
|
||||
|
||||
export async function getPriceList({
|
||||
id,
|
||||
container,
|
||||
remoteQueryFields,
|
||||
apiFields,
|
||||
}: {
|
||||
id: string
|
||||
container: MedusaContainer
|
||||
remoteQueryFields: string[]
|
||||
apiFields: string[]
|
||||
}): Promise<AdminPriceListRemoteQueryDTO> {
|
||||
const remoteQuery = container.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
const queryObject = remoteQueryObjectFromString({
|
||||
entryPoint: "price_list",
|
||||
fields: remoteQueryFields,
|
||||
variables: { id },
|
||||
})
|
||||
|
||||
const priceLists = await remoteQuery(queryObject)
|
||||
const [sanitizedPriceList] = buildPriceListResponse(priceLists, apiFields)
|
||||
|
||||
if (!isPresent(sanitizedPriceList)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_FOUND,
|
||||
`Price list with id: ${id} was not found`
|
||||
)
|
||||
}
|
||||
|
||||
return sanitizedPriceList
|
||||
}
|
||||
@@ -1 +1,23 @@
|
||||
import {
|
||||
buildPriceListRules,
|
||||
buildPriceSetPricesForCore,
|
||||
} from "@medusajs/utils"
|
||||
import { cleanResponseData } from "../../../../utils/clean-response-data"
|
||||
import { AdminPriceListRemoteQueryDTO } from "../types"
|
||||
|
||||
export * from "./get-price-list"
|
||||
export * from "./list-price-lists"
|
||||
|
||||
export function buildPriceListResponse(
|
||||
priceLists,
|
||||
apiFields
|
||||
): AdminPriceListRemoteQueryDTO[] {
|
||||
for (const priceList of priceLists) {
|
||||
priceList.rules = buildPriceListRules(priceList.price_list_rules || [])
|
||||
priceList.prices = buildPriceSetPricesForCore(
|
||||
priceList.price_set_money_amounts || []
|
||||
)
|
||||
}
|
||||
|
||||
return priceLists.map((priceList) => cleanResponseData(priceList, apiFields))
|
||||
}
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
import { MedusaContainer } from "@medusajs/types"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
buildPriceListRules,
|
||||
buildPriceSetPricesForCore,
|
||||
remoteQueryObjectFromString,
|
||||
} from "@medusajs/utils"
|
||||
import { cleanResponseData } from "../../../../utils/clean-response-data"
|
||||
import { AdminPriceListRemoteQueryDTO } from "../types"
|
||||
import { buildPriceListResponse } from "./"
|
||||
|
||||
export async function listPriceLists({
|
||||
container,
|
||||
@@ -32,16 +30,7 @@ export async function listPriceLists({
|
||||
return [[], 0]
|
||||
}
|
||||
|
||||
for (const priceList of priceLists) {
|
||||
priceList.rules = buildPriceListRules(priceList.price_list_rules || [])
|
||||
priceList.prices = buildPriceSetPricesForCore(
|
||||
priceList.price_set_money_amounts || []
|
||||
)
|
||||
}
|
||||
|
||||
const sanitizedPriceLists: AdminPriceListRemoteQueryDTO[] = priceLists.map(
|
||||
(priceList) => cleanResponseData(priceList, apiFields)
|
||||
)
|
||||
const sanitizedPriceLists = buildPriceListResponse(priceLists, apiFields)
|
||||
|
||||
return [sanitizedPriceLists, metadata.count]
|
||||
}
|
||||
|
||||
@@ -98,21 +98,20 @@ export class AdminPostPriceListsPriceListReq {
|
||||
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
prices: (AdminPriceListPricesCreateReq | AdminPriceListPricesUpdateReq)[]
|
||||
prices: AdminPriceListPricesCreateReq[]
|
||||
|
||||
@IsOptional()
|
||||
@IsObject()
|
||||
rules?: Record<string, string[]>
|
||||
}
|
||||
|
||||
export class AdminPostPriceListsPriceListPricesReq {
|
||||
export class AdminPostPriceListsPriceListPricesBatchAddReq {
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
prices: (AdminPriceListPricesCreateReq | AdminPriceListPricesUpdateReq)[]
|
||||
prices: AdminPriceListPricesCreateReq[]
|
||||
}
|
||||
|
||||
export class AdminDeletePriceListsPriceListPricesReq {
|
||||
@IsOptional()
|
||||
export class AdminPostPriceListsPriceListPricesBatchRemoveReq {
|
||||
@IsArray()
|
||||
@IsString({ each: true })
|
||||
ids: string[]
|
||||
|
||||
@@ -37,5 +37,40 @@ export interface UpdatePriceListWorkflowInputDTO {
|
||||
ends_at?: string | null
|
||||
status?: PriceListStatus
|
||||
rules?: Record<string, string[]>
|
||||
prices?: (UpdatePriceListPriceWorkflowDTO | CreatePriceListPriceWorkflowDTO)[]
|
||||
prices?: CreatePriceListPriceWorkflowDTO[]
|
||||
}
|
||||
|
||||
export interface UpdatePriceListPricesWorkflowDTO {
|
||||
id: string
|
||||
prices: UpdatePriceListPriceWorkflowDTO[]
|
||||
}
|
||||
|
||||
export interface CreatePriceListPricesWorkflowDTO {
|
||||
id: string
|
||||
prices: CreatePriceListPriceWorkflowDTO[]
|
||||
}
|
||||
|
||||
export interface UpdatePriceListPriceWorkflowDTO {
|
||||
data: Pick<UpdatePriceListWorkflowInputDTO, "id" | "prices">[]
|
||||
variant_price_map: Record<string, string>
|
||||
}
|
||||
|
||||
export interface UpdatePriceListPriceWorkflowStepDTO {
|
||||
data?: UpdatePriceListPricesWorkflowDTO[]
|
||||
variant_price_map: Record<string, string>
|
||||
}
|
||||
|
||||
export interface UpsertPriceListPricesWorkflowStepDTO {
|
||||
data: Pick<UpdatePriceListWorkflowInputDTO, "id" | "prices">[]
|
||||
variant_price_map: Record<string, string>
|
||||
}
|
||||
|
||||
export interface CreatePriceListsWorkflowStepDTO {
|
||||
data: CreatePriceListWorkflowInputDTO[]
|
||||
variant_price_map: Record<string, string>
|
||||
}
|
||||
|
||||
export interface CreatePriceListPricesWorkflowStepDTO {
|
||||
data: (Pick<CreatePriceListWorkflowInputDTO, "prices"> & { id: string })[]
|
||||
variant_price_map: Record<string, string>
|
||||
}
|
||||
|
||||
@@ -1,3 +1,2 @@
|
||||
export * from "./create-price-list"
|
||||
export * from "./update-price-list"
|
||||
export * from "./remove-price-list"
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import { CreatePriceListRules, PriceListStatus } from "../../pricing"
|
||||
|
||||
import { UpdateProductVariantPricesInputDTO } from "../product"
|
||||
|
||||
export type PriceListVariantPriceDTO = UpdateProductVariantPricesInputDTO & {
|
||||
variant_id?: string
|
||||
price_set_id?: string
|
||||
}
|
||||
|
||||
export interface UpdatePriceListWorkflowDTO {
|
||||
id: string
|
||||
name?: string
|
||||
starts_at?: Date
|
||||
ends_at?: Date
|
||||
status?: PriceListStatus
|
||||
rules?: CreatePriceListRules
|
||||
prices?: PriceListVariantPriceDTO[]
|
||||
customer_groups?: {
|
||||
id: string
|
||||
}[]
|
||||
}
|
||||
|
||||
export interface UpdatePriceListWorkflowInputDTO {
|
||||
price_lists: UpdatePriceListWorkflowDTO[]
|
||||
}
|
||||
Reference in New Issue
Block a user