Feat/add discount condition batch (#2430)
* feat(medusa): Allow to add items to a discount condition by batch + cleanup of discounts and discount conditions end points * style(medusa): cleanup catch and log * feat(medusa-react, medusa-js): Add support to add item batch to discount condition * cleanup * cleanup * rename items to resources * fix(medusa-js): url * Create fast-suns-repair.md * update naming * tests(integration): Update tests to reflect API changes * feat(medusa): Delete a condition should be idempotent on discount and condition * revert
This commit is contained in:
committed by
GitHub
parent
143f8543e5
commit
765a2cccda
@@ -0,0 +1,33 @@
|
||||
import { MedusaError } from "medusa-core-utils"
|
||||
import { DiscountConditionService, DiscountService } from "../../../services"
|
||||
|
||||
export async function doesConditionBelongToDiscount(req, res, next) {
|
||||
try {
|
||||
const { discount_id, condition_id } = req.params
|
||||
const conditionService: DiscountConditionService = req.scope.resolve(
|
||||
"discountConditionService"
|
||||
)
|
||||
const discountService: DiscountService =
|
||||
req.scope.resolve("discountService")
|
||||
|
||||
const discount = await discountService.retrieve(discount_id, {
|
||||
select: ["id", "rule_id"],
|
||||
})
|
||||
const condition = await conditionService.retrieve(condition_id, {
|
||||
select: ["id", "discount_rule_id"],
|
||||
})
|
||||
|
||||
if (condition.discount_rule_id !== discount.rule_id) {
|
||||
return next(
|
||||
new MedusaError(
|
||||
MedusaError.Types.INVALID_DATA,
|
||||
`Condition with id ${condition_id} does not belong to Discount with id ${discount_id}`
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
next()
|
||||
} catch (e) {
|
||||
next(e)
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import { default as wrap } from "./await-middleware"
|
||||
|
||||
export { getRequestedBatchJob } from "./batch-job/get-requested-batch-job"
|
||||
export { canAccessBatchJob } from "./batch-job/can-access-batch-job"
|
||||
export { doesConditionBelongToDiscount } from "./discount/does-condition-belong-to-discount"
|
||||
export { transformQuery } from "./transform-query"
|
||||
export { transformBody } from "./transform-body"
|
||||
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
import DiscountConditionService from "../../../../services/discount-condition"
|
||||
import { Request, Response } from "express"
|
||||
import { EntityManager } from "typeorm"
|
||||
import { DiscountService } from "../../../../services"
|
||||
import {
|
||||
DiscountConditionMapTypeToProperty,
|
||||
UpsertDiscountConditionInput,
|
||||
} from "../../../../types/discount"
|
||||
import { IsArray } from "class-validator"
|
||||
import { FindParams } from "../../../../types/common"
|
||||
|
||||
/**
|
||||
* @oas [post] /discounts/{discount_id}/conditions/{condition_id}/batch
|
||||
* operationId: "PostDiscountsDiscountConditionsConditionBatch"
|
||||
* summary: "Add a batch of resources to a discount condition"
|
||||
* description: "Add a batch of resources to a discount condition."
|
||||
* x-authenticated: true
|
||||
* parameters:
|
||||
* - (path) discount_id=* {string} The ID of the Product.
|
||||
* - (path) condition_id=* {string} The ID of the condition on which to add the item.
|
||||
* - (query) expand {string} (Comma separated) Which fields should be expanded in each discount of the result.
|
||||
* - (query) fields {string} (Comma separated) Which fields should be included in each discount of the result.
|
||||
* requestBody:
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* required:
|
||||
* - resources
|
||||
* properties:
|
||||
* resources:
|
||||
* description: The resources to be added to the discount condition
|
||||
* type: array
|
||||
* items:
|
||||
* required:
|
||||
* - id
|
||||
* properties:
|
||||
* id:
|
||||
* description: The id of the item
|
||||
* type: string
|
||||
* x-codeSamples:
|
||||
* - lang: JavaScript
|
||||
* label: JS Client
|
||||
* source: |
|
||||
* import Medusa from "@medusajs/medusa-js"
|
||||
* import { DiscountConditionOperator } from "@medusajs/medusa"
|
||||
* const medusa = new Medusa({ baseUrl: MEDUSA_BACKEND_URL, maxRetries: 3 })
|
||||
* // must be previously logged in or use api token
|
||||
* medusa.admin.discounts.addConditionResourceBatch(discount_id, condition_id, {
|
||||
* resources: [{ id: item_id }]
|
||||
* })
|
||||
* .then(({ discount }) => {
|
||||
* console.log(discount.id);
|
||||
* });
|
||||
* - lang: Shell
|
||||
* label: cURL
|
||||
* source: |
|
||||
* curl --location --request POST 'https://medusa-url.com/admin/discounts/{id}/conditions/{condition_id}/batch' \
|
||||
* --header 'Authorization: Bearer {api_token}' \
|
||||
* --header 'Content-Type: application/json' \
|
||||
* --data-raw '{
|
||||
* "resources": [{ "id": "item_id" }]
|
||||
* }'
|
||||
* security:
|
||||
* - api_token: []
|
||||
* - cookie_auth: []
|
||||
* tags:
|
||||
* - Discount Condition
|
||||
* responses:
|
||||
* 200:
|
||||
* description: OK
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* properties:
|
||||
* discount:
|
||||
* $ref: "#/components/schemas/discount"
|
||||
* "400":
|
||||
* $ref: "#/components/responses/400_error"
|
||||
* "401":
|
||||
* $ref: "#/components/responses/unauthorized"
|
||||
* "404":
|
||||
* $ref: "#/components/responses/not_found_error"
|
||||
* "409":
|
||||
* $ref: "#/components/responses/invalid_state_error"
|
||||
* "422":
|
||||
* $ref: "#/components/responses/invalid_request_error"
|
||||
* "500":
|
||||
* $ref: "#/components/responses/500_error"
|
||||
*/
|
||||
export default async (req: Request, res: Response) => {
|
||||
const { discount_id, condition_id } = req.params
|
||||
const validatedBody =
|
||||
req.validatedBody as AdminPostDiscountsDiscountConditionsConditionBatchReq
|
||||
|
||||
const conditionService: DiscountConditionService = req.scope.resolve(
|
||||
"discountConditionService"
|
||||
)
|
||||
const manager: EntityManager = req.scope.resolve("manager")
|
||||
|
||||
const condition = await conditionService.retrieve(condition_id, {
|
||||
select: ["id", "type", "discount_rule_id"],
|
||||
})
|
||||
|
||||
const updateObj: UpsertDiscountConditionInput = {
|
||||
id: condition_id,
|
||||
rule_id: condition.discount_rule_id,
|
||||
[DiscountConditionMapTypeToProperty[condition.type]]:
|
||||
validatedBody.resources,
|
||||
}
|
||||
|
||||
await manager.transaction(async (transactionManager) => {
|
||||
await conditionService
|
||||
.withTransaction(transactionManager)
|
||||
.upsertCondition(updateObj, false)
|
||||
})
|
||||
|
||||
const discountService: DiscountService = req.scope.resolve("discountService")
|
||||
const discount = await discountService.retrieve(
|
||||
discount_id,
|
||||
req.retrieveConfig
|
||||
)
|
||||
|
||||
res.status(200).json({ discount })
|
||||
}
|
||||
|
||||
export class AdminPostDiscountsDiscountConditionsConditionBatchReq {
|
||||
@IsArray()
|
||||
resources: { id: string }[]
|
||||
}
|
||||
|
||||
export class AdminPostDiscountsDiscountConditionsConditionBatchParams extends FindParams {}
|
||||
@@ -1,13 +1,12 @@
|
||||
import { Discount, DiscountConditionOperator } from "../../../../models"
|
||||
import { IsOptional, IsString } from "class-validator"
|
||||
import { defaultAdminDiscountsFields, defaultAdminDiscountsRelations } from "."
|
||||
import { Request, Response } from "express"
|
||||
import { DiscountConditionOperator } from "../../../../models"
|
||||
import { IsString } from "class-validator"
|
||||
|
||||
import { AdminUpsertConditionsReq } from "../../../../types/discount"
|
||||
import DiscountConditionService from "../../../../services/discount-condition"
|
||||
import { DiscountService } from "../../../../services"
|
||||
import { EntityManager } from "typeorm"
|
||||
import { getRetrieveConfig } from "../../../../utils/get-query-config"
|
||||
import { validator } from "../../../../utils/validator"
|
||||
import { FindParams } from "../../../../types/common"
|
||||
|
||||
/**
|
||||
* @oas [post] /discounts/{discount_id}/conditions
|
||||
@@ -105,19 +104,8 @@ import { validator } from "../../../../utils/validator"
|
||||
* "500":
|
||||
* $ref: "#/components/responses/500_error"
|
||||
*/
|
||||
export default async (req, res) => {
|
||||
export default async (req: Request, res: Response) => {
|
||||
const { discount_id } = req.params
|
||||
|
||||
const validatedCondition = await validator(
|
||||
AdminPostDiscountsDiscountConditions,
|
||||
req.body
|
||||
)
|
||||
|
||||
const validatedParams = await validator(
|
||||
AdminPostDiscountsDiscountConditionsParams,
|
||||
req.query
|
||||
)
|
||||
|
||||
const conditionService: DiscountConditionService = req.scope.resolve(
|
||||
"discountConditionService"
|
||||
)
|
||||
@@ -130,19 +118,12 @@ export default async (req, res) => {
|
||||
return await conditionService
|
||||
.withTransaction(transactionManager)
|
||||
.upsertCondition({
|
||||
...validatedCondition,
|
||||
...(req.validatedBody as AdminPostDiscountsDiscountConditions),
|
||||
rule_id: discount.rule_id,
|
||||
})
|
||||
})
|
||||
|
||||
const config = getRetrieveConfig<Discount>(
|
||||
defaultAdminDiscountsFields,
|
||||
defaultAdminDiscountsRelations,
|
||||
validatedParams?.fields?.split(",") as (keyof Discount)[],
|
||||
validatedParams?.expand?.split(",")
|
||||
)
|
||||
|
||||
discount = await discountService.retrieve(discount.id, config)
|
||||
discount = await discountService.retrieve(discount.id, req.retrieveConfig)
|
||||
|
||||
res.status(200).json({ discount })
|
||||
}
|
||||
@@ -153,12 +134,4 @@ export class AdminPostDiscountsDiscountConditions extends AdminUpsertConditionsR
|
||||
operator: DiscountConditionOperator
|
||||
}
|
||||
|
||||
export class AdminPostDiscountsDiscountConditionsParams {
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
expand?: string
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
fields?: string
|
||||
}
|
||||
export class AdminPostDiscountsDiscountConditionsParams extends FindParams {}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {
|
||||
AllocationType,
|
||||
Discount,
|
||||
DiscountConditionOperator,
|
||||
DiscountRuleType,
|
||||
} from "../../../../models"
|
||||
@@ -17,17 +16,14 @@ import {
|
||||
IsString,
|
||||
ValidateNested,
|
||||
} from "class-validator"
|
||||
import { defaultAdminDiscountsFields, defaultAdminDiscountsRelations } from "."
|
||||
|
||||
import { AdminPostDiscountsDiscountParams } from "./update-discount"
|
||||
import { AdminUpsertConditionsReq } from "../../../../types/discount"
|
||||
import DiscountService from "../../../../services/discount"
|
||||
import { EntityManager } from "typeorm"
|
||||
import { IsGreaterThan } from "../../../../utils/validators/greater-than"
|
||||
import { IsISO8601Duration } from "../../../../utils/validators/iso8601-duration"
|
||||
import { Type } from "class-transformer"
|
||||
import { getRetrieveConfig } from "../../../../utils/get-query-config"
|
||||
import { validator } from "../../../../utils/validator"
|
||||
import { Request, Response } from "express"
|
||||
import { FindParams } from "../../../../types/common"
|
||||
|
||||
/**
|
||||
* @oas [post] /discounts
|
||||
@@ -202,32 +198,21 @@ import { validator } from "../../../../utils/validator"
|
||||
* $ref: "#/components/responses/500_error"
|
||||
*/
|
||||
|
||||
export default async (req, res) => {
|
||||
const validated = await validator(AdminPostDiscountsReq, req.body)
|
||||
|
||||
const validatedParams = await validator(
|
||||
AdminPostDiscountsDiscountParams,
|
||||
req.query
|
||||
)
|
||||
|
||||
export default async (req: Request, res: Response) => {
|
||||
const discountService: DiscountService = req.scope.resolve("discountService")
|
||||
|
||||
const manager: EntityManager = req.scope.resolve("manager")
|
||||
const created = await manager.transaction(async (transactionManager) => {
|
||||
return await discountService
|
||||
.withTransaction(transactionManager)
|
||||
.create(validated)
|
||||
.create(req.validatedBody as AdminPostDiscountsReq)
|
||||
})
|
||||
|
||||
const config = getRetrieveConfig<Discount>(
|
||||
defaultAdminDiscountsFields,
|
||||
defaultAdminDiscountsRelations,
|
||||
validatedParams?.fields?.split(",") as (keyof Discount)[],
|
||||
validatedParams?.expand?.split(",")
|
||||
const discount = await discountService.retrieve(
|
||||
created.id,
|
||||
req.retrieveConfig
|
||||
)
|
||||
|
||||
const discount = await discountService.retrieve(created.id, config)
|
||||
|
||||
res.status(200).json({ discount })
|
||||
}
|
||||
|
||||
@@ -309,12 +294,4 @@ export class AdminCreateCondition extends AdminUpsertConditionsReq {
|
||||
operator: DiscountConditionOperator
|
||||
}
|
||||
|
||||
export class AdminPostDiscountsParams {
|
||||
@IsArray()
|
||||
@IsOptional()
|
||||
expand?: string[]
|
||||
|
||||
@IsArray()
|
||||
@IsOptional()
|
||||
fields?: string[]
|
||||
}
|
||||
export class AdminPostDiscountsParams extends FindParams {}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { Request, Response } from "express"
|
||||
import {
|
||||
IsNotEmpty,
|
||||
IsNumber,
|
||||
@@ -9,7 +10,6 @@ import { defaultAdminDiscountsFields, defaultAdminDiscountsRelations } from "."
|
||||
|
||||
import DiscountService from "../../../../services/discount"
|
||||
import { EntityManager } from "typeorm"
|
||||
import { validator } from "../../../../utils/validator"
|
||||
|
||||
/**
|
||||
* @oas [post] /discounts/{id}/dynamic-codes
|
||||
@@ -72,20 +72,18 @@ import { validator } from "../../../../utils/validator"
|
||||
* "500":
|
||||
* $ref: "#/components/responses/500_error"
|
||||
*/
|
||||
export default async (req, res) => {
|
||||
export default async (req: Request, res: Response) => {
|
||||
const { discount_id } = req.params
|
||||
|
||||
const validated = await validator(
|
||||
AdminPostDiscountsDiscountDynamicCodesReq,
|
||||
req.body
|
||||
)
|
||||
|
||||
const discountService: DiscountService = req.scope.resolve("discountService")
|
||||
const manager: EntityManager = req.scope.resolve("manager")
|
||||
const created = await manager.transaction(async (transactionManager) => {
|
||||
return await discountService
|
||||
.withTransaction(transactionManager)
|
||||
.createDynamicCode(discount_id, validated)
|
||||
.createDynamicCode(
|
||||
discount_id,
|
||||
req.validatedBody as AdminPostDiscountsDiscountDynamicCodesReq
|
||||
)
|
||||
})
|
||||
|
||||
const discount = await discountService.retrieve(created.id, {
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
import { IsOptional, IsString } from "class-validator"
|
||||
import { defaultAdminDiscountsFields, defaultAdminDiscountsRelations } from "."
|
||||
|
||||
import { Discount } from "../../../../models"
|
||||
import DiscountConditionService from "../../../../services/discount-condition"
|
||||
import { DiscountService } from "../../../../services"
|
||||
import { EntityManager } from "typeorm"
|
||||
import { MedusaError } from "medusa-core-utils"
|
||||
import { getRetrieveConfig } from "../../../../utils/get-query-config"
|
||||
import { validator } from "../../../../utils/validator"
|
||||
import { FindParams } from "../../../../types/common"
|
||||
|
||||
/**
|
||||
* @oas [delete] /discounts/{discount_id}/conditions/{condition_id}
|
||||
@@ -78,39 +73,34 @@ import { validator } from "../../../../utils/validator"
|
||||
export default async (req, res) => {
|
||||
const { discount_id, condition_id } = req.params
|
||||
|
||||
const validatedParams = await validator(
|
||||
AdminDeleteDiscountsDiscountConditionsConditionParams,
|
||||
req.query
|
||||
)
|
||||
|
||||
const conditionService: DiscountConditionService = req.scope.resolve(
|
||||
"discountConditionService"
|
||||
)
|
||||
const discountService: DiscountService = req.scope.resolve("discountService")
|
||||
|
||||
const condition = await conditionService
|
||||
.retrieve(condition_id)
|
||||
.catch(() => void 0)
|
||||
|
||||
if (!condition) {
|
||||
const discount = await discountService.retrieve(
|
||||
discount_id,
|
||||
req.retrieveConfig
|
||||
)
|
||||
// resolves idempotently in case of non-existing condition
|
||||
return res.json({
|
||||
id: condition_id,
|
||||
object: "discount-condition",
|
||||
deleted: true,
|
||||
discount,
|
||||
})
|
||||
}
|
||||
|
||||
const discountService: DiscountService = req.scope.resolve("discountService")
|
||||
|
||||
let discount = await discountService.retrieve(discount_id, {
|
||||
relations: ["rule", "rule.conditions"],
|
||||
select: ["id", "rule_id"],
|
||||
})
|
||||
|
||||
const existsOnDiscount = discount.rule.conditions.some(
|
||||
(c) => c.id === condition_id
|
||||
)
|
||||
|
||||
if (!existsOnDiscount) {
|
||||
if (condition.discount_rule_id !== discount.rule_id) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_FOUND,
|
||||
`Condition with id ${condition_id} does not belong to Discount with id ${discount_id}`
|
||||
@@ -124,14 +114,7 @@ export default async (req, res) => {
|
||||
.delete(condition_id)
|
||||
})
|
||||
|
||||
const config = getRetrieveConfig<Discount>(
|
||||
defaultAdminDiscountsFields,
|
||||
defaultAdminDiscountsRelations,
|
||||
validatedParams?.fields?.split(",") as (keyof Discount)[],
|
||||
validatedParams?.expand?.split(",")
|
||||
)
|
||||
|
||||
discount = await discountService.retrieve(discount_id, config)
|
||||
discount = await discountService.retrieve(discount_id, req.retrieveConfig)
|
||||
|
||||
res.json({
|
||||
id: condition_id,
|
||||
@@ -141,12 +124,4 @@ export default async (req, res) => {
|
||||
})
|
||||
}
|
||||
|
||||
export class AdminDeleteDiscountsDiscountConditionsConditionParams {
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
expand?: string
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
fields?: string
|
||||
}
|
||||
export class AdminDeleteDiscountsDiscountConditionsConditionParams extends FindParams {}
|
||||
|
||||
@@ -1,15 +1,6 @@
|
||||
import { IsOptional, IsString } from "class-validator"
|
||||
import {
|
||||
defaultAdminDiscountConditionFields,
|
||||
defaultAdminDiscountConditionRelations,
|
||||
} from "."
|
||||
|
||||
import { DiscountCondition } from "../../../../models"
|
||||
import { Request, Response } from "express"
|
||||
import DiscountConditionService from "../../../../services/discount-condition"
|
||||
import { DiscountService } from "../../../../services"
|
||||
import { MedusaError } from "medusa-core-utils"
|
||||
import { getRetrieveConfig } from "../../../../utils/get-query-config"
|
||||
import { validator } from "../../../../utils/validator"
|
||||
import { FindParams } from "../../../../types/common"
|
||||
|
||||
/**
|
||||
* @oas [get] /discounts/{discount_id}/conditions/{condition_id}
|
||||
@@ -66,37 +57,8 @@ import { validator } from "../../../../utils/validator"
|
||||
* $ref: "#/components/responses/500_error"
|
||||
*/
|
||||
|
||||
export default async (req, res) => {
|
||||
const { discount_id, condition_id } = req.params
|
||||
|
||||
const validatedParams = await validator(
|
||||
AdminGetDiscountsDiscountConditionsConditionParams,
|
||||
req.query
|
||||
)
|
||||
|
||||
const discountService: DiscountService = req.scope.resolve("discountService")
|
||||
|
||||
const discount = await discountService.retrieve(discount_id, {
|
||||
relations: ["rule", "rule.conditions"],
|
||||
})
|
||||
|
||||
const existsOnDiscount = discount.rule.conditions.some(
|
||||
(c) => c.id === condition_id
|
||||
)
|
||||
|
||||
if (!existsOnDiscount) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_FOUND,
|
||||
`Condition with id ${condition_id} does not belong to Discount with id ${discount_id}`
|
||||
)
|
||||
}
|
||||
|
||||
const config = getRetrieveConfig<DiscountCondition>(
|
||||
defaultAdminDiscountConditionFields,
|
||||
defaultAdminDiscountConditionRelations,
|
||||
validatedParams?.fields?.split(",") as (keyof DiscountCondition)[],
|
||||
validatedParams?.expand?.split(",")
|
||||
)
|
||||
export default async (req: Request, res: Response) => {
|
||||
const { condition_id } = req.params
|
||||
|
||||
const conditionService: DiscountConditionService = req.scope.resolve(
|
||||
"discountConditionService"
|
||||
@@ -104,18 +66,10 @@ export default async (req, res) => {
|
||||
|
||||
const discountCondition = await conditionService.retrieve(
|
||||
condition_id,
|
||||
config
|
||||
req.retrieveConfig
|
||||
)
|
||||
|
||||
res.status(200).json({ discount_condition: discountCondition })
|
||||
}
|
||||
|
||||
export class AdminGetDiscountsDiscountConditionsConditionParams {
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
expand?: string
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
fields?: string
|
||||
}
|
||||
export class AdminGetDiscountsDiscountConditionsConditionParams extends FindParams {}
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import { IsOptional, IsString } from "class-validator"
|
||||
import { defaultAdminDiscountsFields, defaultAdminDiscountsRelations } from "."
|
||||
|
||||
import { Discount } from "../../../../models"
|
||||
import { Request, Response } from "express"
|
||||
import DiscountService from "../../../../services/discount"
|
||||
import { getRetrieveConfig } from "../../../../utils/get-query-config"
|
||||
import { validator } from "../../../../utils/validator"
|
||||
import { FindParams } from "../../../../types/common"
|
||||
|
||||
/**
|
||||
* @oas [get] /discounts/code/{code}
|
||||
* operationId: "GetDiscountsDiscountCode"
|
||||
@@ -58,33 +55,16 @@ import { validator } from "../../../../utils/validator"
|
||||
* "500":
|
||||
* $ref: "#/components/responses/500_error"
|
||||
*/
|
||||
export default async (req, res) => {
|
||||
export default async (req: Request, res: Response) => {
|
||||
const { code } = req.params
|
||||
|
||||
const validated = await validator(
|
||||
AdminGetDiscountsDiscountCodeParams,
|
||||
req.query
|
||||
)
|
||||
|
||||
const config = getRetrieveConfig<Discount>(
|
||||
defaultAdminDiscountsFields,
|
||||
defaultAdminDiscountsRelations,
|
||||
validated?.fields?.split(",") as (keyof Discount)[],
|
||||
validated?.expand?.split(",")
|
||||
)
|
||||
|
||||
const discountService: DiscountService = req.scope.resolve("discountService")
|
||||
const discount = await discountService.retrieveByCode(code, config)
|
||||
const discount = await discountService.retrieveByCode(
|
||||
code,
|
||||
req.retrieveConfig
|
||||
)
|
||||
|
||||
res.status(200).json({ discount })
|
||||
}
|
||||
|
||||
export class AdminGetDiscountsDiscountCodeParams {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
expand?: string
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
fields?: string
|
||||
}
|
||||
export class AdminGetDiscountsDiscountCodeParams extends FindParams {}
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import { IsOptional, IsString } from "class-validator"
|
||||
import { defaultAdminDiscountsFields, defaultAdminDiscountsRelations } from "."
|
||||
|
||||
import { Discount } from "../../../.."
|
||||
import DiscountService from "../../../../services/discount"
|
||||
import { getRetrieveConfig } from "../../../../utils/get-query-config"
|
||||
import { validator } from "../../../../utils/validator"
|
||||
import { Request, Response } from "express"
|
||||
import { FindParams } from "../../../../types/common"
|
||||
|
||||
/**
|
||||
* @oas [get] /discounts/{id}
|
||||
* operationId: "GetDiscountsDiscount"
|
||||
@@ -58,30 +55,13 @@ import { validator } from "../../../../utils/validator"
|
||||
* "500":
|
||||
* $ref: "#/components/responses/500_error"
|
||||
*/
|
||||
export default async (req, res) => {
|
||||
export default async (req: Request, res: Response) => {
|
||||
const { discount_id } = req.params
|
||||
|
||||
const validated = await validator(AdminGetDiscountParams, req.query)
|
||||
|
||||
const config = getRetrieveConfig<Discount>(
|
||||
defaultAdminDiscountsFields,
|
||||
defaultAdminDiscountsRelations,
|
||||
validated?.fields?.split(",") as (keyof Discount)[],
|
||||
validated?.expand?.split(",")
|
||||
)
|
||||
|
||||
const discountService: DiscountService = req.scope.resolve("discountService")
|
||||
const data = await discountService.retrieve(discount_id, config)
|
||||
const data = await discountService.retrieve(discount_id, req.retrieveConfig)
|
||||
|
||||
res.status(200).json({ discount: data })
|
||||
}
|
||||
|
||||
export class AdminGetDiscountParams {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
expand?: string
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
fields?: string
|
||||
}
|
||||
export class AdminGetDiscountParams extends FindParams {}
|
||||
|
||||
@@ -3,26 +3,89 @@ import "reflect-metadata"
|
||||
import { Discount } from "../../../.."
|
||||
import { DiscountCondition } from "../../../../models"
|
||||
import { DeleteResponse, PaginatedResponse } from "../../../../types/common"
|
||||
import middlewares from "../../../middlewares"
|
||||
import middlewares, {
|
||||
doesConditionBelongToDiscount,
|
||||
transformBody,
|
||||
transformQuery,
|
||||
} from "../../../middlewares"
|
||||
import {
|
||||
AdminPostDiscountsDiscountConditionsConditionBatchParams,
|
||||
AdminPostDiscountsDiscountConditionsConditionBatchReq,
|
||||
} from "./add-resources-to-condition-batch"
|
||||
import {
|
||||
AdminPostDiscountsDiscountConditionsCondition,
|
||||
AdminPostDiscountsDiscountConditionsConditionParams,
|
||||
} from "./update-condition"
|
||||
import {
|
||||
AdminPostDiscountsDiscountConditions,
|
||||
AdminPostDiscountsDiscountConditionsParams,
|
||||
} from "./create-condition"
|
||||
import { AdminPostDiscountsDiscountDynamicCodesReq } from "./create-dynamic-code"
|
||||
import {
|
||||
AdminPostDiscountsDiscountParams,
|
||||
AdminPostDiscountsDiscountReq,
|
||||
} from "./update-discount"
|
||||
import {
|
||||
AdminPostDiscountsParams,
|
||||
AdminPostDiscountsReq,
|
||||
} from "./create-discount"
|
||||
import { AdminGetDiscountsParams } from "./list-discounts"
|
||||
import { AdminGetDiscountsDiscountConditionsConditionParams } from "./get-condition"
|
||||
import { AdminDeleteDiscountsDiscountConditionsConditionParams } from "./delete-condition"
|
||||
import { AdminGetDiscountsDiscountCodeParams } from "./get-discount-by-code"
|
||||
import { AdminGetDiscountParams } from "./get-discount"
|
||||
|
||||
const route = Router()
|
||||
|
||||
export default (app) => {
|
||||
app.use("/discounts", route)
|
||||
|
||||
route.get("/", middlewares.wrap(require("./list-discounts").default))
|
||||
route.post("/", middlewares.wrap(require("./create-discount").default))
|
||||
route.get(
|
||||
"/",
|
||||
transformQuery(AdminGetDiscountsParams, {
|
||||
defaultFields: defaultAdminDiscountsFields,
|
||||
defaultRelations: defaultAdminDiscountsRelations,
|
||||
isList: true,
|
||||
}),
|
||||
middlewares.wrap(require("./list-discounts").default)
|
||||
)
|
||||
route.post(
|
||||
"/",
|
||||
transformQuery(AdminPostDiscountsParams, {
|
||||
defaultFields: defaultAdminDiscountsFields,
|
||||
defaultRelations: defaultAdminDiscountsRelations,
|
||||
isList: false,
|
||||
}),
|
||||
transformBody(AdminPostDiscountsReq),
|
||||
middlewares.wrap(require("./create-discount").default)
|
||||
)
|
||||
|
||||
route.get(
|
||||
"/:discount_id",
|
||||
transformQuery(AdminGetDiscountParams, {
|
||||
defaultFields: defaultAdminDiscountsFields,
|
||||
defaultRelations: defaultAdminDiscountsRelations,
|
||||
isList: false,
|
||||
}),
|
||||
middlewares.wrap(require("./get-discount").default)
|
||||
)
|
||||
route.get(
|
||||
"/code/:code",
|
||||
transformQuery(AdminGetDiscountsDiscountCodeParams, {
|
||||
defaultFields: defaultAdminDiscountsFields,
|
||||
defaultRelations: defaultAdminDiscountsRelations,
|
||||
isList: false,
|
||||
}),
|
||||
middlewares.wrap(require("./get-discount-by-code").default)
|
||||
)
|
||||
route.post(
|
||||
"/:discount_id",
|
||||
transformQuery(AdminPostDiscountsDiscountParams, {
|
||||
defaultFields: defaultAdminDiscountsFields,
|
||||
defaultRelations: defaultAdminDiscountsRelations,
|
||||
isList: false,
|
||||
}),
|
||||
transformBody(AdminPostDiscountsDiscountReq),
|
||||
middlewares.wrap(require("./update-discount").default)
|
||||
)
|
||||
route.delete(
|
||||
@@ -33,6 +96,7 @@ export default (app) => {
|
||||
// Dynamic codes
|
||||
route.post(
|
||||
"/:discount_id/dynamic-codes",
|
||||
transformBody(AdminPostDiscountsDiscountDynamicCodesReq),
|
||||
middlewares.wrap(require("./create-dynamic-code").default)
|
||||
)
|
||||
route.delete(
|
||||
@@ -51,23 +115,64 @@ export default (app) => {
|
||||
)
|
||||
|
||||
// Discount condition management
|
||||
route.get(
|
||||
"/:discount_id/conditions/:condition_id",
|
||||
middlewares.wrap(require("./get-condition").default)
|
||||
)
|
||||
route.post(
|
||||
"/:discount_id/conditions/:condition_id",
|
||||
middlewares.wrap(require("./update-condition").default)
|
||||
)
|
||||
route.post(
|
||||
"/:discount_id/conditions",
|
||||
transformQuery(AdminPostDiscountsDiscountConditionsParams, {
|
||||
defaultFields: defaultAdminDiscountsFields,
|
||||
defaultRelations: defaultAdminDiscountsRelations,
|
||||
isList: false,
|
||||
}),
|
||||
transformBody(AdminPostDiscountsDiscountConditions),
|
||||
middlewares.wrap(require("./create-condition").default)
|
||||
)
|
||||
|
||||
route.delete(
|
||||
"/:discount_id/conditions/:condition_id",
|
||||
transformQuery(AdminDeleteDiscountsDiscountConditionsConditionParams, {
|
||||
defaultFields: defaultAdminDiscountsFields,
|
||||
defaultRelations: defaultAdminDiscountsRelations,
|
||||
isList: false,
|
||||
}),
|
||||
middlewares.wrap(require("./delete-condition").default)
|
||||
)
|
||||
|
||||
const conditionRouter = Router({ mergeParams: true })
|
||||
route.use(
|
||||
"/:discount_id/conditions/:condition_id",
|
||||
doesConditionBelongToDiscount,
|
||||
conditionRouter
|
||||
)
|
||||
|
||||
conditionRouter.get(
|
||||
"/",
|
||||
transformQuery(AdminGetDiscountsDiscountConditionsConditionParams, {
|
||||
defaultFields: defaultAdminDiscountConditionFields,
|
||||
defaultRelations: defaultAdminDiscountConditionRelations,
|
||||
isList: false,
|
||||
}),
|
||||
middlewares.wrap(require("./get-condition").default)
|
||||
)
|
||||
conditionRouter.post(
|
||||
"/",
|
||||
transformQuery(AdminPostDiscountsDiscountConditionsConditionParams, {
|
||||
defaultFields: defaultAdminDiscountsFields,
|
||||
defaultRelations: defaultAdminDiscountsRelations,
|
||||
isList: false,
|
||||
}),
|
||||
transformBody(AdminPostDiscountsDiscountConditionsCondition),
|
||||
middlewares.wrap(require("./update-condition").default)
|
||||
)
|
||||
conditionRouter.post(
|
||||
"/batch",
|
||||
transformQuery(AdminPostDiscountsDiscountConditionsConditionBatchParams, {
|
||||
defaultFields: defaultAdminDiscountsFields,
|
||||
defaultRelations: defaultAdminDiscountsRelations,
|
||||
isList: false,
|
||||
}),
|
||||
transformBody(AdminPostDiscountsDiscountConditionsConditionBatchReq),
|
||||
middlewares.wrap(require("./add-resources-to-condition-batch").default)
|
||||
)
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
@@ -129,3 +234,4 @@ export * from "./list-discounts"
|
||||
export * from "./remove-region"
|
||||
export * from "./update-condition"
|
||||
export * from "./update-discount"
|
||||
export * from "./add-resources-to-condition-batch"
|
||||
|
||||
@@ -1,20 +1,15 @@
|
||||
import {
|
||||
IsBoolean,
|
||||
IsInt,
|
||||
IsOptional,
|
||||
IsString,
|
||||
ValidateNested,
|
||||
} from "class-validator"
|
||||
import { Transform, Type } from "class-transformer"
|
||||
import _, { pickBy } from "lodash"
|
||||
import { defaultAdminDiscountsFields, defaultAdminDiscountsRelations } from "."
|
||||
|
||||
import { AdminGetDiscountsDiscountRuleParams } from "../../../../types/discount"
|
||||
import { Discount } from "../../../.."
|
||||
import DiscountService from "../../../../services/discount"
|
||||
import { FindConfig } from "../../../../types/common"
|
||||
import { validator } from "../../../../utils/validator"
|
||||
import { isDefined } from "../../../../utils"
|
||||
import { extendedFindParamsMixin } from "../../../../types/common"
|
||||
import { Request, Response } from "express"
|
||||
import { DiscountService } from "../../../../services"
|
||||
|
||||
/**
|
||||
* @oas [get] /discounts
|
||||
@@ -97,38 +92,29 @@ import { isDefined } from "../../../../utils"
|
||||
* "500":
|
||||
* $ref: "#/components/responses/500_error"
|
||||
*/
|
||||
export default async (req, res) => {
|
||||
const validated = await validator(AdminGetDiscountsParams, req.query)
|
||||
|
||||
export default async (req: Request, res: Response) => {
|
||||
const discountService: DiscountService = req.scope.resolve("discountService")
|
||||
|
||||
const relations =
|
||||
validated.expand?.split(",") ?? defaultAdminDiscountsRelations
|
||||
|
||||
const listConfig: FindConfig<Discount> = {
|
||||
select: defaultAdminDiscountsFields,
|
||||
relations,
|
||||
skip: validated.offset,
|
||||
take: validated.limit,
|
||||
order: { created_at: "DESC" },
|
||||
}
|
||||
|
||||
const filterableFields = _.omit(validated, ["limit", "offset", "expand"])
|
||||
const { filterableFields, listConfig } = req
|
||||
const { skip, take } = listConfig
|
||||
|
||||
const [discounts, count] = await discountService.listAndCount(
|
||||
pickBy(filterableFields, (val) => isDefined(val)),
|
||||
filterableFields,
|
||||
listConfig
|
||||
)
|
||||
|
||||
res.status(200).json({
|
||||
discounts,
|
||||
count,
|
||||
offset: validated.offset,
|
||||
limit: validated.limit,
|
||||
offset: skip,
|
||||
limit: take,
|
||||
})
|
||||
}
|
||||
|
||||
export class AdminGetDiscountsParams {
|
||||
export class AdminGetDiscountsParams extends extendedFindParamsMixin({
|
||||
limit: 20,
|
||||
offset: 0,
|
||||
}) {
|
||||
@ValidateNested()
|
||||
@IsOptional()
|
||||
@Type(() => AdminGetDiscountsDiscountRuleParams)
|
||||
@@ -147,18 +133,4 @@ export class AdminGetDiscountsParams {
|
||||
@IsOptional()
|
||||
@Transform(({ value }) => value === "true")
|
||||
is_disabled?: boolean
|
||||
|
||||
@IsInt()
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
limit = 20
|
||||
|
||||
@IsInt()
|
||||
@IsOptional()
|
||||
@Type(() => Number)
|
||||
offset = 0
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
expand?: string
|
||||
}
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
import { IsOptional, IsString } from "class-validator"
|
||||
import { defaultAdminDiscountsFields, defaultAdminDiscountsRelations } from "."
|
||||
|
||||
import { Request, Response } from "express"
|
||||
import { AdminUpsertConditionsReq } from "../../../../types/discount"
|
||||
import { Discount } from "../../../../models"
|
||||
import DiscountConditionService from "../../../../services/discount-condition"
|
||||
import { DiscountService } from "../../../../services"
|
||||
import { EntityManager } from "typeorm"
|
||||
import { getRetrieveConfig } from "../../../../utils/get-query-config"
|
||||
import { validator } from "../../../../utils/validator"
|
||||
import { FindParams } from "../../../../types/common"
|
||||
|
||||
/**
|
||||
* @oas [post] /discounts/{discount_id}/conditions/{condition_id}
|
||||
@@ -104,19 +100,9 @@ import { validator } from "../../../../utils/validator"
|
||||
* $ref: "#/components/responses/500_error"
|
||||
*/
|
||||
|
||||
export default async (req, res) => {
|
||||
export default async (req: Request, res: Response) => {
|
||||
const { discount_id, condition_id } = req.params
|
||||
|
||||
const validatedCondition = await validator(
|
||||
AdminPostDiscountsDiscountConditionsCondition,
|
||||
req.body
|
||||
)
|
||||
|
||||
const validatedParams = await validator(
|
||||
AdminPostDiscountsDiscountConditionsConditionParams,
|
||||
req.query
|
||||
)
|
||||
|
||||
const conditionService: DiscountConditionService = req.scope.resolve(
|
||||
"discountConditionService"
|
||||
)
|
||||
@@ -128,7 +114,7 @@ export default async (req, res) => {
|
||||
let discount = await discountService.retrieve(discount_id)
|
||||
|
||||
const updateObj = {
|
||||
...validatedCondition,
|
||||
...(req.validatedBody as AdminPostDiscountsDiscountConditionsCondition),
|
||||
rule_id: discount.rule_id,
|
||||
id: condition.id,
|
||||
}
|
||||
@@ -140,14 +126,7 @@ export default async (req, res) => {
|
||||
.upsertCondition(updateObj)
|
||||
})
|
||||
|
||||
const config = getRetrieveConfig<Discount>(
|
||||
defaultAdminDiscountsFields,
|
||||
defaultAdminDiscountsRelations,
|
||||
validatedParams?.fields?.split(",") as (keyof Discount)[],
|
||||
validatedParams?.expand?.split(",")
|
||||
)
|
||||
|
||||
discount = await discountService.retrieve(discount.id, config)
|
||||
discount = await discountService.retrieve(discount.id, req.retrieveConfig)
|
||||
|
||||
res.status(200).json({ discount })
|
||||
}
|
||||
@@ -155,12 +134,4 @@ export default async (req, res) => {
|
||||
// eslint-disable-next-line max-len
|
||||
export class AdminPostDiscountsDiscountConditionsCondition extends AdminUpsertConditionsReq {}
|
||||
|
||||
export class AdminPostDiscountsDiscountConditionsConditionParams {
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
expand?: string
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
fields?: string
|
||||
}
|
||||
export class AdminPostDiscountsDiscountConditionsConditionParams extends FindParams {}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Discount, DiscountConditionOperator } from "../../../../models"
|
||||
import { Request, Response } from "express"
|
||||
import { AllocationType, DiscountConditionOperator } from "../../../../models"
|
||||
import {
|
||||
IsArray,
|
||||
IsBoolean,
|
||||
@@ -12,17 +13,14 @@ import {
|
||||
IsString,
|
||||
ValidateNested,
|
||||
} from "class-validator"
|
||||
import { defaultAdminDiscountsFields, defaultAdminDiscountsRelations } from "."
|
||||
|
||||
import { AdminUpsertConditionsReq } from "../../../../types/discount"
|
||||
import { AllocationType } from "../../../../models"
|
||||
import DiscountService from "../../../../services/discount"
|
||||
import { EntityManager } from "typeorm"
|
||||
import { IsGreaterThan } from "../../../../utils/validators/greater-than"
|
||||
import { IsISO8601Duration } from "../../../../utils/validators/iso8601-duration"
|
||||
import { Type } from "class-transformer"
|
||||
import { getRetrieveConfig } from "../../../../utils/get-query-config"
|
||||
import { validator } from "../../../../utils/validator"
|
||||
import { FindParams } from "../../../../types/common"
|
||||
|
||||
/**
|
||||
* @oas [post] /discounts/{id}
|
||||
@@ -176,34 +174,23 @@ import { validator } from "../../../../utils/validator"
|
||||
* "500":
|
||||
* $ref: "#/components/responses/500_error"
|
||||
*/
|
||||
export default async (req, res) => {
|
||||
export default async (req: Request, res: Response) => {
|
||||
const { discount_id } = req.params
|
||||
|
||||
const validated = await validator(AdminPostDiscountsDiscountReq, req.body)
|
||||
|
||||
const validatedParams = await validator(
|
||||
AdminPostDiscountsDiscountParams,
|
||||
req.query
|
||||
)
|
||||
|
||||
const discountService: DiscountService = req.scope.resolve("discountService")
|
||||
|
||||
const manager: EntityManager = req.scope.resolve("manager")
|
||||
await manager.transaction(async (transactionManager) => {
|
||||
return await discountService
|
||||
.withTransaction(transactionManager)
|
||||
.update(discount_id, validated)
|
||||
.update(discount_id, req.validatedBody as AdminPostDiscountsDiscountReq)
|
||||
})
|
||||
|
||||
const config = getRetrieveConfig<Discount>(
|
||||
defaultAdminDiscountsFields,
|
||||
defaultAdminDiscountsRelations,
|
||||
validatedParams?.fields?.split(",") as (keyof Discount)[],
|
||||
validatedParams?.expand?.split(",")
|
||||
const discount = await discountService.retrieve(
|
||||
discount_id,
|
||||
req.retrieveConfig
|
||||
)
|
||||
|
||||
const discount = await discountService.retrieve(discount_id, config)
|
||||
|
||||
res.status(200).json({ discount })
|
||||
}
|
||||
|
||||
@@ -287,12 +274,4 @@ export class AdminUpsertCondition extends AdminUpsertConditionsReq {
|
||||
operator: DiscountConditionOperator
|
||||
}
|
||||
|
||||
export class AdminPostDiscountsDiscountParams {
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
expand?: string
|
||||
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
fields?: string
|
||||
}
|
||||
export class AdminPostDiscountsDiscountParams extends FindParams {}
|
||||
|
||||
Reference in New Issue
Block a user