feat: Admin shipping options routes to Typescript (#891)
This commit is contained in:
committed by
GitHub
parent
487356a96f
commit
6579c13111
@@ -383,4 +383,95 @@ describe("/admin/shipping-options", () => {
|
||||
}
|
||||
})
|
||||
})
|
||||
describe("GET /admin/shipping-options", () => {
|
||||
beforeEach(async () => {
|
||||
try {
|
||||
await adminSeeder(dbConnection)
|
||||
await shippingOptionSeeder(dbConnection)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
throw err
|
||||
}
|
||||
})
|
||||
|
||||
afterEach(async () => {
|
||||
const db = useDb()
|
||||
await db.teardown()
|
||||
})
|
||||
|
||||
it("lists shipping options", async () => {
|
||||
const api = useApi()
|
||||
const res = await api.get(`/admin/shipping-options`, {
|
||||
headers: {
|
||||
Authorization: "Bearer test_token",
|
||||
},
|
||||
})
|
||||
|
||||
expect(res.status).toEqual(200)
|
||||
})
|
||||
|
||||
it("lists admin only shipping options", async () => {
|
||||
const api = useApi()
|
||||
const res = await api.get(`/admin/shipping-options?admin_only=true`, {
|
||||
headers: {
|
||||
Authorization: "Bearer test_token",
|
||||
},
|
||||
})
|
||||
|
||||
expect(res.status).toEqual(200)
|
||||
expect(res.data.shipping_options).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
id: "test-option-req-admin-only",
|
||||
admin_only: true,
|
||||
}),
|
||||
])
|
||||
)
|
||||
})
|
||||
|
||||
it("lists return shipping options", async () => {
|
||||
const api = useApi()
|
||||
const res = await api.get(`/admin/shipping-options?is_return=true`, {
|
||||
headers: {
|
||||
Authorization: "Bearer test_token",
|
||||
},
|
||||
})
|
||||
|
||||
expect(res.status).toEqual(200)
|
||||
expect(res.data.shipping_options).toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
id: "test-option-req-return",
|
||||
is_return: true,
|
||||
}),
|
||||
])
|
||||
)
|
||||
})
|
||||
|
||||
it("lists shipping options without return and admin options", async () => {
|
||||
const api = useApi()
|
||||
const res = await api.get(
|
||||
`/admin/shipping-options?is_return=false&admin_only=true`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: "Bearer test_token",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
expect(res.status).toEqual(200)
|
||||
expect(res.data.shipping_options).not.toEqual(
|
||||
expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
id: "test-option-req-return",
|
||||
is_return: true,
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: "test-option-req-admin-only",
|
||||
admin_only: true,
|
||||
}),
|
||||
])
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -43,6 +43,30 @@ module.exports = async (connection, data = {}) => {
|
||||
is_return: false,
|
||||
})
|
||||
|
||||
await manager.insert(ShippingOption, {
|
||||
id: "test-option-req-admin-only",
|
||||
name: "With req",
|
||||
profile_id: defaultProfile.id,
|
||||
region_id: "region",
|
||||
admin_only: true,
|
||||
provider_id: "test-ful",
|
||||
data: {},
|
||||
price_type: "flat_rate",
|
||||
amount: 2000,
|
||||
is_return: false,
|
||||
})
|
||||
await manager.insert(ShippingOption, {
|
||||
id: "test-option-req-return",
|
||||
name: "With req",
|
||||
profile_id: defaultProfile.id,
|
||||
region_id: "region",
|
||||
is_return: true,
|
||||
provider_id: "test-ful",
|
||||
data: {},
|
||||
price_type: "flat_rate",
|
||||
amount: 2000,
|
||||
})
|
||||
|
||||
await manager.insert(ShippingOptionRequirement, {
|
||||
id: "option-req",
|
||||
shipping_option_id: "test-option-req",
|
||||
|
||||
@@ -8,15 +8,15 @@
|
||||
"build": "babel src -d dist --extensions \".ts,.js\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@medusajs/medusa": "1.1.57-dev-1638295280349",
|
||||
"medusa-interfaces": "1.1.31-dev-1638295280349",
|
||||
"@medusajs/medusa": "1.1.57-dev-1638874121913",
|
||||
"medusa-interfaces": "1.1.31-dev-1638874121913",
|
||||
"typeorm": "^0.2.31"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/cli": "^7.12.10",
|
||||
"@babel/core": "^7.12.10",
|
||||
"@babel/node": "^7.12.10",
|
||||
"babel-preset-medusa-package": "1.1.18-dev-1638295280349",
|
||||
"babel-preset-medusa-package": "1.1.18-dev-1638874121913",
|
||||
"jest": "^26.6.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1256,10 +1256,10 @@
|
||||
"@types/yargs" "^15.0.0"
|
||||
chalk "^4.0.0"
|
||||
|
||||
"@medusajs/medusa-cli@1.1.23-dev-1638295280349":
|
||||
version "1.1.23-dev-1638295280349"
|
||||
resolved "http://localhost:4873/@medusajs%2fmedusa-cli/-/medusa-cli-1.1.23-dev-1638295280349.tgz#65fb12a6d63a0132f93547373344f2352d184a13"
|
||||
integrity sha512-EcnaL44hGs7vlC7vujPeebzx0HK3nj4ADikoAsrXeaulzGOcAaqrHSgMC8g/pz3f8vDFdimm1tqemWL+Zr1ijQ==
|
||||
"@medusajs/medusa-cli@1.1.23-dev-1638874121913":
|
||||
version "1.1.23-dev-1638874121913"
|
||||
resolved "http://localhost:4873/@medusajs%2fmedusa-cli/-/medusa-cli-1.1.23-dev-1638874121913.tgz#6f12e4f54c08f4846ce3c213fb3407833b1febec"
|
||||
integrity sha512-ZhO3UhIdyjKOoqjfWn09wmV7Vk2A52qOE3JwLvJkyiPVt3tO23/2H7DHF93faYtrKjBCo32xSLBuZYqsRm6p+w==
|
||||
dependencies:
|
||||
"@babel/polyfill" "^7.8.7"
|
||||
"@babel/runtime" "^7.9.6"
|
||||
@@ -1277,8 +1277,8 @@
|
||||
is-valid-path "^0.1.1"
|
||||
joi-objectid "^3.0.1"
|
||||
meant "^1.0.1"
|
||||
medusa-core-utils "1.1.30-dev-1638295280349"
|
||||
medusa-telemetry "0.0.10-dev-1638295280349"
|
||||
medusa-core-utils "1.1.30-dev-1638874121913"
|
||||
medusa-telemetry "0.0.10-dev-1638874121913"
|
||||
netrc-parser "^3.1.6"
|
||||
open "^8.0.6"
|
||||
ora "^5.4.1"
|
||||
@@ -1292,13 +1292,13 @@
|
||||
winston "^3.3.3"
|
||||
yargs "^15.3.1"
|
||||
|
||||
"@medusajs/medusa@1.1.57-dev-1638295280349":
|
||||
version "1.1.57-dev-1638295280349"
|
||||
resolved "http://localhost:4873/@medusajs%2fmedusa/-/medusa-1.1.57-dev-1638295280349.tgz#ea276c471ca79db87ab44e761c22f6c68068e39a"
|
||||
integrity sha512-xAY1NO/7i6hinYkUWXtyH7ievW6oY0WJ3ZPN6q3vQBs8wsaysmsev1CHpjq7pZZJ6JUNGL39m4wTwUnCMQ+stw==
|
||||
"@medusajs/medusa@1.1.57-dev-1638874121913":
|
||||
version "1.1.57-dev-1638874121913"
|
||||
resolved "http://localhost:4873/@medusajs%2fmedusa/-/medusa-1.1.57-dev-1638874121913.tgz#c4a40d588a2567a6f80a84b8017dd64382e224bc"
|
||||
integrity sha512-WSTL4U3TnB7u8YjaqaEnfjQQCmQMpZIqAwRA2+1SuaRrW3A3SYbxoRkL/3bgH13KGv/PCBAvkV1e7l9xcziAnQ==
|
||||
dependencies:
|
||||
"@hapi/joi" "^16.1.8"
|
||||
"@medusajs/medusa-cli" "1.1.23-dev-1638295280349"
|
||||
"@medusajs/medusa-cli" "1.1.23-dev-1638874121913"
|
||||
"@types/lodash" "^4.14.168"
|
||||
awilix "^4.2.3"
|
||||
body-parser "^1.19.0"
|
||||
@@ -1322,8 +1322,8 @@
|
||||
joi "^17.3.0"
|
||||
joi-objectid "^3.0.1"
|
||||
jsonwebtoken "^8.5.1"
|
||||
medusa-core-utils "1.1.30-dev-1638295280349"
|
||||
medusa-test-utils "1.1.33-dev-1638295280349"
|
||||
medusa-core-utils "1.1.30-dev-1638874121913"
|
||||
medusa-test-utils "1.1.33-dev-1638874121913"
|
||||
morgan "^1.9.1"
|
||||
multer "^1.4.2"
|
||||
passport "^0.4.0"
|
||||
@@ -1947,10 +1947,10 @@ babel-preset-jest@^26.6.2:
|
||||
babel-plugin-jest-hoist "^26.6.2"
|
||||
babel-preset-current-node-syntax "^1.0.0"
|
||||
|
||||
babel-preset-medusa-package@1.1.18-dev-1638295280349:
|
||||
version "1.1.18-dev-1638295280349"
|
||||
resolved "http://localhost:4873/babel-preset-medusa-package/-/babel-preset-medusa-package-1.1.18-dev-1638295280349.tgz#fa9b9b75642d40b0235f1fbc06f8bea1a166c600"
|
||||
integrity sha512-hfj+GRAzaG8GY3tBbq7y+Hpcf4CkCp3/GsdbxWjJYdWirBOLgRKxaOip8A9mEtxPk8DEFQfsgMyyJnraRpVSZw==
|
||||
babel-preset-medusa-package@1.1.18-dev-1638874121913:
|
||||
version "1.1.18-dev-1638874121913"
|
||||
resolved "http://localhost:4873/babel-preset-medusa-package/-/babel-preset-medusa-package-1.1.18-dev-1638874121913.tgz#d50b513bbbfe691318c9b9463c7ec0c0c1ca8711"
|
||||
integrity sha512-FDJyHCp+FyncJDlapHIwxHRUkM/RCxKy7+XIMmlJRGsiF6a7KGjPwQF6KUhVN3vkCl7LMBrO4qPa40uE9N5zVQ==
|
||||
dependencies:
|
||||
"@babel/plugin-proposal-class-properties" "^7.12.1"
|
||||
"@babel/plugin-proposal-decorators" "^7.12.1"
|
||||
@@ -5135,25 +5135,25 @@ media-typer@0.3.0:
|
||||
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
||||
integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
|
||||
|
||||
medusa-core-utils@1.1.30-dev-1638295280349:
|
||||
version "1.1.30-dev-1638295280349"
|
||||
resolved "http://localhost:4873/medusa-core-utils/-/medusa-core-utils-1.1.30-dev-1638295280349.tgz#bead12ee83fa00a03dd208329260b73eaea2a019"
|
||||
integrity sha512-i4SXOB5VARyYgDMAydfZXK8DHrHZUjad0ABsxOD4m1XYBGMLJfcBQFfOzAiipQDuX38cVAQUoVnPbM3fm1WLKQ==
|
||||
medusa-core-utils@1.1.30-dev-1638874121913:
|
||||
version "1.1.30-dev-1638874121913"
|
||||
resolved "http://localhost:4873/medusa-core-utils/-/medusa-core-utils-1.1.30-dev-1638874121913.tgz#72e5b0694fecbc83a61c58af212d993bb7b2104a"
|
||||
integrity sha512-ldQ7WXJTdaGzUMVsF8LJqr5uLCJT0ZYUUTYUGazCgj30kULSUV3/VZm4+B7a5D7UoqJMexBqG+qmRDzCZ74Drg==
|
||||
dependencies:
|
||||
joi "^17.3.0"
|
||||
joi-objectid "^3.0.1"
|
||||
|
||||
medusa-interfaces@1.1.31-dev-1638295280349:
|
||||
version "1.1.31-dev-1638295280349"
|
||||
resolved "http://localhost:4873/medusa-interfaces/-/medusa-interfaces-1.1.31-dev-1638295280349.tgz#978e0215a8b232e375a6ec512dc1e3e65a1d6de7"
|
||||
integrity sha512-Qs9qYTtYfGTJfDrjRFvQiSTNsQNjpAfdMlNXxeH/HAXZxk3/bYHdf51c8FNhpoMX/zHA150B4yPDksHf0B1Eeg==
|
||||
medusa-interfaces@1.1.31-dev-1638874121913:
|
||||
version "1.1.31-dev-1638874121913"
|
||||
resolved "http://localhost:4873/medusa-interfaces/-/medusa-interfaces-1.1.31-dev-1638874121913.tgz#0ee6c3efe637eff3364b1bd69419001a8db14422"
|
||||
integrity sha512-NUzBuml4/mxSpx5BBgkQVDNqItdrYlXqqNjwhq5GjHgqkCDVrQRJA5GGcQJ/17NbRSr6KKVEJuKkWlFhOgadkQ==
|
||||
dependencies:
|
||||
medusa-core-utils "1.1.30-dev-1638295280349"
|
||||
medusa-core-utils "1.1.30-dev-1638874121913"
|
||||
|
||||
medusa-telemetry@0.0.10-dev-1638295280349:
|
||||
version "0.0.10-dev-1638295280349"
|
||||
resolved "http://localhost:4873/medusa-telemetry/-/medusa-telemetry-0.0.10-dev-1638295280349.tgz#00c397861ec79453733865a20ca4fc5e37b4152f"
|
||||
integrity sha512-qRdXd5DcGv0eFZJ70Ns79sJL13xKOXd8trVQEkUjPAWTcaxtmb1tCw8vXQAoWXycq+9kb7KS3zcTdBnI+ML2Bw==
|
||||
medusa-telemetry@0.0.10-dev-1638874121913:
|
||||
version "0.0.10-dev-1638874121913"
|
||||
resolved "http://localhost:4873/medusa-telemetry/-/medusa-telemetry-0.0.10-dev-1638874121913.tgz#b8e58daa306dfeffbf28bdadca12ac852beb7912"
|
||||
integrity sha512-3V/Um1B2NzmztGttGFNSFzT0ZPyGg6vsxZc1M4XTDQfB1YeioQYImQiGw62mIpnKxTyRLWpQfkaiRIK9ILNL+Q==
|
||||
dependencies:
|
||||
axios "^0.21.1"
|
||||
axios-retry "^3.1.9"
|
||||
@@ -5165,13 +5165,13 @@ medusa-telemetry@0.0.10-dev-1638295280349:
|
||||
remove-trailing-slash "^0.1.1"
|
||||
uuid "^8.3.2"
|
||||
|
||||
medusa-test-utils@1.1.33-dev-1638295280349:
|
||||
version "1.1.33-dev-1638295280349"
|
||||
resolved "http://localhost:4873/medusa-test-utils/-/medusa-test-utils-1.1.33-dev-1638295280349.tgz#61dc97815f02a3a0756ce5ac4f8cdaace7cd8a92"
|
||||
integrity sha512-CqKubpbybtCt/SVjdbwM44KA2b9jFH8NMfmjTy/FJnuWqus5GWi6nBYhBMJM609uuSbGXCv8HmhI4B5fg4Cy8A==
|
||||
medusa-test-utils@1.1.33-dev-1638874121913:
|
||||
version "1.1.33-dev-1638874121913"
|
||||
resolved "http://localhost:4873/medusa-test-utils/-/medusa-test-utils-1.1.33-dev-1638874121913.tgz#422aa74ceff6e09abf28c070ea941982544afbad"
|
||||
integrity sha512-I7Z0GCdPQWMwygffjKw9CnGkFeudA/TCmxNTkWna+4WOlK3FFoilAi/T6Ps3q4ZDXkJ1O+vNG9yBG9zAldGPmw==
|
||||
dependencies:
|
||||
"@babel/plugin-transform-classes" "^7.9.5"
|
||||
medusa-core-utils "1.1.30-dev-1638295280349"
|
||||
medusa-core-utils "1.1.30-dev-1638874121913"
|
||||
randomatic "^3.1.1"
|
||||
|
||||
merge-descriptors@1.0.1:
|
||||
|
||||
@@ -43,8 +43,9 @@ describe("POST /admin/shipping-options", () => {
|
||||
name: "Test option",
|
||||
region_id: "testregion",
|
||||
provider_id: "test_provider",
|
||||
metadata: undefined,
|
||||
data: { id: "test" },
|
||||
profile_id: expect.stringMatching(/.*/),
|
||||
profile_id: expect.any(String),
|
||||
price_type: "flat_rate",
|
||||
amount: 100,
|
||||
requirements: [
|
||||
@@ -86,7 +87,9 @@ describe("POST /admin/shipping-options", () => {
|
||||
})
|
||||
|
||||
it("returns error", () => {
|
||||
expect(subject.body.message[0].message).toEqual(`"name" is required`)
|
||||
expect(subject.body.message).toEqual(
|
||||
expect.stringContaining(`name must be a string`)
|
||||
)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,11 +1,21 @@
|
||||
import { MedusaError, Validator } from "medusa-core-utils"
|
||||
import { defaultFields, defaultRelations } from "./"
|
||||
import { Type } from "class-transformer"
|
||||
import {
|
||||
IsArray,
|
||||
IsNumber,
|
||||
IsObject,
|
||||
IsOptional,
|
||||
IsString,
|
||||
ValidateNested,
|
||||
} from "class-validator"
|
||||
import { defaultFields, defaultRelations } from "."
|
||||
import { validator } from "../../../../utils/validator"
|
||||
|
||||
/**
|
||||
* @oas [post] /shipping-options
|
||||
* operationId: "PostShippingOptions"
|
||||
* summary: "Create Shipping Option"
|
||||
* description: "Creates a Shipping Option"
|
||||
* x-authenticated: true
|
||||
* requestBody:
|
||||
* content:
|
||||
* application/json:
|
||||
@@ -52,6 +62,12 @@ import { defaultFields, defaultRelations } from "./"
|
||||
* is_return:
|
||||
* description: Whether the Shipping Option defines a return shipment.
|
||||
* type: boolean
|
||||
* admin_only:
|
||||
* description: If true, the option can be used for draft orders
|
||||
* type: boolean
|
||||
* metadata:
|
||||
* description: An optional set of key-value pairs with additional information.
|
||||
* type: object
|
||||
* tags:
|
||||
* - Shipping Option
|
||||
* responses:
|
||||
@@ -65,41 +81,18 @@ import { defaultFields, defaultRelations } from "./"
|
||||
* $ref: "#/components/schemas/shipping_option"
|
||||
*/
|
||||
export default async (req, res) => {
|
||||
const schema = Validator.object().keys({
|
||||
name: Validator.string().required(),
|
||||
region_id: Validator.string().required(),
|
||||
provider_id: Validator.string().required(),
|
||||
profile_id: Validator.string(),
|
||||
data: Validator.object().required(),
|
||||
price_type: Validator.string().required(),
|
||||
amount: Validator.number().integer().optional(),
|
||||
requirements: Validator.array()
|
||||
.items(
|
||||
Validator.object({
|
||||
type: Validator.string().required(),
|
||||
amount: Validator.number().integer().required(),
|
||||
})
|
||||
)
|
||||
.optional(),
|
||||
is_return: Validator.boolean().default(false),
|
||||
admin_only: Validator.boolean().default(false),
|
||||
})
|
||||
|
||||
const { value, error } = schema.validate(req.body)
|
||||
if (error) {
|
||||
throw new MedusaError(MedusaError.Types.INVALID_DATA, error.details)
|
||||
}
|
||||
const validated = await validator(AdminPostShippingOptionsReq, req.body)
|
||||
|
||||
const optionService = req.scope.resolve("shippingOptionService")
|
||||
const shippingProfileService = req.scope.resolve("shippingProfileService")
|
||||
|
||||
// Add to default shipping profile
|
||||
if (!value.profile_id) {
|
||||
if (!validated.profile_id) {
|
||||
const { id } = await shippingProfileService.retrieveDefault()
|
||||
value.profile_id = id
|
||||
validated.profile_id = id
|
||||
}
|
||||
|
||||
const result = await optionService.create(value)
|
||||
const result = await optionService.create(validated)
|
||||
const data = await optionService.retrieve(result.id, {
|
||||
select: defaultFields,
|
||||
relations: defaultRelations,
|
||||
@@ -107,3 +100,53 @@ export default async (req, res) => {
|
||||
|
||||
res.status(200).json({ shipping_option: data })
|
||||
}
|
||||
|
||||
class OptionRequirement {
|
||||
@IsString()
|
||||
type: string
|
||||
@IsNumber()
|
||||
amount: number
|
||||
}
|
||||
|
||||
export class AdminPostShippingOptionsReq {
|
||||
@IsString()
|
||||
name: string
|
||||
|
||||
@IsString()
|
||||
region_id: string
|
||||
|
||||
@IsString()
|
||||
provider_id: string
|
||||
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
profile_id?: string
|
||||
|
||||
@IsObject()
|
||||
data: object
|
||||
|
||||
@IsString()
|
||||
price_type: string
|
||||
|
||||
@IsOptional()
|
||||
@IsNumber()
|
||||
amount?: number
|
||||
|
||||
@IsArray()
|
||||
@IsOptional()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => OptionRequirement)
|
||||
requirements?: OptionRequirement[]
|
||||
|
||||
@IsOptional()
|
||||
@Type(() => Boolean)
|
||||
admin_only?: boolean = false
|
||||
|
||||
@IsOptional()
|
||||
@Type(() => Boolean)
|
||||
is_return?: boolean = false
|
||||
|
||||
@IsObject()
|
||||
@IsOptional()
|
||||
metadata?: object
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
* operationId: "DeleteShippingOptionsOption"
|
||||
* summary: "Delete a Shipping Option"
|
||||
* description: "Deletes a Shipping Option."
|
||||
* x-authenticated: true
|
||||
* parameters:
|
||||
* - (path) id=* {string} The id of the Shipping Option.
|
||||
* tags:
|
||||
@@ -3,6 +3,7 @@
|
||||
* operationId: "GetShippingOptionsOption"
|
||||
* summary: "Retrieve a Shipping Option"
|
||||
* description: "Retrieves a Shipping Option."
|
||||
* x-authenticated: true
|
||||
* parameters:
|
||||
* - (path) id=* {string} The id of the Shipping Option.
|
||||
* tags:
|
||||
@@ -1,4 +1,6 @@
|
||||
import { Router } from "express"
|
||||
import { ShippingOption } from "../../../.."
|
||||
import { DeleteResponse } from "../../../../types/common"
|
||||
import middlewares from "../../../middlewares"
|
||||
|
||||
const route = Router()
|
||||
@@ -43,3 +45,19 @@ export const defaultFields = [
|
||||
]
|
||||
|
||||
export const defaultRelations = ["region", "profile", "requirements"]
|
||||
|
||||
export type AdminShippingOptionsListRes = {
|
||||
shipping_options: ShippingOption[]
|
||||
}
|
||||
|
||||
export type AdminShippingOptionsRes = {
|
||||
shipping_option: ShippingOption
|
||||
}
|
||||
|
||||
export type AdminShippingOptionsDeleteRes = DeleteResponse
|
||||
|
||||
export * from "./create-shipping-option"
|
||||
export * from "./delete-shipping-option"
|
||||
export * from "./get-shipping-option"
|
||||
export * from "./list-shipping-options"
|
||||
export * from "./update-shipping-option"
|
||||
@@ -1,33 +0,0 @@
|
||||
import _ from "lodash"
|
||||
import { defaultFields, defaultRelations } from "./"
|
||||
|
||||
/**
|
||||
* @oas [get] /shipping-options
|
||||
* operationId: "GetShippingOptions"
|
||||
* summary: "List Shipping Options"
|
||||
* description: "Retrieves a list of Shipping Options."
|
||||
* tags:
|
||||
* - Shipping Option
|
||||
* responses:
|
||||
* 200:
|
||||
* description: OK
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* properties:
|
||||
* shipping_options:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: "#/components/schemas/shipping_option"
|
||||
*/
|
||||
export default async (req, res) => {
|
||||
const query = _.pick(req.query, ["region_id", "is_return", "admin_only"])
|
||||
|
||||
const optionService = req.scope.resolve("shippingOptionService")
|
||||
const data = await optionService.list(query, {
|
||||
select: defaultFields,
|
||||
relations: defaultRelations,
|
||||
})
|
||||
|
||||
res.status(200).json({ shipping_options: data })
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
import { Transform } from "class-transformer"
|
||||
import { IsBoolean, IsOptional, IsString } from "class-validator"
|
||||
import { defaultFields, defaultRelations } from "."
|
||||
import { validator } from "../../../../utils/validator"
|
||||
import { optionalBooleanMapper } from "../../../../utils/validators/is-boolean"
|
||||
|
||||
/**
|
||||
* @oas [get] /shipping-options
|
||||
* operationId: "GetShippingOptions"
|
||||
* summary: "List Shipping Options"
|
||||
* description: "Retrieves a list of Shipping Options."
|
||||
* x-authenticated: true
|
||||
* parameters:
|
||||
* - in: path
|
||||
* name: region_id
|
||||
* schema:
|
||||
* type: string
|
||||
* required: false
|
||||
* description: Region to fetch options from
|
||||
* - in: path
|
||||
* name: is_return
|
||||
* schema:
|
||||
* type: boolean
|
||||
* required: false
|
||||
* description: Flag for fetching return options
|
||||
* - in: path
|
||||
* name: admin_only
|
||||
* schema:
|
||||
* type: boolean
|
||||
* required: false
|
||||
* description: Flag for fetching admin specific options
|
||||
* tags:
|
||||
* - Shipping Option
|
||||
* responses:
|
||||
* 200:
|
||||
* description: OK
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* properties:
|
||||
* shipping_options:
|
||||
* type: array
|
||||
* items:
|
||||
* $ref: "#/components/schemas/shipping_option"
|
||||
*/
|
||||
export default async (req, res) => {
|
||||
const validatedParams = await validator(
|
||||
AdminGetShippingOptionsParams,
|
||||
req.query
|
||||
)
|
||||
|
||||
const optionService = req.scope.resolve("shippingOptionService")
|
||||
const data = await optionService.list(validatedParams, {
|
||||
select: defaultFields,
|
||||
relations: defaultRelations,
|
||||
})
|
||||
|
||||
res.status(200).json({ shipping_options: data })
|
||||
}
|
||||
|
||||
export class AdminGetShippingOptionsParams {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
region_id?: string
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
@Transform(({ value }) => optionalBooleanMapper.get(value))
|
||||
is_return?: string
|
||||
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
@Transform(({ value }) => optionalBooleanMapper.get(value))
|
||||
admin_only?: string
|
||||
}
|
||||
@@ -1,11 +1,22 @@
|
||||
import { MedusaError, Validator } from "medusa-core-utils"
|
||||
import { defaultFields, defaultRelations } from "./"
|
||||
import { Type } from "class-transformer"
|
||||
import {
|
||||
IsArray,
|
||||
IsBoolean,
|
||||
IsNumber,
|
||||
IsObject,
|
||||
IsOptional,
|
||||
IsString,
|
||||
ValidateNested,
|
||||
} from "class-validator"
|
||||
import { defaultFields, defaultRelations } from "."
|
||||
import { validator } from "../../../../utils/validator"
|
||||
|
||||
/**
|
||||
* @oas [post] /shipping-options/{id}
|
||||
* operationId: "PostShippingOptionsOption"
|
||||
* summary: "Update Shipping Option"
|
||||
* description: "Updates a Shipping Option"
|
||||
* x-authenticated: true
|
||||
* parameters:
|
||||
* - (path) id=* {string} The id of the Shipping Option.
|
||||
* requestBody:
|
||||
@@ -19,6 +30,12 @@ import { defaultFields, defaultRelations } from "./"
|
||||
* amount:
|
||||
* description: "The amount to charge for the Shipping Option."
|
||||
* type: integer
|
||||
* admin_only:
|
||||
* description: "If true, the option can be used for draft orders"
|
||||
* type: boolean
|
||||
* metadata:
|
||||
* description: "An optional set of key-value pairs with additional information."
|
||||
* type: object
|
||||
* requirements:
|
||||
* description: "The requirements that must be satisfied for the Shipping Option to be available."
|
||||
* type: array
|
||||
@@ -47,30 +64,12 @@ import { defaultFields, defaultRelations } from "./"
|
||||
*/
|
||||
export default async (req, res) => {
|
||||
const { option_id } = req.params
|
||||
const schema = Validator.object().keys({
|
||||
name: Validator.string().optional(),
|
||||
amount: Validator.number().integer().optional(),
|
||||
requirements: Validator.array()
|
||||
.items(
|
||||
Validator.object({
|
||||
id: Validator.string().optional(),
|
||||
type: Validator.string().required(),
|
||||
amount: Validator.number().integer().required(),
|
||||
})
|
||||
)
|
||||
.optional(),
|
||||
admin_only: Validator.boolean().optional(),
|
||||
metadata: Validator.object().optional(),
|
||||
})
|
||||
|
||||
const { value, error } = schema.validate(req.body)
|
||||
if (error) {
|
||||
throw new MedusaError(MedusaError.Types.INVALID_DATA, error.details)
|
||||
}
|
||||
const validated = await validator(AdminPostShippingOptionsOptionReq, req.body)
|
||||
|
||||
const optionService = req.scope.resolve("shippingOptionService")
|
||||
|
||||
await optionService.update(option_id, value)
|
||||
await optionService.update(option_id, validated)
|
||||
|
||||
const data = await optionService.retrieve(option_id, {
|
||||
select: defaultFields,
|
||||
@@ -79,3 +78,36 @@ export default async (req, res) => {
|
||||
|
||||
res.status(200).json({ shipping_option: data })
|
||||
}
|
||||
|
||||
class OptionRequirement {
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
id: string
|
||||
@IsString()
|
||||
type: string
|
||||
@IsNumber()
|
||||
amount: number
|
||||
}
|
||||
|
||||
export class AdminPostShippingOptionsOptionReq {
|
||||
@IsString()
|
||||
@IsOptional()
|
||||
name: string
|
||||
|
||||
@IsNumber()
|
||||
@IsOptional()
|
||||
amount?: number
|
||||
|
||||
@IsArray()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => OptionRequirement)
|
||||
requirements: OptionRequirement[]
|
||||
|
||||
@IsBoolean()
|
||||
@IsOptional()
|
||||
admin_only?: boolean
|
||||
|
||||
@IsObject()
|
||||
@IsOptional()
|
||||
metadata?: object
|
||||
}
|
||||
14
packages/medusa/src/utils/validators/is-boolean.ts
Normal file
14
packages/medusa/src/utils/validators/is-boolean.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
// Util function defining the transformation of booleans when part of req.query
|
||||
// e.g. /admin/shipping-options?is_return=false -> false
|
||||
//
|
||||
// We've previously been using @Type(() => Boolean), but this will always return true for strings.
|
||||
// See https://github.com/typestack/class-transformer/issues/676
|
||||
// and https://github.com/typestack/class-transformer/issues/306
|
||||
//
|
||||
// The solution here is stolen from: https://github.com/typestack/class-transformer/issues/676#issuecomment-822699830
|
||||
export const optionalBooleanMapper = new Map([
|
||||
["undefined", undefined],
|
||||
["null", null],
|
||||
["true", true],
|
||||
["false", false],
|
||||
])
|
||||
Reference in New Issue
Block a user