Skip to content

Commit

Permalink
feat(medusa,pricing,types): added get endpoints for pricing rule types (
Browse files Browse the repository at this point in the history
#6678)

what:

- adds list endpoint for rule types
- adds get endpoint for rule types
  • Loading branch information
riqwan authored Mar 12, 2024
1 parent f0c8142 commit d4b921f
Show file tree
Hide file tree
Showing 14 changed files with 312 additions and 14 deletions.
7 changes: 7 additions & 0 deletions .changeset/chatty-trainers-grow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@medusajs/pricing": patch
"@medusajs/medusa": patch
"@medusajs/types": patch
---

feat(medusa,pricing,types): added get endpoints for pricing rule types
112 changes: 112 additions & 0 deletions integration-tests/modules/__tests__/pricing/admin/rule-types.spec.ts
Original file line number Diff line number Diff line change
@@ -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",
})
})
})
})
},
})
35 changes: 35 additions & 0 deletions packages/medusa/src/api-v2/admin/pricing/middlewares.ts
Original file line number Diff line number Diff line change
@@ -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
),
],
},
]
20 changes: 20 additions & 0 deletions packages/medusa/src/api-v2/admin/pricing/query-config.ts
Original file line number Diff line number Diff line change
@@ -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,
}
23 changes: 23 additions & 0 deletions packages/medusa/src/api-v2/admin/pricing/rule-types/[id]/route.ts
Original file line number Diff line number Diff line change
@@ -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 })
}
30 changes: 30 additions & 0 deletions packages/medusa/src/api-v2/admin/pricing/rule-types/route.ts
Original file line number Diff line number Diff line change
@@ -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,
})
}
12 changes: 12 additions & 0 deletions packages/medusa/src/api-v2/admin/pricing/validators.ts
Original file line number Diff line number Diff line change
@@ -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[]
}
2 changes: 2 additions & 0 deletions packages/medusa/src/api-v2/middlewares.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -49,5 +50,6 @@ export const config: MiddlewaresConfig = {
...adminPaymentRoutesMiddlewares,
...adminPriceListsRoutesMiddlewares,
...adminCollectionRoutesMiddlewares,
...adminPricingRoutesMiddlewares,
],
}
25 changes: 23 additions & 2 deletions packages/pricing/src/migrations/.snapshot-medusa-pricing.json
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,7 @@
}
],
"checks": [],
"foreignKeys": {
}
"foreignKeys": {}
},
{
"columns": {
Expand Down Expand Up @@ -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",
Expand Down
3 changes: 2 additions & 1 deletion packages/pricing/src/migrations/Migration20230929122253.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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");'
)
Expand Down
9 changes: 6 additions & 3 deletions packages/pricing/src/models/money-amount.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ import {
Filter,
Index,
ManyToMany,
ManyToOne,
OneToOne,
OnInit,
OneToOne,
OptionalProps,
PrimaryKey,
Property,
Expand All @@ -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({
Expand Down
15 changes: 15 additions & 0 deletions packages/pricing/src/models/rule-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
9 changes: 9 additions & 0 deletions packages/pricing/src/types/services/rule-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit d4b921f

Please sign in to comment.