feat(medusa): Support deleting prices from a price list by product or variant (#1555)
This commit is contained in:
@@ -1207,4 +1207,158 @@ describe("/admin/price-lists", () => {
|
|||||||
])
|
])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("delete prices from price list related to the specified product or variant", () => {
|
||||||
|
let product1, product2
|
||||||
|
|
||||||
|
function getCustomPriceIdFromVariant(variantId, index) {
|
||||||
|
return "ma_" + index + "_" + variantId
|
||||||
|
}
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
try {
|
||||||
|
await adminSeeder(dbConnection)
|
||||||
|
|
||||||
|
product1 = await simpleProductFactory(
|
||||||
|
dbConnection,
|
||||||
|
{
|
||||||
|
id: "test-prod-1",
|
||||||
|
title: "some product",
|
||||||
|
variants: [
|
||||||
|
{
|
||||||
|
id: `simple-test-variant-${Math.random() * 1000}`,
|
||||||
|
title: "Test",
|
||||||
|
prices: [{ currency: "usd", amount: 100 }],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: `simple-test-variant-${Math.random() * 1000}`,
|
||||||
|
title: "Test 2",
|
||||||
|
prices: [{ currency: "usd", amount: 200 }],
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
1
|
||||||
|
)
|
||||||
|
|
||||||
|
product2 = await simpleProductFactory(
|
||||||
|
dbConnection,
|
||||||
|
{
|
||||||
|
id: "test-prod-2",
|
||||||
|
title: "some product 2"
|
||||||
|
},
|
||||||
|
2
|
||||||
|
)
|
||||||
|
|
||||||
|
await simplePriceListFactory(dbConnection, {
|
||||||
|
id: "test-list",
|
||||||
|
customer_groups: ["test-group"],
|
||||||
|
prices: [
|
||||||
|
...product1.variants.map((variant, i) => (
|
||||||
|
{
|
||||||
|
id: getCustomPriceIdFromVariant(variant.id, i),
|
||||||
|
variant_id: variant.id,
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: (i + 1) * 150
|
||||||
|
}
|
||||||
|
)),
|
||||||
|
...product2.variants.map((variant, i) => (
|
||||||
|
{
|
||||||
|
id: getCustomPriceIdFromVariant(variant.id, i),
|
||||||
|
variant_id: variant.id,
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: (i + 1) * 150
|
||||||
|
}
|
||||||
|
)),
|
||||||
|
]
|
||||||
|
})
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
const db = useDb()
|
||||||
|
await db.teardown()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should delete all the prices that are part of the price list for the specified product', async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
response = await api
|
||||||
|
.get("/admin/price-lists/test-list", {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response.status).toBe(200)
|
||||||
|
expect(response.data.price_list.prices.length).toBe(3)
|
||||||
|
|
||||||
|
let response = await api
|
||||||
|
.delete(`/admin/price-lists/test-list/products/${product1.id}/prices`, {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response.status).toBe(200)
|
||||||
|
expect(response.data).toEqual({
|
||||||
|
ids: product1.variants.map((variant, i) => {
|
||||||
|
return getCustomPriceIdFromVariant(variant.id, i)
|
||||||
|
}),
|
||||||
|
object: "money-amount",
|
||||||
|
deleted: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
response = await api
|
||||||
|
.get("/admin/price-lists/test-list", {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response.status).toBe(200)
|
||||||
|
expect(response.data.price_list.prices.length).toBe(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should delete all the prices that are part of the price list for the specified variant', async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
response = await api
|
||||||
|
.get("/admin/price-lists/test-list", {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response.status).toBe(200)
|
||||||
|
expect(response.data.price_list.prices.length).toBe(3)
|
||||||
|
|
||||||
|
const variant = product2.variants[0]
|
||||||
|
let response = await api
|
||||||
|
.delete(`/admin/price-lists/test-list/variants/${variant.id}/prices`, {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response.status).toBe(200)
|
||||||
|
expect(response.data).toEqual({
|
||||||
|
ids: [getCustomPriceIdFromVariant(variant.id, 0)],
|
||||||
|
object: "money-amount",
|
||||||
|
deleted: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
response = await api
|
||||||
|
.get("/admin/price-lists/test-list", {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response.status).toBe(200)
|
||||||
|
expect(response.data.price_list.prices.length).toBe(2)
|
||||||
|
})
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -112,5 +112,5 @@ export const simpleProductFactory = async (
|
|||||||
await simpleProductVariantFactory(connection, factoryData)
|
await simpleProductVariantFactory(connection, factoryData)
|
||||||
}
|
}
|
||||||
|
|
||||||
return manager.findOne(Product, { id: prodId }, { relations: ["tags"] })
|
return manager.findOne(Product, { id: prodId }, { relations: ["tags", "variants", "variants.prices"] })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,6 +94,24 @@ class AdminPriceListResource extends BaseResource {
|
|||||||
const path = `/admin/price-lists/${id}/prices/batch`
|
const path = `/admin/price-lists/${id}/prices/batch`
|
||||||
return this.client.request("DELETE", path, payload, {}, customHeaders)
|
return this.client.request("DELETE", path, payload, {}, customHeaders)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
deleteProductPrices(
|
||||||
|
priceListId: string,
|
||||||
|
productId: string,
|
||||||
|
customHeaders: Record<string, any> = {}
|
||||||
|
): ResponsePromise<AdminPriceListDeleteBatchRes> {
|
||||||
|
const path = `/admin/price-lists/${priceListId}/products/${productId}/prices`
|
||||||
|
return this.client.request("DELETE", path, {}, {}, customHeaders)
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteVariantPrices(
|
||||||
|
priceListId: string,
|
||||||
|
variantId: string,
|
||||||
|
customHeaders: Record<string, any> = {}
|
||||||
|
): ResponsePromise<AdminPriceListDeleteBatchRes> {
|
||||||
|
const path = `/admin/price-lists/${priceListId}/variants/${variantId}/prices`
|
||||||
|
return this.client.request("DELETE", path, {}, {}, customHeaders)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AdminPriceListResource
|
export default AdminPriceListResource
|
||||||
|
|||||||
@@ -253,6 +253,28 @@ export const adminHandlers = [
|
|||||||
)
|
)
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
rest.delete("/admin/price-lists/:id/products/:product_id/prices", (req, res, ctx) => {
|
||||||
|
return res(
|
||||||
|
ctx.status(200),
|
||||||
|
ctx.json({
|
||||||
|
ids: [],
|
||||||
|
object: "money-amount",
|
||||||
|
deleted: true,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
|
||||||
|
rest.delete("/admin/price-lists/:id/variants/:variant_id/prices", (req, res, ctx) => {
|
||||||
|
return res(
|
||||||
|
ctx.status(200),
|
||||||
|
ctx.json({
|
||||||
|
ids: [],
|
||||||
|
object: "money-amount",
|
||||||
|
deleted: true,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
|
||||||
rest.post("/admin/return-reasons/", (req, res, ctx) => {
|
rest.post("/admin/return-reasons/", (req, res, ctx) => {
|
||||||
const body = req.body as Record<string, any>
|
const body = req.body as Record<string, any>
|
||||||
return res(
|
return res(
|
||||||
|
|||||||
@@ -6,12 +6,16 @@ import {
|
|||||||
AdminDeletePriceListPricesPricesReq,
|
AdminDeletePriceListPricesPricesReq,
|
||||||
AdminPriceListDeleteRes,
|
AdminPriceListDeleteRes,
|
||||||
AdminPriceListDeleteBatchRes,
|
AdminPriceListDeleteBatchRes,
|
||||||
|
AdminPriceListDeleteProductPricesRes,
|
||||||
|
AdminPriceListDeleteVariantPricesRes,
|
||||||
} from "@medusajs/medusa"
|
} from "@medusajs/medusa"
|
||||||
import { Response } from "@medusajs/medusa-js"
|
import { Response } from "@medusajs/medusa-js"
|
||||||
import { useMutation, UseMutationOptions, useQueryClient } from "react-query"
|
import { useMutation, UseMutationOptions, useQueryClient } from "react-query"
|
||||||
import { useMedusa } from "../../../contexts/medusa"
|
import { useMedusa } from "../../../contexts/medusa"
|
||||||
import { buildOptions } from "../../utils/buildOptions"
|
import { buildOptions } from "../../utils/buildOptions"
|
||||||
import { adminPriceListKeys } from "./queries"
|
import { adminPriceListKeys } from "./queries"
|
||||||
|
import { adminProductKeys } from "../products"
|
||||||
|
import { adminVariantKeys } from "../variants"
|
||||||
|
|
||||||
export const useAdminCreatePriceList = (
|
export const useAdminCreatePriceList = (
|
||||||
options?: UseMutationOptions<
|
options?: UseMutationOptions<
|
||||||
@@ -118,3 +122,53 @@ export const useAdminDeletePriceListPrices = (
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const useAdminDeletePriceListProductPrices = (
|
||||||
|
id: string,
|
||||||
|
productId: string,
|
||||||
|
options?: UseMutationOptions<
|
||||||
|
Response<AdminPriceListDeleteProductPricesRes>,
|
||||||
|
Error
|
||||||
|
>
|
||||||
|
) => {
|
||||||
|
const { client } = useMedusa()
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
|
return useMutation(
|
||||||
|
() => client.admin.priceLists.deleteProductPrices(id, productId),
|
||||||
|
buildOptions(
|
||||||
|
queryClient,
|
||||||
|
[
|
||||||
|
adminPriceListKeys.detail(id),
|
||||||
|
adminPriceListKeys.lists(),
|
||||||
|
adminProductKeys.detail(productId)
|
||||||
|
],
|
||||||
|
options
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useAdminDeletePriceListVariantPrices = (
|
||||||
|
id: string,
|
||||||
|
variantId: string,
|
||||||
|
options?: UseMutationOptions<
|
||||||
|
Response<AdminPriceListDeleteVariantPricesRes>,
|
||||||
|
Error
|
||||||
|
>
|
||||||
|
) => {
|
||||||
|
const { client } = useMedusa()
|
||||||
|
const queryClient = useQueryClient()
|
||||||
|
|
||||||
|
return useMutation(
|
||||||
|
() => client.admin.priceLists.deleteVariantPrices(id, variantId),
|
||||||
|
buildOptions(
|
||||||
|
queryClient,
|
||||||
|
[
|
||||||
|
adminPriceListKeys.detail(id),
|
||||||
|
adminPriceListKeys.lists(),
|
||||||
|
adminVariantKeys.detail(variantId)
|
||||||
|
],
|
||||||
|
options
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export const adminPriceListKeys = {
|
|||||||
"products" as const,
|
"products" as const,
|
||||||
{ ...(query || {}) },
|
{ ...(query || {}) },
|
||||||
] as const
|
] as const
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type PriceListQueryKeys = typeof adminPriceListKeys
|
type PriceListQueryKeys = typeof adminPriceListKeys
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import {
|
|||||||
useAdminCreatePriceListPrices,
|
useAdminCreatePriceListPrices,
|
||||||
useAdminDeletePriceList,
|
useAdminDeletePriceList,
|
||||||
useAdminDeletePriceListPrices,
|
useAdminDeletePriceListPrices,
|
||||||
|
useAdminDeletePriceListProductPrices,
|
||||||
|
useAdminDeletePriceListVariantPrices,
|
||||||
useAdminUpdatePriceList,
|
useAdminUpdatePriceList,
|
||||||
} from "../../../../src"
|
} from "../../../../src"
|
||||||
import { renderHook } from "@testing-library/react-hooks"
|
import { renderHook } from "@testing-library/react-hooks"
|
||||||
@@ -137,3 +139,53 @@ describe("useAdminDeletePriceList hook", () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("useAdminDeletePriceListProductPrices hook", () => {
|
||||||
|
test("should delete prices from a price list for all the variants related to the specified product", async () => {
|
||||||
|
const { result, waitFor } = renderHook(
|
||||||
|
() => useAdminDeletePriceListProductPrices(
|
||||||
|
fixtures.get("price_list").id,
|
||||||
|
fixtures.get("product").id
|
||||||
|
),
|
||||||
|
{
|
||||||
|
wrapper: createWrapper(),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
result.current.mutate()
|
||||||
|
|
||||||
|
await waitFor(() => result.current.isSuccess)
|
||||||
|
|
||||||
|
expect(result.current.data.response.status).toEqual(200)
|
||||||
|
expect(result.current.data).toEqual(expect.objectContaining({
|
||||||
|
ids: [],
|
||||||
|
object: "money-amount",
|
||||||
|
deleted: true
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("useAdminDeletePriceListVariantPrices hook", () => {
|
||||||
|
test("should delete prices from a price list for the specified variant", async () => {
|
||||||
|
const { result, waitFor } = renderHook(
|
||||||
|
() => useAdminDeletePriceListVariantPrices(
|
||||||
|
fixtures.get("price_list").id,
|
||||||
|
fixtures.get("product_variant").id
|
||||||
|
),
|
||||||
|
{
|
||||||
|
wrapper: createWrapper(),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
result.current.mutate()
|
||||||
|
|
||||||
|
await waitFor(() => result.current.isSuccess)
|
||||||
|
|
||||||
|
expect(result.current.data.response.status).toEqual(200)
|
||||||
|
expect(result.current.data).toEqual(expect.objectContaining({
|
||||||
|
ids: [],
|
||||||
|
object: "money-amount",
|
||||||
|
deleted: true
|
||||||
|
}))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import PriceListService from "../../../../services/price-list"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @oas [delete] /price-lists/{id}/products/{product_id}/prices
|
||||||
|
* operationId: "DeletePriceListsPriceListProductsProductPrices"
|
||||||
|
* summary: "Delete all the prices related to a specific product in a price list"
|
||||||
|
* description: "Delete all the prices related to a specific product in a price list"
|
||||||
|
* x-authenticated: true
|
||||||
|
* parameters:
|
||||||
|
* - (path) id=* {string} The id of the Price List that the Money Amounts that will be deleted belongs to.
|
||||||
|
* - (path) product_id=* {string} The id of the product from which the money amount will be deleted.
|
||||||
|
* tags:
|
||||||
|
* - Price List
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: OK
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* properties:
|
||||||
|
* ids:
|
||||||
|
* type: number
|
||||||
|
* description: The price ids that have been deleted.
|
||||||
|
* count:
|
||||||
|
* type: number
|
||||||
|
* description: The number of prices that have been deleted.
|
||||||
|
* object:
|
||||||
|
* type: string
|
||||||
|
* description: The type of the object that was deleted.
|
||||||
|
* deleted:
|
||||||
|
* type: boolean
|
||||||
|
*/
|
||||||
|
export default async (req, res) => {
|
||||||
|
const { id, product_id } = req.params
|
||||||
|
|
||||||
|
const priceListService: PriceListService =
|
||||||
|
req.scope.resolve("priceListService")
|
||||||
|
|
||||||
|
const [deletedPriceIds] = await priceListService.deleteProductPrices(id, [
|
||||||
|
product_id,
|
||||||
|
])
|
||||||
|
|
||||||
|
return res.json({
|
||||||
|
ids: deletedPriceIds,
|
||||||
|
object: "money-amount",
|
||||||
|
deleted: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
import PriceListService from "../../../../services/price-list"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @oas [delete] /price-lists/{id}/variants/{variant_id}/prices
|
||||||
|
* operationId: "DeletePriceListsPriceListVariantsVariantPrices"
|
||||||
|
* summary: "Delete all the prices related to a specific variant in a price list"
|
||||||
|
* description: "Delete all the prices related to a specific variant in a price list"
|
||||||
|
* x-authenticated: true
|
||||||
|
* parameters:
|
||||||
|
* - (path) id=* {string} The id of the Price List that the Money Amounts that will be deleted belongs to.
|
||||||
|
* - (path) variant_id=* {string} The id of the variant from which the money amount will be deleted.
|
||||||
|
* tags:
|
||||||
|
* - Price List
|
||||||
|
* responses:
|
||||||
|
* 200:
|
||||||
|
* description: OK
|
||||||
|
* content:
|
||||||
|
* application/json:
|
||||||
|
* schema:
|
||||||
|
* properties:
|
||||||
|
* ids:
|
||||||
|
* type: number
|
||||||
|
* description: The price ids that have been deleted.
|
||||||
|
* count:
|
||||||
|
* type: number
|
||||||
|
* description: The number of prices that have been deleted.
|
||||||
|
* object:
|
||||||
|
* type: string
|
||||||
|
* description: The type of the object that was deleted.
|
||||||
|
* deleted:
|
||||||
|
* type: boolean
|
||||||
|
*/
|
||||||
|
export default async (req, res) => {
|
||||||
|
const { id, variant_id } = req.params
|
||||||
|
|
||||||
|
const priceListService: PriceListService =
|
||||||
|
req.scope.resolve("priceListService")
|
||||||
|
|
||||||
|
const [deletedPriceIds] = await priceListService.deleteVariantPrices(id, [
|
||||||
|
variant_id,
|
||||||
|
])
|
||||||
|
|
||||||
|
return res.json({
|
||||||
|
ids: deletedPriceIds,
|
||||||
|
object: "money-amount",
|
||||||
|
deleted: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -22,6 +22,15 @@ export default (app) => {
|
|||||||
middlewares.wrap(require("./list-price-list-products").default)
|
middlewares.wrap(require("./list-price-list-products").default)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
route.delete(
|
||||||
|
"/:id/products/:product_id/prices",
|
||||||
|
middlewares.wrap(require("./delete-product-prices").default)
|
||||||
|
)
|
||||||
|
route.delete(
|
||||||
|
"/:id/variants/:variant_id/prices",
|
||||||
|
middlewares.wrap(require("./delete-variant-prices").default)
|
||||||
|
)
|
||||||
|
|
||||||
route.post("/", middlewares.wrap(require("./create-price-list").default))
|
route.post("/", middlewares.wrap(require("./create-price-list").default))
|
||||||
|
|
||||||
route.post("/:id", middlewares.wrap(require("./update-price-list").default))
|
route.post("/:id", middlewares.wrap(require("./update-price-list").default))
|
||||||
@@ -68,6 +77,9 @@ export type AdminPriceListDeleteBatchRes = {
|
|||||||
object: string
|
object: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type AdminPriceListDeleteProductPricesRes = AdminPriceListDeleteBatchRes
|
||||||
|
export type AdminPriceListDeleteVariantPricesRes = AdminPriceListDeleteBatchRes
|
||||||
|
|
||||||
export type AdminPriceListDeleteRes = DeleteResponse
|
export type AdminPriceListDeleteRes = DeleteResponse
|
||||||
|
|
||||||
export type AdminPriceListsListRes = PaginatedResponse & {
|
export type AdminPriceListsListRes = PaginatedResponse & {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
IsString,
|
IsString,
|
||||||
ValidateNested,
|
ValidateNested,
|
||||||
} from "class-validator"
|
} from "class-validator"
|
||||||
import { Product } from "../../../../models/product"
|
import { Product } from "../../../../models"
|
||||||
import { DateComparisonOperator } from "../../../../types/common"
|
import { DateComparisonOperator } from "../../../../types/common"
|
||||||
import { validator } from "../../../../utils/validator"
|
import { validator } from "../../../../utils/validator"
|
||||||
import { FilterableProductProps } from "../../../../types/product"
|
import { FilterableProductProps } from "../../../../types/product"
|
||||||
@@ -18,7 +18,6 @@ import {
|
|||||||
defaultAdminProductFields,
|
defaultAdminProductFields,
|
||||||
defaultAdminProductRelations,
|
defaultAdminProductRelations,
|
||||||
} from "../products"
|
} from "../products"
|
||||||
import listAndCount from "../../../../controllers/products/admin-list-products"
|
|
||||||
import { MedusaError } from "medusa-core-utils"
|
import { MedusaError } from "medusa-core-utils"
|
||||||
import { getListConfig } from "../../../../utils/get-query-config"
|
import { getListConfig } from "../../../../utils/get-query-config"
|
||||||
import PriceListService from "../../../../services/price-list"
|
import PriceListService from "../../../../services/price-list"
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export default async (req, res) => {
|
|||||||
expandFields = validated.expand.split(",")
|
expandFields = validated.expand.split(",")
|
||||||
}
|
}
|
||||||
|
|
||||||
const listConfig: FindConfig<PriceList> = {
|
const listConfig: FindConfig<FilterablePriceListProps> = {
|
||||||
relations: expandFields,
|
relations: expandFields,
|
||||||
skip: validated.offset,
|
skip: validated.offset,
|
||||||
take: validated.limit,
|
take: validated.limit,
|
||||||
@@ -65,7 +65,7 @@ export default async (req, res) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterableFields = omit(validated, [
|
const filterableFields: FilterablePriceListProps = omit(validated, [
|
||||||
"limit",
|
"limit",
|
||||||
"offset",
|
"offset",
|
||||||
"expand",
|
"expand",
|
||||||
|
|||||||
@@ -119,18 +119,24 @@ export class MoneyAmountRepository extends Repository<MoneyAmount> {
|
|||||||
|
|
||||||
public async findManyForVariantInPriceList(
|
public async findManyForVariantInPriceList(
|
||||||
variant_id: string,
|
variant_id: string,
|
||||||
price_list_id: string
|
price_list_id: string,
|
||||||
|
requiresPriceList = false
|
||||||
): Promise<[MoneyAmount[], number]> {
|
): Promise<[MoneyAmount[], number]> {
|
||||||
const qb = this.createQueryBuilder("ma")
|
const qb = this.createQueryBuilder("ma")
|
||||||
.leftJoinAndSelect("ma.price_list", "price_list")
|
.leftJoinAndSelect("ma.price_list", "price_list")
|
||||||
.where("ma.variant_id = :variant_id", { variant_id })
|
.where("ma.variant_id = :variant_id", { variant_id })
|
||||||
.andWhere(
|
|
||||||
new Brackets((qb) => {
|
const getAndWhere = (subQb) => {
|
||||||
qb.where("ma.price_list_id = :price_list_id", {
|
const andWhere = subQb.where("ma.price_list_id = :price_list_id", {
|
||||||
price_list_id,
|
price_list_id,
|
||||||
}).orWhere("ma.price_list_id IS NULL")
|
})
|
||||||
})
|
if (!requiresPriceList) {
|
||||||
)
|
andWhere.orWhere("ma.price_list_id IS NULL")
|
||||||
|
}
|
||||||
|
return andWhere
|
||||||
|
}
|
||||||
|
|
||||||
|
qb.andWhere(new Brackets(getAndWhere))
|
||||||
|
|
||||||
return await qb.getManyAndCount()
|
return await qb.getManyAndCount()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,16 +8,18 @@ import {
|
|||||||
} from "typeorm"
|
} from "typeorm"
|
||||||
import { PriceList } from "../models/price-list"
|
import { PriceList } from "../models/price-list"
|
||||||
import { CustomFindOptions, ExtendedFindConfig } from "../types/common"
|
import { CustomFindOptions, ExtendedFindConfig } from "../types/common"
|
||||||
|
import { CustomerGroup } from "../models"
|
||||||
|
import { FilterablePriceListProps } from "../types/price-list"
|
||||||
|
|
||||||
type PriceListFindOptions = CustomFindOptions<PriceList, "status" | "type">
|
export type PriceListFindOptions = CustomFindOptions<PriceList, "status" | "type">
|
||||||
|
|
||||||
@EntityRepository(PriceList)
|
@EntityRepository(PriceList)
|
||||||
export class PriceListRepository extends Repository<PriceList> {
|
export class PriceListRepository extends Repository<PriceList> {
|
||||||
public async getFreeTextSearchResultsAndCount(
|
public async getFreeTextSearchResultsAndCount(
|
||||||
q: string,
|
q: string,
|
||||||
options: PriceListFindOptions = { where: {} },
|
options: PriceListFindOptions = { where: {} },
|
||||||
groups?: FindOperator<PriceList>,
|
groups: FindOperator<string[]>,
|
||||||
relations: (keyof PriceList)[] = []
|
relations: string[] = []
|
||||||
): Promise<[PriceList[], number]> {
|
): Promise<[PriceList[], number]> {
|
||||||
options.where = options.where ?? {}
|
options.where = options.where ?? {}
|
||||||
|
|
||||||
@@ -50,7 +52,7 @@ export class PriceListRepository extends Repository<PriceList> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async findWithRelations(
|
public async findWithRelations(
|
||||||
relations: (keyof PriceList)[] = [],
|
relations: string[] = [],
|
||||||
idsOrOptionsWithoutRelations:
|
idsOrOptionsWithoutRelations:
|
||||||
| Omit<FindManyOptions<PriceList>, "relations">
|
| Omit<FindManyOptions<PriceList>, "relations">
|
||||||
| string[] = {}
|
| string[] = {}
|
||||||
@@ -97,8 +99,8 @@ export class PriceListRepository extends Repository<PriceList> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async listAndCount(
|
async listAndCount(
|
||||||
query: ExtendedFindConfig<PriceList>,
|
query: ExtendedFindConfig<FilterablePriceListProps>,
|
||||||
groups?: FindOperator<PriceList>
|
groups: FindOperator<string[]>
|
||||||
): Promise<[PriceList[], number]> {
|
): Promise<[PriceList[], number]> {
|
||||||
const qb = this.createQueryBuilder("price_list")
|
const qb = this.createQueryBuilder("price_list")
|
||||||
.where(query.where)
|
.where(query.where)
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { MedusaError } from "medusa-core-utils"
|
import { MedusaError } from "medusa-core-utils"
|
||||||
import { BaseService } from "medusa-interfaces"
|
import { EntityManager, FindOperator } from "typeorm"
|
||||||
import { EntityManager } from "typeorm"
|
|
||||||
import { CustomerGroupService } from "."
|
import { CustomerGroupService } from "."
|
||||||
import { Product } from "../models"
|
import { CustomerGroup, PriceList, Product, ProductVariant } from "../models"
|
||||||
import { CustomerGroup } from "../models/customer-group"
|
|
||||||
import { PriceList } from "../models/price-list"
|
|
||||||
import { MoneyAmountRepository } from "../repositories/money-amount"
|
import { MoneyAmountRepository } from "../repositories/money-amount"
|
||||||
import { PriceListRepository } from "../repositories/price-list"
|
import {
|
||||||
import { FindConfig } from "../types/common"
|
PriceListFindOptions,
|
||||||
|
PriceListRepository,
|
||||||
|
} from "../repositories/price-list"
|
||||||
|
import { FindConfig, Selector } from "../types/common"
|
||||||
import {
|
import {
|
||||||
CreatePriceListInput,
|
CreatePriceListInput,
|
||||||
FilterablePriceListProps,
|
FilterablePriceListProps,
|
||||||
@@ -18,12 +18,18 @@ import {
|
|||||||
import { formatException } from "../utils/exception-formatter"
|
import { formatException } from "../utils/exception-formatter"
|
||||||
import ProductService from "./product"
|
import ProductService from "./product"
|
||||||
import RegionService from "./region"
|
import RegionService from "./region"
|
||||||
|
import { TransactionBaseService } from "../interfaces"
|
||||||
|
import { buildQuery } from "../utils"
|
||||||
|
import { FilterableProductProps } from "../types/product"
|
||||||
|
import ProductVariantService from "./product-variant"
|
||||||
|
import { FilterableProductVariantProps } from "../types/product-variant"
|
||||||
|
|
||||||
type PriceListConstructorProps = {
|
type PriceListConstructorProps = {
|
||||||
manager: EntityManager
|
manager: EntityManager
|
||||||
customerGroupService: CustomerGroupService
|
customerGroupService: CustomerGroupService
|
||||||
regionService: RegionService
|
regionService: RegionService
|
||||||
productService: ProductService
|
productService: ProductService
|
||||||
|
productVariantService: ProductVariantService
|
||||||
priceListRepository: typeof PriceListRepository
|
priceListRepository: typeof PriceListRepository
|
||||||
moneyAmountRepository: typeof MoneyAmountRepository
|
moneyAmountRepository: typeof MoneyAmountRepository
|
||||||
}
|
}
|
||||||
@@ -32,50 +38,38 @@ type PriceListConstructorProps = {
|
|||||||
* Provides layer to manipulate product tags.
|
* Provides layer to manipulate product tags.
|
||||||
* @extends BaseService
|
* @extends BaseService
|
||||||
*/
|
*/
|
||||||
class PriceListService extends BaseService {
|
class PriceListService extends TransactionBaseService<PriceListService> {
|
||||||
private manager_: EntityManager
|
protected manager_: EntityManager
|
||||||
private customerGroupService_: CustomerGroupService
|
protected transactionManager_: EntityManager | undefined
|
||||||
private regionService_: RegionService
|
|
||||||
private productService_: ProductService
|
protected readonly customerGroupService_: CustomerGroupService
|
||||||
private priceListRepo_: typeof PriceListRepository
|
protected readonly regionService_: RegionService
|
||||||
private moneyAmountRepo_: typeof MoneyAmountRepository
|
protected readonly productService_: ProductService
|
||||||
|
protected readonly variantService_: ProductVariantService
|
||||||
|
protected readonly priceListRepo_: typeof PriceListRepository
|
||||||
|
protected readonly moneyAmountRepo_: typeof MoneyAmountRepository
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
manager,
|
manager,
|
||||||
customerGroupService,
|
customerGroupService,
|
||||||
regionService,
|
regionService,
|
||||||
productService,
|
productService,
|
||||||
|
productVariantService,
|
||||||
priceListRepository,
|
priceListRepository,
|
||||||
moneyAmountRepository,
|
moneyAmountRepository,
|
||||||
}: PriceListConstructorProps) {
|
}: PriceListConstructorProps) {
|
||||||
super()
|
// eslint-disable-next-line prefer-rest-params
|
||||||
|
super(arguments[0])
|
||||||
|
|
||||||
this.manager_ = manager
|
this.manager_ = manager
|
||||||
this.customerGroupService_ = customerGroupService
|
this.customerGroupService_ = customerGroupService
|
||||||
this.productService_ = productService
|
this.productService_ = productService
|
||||||
|
this.variantService_ = productVariantService
|
||||||
this.regionService_ = regionService
|
this.regionService_ = regionService
|
||||||
this.priceListRepo_ = priceListRepository
|
this.priceListRepo_ = priceListRepository
|
||||||
this.moneyAmountRepo_ = moneyAmountRepository
|
this.moneyAmountRepo_ = moneyAmountRepository
|
||||||
}
|
}
|
||||||
|
|
||||||
withTransaction(transactionManager: EntityManager): PriceListService {
|
|
||||||
if (!transactionManager) {
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
const cloned = new PriceListService({
|
|
||||||
manager: transactionManager,
|
|
||||||
customerGroupService: this.customerGroupService_,
|
|
||||||
productService: this.productService_,
|
|
||||||
regionService: this.regionService_,
|
|
||||||
priceListRepository: this.priceListRepo_,
|
|
||||||
moneyAmountRepository: this.moneyAmountRepo_,
|
|
||||||
})
|
|
||||||
|
|
||||||
cloned.transactionManager_ = transactionManager
|
|
||||||
|
|
||||||
return cloned
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves a product tag by id.
|
* Retrieves a product tag by id.
|
||||||
* @param {string} priceListId - the id of the product tag to retrieve
|
* @param {string} priceListId - the id of the product tag to retrieve
|
||||||
@@ -88,7 +82,7 @@ class PriceListService extends BaseService {
|
|||||||
): Promise<PriceList> {
|
): Promise<PriceList> {
|
||||||
const priceListRepo = this.manager_.getCustomRepository(this.priceListRepo_)
|
const priceListRepo = this.manager_.getCustomRepository(this.priceListRepo_)
|
||||||
|
|
||||||
const query = this.buildQuery_({ id: priceListId }, config)
|
const query = buildQuery({ id: priceListId }, config)
|
||||||
const priceList = await priceListRepo.findOne(query)
|
const priceList = await priceListRepo.findOne(query)
|
||||||
|
|
||||||
if (!priceList) {
|
if (!priceList) {
|
||||||
@@ -167,11 +161,9 @@ class PriceListService extends BaseService {
|
|||||||
await this.upsertCustomerGroups_(id, customer_groups)
|
await this.upsertCustomerGroups_(id, customer_groups)
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await this.retrieve(id, {
|
return await this.retrieve(id, {
|
||||||
relations: ["prices", "customer_groups"],
|
relations: ["prices", "customer_groups"],
|
||||||
})
|
})
|
||||||
|
|
||||||
return result
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,11 +187,9 @@ class PriceListService extends BaseService {
|
|||||||
const prices_ = await this.addCurrencyFromRegion(prices)
|
const prices_ = await this.addCurrencyFromRegion(prices)
|
||||||
await moneyAmountRepo.addPriceListPrices(priceList.id, prices_, replace)
|
await moneyAmountRepo.addPriceListPrices(priceList.id, prices_, replace)
|
||||||
|
|
||||||
const result = await this.retrieve(priceList.id, {
|
return await this.retrieve(priceList.id, {
|
||||||
relations: ["prices"],
|
relations: ["prices"],
|
||||||
})
|
})
|
||||||
|
|
||||||
return result
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,8 +206,6 @@ class PriceListService extends BaseService {
|
|||||||
const priceList = await this.retrieve(id, { select: ["id"] })
|
const priceList = await this.retrieve(id, { select: ["id"] })
|
||||||
|
|
||||||
await moneyAmountRepo.deletePriceListPrices(priceList.id, priceIds)
|
await moneyAmountRepo.deletePriceListPrices(priceList.id, priceIds)
|
||||||
|
|
||||||
return Promise.resolve()
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -249,14 +237,18 @@ class PriceListService extends BaseService {
|
|||||||
*/
|
*/
|
||||||
async list(
|
async list(
|
||||||
selector: FilterablePriceListProps = {},
|
selector: FilterablePriceListProps = {},
|
||||||
config: FindConfig<PriceList> = { skip: 0, take: 20 }
|
config: FindConfig<FilterablePriceListProps> = { skip: 0, take: 20 }
|
||||||
): Promise<PriceList[]> {
|
): Promise<PriceList[]> {
|
||||||
return await this.atomicPhase_(async (manager: EntityManager) => {
|
return await this.atomicPhase_(async (manager: EntityManager) => {
|
||||||
const priceListRepo = manager.getCustomRepository(this.priceListRepo_)
|
const priceListRepo = manager.getCustomRepository(this.priceListRepo_)
|
||||||
|
|
||||||
const query = this.buildQuery_(selector, config)
|
const { q, ...priceListSelector } = selector
|
||||||
|
const query = buildQuery<FilterablePriceListProps>(
|
||||||
|
priceListSelector,
|
||||||
|
config
|
||||||
|
)
|
||||||
|
|
||||||
const groups = query.where.customer_groups
|
const groups = query.where.customer_groups as FindOperator<string[]>
|
||||||
query.where.customer_groups = undefined
|
query.where.customer_groups = undefined
|
||||||
|
|
||||||
const [priceLists] = await priceListRepo.listAndCount(query, groups)
|
const [priceLists] = await priceListRepo.listAndCount(query, groups)
|
||||||
@@ -273,21 +265,26 @@ class PriceListService extends BaseService {
|
|||||||
*/
|
*/
|
||||||
async listAndCount(
|
async listAndCount(
|
||||||
selector: FilterablePriceListProps = {},
|
selector: FilterablePriceListProps = {},
|
||||||
config: FindConfig<PriceList> = { skip: 0, take: 20 }
|
config: FindConfig<FilterablePriceListProps> = {
|
||||||
|
skip: 0,
|
||||||
|
take: 20,
|
||||||
|
}
|
||||||
): Promise<[PriceList[], number]> {
|
): Promise<[PriceList[], number]> {
|
||||||
return await this.atomicPhase_(async (manager: EntityManager) => {
|
return await this.atomicPhase_(async (manager: EntityManager) => {
|
||||||
const priceListRepo = manager.getCustomRepository(this.priceListRepo_)
|
const priceListRepo = manager.getCustomRepository(this.priceListRepo_)
|
||||||
const q = selector.q
|
const { q, ...priceListSelector } = selector
|
||||||
const { relations, ...query } = this.buildQuery_(selector, config)
|
const { relations, ...query } = buildQuery<FilterablePriceListProps>(
|
||||||
|
priceListSelector,
|
||||||
|
config
|
||||||
|
)
|
||||||
|
|
||||||
const groups = query.where.customer_groups
|
const groups = query.where.customer_groups as FindOperator<string[]>
|
||||||
delete query.where.customer_groups
|
delete query.where.customer_groups
|
||||||
|
|
||||||
if (q) {
|
if (q) {
|
||||||
delete query.where.q
|
|
||||||
return await priceListRepo.getFreeTextSearchResultsAndCount(
|
return await priceListRepo.getFreeTextSearchResultsAndCount(
|
||||||
q,
|
q,
|
||||||
query,
|
query as PriceListFindOptions,
|
||||||
groups,
|
groups,
|
||||||
relations
|
relations
|
||||||
)
|
)
|
||||||
@@ -296,7 +293,7 @@ class PriceListService extends BaseService {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async upsertCustomerGroups_(
|
protected async upsertCustomerGroups_(
|
||||||
priceListId: string,
|
priceListId: string,
|
||||||
customerGroups: { id: string }[]
|
customerGroups: { id: string }[]
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
@@ -317,12 +314,13 @@ class PriceListService extends BaseService {
|
|||||||
|
|
||||||
async listProducts(
|
async listProducts(
|
||||||
priceListId: string,
|
priceListId: string,
|
||||||
selector = {},
|
selector: FilterableProductProps | Selector<Product> = {},
|
||||||
config: FindConfig<Product> = {
|
config: FindConfig<Product> = {
|
||||||
relations: [],
|
relations: [],
|
||||||
skip: 0,
|
skip: 0,
|
||||||
take: 20,
|
take: 20,
|
||||||
}
|
},
|
||||||
|
requiresPriceList = false
|
||||||
): Promise<[Product[], number]> {
|
): Promise<[Product[], number]> {
|
||||||
return await this.atomicPhase_(async (manager: EntityManager) => {
|
return await this.atomicPhase_(async (manager: EntityManager) => {
|
||||||
const [products, count] = await this.productService_.listAndCount(
|
const [products, count] = await this.productService_.listAndCount(
|
||||||
@@ -340,7 +338,8 @@ class PriceListService extends BaseService {
|
|||||||
const [prices] =
|
const [prices] =
|
||||||
await moneyAmountRepo.findManyForVariantInPriceList(
|
await moneyAmountRepo.findManyForVariantInPriceList(
|
||||||
v.id,
|
v.id,
|
||||||
priceListId
|
priceListId,
|
||||||
|
requiresPriceList
|
||||||
)
|
)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -359,6 +358,109 @@ class PriceListService extends BaseService {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async listVariants(
|
||||||
|
priceListId: string,
|
||||||
|
selector: FilterableProductVariantProps = {},
|
||||||
|
config: FindConfig<ProductVariant> = {
|
||||||
|
relations: [],
|
||||||
|
skip: 0,
|
||||||
|
take: 20,
|
||||||
|
},
|
||||||
|
requiresPriceList = false
|
||||||
|
): Promise<[ProductVariant[], number]> {
|
||||||
|
return await this.atomicPhase_(async (manager: EntityManager) => {
|
||||||
|
const [variants, count] = await this.variantService_.listAndCount(
|
||||||
|
selector,
|
||||||
|
config
|
||||||
|
)
|
||||||
|
|
||||||
|
const moneyAmountRepo = manager.getCustomRepository(this.moneyAmountRepo_)
|
||||||
|
|
||||||
|
const variantsWithPrices = await Promise.all(
|
||||||
|
variants.map(async (variant) => {
|
||||||
|
const [prices] = await moneyAmountRepo.findManyForVariantInPriceList(
|
||||||
|
variant.id,
|
||||||
|
priceListId,
|
||||||
|
requiresPriceList
|
||||||
|
)
|
||||||
|
|
||||||
|
variant.prices = prices
|
||||||
|
return variant
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
return [variantsWithPrices, count]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public async deleteProductPrices(
|
||||||
|
priceListId: string,
|
||||||
|
productIds: string[]
|
||||||
|
): Promise<[string[], number]> {
|
||||||
|
return await this.atomicPhase_(async () => {
|
||||||
|
const [products, count] = await this.listProducts(
|
||||||
|
priceListId,
|
||||||
|
{
|
||||||
|
id: productIds,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
relations: ["variants"],
|
||||||
|
},
|
||||||
|
true
|
||||||
|
)
|
||||||
|
|
||||||
|
if (count === 0) {
|
||||||
|
return [[], count]
|
||||||
|
}
|
||||||
|
|
||||||
|
const priceIds = products
|
||||||
|
.map(({ variants }) =>
|
||||||
|
variants
|
||||||
|
.map((variant) => variant.prices.map((price) => price.id))
|
||||||
|
.flat()
|
||||||
|
)
|
||||||
|
.flat()
|
||||||
|
|
||||||
|
if (!priceIds.length) {
|
||||||
|
return [[], 0]
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.deletePrices(priceListId, priceIds)
|
||||||
|
return [priceIds, priceIds.length]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public async deleteVariantPrices(
|
||||||
|
priceListId: string,
|
||||||
|
variantIds: string[]
|
||||||
|
): Promise<[string[], number]> {
|
||||||
|
return await this.atomicPhase_(async () => {
|
||||||
|
const [variants, count] = await this.listVariants(
|
||||||
|
priceListId,
|
||||||
|
{
|
||||||
|
id: variantIds,
|
||||||
|
},
|
||||||
|
{},
|
||||||
|
true
|
||||||
|
)
|
||||||
|
|
||||||
|
if (count === 0) {
|
||||||
|
return [[], count]
|
||||||
|
}
|
||||||
|
|
||||||
|
const priceIds = variants
|
||||||
|
.map((variant) => variant.prices.map((price) => price.id))
|
||||||
|
.flat()
|
||||||
|
|
||||||
|
if (!priceIds.length) {
|
||||||
|
return [[], 0]
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.deletePrices(priceListId, priceIds)
|
||||||
|
return [priceIds, priceIds.length]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add `currency_code` to an MA record if `region_id`is passed.
|
* Add `currency_code` to an MA record if `region_id`is passed.
|
||||||
* @param prices - a list of PriceListPrice(Create/Update)Input records
|
* @param prices - a list of PriceListPrice(Create/Update)Input records
|
||||||
|
|||||||
@@ -7,18 +7,24 @@ import {
|
|||||||
IsString,
|
IsString,
|
||||||
} from "class-validator"
|
} from "class-validator"
|
||||||
import "reflect-metadata"
|
import "reflect-metadata"
|
||||||
import { FindManyOptions, OrderByCondition } from "typeorm"
|
import { FindManyOptions, FindOperator, OrderByCondition } from "typeorm"
|
||||||
import { transformDate } from "../utils/validators/date-transform"
|
import { transformDate } from "../utils/validators/date-transform"
|
||||||
|
|
||||||
export type PartialPick<T, K extends keyof T> = {
|
export type PartialPick<T, K extends keyof T> = {
|
||||||
[P in K]?: T[P]
|
[P in K]?: T[P]
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Writable<T> = { -readonly [key in keyof T]: T[key] }
|
export type Writable<T> = {
|
||||||
|
-readonly [key in keyof T]:
|
||||||
|
| T[key]
|
||||||
|
| FindOperator<T[key][]>
|
||||||
|
| FindOperator<string[]>
|
||||||
|
}
|
||||||
|
|
||||||
export type ExtendedFindConfig<TEntity> = FindConfig<TEntity> & {
|
export type ExtendedFindConfig<TEntity> = FindConfig<TEntity> & {
|
||||||
where: Partial<Writable<TEntity>>
|
where: Partial<Writable<TEntity>>
|
||||||
withDeleted?: boolean
|
withDeleted?: boolean
|
||||||
|
relations?: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Selector<TEntity> = {
|
export type Selector<TEntity> = {
|
||||||
@@ -28,6 +34,7 @@ export type Selector<TEntity> = {
|
|||||||
| DateComparisonOperator
|
| DateComparisonOperator
|
||||||
| StringComparisonOperator
|
| StringComparisonOperator
|
||||||
| NumericalComparisonOperator
|
| NumericalComparisonOperator
|
||||||
|
| FindOperator<TEntity[key][] | string[]>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TotalField =
|
export type TotalField =
|
||||||
|
|||||||
Reference in New Issue
Block a user