feat: Product filtering (#439)
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`/admin/discounts creates admin session correctly 1`] = `
|
exports[`/admin/auth creates admin session correctly 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"api_token": "test_token",
|
"api_token": "test_token",
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
@@ -13,4 +13,3 @@ Object {
|
|||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
@@ -380,5 +380,198 @@ Array [
|
|||||||
"weight": null,
|
"weight": null,
|
||||||
"width": null,
|
"width": null,
|
||||||
},
|
},
|
||||||
|
Object {
|
||||||
|
"collection": Any<Object>,
|
||||||
|
"collection_id": "test-collection1",
|
||||||
|
"created_at": Any<String>,
|
||||||
|
"deleted_at": null,
|
||||||
|
"description": "test-product-description",
|
||||||
|
"discountable": true,
|
||||||
|
"handle": "test-product_filtering_3",
|
||||||
|
"height": null,
|
||||||
|
"hs_code": null,
|
||||||
|
"id": StringMatching /\\^test-\\*/,
|
||||||
|
"images": Array [],
|
||||||
|
"is_giftcard": false,
|
||||||
|
"length": null,
|
||||||
|
"material": null,
|
||||||
|
"metadata": null,
|
||||||
|
"mid_code": null,
|
||||||
|
"options": Any<Array>,
|
||||||
|
"origin_country": null,
|
||||||
|
"profile_id": StringMatching /\\^sp_\\*/,
|
||||||
|
"status": "draft",
|
||||||
|
"subtitle": null,
|
||||||
|
"tags": Any<Array>,
|
||||||
|
"thumbnail": null,
|
||||||
|
"title": "Test product filtering 3",
|
||||||
|
"type": Any<Object>,
|
||||||
|
"type_id": "test-type",
|
||||||
|
"updated_at": Any<String>,
|
||||||
|
"variants": Any<Array>,
|
||||||
|
"weight": null,
|
||||||
|
"width": null,
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"collection": Any<Object>,
|
||||||
|
"collection_id": "test-collection1",
|
||||||
|
"created_at": Any<String>,
|
||||||
|
"deleted_at": null,
|
||||||
|
"description": "test-product-description",
|
||||||
|
"discountable": true,
|
||||||
|
"handle": "test-product_filtering_1",
|
||||||
|
"height": null,
|
||||||
|
"hs_code": null,
|
||||||
|
"id": StringMatching /\\^test-\\*/,
|
||||||
|
"images": Array [],
|
||||||
|
"is_giftcard": false,
|
||||||
|
"length": null,
|
||||||
|
"material": null,
|
||||||
|
"metadata": null,
|
||||||
|
"mid_code": null,
|
||||||
|
"options": Any<Array>,
|
||||||
|
"origin_country": null,
|
||||||
|
"profile_id": StringMatching /\\^sp_\\*/,
|
||||||
|
"status": "proposed",
|
||||||
|
"subtitle": null,
|
||||||
|
"tags": Any<Array>,
|
||||||
|
"thumbnail": null,
|
||||||
|
"title": "Test product filtering 1",
|
||||||
|
"type": Any<Object>,
|
||||||
|
"type_id": "test-type",
|
||||||
|
"updated_at": Any<String>,
|
||||||
|
"variants": Any<Array>,
|
||||||
|
"weight": null,
|
||||||
|
"width": null,
|
||||||
|
},
|
||||||
|
Object {
|
||||||
|
"collection": Any<Object>,
|
||||||
|
"collection_id": "test-collection2",
|
||||||
|
"created_at": Any<String>,
|
||||||
|
"deleted_at": null,
|
||||||
|
"description": "test-product-description",
|
||||||
|
"discountable": true,
|
||||||
|
"handle": "test-product_filtering_2",
|
||||||
|
"height": null,
|
||||||
|
"hs_code": null,
|
||||||
|
"id": StringMatching /\\^test-\\*/,
|
||||||
|
"images": Array [],
|
||||||
|
"is_giftcard": false,
|
||||||
|
"length": null,
|
||||||
|
"material": null,
|
||||||
|
"metadata": null,
|
||||||
|
"mid_code": null,
|
||||||
|
"options": Any<Array>,
|
||||||
|
"origin_country": null,
|
||||||
|
"profile_id": StringMatching /\\^sp_\\*/,
|
||||||
|
"status": "published",
|
||||||
|
"subtitle": null,
|
||||||
|
"tags": Any<Array>,
|
||||||
|
"thumbnail": null,
|
||||||
|
"title": "Test product filtering 2",
|
||||||
|
"type": Any<Object>,
|
||||||
|
"type_id": "test-type",
|
||||||
|
"updated_at": Any<String>,
|
||||||
|
"variants": Any<Array>,
|
||||||
|
"weight": null,
|
||||||
|
"width": null,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`/admin/products GET /admin/products returns a list of products with giftcard in list 1`] = `
|
||||||
|
Array [
|
||||||
|
Object {
|
||||||
|
"collection": null,
|
||||||
|
"collection_id": null,
|
||||||
|
"created_at": Any<String>,
|
||||||
|
"deleted_at": null,
|
||||||
|
"description": "test-giftcard-description",
|
||||||
|
"discountable": false,
|
||||||
|
"handle": "test-giftcard",
|
||||||
|
"height": null,
|
||||||
|
"hs_code": null,
|
||||||
|
"id": StringMatching /\\^prod_\\*/,
|
||||||
|
"images": Array [],
|
||||||
|
"is_giftcard": true,
|
||||||
|
"length": null,
|
||||||
|
"material": null,
|
||||||
|
"metadata": null,
|
||||||
|
"mid_code": null,
|
||||||
|
"options": Array [
|
||||||
|
Object {
|
||||||
|
"created_at": Any<String>,
|
||||||
|
"deleted_at": null,
|
||||||
|
"id": StringMatching /\\^opt_\\*/,
|
||||||
|
"metadata": null,
|
||||||
|
"product_id": StringMatching /\\^prod_\\*/,
|
||||||
|
"title": "Denominations",
|
||||||
|
"updated_at": Any<String>,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"origin_country": null,
|
||||||
|
"profile_id": StringMatching /\\^sp_\\*/,
|
||||||
|
"status": "draft",
|
||||||
|
"subtitle": null,
|
||||||
|
"tags": Array [],
|
||||||
|
"thumbnail": null,
|
||||||
|
"title": "Test Giftcard",
|
||||||
|
"type": null,
|
||||||
|
"type_id": null,
|
||||||
|
"updated_at": Any<String>,
|
||||||
|
"variants": Array [
|
||||||
|
Object {
|
||||||
|
"allow_backorder": false,
|
||||||
|
"barcode": null,
|
||||||
|
"created_at": Any<String>,
|
||||||
|
"deleted_at": null,
|
||||||
|
"ean": null,
|
||||||
|
"height": null,
|
||||||
|
"hs_code": null,
|
||||||
|
"id": StringMatching /\\^variant_\\*/,
|
||||||
|
"inventory_quantity": 0,
|
||||||
|
"length": null,
|
||||||
|
"manage_inventory": true,
|
||||||
|
"material": null,
|
||||||
|
"metadata": null,
|
||||||
|
"mid_code": null,
|
||||||
|
"options": Array [
|
||||||
|
Object {
|
||||||
|
"created_at": Any<String>,
|
||||||
|
"deleted_at": null,
|
||||||
|
"id": StringMatching /\\^opt_\\*/,
|
||||||
|
"metadata": null,
|
||||||
|
"option_id": StringMatching /\\^opt_\\*/,
|
||||||
|
"updated_at": Any<String>,
|
||||||
|
"value": "100",
|
||||||
|
"variant_id": StringMatching /\\^variant_\\*/,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"origin_country": null,
|
||||||
|
"prices": Array [
|
||||||
|
Object {
|
||||||
|
"amount": 100,
|
||||||
|
"created_at": Any<String>,
|
||||||
|
"currency_code": "usd",
|
||||||
|
"deleted_at": null,
|
||||||
|
"id": Any<String>,
|
||||||
|
"region_id": null,
|
||||||
|
"sale_amount": null,
|
||||||
|
"updated_at": Any<String>,
|
||||||
|
"variant_id": StringMatching /\\^variant_\\*/,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"product_id": StringMatching /\\^prod_\\*/,
|
||||||
|
"sku": null,
|
||||||
|
"title": "Test variant",
|
||||||
|
"upc": null,
|
||||||
|
"updated_at": Any<String>,
|
||||||
|
"weight": null,
|
||||||
|
"width": null,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"weight": null,
|
||||||
|
"width": null,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -46,7 +46,35 @@ describe("/admin/products", () => {
|
|||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
const res = await api
|
const res = await api
|
||||||
.get("/admin/products?status%5B%5D=null", {
|
.get("/admin/products", {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(res.status).toEqual(200)
|
||||||
|
expect(res.data.products).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-product",
|
||||||
|
status: "draft",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-product1",
|
||||||
|
status: "draft",
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a list of all products when no query is provided", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
const res = await api
|
||||||
|
.get("/admin/products?q=", {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: "Bearer test_token",
|
Authorization: "Bearer test_token",
|
||||||
},
|
},
|
||||||
@@ -89,7 +117,7 @@ describe("/admin/products", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const response = await api
|
const response = await api
|
||||||
.get("/admin/products?status%5B%5D=proposed", {
|
.get("/admin/products?status[]=proposed", {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: "Bearer test_token",
|
Authorization: "Bearer test_token",
|
||||||
},
|
},
|
||||||
@@ -109,6 +137,258 @@ describe("/admin/products", () => {
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("returns a list of products where status is proposed or published", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
const notExpected = [
|
||||||
|
expect.objectContaining({ status: "draft" }),
|
||||||
|
expect.objectContaining({ status: "rejected" }),
|
||||||
|
]
|
||||||
|
|
||||||
|
const response = await api
|
||||||
|
.get("/admin/products?status[]=published,proposed", {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.products).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-product_filtering_1",
|
||||||
|
status: "proposed",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-product_filtering_2",
|
||||||
|
status: "published",
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
|
||||||
|
for (const notExpect of notExpected) {
|
||||||
|
expect(response.data.products).toEqual(
|
||||||
|
expect.not.arrayContaining([notExpect])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a list of products in collection", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
const notExpected = [
|
||||||
|
expect.objectContaining({ collection_id: "test-collection" }),
|
||||||
|
expect.objectContaining({ collection_id: "test-collection2" }),
|
||||||
|
]
|
||||||
|
|
||||||
|
const response = await api
|
||||||
|
.get("/admin/products?collection_id[]=test-collection1", {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.products).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-product_filtering_1",
|
||||||
|
collection_id: "test-collection1",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-product_filtering_3",
|
||||||
|
collection_id: "test-collection1",
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
|
||||||
|
for (const notExpect of notExpected) {
|
||||||
|
expect(response.data.products).toEqual(
|
||||||
|
expect.not.arrayContaining([notExpect])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a list of products with tags", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
const notExpected = [
|
||||||
|
expect.objectContaining({ id: "tag1" }),
|
||||||
|
expect.objectContaining({ id: "tag2" }),
|
||||||
|
expect.objectContaining({ id: "tag4" }),
|
||||||
|
]
|
||||||
|
|
||||||
|
const response = await api
|
||||||
|
.get("/admin/products?tags[]=tag3", {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.products).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-product_filtering_1",
|
||||||
|
tags: [expect.objectContaining({ id: "tag3" })],
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-product_filtering_2",
|
||||||
|
tags: [expect.objectContaining({ id: "tag3" })],
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
for (const product of response.data.products) {
|
||||||
|
for (const notExpect of notExpected) {
|
||||||
|
expect(product.tags).toEqual(expect.not.arrayContaining([notExpect]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a list of products with tags in a collection", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
const notExpectedTags = [
|
||||||
|
expect.objectContaining({ id: "tag1" }),
|
||||||
|
expect.objectContaining({ id: "tag2" }),
|
||||||
|
expect.objectContaining({ id: "tag3" }),
|
||||||
|
]
|
||||||
|
|
||||||
|
const notExpectedCollections = [
|
||||||
|
expect.objectContaining({ collection_id: "test-collection" }),
|
||||||
|
expect.objectContaining({ collection_id: "test-collection2" }),
|
||||||
|
]
|
||||||
|
|
||||||
|
const response = await api
|
||||||
|
.get("/admin/products?collection_id[]=test-collection1&tags[]=tag4", {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.products).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-product_filtering_3",
|
||||||
|
collection_id: "test-collection1",
|
||||||
|
tags: [expect.objectContaining({ id: "tag4" })],
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
|
||||||
|
for (const notExpect of notExpectedCollections) {
|
||||||
|
expect(response.data.products).toEqual(
|
||||||
|
expect.not.arrayContaining([notExpect])
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const product of response.data.products) {
|
||||||
|
for (const notExpect of notExpectedTags) {
|
||||||
|
expect(product.tags).toEqual(expect.not.arrayContaining([notExpect]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a list of products with giftcard in list", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
title: "Test Giftcard",
|
||||||
|
is_giftcard: true,
|
||||||
|
description: "test-giftcard-description",
|
||||||
|
options: [{ title: "Denominations" }],
|
||||||
|
variants: [
|
||||||
|
{
|
||||||
|
title: "Test variant",
|
||||||
|
prices: [{ currency_code: "usd", amount: 100 }],
|
||||||
|
options: [{ value: "100" }],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
await api
|
||||||
|
.post("/admin/products", payload, {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
const response = await api
|
||||||
|
.get("/admin/products?is_giftcard=true", {
|
||||||
|
headers: {
|
||||||
|
Authorization: "Bearer test_token",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response.data.products).toEqual(
|
||||||
|
expect.not.arrayContaining([
|
||||||
|
expect.objectContaining({ is_giftcard: false }),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.products).toMatchSnapshot([
|
||||||
|
{
|
||||||
|
title: "Test Giftcard",
|
||||||
|
id: expect.stringMatching(/^prod_*/),
|
||||||
|
is_giftcard: true,
|
||||||
|
description: "test-giftcard-description",
|
||||||
|
profile_id: expect.stringMatching(/^sp_*/),
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
title: "Denominations",
|
||||||
|
id: expect.stringMatching(/^opt_*/),
|
||||||
|
product_id: expect.stringMatching(/^prod_*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
variants: [
|
||||||
|
{
|
||||||
|
title: "Test variant",
|
||||||
|
id: expect.stringMatching(/^variant_*/),
|
||||||
|
product_id: expect.stringMatching(/^prod_*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
prices: [
|
||||||
|
{
|
||||||
|
id: expect.any(String),
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 100,
|
||||||
|
variant_id: expect.stringMatching(/^variant_*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
id: expect.stringMatching(/^opt_*/),
|
||||||
|
option_id: expect.stringMatching(/^opt_*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
variant_id: expect.stringMatching(/^variant_*/),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
},
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
it("returns a list of products with child entities", async () => {
|
it("returns a list of products with child entities", async () => {
|
||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
@@ -306,6 +586,42 @@ describe("/admin/products", () => {
|
|||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: expect.stringMatching(/^test-*/),
|
||||||
|
profile_id: expect.stringMatching(/^sp_*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
type: expect.any(Object),
|
||||||
|
collection: expect.any(Object),
|
||||||
|
options: expect.any(Array),
|
||||||
|
tags: expect.any(Array),
|
||||||
|
variants: expect.any(Array),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: expect.stringMatching(/^test-*/),
|
||||||
|
profile_id: expect.stringMatching(/^sp_*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
type: expect.any(Object),
|
||||||
|
collection: expect.any(Object),
|
||||||
|
options: expect.any(Array),
|
||||||
|
tags: expect.any(Array),
|
||||||
|
variants: expect.any(Array),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: expect.stringMatching(/^test-*/),
|
||||||
|
profile_id: expect.stringMatching(/^sp_*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
type: expect.any(Object),
|
||||||
|
collection: expect.any(Object),
|
||||||
|
options: expect.any(Array),
|
||||||
|
tags: expect.any(Array),
|
||||||
|
variants: expect.any(Array),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
},
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`/admin/discounts creates store session correctly 1`] = `
|
exports[`/admin/auth creates store session correctly 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"billing_address_id": null,
|
"billing_address_id": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
@@ -15,4 +15,4 @@ Object {
|
|||||||
"phone": "12345678",
|
"phone": "12345678",
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
@@ -152,16 +152,16 @@ describe("/store/carts", () => {
|
|||||||
expect.assertions(2)
|
expect.assertions(2)
|
||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
try {
|
let response = await api
|
||||||
await api.post("/store/carts/test-cart", {
|
.post("/store/carts/test-cart", {
|
||||||
discounts: [{ code: "CREATED" }],
|
discounts: [{ code: "SPENT" }],
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
expect(error.response.status).toEqual(400)
|
||||||
|
expect(error.response.data.message).toEqual(
|
||||||
|
"Discount has been used maximum allowed times"
|
||||||
|
)
|
||||||
})
|
})
|
||||||
} catch (error) {
|
|
||||||
expect(error.response.status).toEqual(400)
|
|
||||||
expect(error.response.data.message).toEqual(
|
|
||||||
"Discount has been used maximum allowed times"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("fails to apply expired discount", async () => {
|
it("fails to apply expired discount", async () => {
|
||||||
|
|||||||
@@ -108,6 +108,28 @@ module.exports = async (connection, data = {}) => {
|
|||||||
tenPercent.rule = tenPercentRule
|
tenPercent.rule = tenPercentRule
|
||||||
await manager.save(tenPercent)
|
await manager.save(tenPercent)
|
||||||
|
|
||||||
|
const dUsageLimit = await manager.create(Discount, {
|
||||||
|
id: "test-discount-usage-limit",
|
||||||
|
code: "SPENT",
|
||||||
|
is_dynamic: false,
|
||||||
|
is_disabled: false,
|
||||||
|
usage_limit: 10,
|
||||||
|
usage_count: 10,
|
||||||
|
})
|
||||||
|
|
||||||
|
const drUsage = await manager.create(DiscountRule, {
|
||||||
|
id: "test-discount-rule-usage-limit",
|
||||||
|
description: "Created",
|
||||||
|
type: "fixed",
|
||||||
|
value: 10000,
|
||||||
|
allocation: "total",
|
||||||
|
})
|
||||||
|
|
||||||
|
dUsageLimit.rule = drUsage
|
||||||
|
dUsageLimit.regions = [r]
|
||||||
|
|
||||||
|
await manager.save(dUsageLimit)
|
||||||
|
|
||||||
const d = await manager.create(Discount, {
|
const d = await manager.create(Discount, {
|
||||||
id: "test-discount",
|
id: "test-discount",
|
||||||
code: "CREATED",
|
code: "CREATED",
|
||||||
|
|||||||
@@ -25,6 +25,22 @@ module.exports = async (connection, data = {}) => {
|
|||||||
|
|
||||||
await manager.save(coll)
|
await manager.save(coll)
|
||||||
|
|
||||||
|
const coll1 = manager.create(ProductCollection, {
|
||||||
|
id: "test-collection1",
|
||||||
|
handle: "test-collection1",
|
||||||
|
title: "Test collection 1",
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(coll1)
|
||||||
|
|
||||||
|
const coll2 = manager.create(ProductCollection, {
|
||||||
|
id: "test-collection2",
|
||||||
|
handle: "test-collection2",
|
||||||
|
title: "Test collection 2",
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(coll2)
|
||||||
|
|
||||||
const tag = manager.create(ProductTag, {
|
const tag = manager.create(ProductTag, {
|
||||||
id: "tag1",
|
id: "tag1",
|
||||||
value: "123",
|
value: "123",
|
||||||
@@ -32,6 +48,20 @@ module.exports = async (connection, data = {}) => {
|
|||||||
|
|
||||||
await manager.save(tag)
|
await manager.save(tag)
|
||||||
|
|
||||||
|
const tag3 = manager.create(ProductTag, {
|
||||||
|
id: "tag3",
|
||||||
|
value: "123",
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(tag3)
|
||||||
|
|
||||||
|
const tag4 = manager.create(ProductTag, {
|
||||||
|
id: "tag4",
|
||||||
|
value: "123",
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(tag4)
|
||||||
|
|
||||||
const type = manager.create(ProductType, {
|
const type = manager.create(ProductType, {
|
||||||
id: "test-type",
|
id: "test-type",
|
||||||
value: "test-type",
|
value: "test-type",
|
||||||
@@ -199,4 +229,46 @@ module.exports = async (connection, data = {}) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
await manager.save(variant5)
|
await manager.save(variant5)
|
||||||
|
|
||||||
|
const product1 = manager.create(Product, {
|
||||||
|
id: "test-product_filtering_1",
|
||||||
|
handle: "test-product_filtering_1",
|
||||||
|
title: "Test product filtering 1",
|
||||||
|
profile_id: defaultProfile.id,
|
||||||
|
description: "test-product-description",
|
||||||
|
type: { id: "test-type", value: "test-type" },
|
||||||
|
collection_id: "test-collection1",
|
||||||
|
status: "proposed",
|
||||||
|
tags: [{ id: "tag3", value: "123" }],
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(product1)
|
||||||
|
|
||||||
|
const product2 = manager.create(Product, {
|
||||||
|
id: "test-product_filtering_2",
|
||||||
|
handle: "test-product_filtering_2",
|
||||||
|
title: "Test product filtering 2",
|
||||||
|
profile_id: defaultProfile.id,
|
||||||
|
description: "test-product-description",
|
||||||
|
type: { id: "test-type", value: "test-type" },
|
||||||
|
collection_id: "test-collection2",
|
||||||
|
status: "published",
|
||||||
|
tags: [{ id: "tag3", value: "123" }],
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(product2)
|
||||||
|
|
||||||
|
const product3 = manager.create(Product, {
|
||||||
|
id: "test-product_filtering_3",
|
||||||
|
handle: "test-product_filtering_3",
|
||||||
|
title: "Test product filtering 3",
|
||||||
|
profile_id: defaultProfile.id,
|
||||||
|
description: "test-product-description",
|
||||||
|
type: { id: "test-type", value: "test-type" },
|
||||||
|
collection_id: "test-collection1",
|
||||||
|
status: "draft",
|
||||||
|
tags: [{ id: "tag4", value: "1234" }],
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(product3)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,4 +96,33 @@ Joi.orderFilter = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Joi.productFilter = () => {
|
||||||
|
return Joi.object().keys({
|
||||||
|
id: Joi.string(),
|
||||||
|
q: Joi.string().allow(null, ""),
|
||||||
|
status: Joi.array()
|
||||||
|
.items(Joi.string().valid("proposed", "draft", "published", "rejected"))
|
||||||
|
.single(),
|
||||||
|
collection_id: Joi.array()
|
||||||
|
.items(Joi.string())
|
||||||
|
.single(),
|
||||||
|
tags: Joi.array()
|
||||||
|
.items(Joi.string())
|
||||||
|
.single(),
|
||||||
|
title: Joi.string(),
|
||||||
|
description: Joi.string(),
|
||||||
|
handle: Joi.string(),
|
||||||
|
is_giftcard: Joi.string(),
|
||||||
|
type: Joi.string(),
|
||||||
|
offset: Joi.string(),
|
||||||
|
limit: Joi.string(),
|
||||||
|
expand: Joi.string(),
|
||||||
|
fields: Joi.string(),
|
||||||
|
order: Joi.string().optional(),
|
||||||
|
created_at: Joi.dateFilter(),
|
||||||
|
updated_at: Joi.dateFilter(),
|
||||||
|
deleted_at: Joi.dateFilter(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
export default Joi
|
export default Joi
|
||||||
|
|||||||
@@ -46,7 +46,11 @@ export default app => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
route.get("/:id", middlewares.wrap(require("./get-product").default))
|
route.get("/:id", middlewares.wrap(require("./get-product").default))
|
||||||
route.get("/", middlewares.wrap(require("./list-products").default))
|
route.get(
|
||||||
|
"/",
|
||||||
|
middlewares.normalizeQuery(),
|
||||||
|
middlewares.wrap(require("./list-products").default)
|
||||||
|
)
|
||||||
|
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
@@ -121,3 +125,18 @@ export const allowedRelations = [
|
|||||||
"type",
|
"type",
|
||||||
"collection",
|
"collection",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
export const filterableFields = [
|
||||||
|
"id",
|
||||||
|
"status",
|
||||||
|
"collection_id",
|
||||||
|
"tags",
|
||||||
|
"title",
|
||||||
|
"description",
|
||||||
|
"handle",
|
||||||
|
"is_giftcard",
|
||||||
|
"type",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
|
"deleted_at",
|
||||||
|
]
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import _ from "lodash"
|
import _ from "lodash"
|
||||||
import { MedusaError, Validator } from "medusa-core-utils"
|
import { MedusaError, Validator } from "medusa-core-utils"
|
||||||
import { defaultFields, defaultRelations } from "./"
|
import { defaultFields, defaultRelations, filterableFields } from "./"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @oas [get] /products
|
* @oas [get] /products
|
||||||
@@ -31,6 +31,17 @@ import { defaultFields, defaultRelations } from "./"
|
|||||||
* $ref: "#/components/schemas/product"
|
* $ref: "#/components/schemas/product"
|
||||||
*/
|
*/
|
||||||
export default async (req, res) => {
|
export default async (req, res) => {
|
||||||
|
const schema = Validator.productFilter()
|
||||||
|
|
||||||
|
const { value, error } = schema.validate(req.query)
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_DATA,
|
||||||
|
JSON.stringify(error.details)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const productService = req.scope.resolve("productService")
|
const productService = req.scope.resolve("productService")
|
||||||
|
|
||||||
@@ -53,21 +64,16 @@ export default async (req, res) => {
|
|||||||
expandFields = req.query.expand.split(",")
|
expandFields = req.query.expand.split(",")
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("is_giftcard" in req.query) {
|
for (const k of filterableFields) {
|
||||||
selector.is_giftcard = req.query.is_giftcard === "true"
|
if (k in value) {
|
||||||
|
selector[k] = value[k]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ("status" in req.query) {
|
if (selector.status?.indexOf("null") > -1) {
|
||||||
const schema = Validator.array()
|
selector.status.splice(selector.status.indexOf("null"), 1)
|
||||||
.items(
|
if (selector.status.length === 0) {
|
||||||
Validator.string().valid("proposed", "draft", "published", "rejected")
|
delete selector.status
|
||||||
)
|
|
||||||
.single()
|
|
||||||
|
|
||||||
const { value, error } = schema.validate(req.query.status)
|
|
||||||
|
|
||||||
if (value && !error) {
|
|
||||||
selector.status = value
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,27 @@ export class ProductRepository extends Repository<Product> {
|
|||||||
if (Array.isArray(idsOrOptionsWithoutRelations)) {
|
if (Array.isArray(idsOrOptionsWithoutRelations)) {
|
||||||
entities = await this.findByIds(idsOrOptionsWithoutRelations)
|
entities = await this.findByIds(idsOrOptionsWithoutRelations)
|
||||||
} else {
|
} else {
|
||||||
entities = await this.find(idsOrOptionsWithoutRelations)
|
// Since tags are in a one-to-many realtion they cant be included in a
|
||||||
|
// regular query, to solve this add the join on tags seperately if
|
||||||
|
// the query exists
|
||||||
|
const tags = idsOrOptionsWithoutRelations.where.tags
|
||||||
|
delete idsOrOptionsWithoutRelations.where.tags
|
||||||
|
let qb = this.createQueryBuilder("product")
|
||||||
|
.select(["product.id"])
|
||||||
|
.where(idsOrOptionsWithoutRelations.where)
|
||||||
|
.skip(idsOrOptionsWithoutRelations.skip)
|
||||||
|
.take(idsOrOptionsWithoutRelations.take)
|
||||||
|
|
||||||
|
if (tags) {
|
||||||
|
qb = qb
|
||||||
|
.leftJoinAndSelect("product.tags", "tags")
|
||||||
|
.andWhere(
|
||||||
|
`tags.id IN (:...ids)`, { ids: tags._value}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
entities = await qb
|
||||||
|
.getMany()
|
||||||
}
|
}
|
||||||
const entitiesIds = entities.map(({ id }) => id)
|
const entitiesIds = entities.map(({ id }) => id)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user