Skip to content

Commit

Permalink
chore: add promotion list endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
riqwan committed Jan 17, 2024
1 parent 68ddd86 commit 2bbd62d
Show file tree
Hide file tree
Showing 12 changed files with 765 additions and 60 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { IPromotionModuleService } from "@medusajs/types"
import { PromotionType } from "@medusajs/utils"
import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import { useApi } from "../../../../environment-helpers/use-api"
import { getContainer } from "../../../../environment-helpers/use-container"
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import adminSeeder from "../../../../helpers/admin-seeder"

const env = { MEDUSA_FF_MEDUSA_V2: true }
const adminHeaders = {
headers: { "x-medusa-access-token": "test_token" },
}

describe("GET /admin/promotions", () => {
let dbConnection
let appContainer
let shutdownServer
let promotionModuleService: IPromotionModuleService

beforeAll(async () => {
const cwd = path.resolve(path.join(__dirname, "..", "..", ".."))
dbConnection = await initDb({ cwd, env } as any)
shutdownServer = await startBootstrapApp({ cwd, env })
appContainer = getContainer()
promotionModuleService = appContainer.resolve(
ModuleRegistrationName.PROMOTION
)
})

afterAll(async () => {
const db = useDb()
await db.shutdown()
await shutdownServer()
})

beforeEach(async () => {
await adminSeeder(dbConnection)
})

afterEach(async () => {
const db = useDb()
await db.teardown()
})

it("should get all promotions and its count", async () => {
await promotionModuleService.create([
{
code: "TEST",
type: PromotionType.STANDARD,
application_method: {
type: "fixed",
target_type: "order",
value: "100",
},
},
])

const api = useApi() as any
const response = await api.get(`/admin/promotions`, adminHeaders)

expect(response.status).toEqual(200)
expect(response.data.count).toEqual(1)
expect(response.data.promotions).toEqual([
expect.objectContaining({
id: expect.any(String),
code: "TEST",
campaign: null,
is_automatic: false,
type: "standard",
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
application_method: expect.objectContaining({
id: expect.any(String),
value: 100,
type: "fixed",
target_type: "order",
allocation: null,
created_at: expect.any(String),
updated_at: expect.any(String),
deleted_at: null,
}),
}),
])
})

it("should get all promotions and its count filtered", async () => {
const [createdPromotion] = await promotionModuleService.create([
{
code: "TEST",
type: PromotionType.STANDARD,
application_method: {
type: "fixed",
target_type: "order",
value: "100",
},
},
])

const api = useApi() as any
const response = await api.get(
`/admin/promotions?fields=code,created_at,application_method.id`,
adminHeaders
)

expect(response.status).toEqual(200)
expect(response.data.count).toEqual(1)
expect(response.data.promotions).toEqual([
{
id: expect.any(String),
code: "TEST",
created_at: expect.any(String),
application_method: {
id: expect.any(String),
promotion: expect.any(Object),
},
},
])
})
})
5 changes: 5 additions & 0 deletions integration-tests/plugins/medusa-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,10 @@ module.exports = {
resources: "shared",
resolve: "@medusajs/pricing",
},
[Modules.PROMOTION]: {
scope: "internal",
resources: "shared",
resolve: "@medusajs/promotion",
},
},
}
3 changes: 3 additions & 0 deletions integration-tests/plugins/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
"@medusajs/modules-sdk": "workspace:^",
"@medusajs/pricing": "workspace:^",
"@medusajs/product": "workspace:^",
"@medusajs/promotion": "workspace:^",
"@medusajs/utils": "workspace:^",
"faker": "^5.5.3",
"medusa-fulfillment-webshipper": "workspace:*",
"medusa-interfaces": "workspace:*",
Expand All @@ -27,6 +29,7 @@
"@babel/cli": "^7.12.10",
"@babel/core": "^7.12.10",
"@babel/node": "^7.12.10",
"@medusajs/types": "workspace:^",
"babel-preset-medusa-package": "*",
"jest": "^26.6.3",
"jest-environment-node": "26.6.2"
Expand Down
14 changes: 7 additions & 7 deletions packages/medusa/src/api/routes/admin/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import cors from "cors"
import { Router } from "express"
import { parseCorsOrigins } from "medusa-core-utils"
import middlewares from "../../middlewares"
import analyticsConfigs from "./analytics-configs"
import appRoutes from "./apps"
Expand All @@ -18,16 +19,19 @@ import noteRoutes from "./notes"
import notificationRoutes from "./notifications"
import orderEditRoutes from "./order-edits"
import orderRoutes from "./orders"
import paymentCollectionRoutes from "./payment-collections"
import paymentRoutes from "./payments"
import priceListRoutes from "./price-lists"
import productCategoryRoutes from "./product-categories"
import productTagRoutes from "./product-tags"
import productTypesRoutes from "./product-types"
import publishableApiKeyRoutes from "./publishable-api-keys"
import productRoutes from "./products"
import promotionRoutes from "./promotions"
import publishableApiKeyRoutes from "./publishable-api-keys"
import regionRoutes from "./regions"
import reservationRoutes from "./reservations"
import returnReasonRoutes from "./return-reasons"
import returnRoutes from "./returns"
import reservationRoutes from "./reservations"
import salesChannelRoutes from "./sales-channels"
import shippingOptionRoutes from "./shipping-options"
import shippingProfileRoutes from "./shipping-profiles"
Expand All @@ -38,10 +42,6 @@ import taxRateRoutes from "./tax-rates"
import uploadRoutes from "./uploads"
import userRoutes, { unauthenticatedUserRoutes } from "./users"
import variantRoutes from "./variants"
import paymentCollectionRoutes from "./payment-collections"
import paymentRoutes from "./payments"
import productCategoryRoutes from "./product-categories"
import { parseCorsOrigins } from "medusa-core-utils"

