feat(medusa,pricing,types): added get endpoints for pricing rule types (#6678)

what:

- adds list endpoint for rule types
- adds get endpoint for rule types
This commit is contained in:
Riqwan Thamir
2024-03-12 18:35:24 +01:00
committed by GitHub
parent f0c8142635
commit d4b921f3db
14 changed files with 312 additions and 14 deletions
+7
View File
@@ -0,0 +1,7 @@
---
"@medusajs/pricing": patch
"@medusajs/medusa": patch
"@medusajs/types": patch
---
feat(medusa,pricing,types): added get endpoints for pricing rule types
@@ -0,0 +1,112 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { IPricingModuleService, RuleTypeDTO } from "@medusajs/types"
import { medusaIntegrationTestRunner } from "medusa-test-utils"
import { createAdminUser } from "../../../../helpers/create-admin-user"
jest.setTimeout(50000)
const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = { headers: { "x-medusa-access-token": "test_token" } }
medusaIntegrationTestRunner({
env,
testSuite: ({ dbConnection, getContainer, api }) => {
describe("Admin: Pricing Rule Types API", () => {
let appContainer
let pricingModule: IPricingModuleService
let ruleTypes: RuleTypeDTO[]
beforeAll(async () => {
appContainer = getContainer()
pricingModule = appContainer.resolve(ModuleRegistrationName.PRICING)
})
beforeEach(async () => {
await createAdminUser(dbConnection, adminHeaders, appContainer)
ruleTypes = await pricingModule.createRuleTypes([
{ name: "Customer Group ID", rule_attribute: "customer_group_id" },
{ name: "Region ID", rule_attribute: "region_id" },
])
})
describe("GET /admin/pricing", () => {
it("should get all rule types and its prices with rules", async () => {
let response = await api.get(
`/admin/pricing/rule-types`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.count).toEqual(2)
expect(response.data.rule_types).toEqual([
expect.objectContaining({ id: expect.any(String) }),
expect.objectContaining({ id: expect.any(String) }),
])
response = await api.get(
`/admin/pricing/rule-types?fields=id,rule_attribute,created_at`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.count).toEqual(2)
expect(response.data.rule_types).toEqual(
expect.arrayContaining([
{
id: ruleTypes[0].id,
rule_attribute: ruleTypes[0].rule_attribute,
created_at: expect.any(String),
},
{
id: ruleTypes[1].id,
rule_attribute: ruleTypes[1].rule_attribute,
created_at: expect.any(String),
},
])
)
})
})
describe("GET /admin/pricing/:id", () => {
it("should retrieve a rule type and its prices with rules", async () => {
const ruleType = ruleTypes[0]
let response = await api.get(
`/admin/pricing/rule-types/${ruleType.id}`,
adminHeaders
)
expect(response.status).toEqual(200)
expect(response.data.rule_type).toEqual(
expect.objectContaining({
id: ruleType.id,
})
)
response = await api.get(
`/admin/pricing/rule-types/${ruleType.id}?fields=id,created_at`,
adminHeaders
)
expect(response.data.rule_type).toEqual({
id: ruleType.id,
created_at: expect.any(String),
})
})
it("should throw an error when rule type is not found", async () => {
const error = await api
.get(`/admin/pricing/rule-types/does-not-exist`, adminHeaders)
.catch((e) => e)
expect(error.response.status).toBe(404)
expect(error.response.data).toEqual({
type: "not_found",
message: "RuleType with id: does-not-exist was not found",
})
})
})
})
},
})
@@ -0,0 +1,35 @@
import { transformQuery } from "../../../api/middlewares"
import { MiddlewareRoute } from "../../../loaders/helpers/routing/types"
import { authenticate } from "../../../utils/authenticate-middleware"
import * as QueryConfig from "./query-config"
import {
AdminGetPricingRuleTypesParams,
AdminGetPricingRuleTypesRuleTypeParams,
} from "./validators"
export const adminPricingRoutesMiddlewares: MiddlewareRoute[] = [
{
matcher: "/admin/pricing*",
middlewares: [authenticate("admin", ["bearer", "session"])],
},
{
method: ["GET"],
matcher: "/admin/pricing/rule-types",
middlewares: [
transformQuery(
AdminGetPricingRuleTypesParams,
QueryConfig.listTransformQueryConfig
),
],
},
{
method: ["GET"],
matcher: "/admin/pricing/rule-types/:id",
middlewares: [
transformQuery(
AdminGetPricingRuleTypesRuleTypeParams,
QueryConfig.retrieveTransformQueryConfig
),
],
},
]
@@ -0,0 +1,20 @@
export const defaultAdminPricingRuleTypeRelations = []
export const allowedAdminPricingRuleTypeRelations = []
export const defaultAdminPricingRuleTypeFields = [
"id",
"name",
"rule_attribute",
"default_priority",
]
export const retrieveTransformQueryConfig = {
defaultFields: defaultAdminPricingRuleTypeFields,
defaultRelations: defaultAdminPricingRuleTypeRelations,
allowedRelations: allowedAdminPricingRuleTypeRelations,
isList: false,
}
export const listTransformQueryConfig = {
...retrieveTransformQueryConfig,
isList: true,
}
@@ -0,0 +1,23 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { IPricingModuleService } from "@medusajs/types"
import {
AuthenticatedMedusaRequest,
MedusaResponse,
} from "../../../../../types/routing"
import { AdminGetPricingRuleTypesRuleTypeParams } from "../../validators"
export const GET = async (
req: AuthenticatedMedusaRequest<AdminGetPricingRuleTypesRuleTypeParams>,
res: MedusaResponse
) => {
const pricingModule: IPricingModuleService = req.scope.resolve(
ModuleRegistrationName.PRICING
)
const ruleType = await pricingModule.retrieveRuleType(req.params.id, {
select: req.retrieveConfig.select,
relations: req.retrieveConfig.relations,
})
res.status(200).json({ rule_type: ruleType })
}
@@ -0,0 +1,30 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { IPricingModuleService } from "@medusajs/types"
import {
AuthenticatedMedusaRequest,
MedusaResponse,
} from "../../../../types/routing"
import { AdminGetPricingRuleTypesParams } from "../validators"
export const GET = async (
req: AuthenticatedMedusaRequest<AdminGetPricingRuleTypesParams>,
res: MedusaResponse
) => {
const pricingModule: IPricingModuleService = req.scope.resolve(
ModuleRegistrationName.PRICING
)
const [ruleTypes, count] = await pricingModule.listAndCountRuleTypes(
req.filterableFields,
req.listConfig
)
const { limit, offset } = req.validatedQuery
res.json({
count,
rule_types: ruleTypes,
offset,
limit,
})
}
@@ -0,0 +1,12 @@
import { IsOptional, IsString } from "class-validator"
import { FindParams, extendedFindParamsMixin } from "../../../types/common"
export class AdminGetPricingRuleTypesRuleTypeParams extends FindParams {}
export class AdminGetPricingRuleTypesParams extends extendedFindParamsMixin({
limit: 100,
offset: 0,
}) {
@IsString()
@IsOptional()
rule_attribute?: string[]
}
@@ -8,6 +8,7 @@ import { adminCustomerRoutesMiddlewares } from "./admin/customers/middlewares"
import { adminInviteRoutesMiddlewares } from "./admin/invites/middlewares"
import { adminPaymentRoutesMiddlewares } from "./admin/payments/middlewares"
import { adminPriceListsRoutesMiddlewares } from "./admin/price-lists/middlewares"
import { adminPricingRoutesMiddlewares } from "./admin/pricing/middlewares"
import { adminProductRoutesMiddlewares } from "./admin/products/middlewares"
import { adminPromotionRoutesMiddlewares } from "./admin/promotions/middlewares"
import { adminRegionRoutesMiddlewares } from "./admin/regions/middlewares"
@@ -49,5 +50,6 @@ export const config: MiddlewaresConfig = {
...adminPaymentRoutesMiddlewares,
...adminPriceListsRoutesMiddlewares,
...adminCollectionRoutesMiddlewares,
...adminPricingRoutesMiddlewares,
],
}
@@ -116,8 +116,7 @@
}
],
"checks": [],
"foreignKeys": {
}
"foreignKeys": {}
},
{
"columns": {
@@ -520,6 +519,28 @@
"nullable": false,
"default": "0",
"mappedType": "integer"
},
"created_at": {
"name": "created_at",
"type": "timestamptz",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"length": 6,
"default": "now()",
"mappedType": "datetime"
},
"updated_at": {
"name": "updated_at",
"type": "timestamptz",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"length": 6,
"default": "now()",
"mappedType": "datetime"
}
},
"name": "rule_type",
@@ -24,8 +24,9 @@ export class Migration20230929122253 extends Migration {
)
this.addSql(
'create table "rule_type" ("id" text not null, "name" text not null, "rule_attribute" text not null, "default_priority" integer not null default 0, constraint "rule_type_pkey" primary key ("id"));'
'create table "rule_type" ("id" text not null, "name" text not null, "rule_attribute" text not null, "default_priority" integer not null default 0, "created_at" timestamptz not null default now(), "updated_at" timestamptz not null default now(), constraint "rule_type_pkey" primary key ("id"));'
)
this.addSql(
'create index "IDX_rule_type_rule_attribute" on "rule_type" ("rule_attribute");'
)
+6 -3
View File
@@ -6,9 +6,8 @@ import {
Filter,
Index,
ManyToMany,
ManyToOne,
OneToOne,
OnInit,
OneToOne,
OptionalProps,
PrimaryKey,
Property,
@@ -30,7 +29,11 @@ class MoneyAmount {
@PrimaryKey({ columnType: "text" })
id!: string
@Property({ columnType: "text", nullable: true })
@Property({
columnType: "text",
nullable: true,
index: "IDX_money_amount_currency_code",
})
currency_code: string | null
@ManyToMany({
+15
View File
@@ -32,6 +32,21 @@ class RuleType {
@ManyToMany(() => PriceSet, (priceSet) => priceSet.rule_types)
price_sets = new Collection<PriceSet>(this)
@Property({
onCreate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
created_at: Date
@Property({
onCreate: () => new Date(),
onUpdate: () => new Date(),
columnType: "timestamptz",
defaultRaw: "now()",
})
updated_at: Date
@BeforeCreate()
onCreate() {
this.id = generateEntityId(this.id, "rul-typ")
@@ -19,6 +19,15 @@ export interface RuleTypeDTO {
name: string
rule_attribute: string
default_priority: number
/**
* The creation date of the rule type.
*/
created_at?: Date | string
/**
* The update date of the rule type.
*/
updated_at?: Date | string
}
export interface FilterableRuleTypeProps
+16 -8
View File
@@ -2,7 +2,7 @@ import { BaseFilterable } from "../../dal"
/**
* @interface
*
*
* A rule type's data.
*/
export interface RuleTypeDTO {
@@ -15,20 +15,28 @@ export interface RuleTypeDTO {
*/
name: string
/**
* The unique name used to later identify the rule_attribute. For example, it can be used in the `context` parameter of
* The unique name used to later identify the rule_attribute. For example, it can be used in the `context` parameter of
* the `calculatePrices` method to specify a rule for calculating the price.
*/
rule_attribute: string
/**
* The priority of the rule type. This is useful when calculating the price of a price set, and multiple rules satisfy
* The priority of the rule type. This is useful when calculating the price of a price set, and multiple rules satisfy
* the provided context. The higher the value, the higher the priority of the rule type.
*/
default_priority: number
/**
* The creation date of the rule type.
*/
created_at?: Date | string
/**
* The update date of the rule type.
*/
updated_at?: Date | string
}
/**
* @interface
*
*
* The rule type to create.
*/
export interface CreateRuleTypeDTO {
@@ -41,12 +49,12 @@ export interface CreateRuleTypeDTO {
*/
name: string
/**
* The unique name used to later identify the rule_attribute. For example, it can be used in the `context` parameter of the `calculatePrices`
* The unique name used to later identify the rule_attribute. For example, it can be used in the `context` parameter of the `calculatePrices`
* method to specify a rule for calculating the price.
*/
rule_attribute: string
/**
* The priority of the rule type. This is useful when calculating the price of a price set, and multiple rules satisfy the provided context.
* The priority of the rule type. This is useful when calculating the price of a price set, and multiple rules satisfy the provided context.
* The higher the value, the higher the priority of the rule type.
*/
default_priority?: number
@@ -54,7 +62,7 @@ export interface CreateRuleTypeDTO {
/**
* @interface
*
*
* The data to update in a rule type. The `id` is used to identify which price set to update.
*/
export interface UpdateRuleTypeDTO {
@@ -78,7 +86,7 @@ export interface UpdateRuleTypeDTO {
/**
* @interface
*
*
* Filters to apply on rule types.
*/
export interface FilterableRuleTypeProps