-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: Add HTTP endpoints and workflows for price preference management #7960
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,221 @@ | ||
import { medusaIntegrationTestRunner } from "medusa-test-utils" | ||
import { | ||
createAdminUser, | ||
adminHeaders, | ||
} from "../../../../helpers/create-admin-user" | ||
|
||
jest.setTimeout(30000) | ||
|
||
medusaIntegrationTestRunner({ | ||
env: {}, | ||
testSuite: ({ dbConnection, getContainer, api }) => { | ||
let pricePreference1 | ||
let pricePreference2 | ||
|
||
beforeEach(async () => { | ||
const container = getContainer() | ||
await createAdminUser(dbConnection, adminHeaders, container) | ||
|
||
pricePreference1 = ( | ||
await api.post( | ||
"/admin/price-preferences", | ||
{ | ||
attribute: "region_id", | ||
value: "region-1", | ||
is_tax_inclusive: true, | ||
}, | ||
adminHeaders | ||
) | ||
).data.price_preference | ||
|
||
pricePreference2 = ( | ||
await api.post( | ||
"/admin/price-preferences", | ||
{ | ||
attribute: "currency_code", | ||
value: "EUR", | ||
is_tax_inclusive: true, | ||
}, | ||
adminHeaders | ||
) | ||
).data.price_preference | ||
}) | ||
|
||
describe("/admin/price-preferences", () => { | ||
describe("POST /admin/price-preferences", () => { | ||
it("creates a price preference", async () => { | ||
const newPricePreference = ( | ||
await api.post( | ||
"/admin/price-preferences", | ||
{ | ||
attribute: "region_id", | ||
value: "region-2", | ||
is_tax_inclusive: true, | ||
}, | ||
adminHeaders | ||
) | ||
).data.price_preference | ||
|
||
expect(newPricePreference).toEqual( | ||
expect.objectContaining({ | ||
attribute: "region_id", | ||
value: "region-2", | ||
is_tax_inclusive: true, | ||
}) | ||
) | ||
}) | ||
|
||
it("creates a price preference with false tax inclusivity by default", async () => { | ||
const newPricePreference = ( | ||
await api.post( | ||
"/admin/price-preferences", | ||
{ | ||
attribute: "region_id", | ||
value: "region-2", | ||
}, | ||
adminHeaders | ||
) | ||
).data.price_preference | ||
|
||
expect(newPricePreference).toEqual( | ||
expect.objectContaining({ | ||
attribute: "region_id", | ||
value: "region-2", | ||
is_tax_inclusive: false, | ||
}) | ||
) | ||
}) | ||
}) | ||
|
||
describe("GET /admin/price-preferences", () => { | ||
it("returns a list of price preferences", async () => { | ||
const response = ( | ||
await api.get("/admin/price-preferences", adminHeaders) | ||
).data.price_preferences | ||
|
||
expect(response).toEqual( | ||
expect.arrayContaining([ | ||
expect.objectContaining({ | ||
attribute: "region_id", | ||
value: "region-1", | ||
is_tax_inclusive: true, | ||
}), | ||
expect.objectContaining({ | ||
attribute: "currency_code", | ||
value: "EUR", | ||
is_tax_inclusive: true, | ||
}), | ||
]) | ||
) | ||
}) | ||
it("filters price preferences by attribute", async () => { | ||
const response = ( | ||
await api.get( | ||
"/admin/price-preferences?attribute=region_id", | ||
adminHeaders | ||
) | ||
).data.price_preferences | ||
|
||
expect(response).toEqual([ | ||
expect.objectContaining({ | ||
attribute: "region_id", | ||
value: "region-1", | ||
is_tax_inclusive: true, | ||
}), | ||
]) | ||
}) | ||
}) | ||
|
||
describe("GET /admin/price-preferences/:id", () => { | ||
it("returns a price preference by :id", async () => { | ||
const response = ( | ||
await api.get( | ||
`/admin/price-preferences/${pricePreference1.id}`, | ||
adminHeaders | ||
) | ||
).data.price_preference | ||
|
||
expect(response).toEqual( | ||
expect.objectContaining({ | ||
attribute: "region_id", | ||
value: "region-1", | ||
is_tax_inclusive: true, | ||
}) | ||
) | ||
}) | ||
}) | ||
|
||
describe("POST /admin/price-preferences/:id", () => { | ||
it("updates a price preference", async () => { | ||
const response = ( | ||
await api.post( | ||
`/admin/price-preferences/${pricePreference1.id}`, | ||
{ | ||
attribute: "region_id", | ||
value: "region-2", | ||
is_tax_inclusive: false, | ||
}, | ||
adminHeaders | ||
) | ||
).data.price_preference | ||
|
||
expect(response).toEqual( | ||
expect.objectContaining({ | ||
attribute: "region_id", | ||
value: "region-2", | ||
is_tax_inclusive: false, | ||
}) | ||
) | ||
}) | ||
it("updates the tax inclusivity in the price preference", async () => { | ||
const response = ( | ||
await api.post( | ||
`/admin/price-preferences/${pricePreference1.id}`, | ||
{ | ||
is_tax_inclusive: false, | ||
}, | ||
adminHeaders | ||
) | ||
).data.price_preference | ||
|
||
expect(response).toEqual( | ||
expect.objectContaining({ | ||
attribute: "region_id", | ||
value: "region-1", | ||
is_tax_inclusive: false, | ||
}) | ||
) | ||
}) | ||
}) | ||
|
||
describe("DELETE /admin/price-preferences/:id", () => { | ||
it("Deletes a price preference", async () => { | ||
const deleteResponse = await api.delete( | ||
`/admin/price-preferences/${pricePreference1.id}`, | ||
adminHeaders | ||
) | ||
|
||
const remainingPricePreferences = ( | ||
await api.get("/admin/price-preferences", adminHeaders) | ||
).data.price_preferences | ||
|
||
expect(deleteResponse.data).toEqual( | ||
expect.objectContaining({ | ||
id: pricePreference1.id, | ||
object: "price_preference", | ||
deleted: true, | ||
}) | ||
) | ||
|
||
expect(remainingPricePreferences).toEqual([ | ||
expect.objectContaining({ | ||
attribute: "currency_code", | ||
value: "EUR", | ||
is_tax_inclusive: true, | ||
}), | ||
]) | ||
}) | ||
}) | ||
}) | ||
}, | ||
}) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
export * from "./steps" | ||
export * from "./workflows" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { IPricingModuleService } from "@medusajs/types" | ||
import { PricingWorkflow } from "@medusajs/types/dist/workflow" | ||
import { ModuleRegistrationName } from "@medusajs/utils" | ||
import { StepResponse, createStep } from "@medusajs/workflows-sdk" | ||
|
||
type StepInput = PricingWorkflow.CreatePricePreferencesWorkflowInput[] | ||
|
||
export const createPricePreferencesStepId = "create-price-preferences" | ||
export const createPricePreferencesStep = createStep( | ||
createPricePreferencesStepId, | ||
async (data: StepInput, { container }) => { | ||
const pricingModule = container.resolve<IPricingModuleService>( | ||
ModuleRegistrationName.PRICING | ||
) | ||
|
||
const pricePreferences = await pricingModule.createPricePreferences(data) | ||
|
||
return new StepResponse( | ||
pricePreferences, | ||
pricePreferences.map((pricePreference) => pricePreference.id) | ||
) | ||
}, | ||
async (pricePreferences, { container }) => { | ||
if (!pricePreferences?.length) { | ||
return | ||
} | ||
|
||
const pricingModule = container.resolve<IPricingModuleService>( | ||
ModuleRegistrationName.PRICING | ||
) | ||
|
||
await pricingModule.deletePricePreferences(pricePreferences) | ||
} | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { IPricingModuleService } from "@medusajs/types" | ||
import { ModuleRegistrationName } from "@medusajs/utils" | ||
import { StepResponse, createStep } from "@medusajs/workflows-sdk" | ||
|
||
export const deletePricePreferencesStepId = "delete-price-preferences" | ||
export const deletePricePreferencesStep = createStep( | ||
deletePricePreferencesStepId, | ||
async (ids: string[], { container }) => { | ||
const service = container.resolve<IPricingModuleService>( | ||
ModuleRegistrationName.PRICING | ||
) | ||
|
||
await service.softDeletePricePreferences(ids) | ||
|
||
return new StepResponse(void 0, ids) | ||
}, | ||
async (prevIds, { container }) => { | ||
if (!prevIds?.length) { | ||
return | ||
} | ||
|
||
const service = container.resolve<IPricingModuleService>( | ||
ModuleRegistrationName.PRICING | ||
) | ||
|
||
await service.restorePricePreferences(prevIds) | ||
} | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,5 @@ | ||
export * from "./create-price-sets" | ||
export * from "./update-price-sets" | ||
export * from "./create-price-preferences" | ||
export * from "./update-price-preferences" | ||
export * from "./delete-price-preferences" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { PricingWorkflow, IPricingModuleService } from "@medusajs/types" | ||
import { | ||
ModuleRegistrationName, | ||
getSelectsAndRelationsFromObjectArray, | ||
} from "@medusajs/utils" | ||
import { StepResponse, createStep } from "@medusajs/workflows-sdk" | ||
|
||
type StepInput = PricingWorkflow.UpdatePricePreferencesWorkflowInput | ||
|
||
export const updatePricePreferencesStepId = "update-price-preferences" | ||
export const updatePricePreferencesStep = createStep( | ||
updatePricePreferencesStepId, | ||
async (input: StepInput, { container }) => { | ||
const service = container.resolve<IPricingModuleService>( | ||
ModuleRegistrationName.PRICING | ||
) | ||
|
||
const { selects, relations } = getSelectsAndRelationsFromObjectArray([ | ||
input.update, | ||
]) | ||
|
||
const prevData = await service.listPricePreferences(input.selector, { | ||
select: selects, | ||
relations, | ||
}) | ||
|
||
const updatedPricePreferences = await service.updatePricePreferences( | ||
input.selector, | ||
input.update | ||
) | ||
|
||
return new StepResponse(updatedPricePreferences, prevData) | ||
}, | ||
async (prevData, { container }) => { | ||
if (!prevData?.length) { | ||
return | ||
} | ||
|
||
const service = container.resolve<IPricingModuleService>( | ||
ModuleRegistrationName.PRICING | ||
) | ||
|
||
await service.upsertPricePreferences(prevData) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. q: shouldn't this be update as well? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We pass the prevData as an array of entities, and only the Upsert method accepts such input. |
||
} | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { PricingWorkflow } from "@medusajs/types" | ||
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk" | ||
import { createPricePreferencesStep } from "../steps" | ||
|
||
type WorkflowInputData = PricingWorkflow.CreatePricePreferencesWorkflowInput[] | ||
|
||
export const createPricePreferencesWorkflowId = "create-price-preferences" | ||
export const createPricePreferencesWorkflow = createWorkflow( | ||
createPricePreferencesWorkflowId, | ||
(input: WorkflowData<WorkflowInputData>) => { | ||
return createPricePreferencesStep(input) | ||
} | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk" | ||
import { deletePricePreferencesStep } from "../steps" | ||
|
||
export const deletePricePreferencesWorkflowId = "delete-price-preferences" | ||
export const deletePricePreferencesWorkflow = createWorkflow( | ||
deletePricePreferencesWorkflowId, | ||
(input: WorkflowData<string[]>) => { | ||
return deletePricePreferencesStep(input) | ||
} | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
export * from "./create-price-preferences" | ||
export * from "./update-price-preferences" | ||
export * from "./delete-price-preferences" |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { PricingWorkflow } from "@medusajs/types" | ||
import { WorkflowData, createWorkflow } from "@medusajs/workflows-sdk" | ||
import { updatePricePreferencesStep } from "../steps" | ||
|
||
type WorkflowInputData = PricingWorkflow.UpdatePricePreferencesWorkflowInput | ||
|
||
export const updatePricePreferencesWorkflowId = "update-price-preferences" | ||
export const updatePricePreferencesWorkflow = createWorkflow( | ||
updatePricePreferencesWorkflowId, | ||
(input: WorkflowData<WorkflowInputData>) => { | ||
return updatePricePreferencesStep(input) | ||
} | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
damn the automerge was faster 😄 I'll open a new PR now anyway and address this.