const route = Router()

Expand Down Expand Up @@ -97,12 +97,12 @@ export default (app, container, config) => {
productRoutes(route, featureFlagRouter)
productTagRoutes(route)
productTypesRoutes(route)
promotionRoutes(route)
publishableApiKeyRoutes(route)
regionRoutes(route, featureFlagRouter)
reservationRoutes(route)
returnReasonRoutes(route)
returnRoutes(route)
reservationRoutes(route)
salesChannelRoutes(route)
shippingOptionRoutes(route, featureFlagRouter)
shippingProfileRoutes(route)
Expand Down
52 changes: 52 additions & 0 deletions packages/medusa/src/api/routes/admin/promotions/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { PromotionDTO } from "@medusajs/types"
import { MedusaV2Flag, wrapHandler } from "@medusajs/utils"
import { Express, Router } from "express"
import { PaginatedResponse } from "../../../../types/common"
import { transformQuery } from "../../../middlewares"
import { isFeatureFlagEnabled } from "../../../middlewares/feature-flag-enabled"
import listPromotions, { AdminGetPromotionsParams } from "./list-promotions"

const route = Router()

export default (app: Express) => {
const retrieveTransformQueryConfig = {
defaultFields: defaultPromotionFields,
defaultRelations: defaultAdminPromotionRelations,
allowedRelations: allowedAdminPromotionRelations,
isList: false,
}

const listTransformQueryConfig = {
...retrieveTransformQueryConfig,
isList: true,
}

app.use("/promotions", isFeatureFlagEnabled(MedusaV2Flag.key), route)

route.get(
"/",
transformQuery(AdminGetPromotionsParams, listTransformQueryConfig),
wrapHandler(listPromotions)
)

return app
}

export const defaultAdminPromotionRelations = ["campaign", "application_method"]
export const allowedAdminPromotionRelations = [
...defaultAdminPromotionRelations,
]
export const defaultPromotionFields = [
"id",
"code",
"campaign",
"is_automatic",
"type",
"created_at",
"updated_at",
"deleted_at",
]

export type AdminPromotionsListRes = PaginatedResponse & {
promotions: PromotionDTO[]
}
33 changes: 33 additions & 0 deletions packages/medusa/src/api/routes/admin/promotions/list-promotions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { IPromotionModuleService } from "@medusajs/types"
import { IsOptional, IsString } from "class-validator"
import { Request, Response } from "express"
import { extendedFindParamsMixin } from "../../../../types/common"

export default async (req: Request, res: Response) => {
const promotionModuleService: IPromotionModuleService = req.scope.resolve(
"promotionModuleService"
)

const [promotions, count] = await promotionModuleService.listAndCount(
req.filterableFields,
req.listConfig
)
console.log("running here - ", promotions)
const { limit, offset } = req.validatedQuery

res.json({
count,
promotions,
offset,
limit,
})
}

export class AdminGetPromotionsParams extends extendedFindParamsMixin({
limit: 100,
offset: 0,
}) {
@IsString()
@IsOptional()
code?: string
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { IPromotionModuleService } from "@medusajs/types"
import { CampaignBudgetType, PromotionType } from "@medusajs/utils"
import {
ApplicationMethodType,
CampaignBudgetType,
PromotionType,
} from "@medusajs/utils"
import { SqlEntityManager } from "@mikro-orm/postgresql"
import { initialize } from "../../../../src"
import { createCampaigns } from "../../../__fixtures__/campaigns"
Expand Down Expand Up @@ -680,6 +684,83 @@ describe("Promotion Service", () => {
})
})

describe("listAndCount", () => {
beforeEach(async () => {
await createPromotions(repositoryManager, [
{
id: "promotion-id-1",
code: "PROMOTION_1",
type: PromotionType.STANDARD,
application_method: {
type: ApplicationMethodType.FIXED,
value: "200",
target_type: "items",
},
},
{
id: "promotion-id-2",
code: "PROMOTION_2",
type: PromotionType.STANDARD,
},
])
})

it("should return all promotions and count", async () => {
const [promotions, count] = await service.listAndCount()

expect(count).toEqual(2)
expect(promotions).toEqual([
{
id: "promotion-id-1",
code: "PROMOTION_1",
campaign: null,
is_automatic: false,
type: "standard",
application_method: expect.any(String),
created_at: expect.any(Date),
updated_at: expect.any(Date),
deleted_at: null,
},
{
id: "promotion-id-2",
code: "PROMOTION_2",
campaign: null,
is_automatic: false,
type: "standard",
application_method: null,
created_at: expect.any(Date),
updated_at: expect.any(Date),
deleted_at: null,
},
])
})

it("should return all promotions based on config select and relations param", async () => {
const [promotions, count] = await service.listAndCount(
{
id: ["promotion-id-1"],
},
{
relations: ["application_method"],
select: ["code", "application_method.type"],
}
)

expect(count).toEqual(1)
expect(promotions).toEqual([
{
id: "promotion-id-1",
code: "PROMOTION_1",
application_method: {
id: expect.any(String),
promotion: expect.any(Object),
type: "fixed",
},
},
])
})
})

describe("delete", () => {
beforeEach(async () => {
await createPromotions(repositoryManager)
Expand Down
Loading

0 comments on commit 2bbd62d

Please sign in to comment.