feat(medusa): Ordering products on retrieval (#2815)
**What** Move to transformQuery which adds a default ordering and also allows to order the product list from the store API **How** Among other things, fix the product repo to allow ordering by either a key from the product or a key from a relation FIXES CORE-911 FIXES CORE-901
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@medusajs/medusa": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
feat(medusa): Order products on retrieval
|
||||||
@@ -1,598 +1,5 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`/admin/products GET /admin/products returns a list of products with child entities 1`] = `
|
|
||||||
Array [
|
|
||||||
Object {
|
|
||||||
"collection": Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"handle": "test-collection",
|
|
||||||
"id": StringMatching /\\^test-\\*/,
|
|
||||||
"metadata": null,
|
|
||||||
"title": "Test collection",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
},
|
|
||||||
"collection_id": "test-collection",
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"description": "test-product-description",
|
|
||||||
"discountable": true,
|
|
||||||
"external_id": null,
|
|
||||||
"handle": "test-product",
|
|
||||||
"height": null,
|
|
||||||
"hs_code": null,
|
|
||||||
"id": "test-product",
|
|
||||||
"images": Array [
|
|
||||||
Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": StringMatching /\\^test-\\*/,
|
|
||||||
"metadata": null,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"url": "test-image.png",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"is_giftcard": false,
|
|
||||||
"length": null,
|
|
||||||
"material": null,
|
|
||||||
"metadata": null,
|
|
||||||
"mid_code": null,
|
|
||||||
"options": Array [
|
|
||||||
Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": StringMatching /\\^test-\\*/,
|
|
||||||
"metadata": null,
|
|
||||||
"product_id": StringMatching /\\^test-\\*/,
|
|
||||||
"title": "test-option",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"origin_country": null,
|
|
||||||
"profile_id": StringMatching /\\^sp_\\*/,
|
|
||||||
"status": "draft",
|
|
||||||
"subtitle": null,
|
|
||||||
"tags": Array [
|
|
||||||
Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": StringMatching /\\^tag\\*/,
|
|
||||||
"metadata": null,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"value": "123",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"thumbnail": null,
|
|
||||||
"title": "Test product",
|
|
||||||
"type": Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": StringMatching /\\^test-\\*/,
|
|
||||||
"metadata": null,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"value": "test-type",
|
|
||||||
},
|
|
||||||
"type_id": "test-type",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"variants": Array [
|
|
||||||
Object {
|
|
||||||
"allow_backorder": false,
|
|
||||||
"barcode": "test-barcode",
|
|
||||||
"calculated_price": null,
|
|
||||||
"calculated_price_incl_tax": null,
|
|
||||||
"calculated_tax": null,
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"ean": "test-ean",
|
|
||||||
"height": null,
|
|
||||||
"hs_code": null,
|
|
||||||
"id": "test-variant",
|
|
||||||
"inventory_quantity": 10,
|
|
||||||
"length": null,
|
|
||||||
"manage_inventory": true,
|
|
||||||
"material": null,
|
|
||||||
"metadata": null,
|
|
||||||
"mid_code": null,
|
|
||||||
"options": Array [
|
|
||||||
Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": StringMatching /\\^test-variant-option\\*/,
|
|
||||||
"metadata": null,
|
|
||||||
"option_id": StringMatching /\\^test-opt\\*/,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"value": "Default variant",
|
|
||||||
"variant_id": StringMatching /\\^test-variant\\*/,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"origin_country": null,
|
|
||||||
"original_price": null,
|
|
||||||
"original_price_incl_tax": null,
|
|
||||||
"original_tax": null,
|
|
||||||
"prices": Array [
|
|
||||||
Object {
|
|
||||||
"amount": 100,
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"currency_code": "usd",
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": "test-price",
|
|
||||||
"max_quantity": null,
|
|
||||||
"min_quantity": null,
|
|
||||||
"price_list": null,
|
|
||||||
"price_list_id": null,
|
|
||||||
"region_id": null,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"variant_id": StringMatching /\\^test-variant\\*/,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"product_id": StringMatching /\\^test-\\*/,
|
|
||||||
"sku": "test-sku",
|
|
||||||
"tax_rates": null,
|
|
||||||
"title": "Test variant",
|
|
||||||
"upc": "test-upc",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"weight": null,
|
|
||||||
"width": null,
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"allow_backorder": false,
|
|
||||||
"barcode": null,
|
|
||||||
"calculated_price": null,
|
|
||||||
"calculated_price_incl_tax": null,
|
|
||||||
"calculated_tax": null,
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"ean": "test-ean2",
|
|
||||||
"height": null,
|
|
||||||
"hs_code": null,
|
|
||||||
"id": "test-variant_2",
|
|
||||||
"inventory_quantity": 10,
|
|
||||||
"length": null,
|
|
||||||
"manage_inventory": true,
|
|
||||||
"material": null,
|
|
||||||
"metadata": null,
|
|
||||||
"mid_code": null,
|
|
||||||
"options": Array [
|
|
||||||
Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": StringMatching /\\^test-variant-option\\*/,
|
|
||||||
"metadata": null,
|
|
||||||
"option_id": StringMatching /\\^test-opt\\*/,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"value": "Default variant 2",
|
|
||||||
"variant_id": StringMatching /\\^test-variant\\*/,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"origin_country": null,
|
|
||||||
"original_price": null,
|
|
||||||
"original_price_incl_tax": null,
|
|
||||||
"original_tax": null,
|
|
||||||
"prices": Array [
|
|
||||||
Object {
|
|
||||||
"amount": 100,
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"currency_code": "usd",
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": StringMatching /\\^test-price\\*/,
|
|
||||||
"max_quantity": null,
|
|
||||||
"min_quantity": null,
|
|
||||||
"price_list": null,
|
|
||||||
"price_list_id": null,
|
|
||||||
"region_id": null,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"variant_id": "test-variant_2",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"product_id": StringMatching /\\^test-\\*/,
|
|
||||||
"sku": "test-sku2",
|
|
||||||
"tax_rates": null,
|
|
||||||
"title": "Test variant rank (2)",
|
|
||||||
"upc": "test-upc2",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"weight": null,
|
|
||||||
"width": null,
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"allow_backorder": false,
|
|
||||||
"barcode": "test-barcode 1",
|
|
||||||
"calculated_price": null,
|
|
||||||
"calculated_price_incl_tax": null,
|
|
||||||
"calculated_tax": null,
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"ean": "test-ean1",
|
|
||||||
"height": null,
|
|
||||||
"hs_code": null,
|
|
||||||
"id": "test-variant_1",
|
|
||||||
"inventory_quantity": 10,
|
|
||||||
"length": null,
|
|
||||||
"manage_inventory": true,
|
|
||||||
"material": null,
|
|
||||||
"metadata": null,
|
|
||||||
"mid_code": null,
|
|
||||||
"options": Array [
|
|
||||||
Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": StringMatching /\\^test-variant-option\\*/,
|
|
||||||
"metadata": null,
|
|
||||||
"option_id": StringMatching /\\^test-opt\\*/,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"value": "Default variant 1",
|
|
||||||
"variant_id": StringMatching /\\^test-variant\\*/,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"origin_country": null,
|
|
||||||
"original_price": null,
|
|
||||||
"original_price_incl_tax": null,
|
|
||||||
"original_tax": null,
|
|
||||||
"prices": Array [
|
|
||||||
Object {
|
|
||||||
"amount": 100,
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"currency_code": "usd",
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": StringMatching /\\^test-price\\*/,
|
|
||||||
"max_quantity": null,
|
|
||||||
"min_quantity": null,
|
|
||||||
"price_list": null,
|
|
||||||
"price_list_id": null,
|
|
||||||
"region_id": null,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"variant_id": StringMatching /\\^test-variant\\*/,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"product_id": StringMatching /\\^test-\\*/,
|
|
||||||
"sku": "test-sku1",
|
|
||||||
"tax_rates": null,
|
|
||||||
"title": "Test variant rank (1)",
|
|
||||||
"upc": "test-upc1",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"weight": null,
|
|
||||||
"width": null,
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"allow_backorder": false,
|
|
||||||
"barcode": "test-barcode-sale",
|
|
||||||
"calculated_price": null,
|
|
||||||
"calculated_price_incl_tax": null,
|
|
||||||
"calculated_tax": null,
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"ean": "test-ean-sale",
|
|
||||||
"height": null,
|
|
||||||
"hs_code": null,
|
|
||||||
"id": "test-variant-sale",
|
|
||||||
"inventory_quantity": 10,
|
|
||||||
"length": null,
|
|
||||||
"manage_inventory": true,
|
|
||||||
"material": null,
|
|
||||||
"metadata": null,
|
|
||||||
"mid_code": null,
|
|
||||||
"options": Array [
|
|
||||||
Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": StringMatching /\\^test-variant-option\\*/,
|
|
||||||
"metadata": null,
|
|
||||||
"option_id": StringMatching /\\^test-opt\\*/,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"value": "Default variant",
|
|
||||||
"variant_id": StringMatching /\\^test-variant\\*/,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"origin_country": null,
|
|
||||||
"original_price": null,
|
|
||||||
"original_price_incl_tax": null,
|
|
||||||
"original_tax": null,
|
|
||||||
"prices": Array [
|
|
||||||
Object {
|
|
||||||
"amount": 1000,
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"currency_code": "usd",
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": "test-price-sale",
|
|
||||||
"max_quantity": null,
|
|
||||||
"min_quantity": null,
|
|
||||||
"price_list": null,
|
|
||||||
"price_list_id": null,
|
|
||||||
"region_id": null,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"variant_id": StringMatching /\\^test-variant\\*/,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"product_id": StringMatching /\\^test-\\*/,
|
|
||||||
"sku": "test-sku-sale",
|
|
||||||
"tax_rates": null,
|
|
||||||
"title": "Test variant",
|
|
||||||
"upc": "test-upc-sale",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"weight": null,
|
|
||||||
"width": null,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"weight": null,
|
|
||||||
"width": null,
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"collection": Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"handle": "test-collection",
|
|
||||||
"id": StringMatching /\\^test-\\*/,
|
|
||||||
"metadata": null,
|
|
||||||
"title": "Test collection",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
},
|
|
||||||
"collection_id": "test-collection",
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"description": "test-product-description1",
|
|
||||||
"discountable": true,
|
|
||||||
"external_id": null,
|
|
||||||
"handle": "test-product1",
|
|
||||||
"height": null,
|
|
||||||
"hs_code": null,
|
|
||||||
"id": "test-product1",
|
|
||||||
"images": Array [],
|
|
||||||
"is_giftcard": false,
|
|
||||||
"length": null,
|
|
||||||
"material": null,
|
|
||||||
"metadata": null,
|
|
||||||
"mid_code": null,
|
|
||||||
"options": Array [],
|
|
||||||
"origin_country": null,
|
|
||||||
"profile_id": StringMatching /\\^sp_\\*/,
|
|
||||||
"status": "draft",
|
|
||||||
"subtitle": null,
|
|
||||||
"tags": Array [
|
|
||||||
Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": StringMatching /\\^tag\\*/,
|
|
||||||
"metadata": null,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"value": "123",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"thumbnail": null,
|
|
||||||
"title": "Test product1",
|
|
||||||
"type": Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": StringMatching /\\^test-\\*/,
|
|
||||||
"metadata": null,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"value": "test-type",
|
|
||||||
},
|
|
||||||
"type_id": "test-type",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"variants": Array [
|
|
||||||
Object {
|
|
||||||
"allow_backorder": false,
|
|
||||||
"barcode": null,
|
|
||||||
"calculated_price": null,
|
|
||||||
"calculated_price_incl_tax": null,
|
|
||||||
"calculated_tax": null,
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"ean": "test-ean4",
|
|
||||||
"height": null,
|
|
||||||
"hs_code": null,
|
|
||||||
"id": "test-variant_4",
|
|
||||||
"inventory_quantity": 10,
|
|
||||||
"length": null,
|
|
||||||
"manage_inventory": true,
|
|
||||||
"material": null,
|
|
||||||
"metadata": null,
|
|
||||||
"mid_code": null,
|
|
||||||
"options": Array [
|
|
||||||
Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": StringMatching /\\^test-variant-option\\*/,
|
|
||||||
"metadata": null,
|
|
||||||
"option_id": StringMatching /\\^test-opt\\*/,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"value": "Default variant 4",
|
|
||||||
"variant_id": StringMatching /\\^test-variant\\*/,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"origin_country": null,
|
|
||||||
"original_price": null,
|
|
||||||
"original_price_incl_tax": null,
|
|
||||||
"original_tax": null,
|
|
||||||
"prices": Array [
|
|
||||||
Object {
|
|
||||||
"amount": 100,
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"currency_code": "usd",
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": StringMatching /\\^test-price\\*/,
|
|
||||||
"max_quantity": null,
|
|
||||||
"min_quantity": null,
|
|
||||||
"price_list": null,
|
|
||||||
"price_list_id": null,
|
|
||||||
"region_id": null,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"variant_id": StringMatching /\\^test-variant\\*/,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"product_id": StringMatching /\\^test-\\*/,
|
|
||||||
"sku": "test-sku4",
|
|
||||||
"tax_rates": null,
|
|
||||||
"title": "Test variant rank (2)",
|
|
||||||
"upc": "test-upc4",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"weight": null,
|
|
||||||
"width": null,
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"allow_backorder": false,
|
|
||||||
"barcode": null,
|
|
||||||
"calculated_price": null,
|
|
||||||
"calculated_price_incl_tax": null,
|
|
||||||
"calculated_tax": null,
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"ean": "test-ean3",
|
|
||||||
"height": null,
|
|
||||||
"hs_code": null,
|
|
||||||
"id": "test-variant_3",
|
|
||||||
"inventory_quantity": 10,
|
|
||||||
"length": null,
|
|
||||||
"manage_inventory": true,
|
|
||||||
"material": null,
|
|
||||||
"metadata": null,
|
|
||||||
"mid_code": null,
|
|
||||||
"options": Array [
|
|
||||||
Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": StringMatching /\\^test-variant-option\\*/,
|
|
||||||
"metadata": null,
|
|
||||||
"option_id": StringMatching /\\^test-opt\\*/,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"value": "Default variant 3",
|
|
||||||
"variant_id": StringMatching /\\^test-variant\\*/,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"origin_country": null,
|
|
||||||
"original_price": null,
|
|
||||||
"original_price_incl_tax": null,
|
|
||||||
"original_tax": null,
|
|
||||||
"prices": Array [
|
|
||||||
Object {
|
|
||||||
"amount": 100,
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"currency_code": "usd",
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": StringMatching /\\^test-price\\*/,
|
|
||||||
"max_quantity": null,
|
|
||||||
"min_quantity": null,
|
|
||||||
"price_list": null,
|
|
||||||
"price_list_id": null,
|
|
||||||
"region_id": "test-region",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"variant_id": StringMatching /\\^test-variant\\*/,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"product_id": StringMatching /\\^test-\\*/,
|
|
||||||
"sku": "test-sku3",
|
|
||||||
"tax_rates": null,
|
|
||||||
"title": "Test variant rank (2)",
|
|
||||||
"upc": "test-upc3",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"weight": null,
|
|
||||||
"width": null,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"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,
|
|
||||||
"external_id": null,
|
|
||||||
"handle": "test-product_filtering_1",
|
|
||||||
"height": null,
|
|
||||||
"hs_code": null,
|
|
||||||
"id": "test-product_filtering_1",
|
|
||||||
"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,
|
|
||||||
"external_id": null,
|
|
||||||
"handle": "test-product_filtering_2",
|
|
||||||
"height": null,
|
|
||||||
"hs_code": null,
|
|
||||||
"id": "test-product_filtering_2",
|
|
||||||
"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,
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"collection": Any<Object>,
|
|
||||||
"collection_id": "test-collection1",
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"description": "test-product-description",
|
|
||||||
"discountable": true,
|
|
||||||
"external_id": null,
|
|
||||||
"handle": "test-product_filtering_3",
|
|
||||||
"height": null,
|
|
||||||
"hs_code": null,
|
|
||||||
"id": "test-product_filtering_3",
|
|
||||||
"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,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`/admin/products GET /admin/products returns a list of products with only giftcard in list 1`] = `
|
exports[`/admin/products GET /admin/products returns a list of products with only giftcard in list 1`] = `
|
||||||
Array [
|
Array [
|
||||||
Object {
|
Object {
|
||||||
|
|||||||
@@ -88,11 +88,7 @@ describe("/admin/price-lists", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const response = await api
|
const response = await api
|
||||||
.post("/admin/price-lists", payload, {
|
.post("/admin/price-lists", payload, adminReqConfig)
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer test_token",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.warn(err.response.data)
|
console.warn(err.response.data)
|
||||||
})
|
})
|
||||||
@@ -147,11 +143,7 @@ describe("/admin/price-lists", () => {
|
|||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
const response = await api
|
const response = await api
|
||||||
.get("/admin/price-lists/pl_no_customer_groups", {
|
.get("/admin/price-lists/pl_no_customer_groups", adminReqConfig)
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer test_token",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.warn(err.response.data)
|
console.warn(err.response.data)
|
||||||
})
|
})
|
||||||
@@ -209,11 +201,7 @@ describe("/admin/price-lists", () => {
|
|||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
const response = await api
|
const response = await api
|
||||||
.get("/admin/price-lists", {
|
.get("/admin/price-lists", adminReqConfig)
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer test_token",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.warn(err.response.data)
|
console.warn(err.response.data)
|
||||||
})
|
})
|
||||||
@@ -232,11 +220,7 @@ describe("/admin/price-lists", () => {
|
|||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
const response = await api
|
const response = await api
|
||||||
.get("/admin/price-lists?q=winter", {
|
.get("/admin/price-lists?q=winter", adminReqConfig)
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer test_token",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.warn(err.response.data)
|
console.warn(err.response.data)
|
||||||
})
|
})
|
||||||
@@ -256,11 +240,7 @@ describe("/admin/price-lists", () => {
|
|||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
const response = await api
|
const response = await api
|
||||||
.get("/admin/price-lists?q=25%", {
|
.get("/admin/price-lists?q=25%", adminReqConfig)
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer test_token",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.warn(err.response.data)
|
console.warn(err.response.data)
|
||||||
})
|
})
|
||||||
@@ -282,11 +262,7 @@ describe("/admin/price-lists", () => {
|
|||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
const response = await api
|
const response = await api
|
||||||
.get("/admin/price-lists?q=blablabla", {
|
.get("/admin/price-lists?q=blablabla", adminReqConfig)
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer test_token",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.warn(err.response.data)
|
console.warn(err.response.data)
|
||||||
})
|
})
|
||||||
@@ -300,11 +276,7 @@ describe("/admin/price-lists", () => {
|
|||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
const response = await api
|
const response = await api
|
||||||
.get("/admin/price-lists?q=vip&status[]=draft", {
|
.get("/admin/price-lists?q=vip&status[]=draft", adminReqConfig)
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer test_token",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.warn(err.response.data)
|
console.warn(err.response.data)
|
||||||
})
|
})
|
||||||
@@ -318,11 +290,7 @@ describe("/admin/price-lists", () => {
|
|||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
const response = await api
|
const response = await api
|
||||||
.get("/admin/price-lists?q=vip&status[]=active", {
|
.get("/admin/price-lists?q=vip&status[]=active", adminReqConfig)
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer test_token",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.warn(err.response.data)
|
console.warn(err.response.data)
|
||||||
})
|
})
|
||||||
@@ -363,11 +331,7 @@ describe("/admin/price-lists", () => {
|
|||||||
const response = await api
|
const response = await api
|
||||||
.get(
|
.get(
|
||||||
`/admin/price-lists?customer_groups[]=customer-group-1,customer-group-2`,
|
`/admin/price-lists?customer_groups[]=customer-group-1,customer-group-2`,
|
||||||
{
|
adminReqConfig
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer test_token",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.warn(err.response.data)
|
console.warn(err.response.data)
|
||||||
@@ -406,11 +370,10 @@ describe("/admin/price-lists", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const api = useApi()
|
const api = useApi()
|
||||||
const getResult = await api.get(`/admin/price-lists/${priceList.id}`, {
|
const getResult = await api.get(
|
||||||
headers: {
|
`/admin/price-lists/${priceList.id}`,
|
||||||
Authorization: "Bearer test_token",
|
adminReqConfig
|
||||||
},
|
)
|
||||||
})
|
|
||||||
|
|
||||||
expect(getResult.status).toEqual(200)
|
expect(getResult.status).toEqual(200)
|
||||||
expect(getResult.data.price_list.starts_at).toBeTruthy()
|
expect(getResult.data.price_list.starts_at).toBeTruthy()
|
||||||
@@ -420,11 +383,7 @@ describe("/admin/price-lists", () => {
|
|||||||
const updateResult = await api.post(
|
const updateResult = await api.post(
|
||||||
`/admin/price-lists/${priceList.id}`,
|
`/admin/price-lists/${priceList.id}`,
|
||||||
{ ends_at: null, starts_at: null, customer_groups: [] },
|
{ ends_at: null, starts_at: null, customer_groups: [] },
|
||||||
{
|
adminReqConfig
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer test_token",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(updateResult.status).toEqual(200)
|
expect(updateResult.status).toEqual(200)
|
||||||
@@ -463,11 +422,11 @@ describe("/admin/price-lists", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const response = await api
|
const response = await api
|
||||||
.post("/admin/price-lists/pl_no_customer_groups", payload, {
|
.post(
|
||||||
headers: {
|
"/admin/price-lists/pl_no_customer_groups",
|
||||||
Authorization: "Bearer test_token",
|
payload,
|
||||||
},
|
adminReqConfig
|
||||||
})
|
)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.warn(err.response.data)
|
console.warn(err.response.data)
|
||||||
})
|
})
|
||||||
@@ -575,11 +534,11 @@ describe("/admin/price-lists", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const response = await api
|
const response = await api
|
||||||
.post("/admin/price-lists/pl_no_customer_groups", payload, {
|
.post(
|
||||||
headers: {
|
"/admin/price-lists/pl_no_customer_groups",
|
||||||
Authorization: "Bearer test_token",
|
payload,
|
||||||
},
|
adminReqConfig
|
||||||
})
|
)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.warn(err.response.data)
|
console.warn(err.response.data)
|
||||||
})
|
})
|
||||||
@@ -626,11 +585,7 @@ describe("/admin/price-lists", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const response = await api
|
const response = await api
|
||||||
.post("/admin/price-lists/pl_with_some_ma", payload, {
|
.post("/admin/price-lists/pl_with_some_ma", payload, adminReqConfig)
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer test_token",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.warn(err.response.data)
|
console.warn(err.response.data)
|
||||||
})
|
})
|
||||||
@@ -714,11 +669,7 @@ describe("/admin/price-lists", () => {
|
|||||||
.post(
|
.post(
|
||||||
"/admin/price-lists/pl_no_customer_groups/prices/batch",
|
"/admin/price-lists/pl_no_customer_groups/prices/batch",
|
||||||
payload,
|
payload,
|
||||||
{
|
adminReqConfig
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer test_token",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.warn(err.response.data)
|
console.warn(err.response.data)
|
||||||
@@ -832,11 +783,7 @@ describe("/admin/price-lists", () => {
|
|||||||
.post(
|
.post(
|
||||||
"/admin/price-lists/pl_no_customer_groups/prices/batch",
|
"/admin/price-lists/pl_no_customer_groups/prices/batch",
|
||||||
payload,
|
payload,
|
||||||
{
|
adminReqConfig
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer test_token",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.warn(err.response.data)
|
console.warn(err.response.data)
|
||||||
@@ -900,11 +847,11 @@ describe("/admin/price-lists", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const response = await api
|
const response = await api
|
||||||
.post("/admin/price-lists/pl_with_some_ma/prices/batch", payload, {
|
.post(
|
||||||
headers: {
|
"/admin/price-lists/pl_with_some_ma/prices/batch",
|
||||||
Authorization: "Bearer test_token",
|
payload,
|
||||||
},
|
adminReqConfig
|
||||||
})
|
)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.warn(err.response.data)
|
console.warn(err.response.data)
|
||||||
})
|
})
|
||||||
@@ -970,11 +917,7 @@ describe("/admin/price-lists", () => {
|
|||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
const response = await api
|
const response = await api
|
||||||
.delete("/admin/price-lists/pl_no_customer_groups", {
|
.delete("/admin/price-lists/pl_no_customer_groups", adminReqConfig)
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer test_token",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.warn(err.response.data)
|
console.warn(err.response.data)
|
||||||
})
|
})
|
||||||
@@ -987,11 +930,10 @@ describe("/admin/price-lists", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await api.get("/admin/price-lists/pl_no_customer_groups", {
|
await api.get(
|
||||||
headers: {
|
"/admin/price-lists/pl_no_customer_groups",
|
||||||
Authorization: "Bearer test_token",
|
adminReqConfig
|
||||||
},
|
)
|
||||||
})
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
expect(error.response.status).toBe(404)
|
expect(error.response.status).toBe(404)
|
||||||
expect(error.response.data.message).toEqual(
|
expect(error.response.data.message).toEqual(
|
||||||
@@ -1017,22 +959,17 @@ describe("/admin/price-lists", () => {
|
|||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
await api
|
await api
|
||||||
.delete("/admin/products/test-product/variants/test-variant", {
|
.delete(
|
||||||
headers: {
|
"/admin/products/test-product/variants/test-variant",
|
||||||
Authorization: "Bearer test_token",
|
adminReqConfig
|
||||||
},
|
)
|
||||||
})
|
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.warn(err.response.data)
|
console.warn(err.response.data)
|
||||||
})
|
})
|
||||||
|
|
||||||
const response = await api.get(
|
const response = await api.get(
|
||||||
"/admin/price-lists/pl_no_customer_groups",
|
"/admin/price-lists/pl_no_customer_groups",
|
||||||
{
|
adminReqConfig
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer test_token",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200)
|
||||||
@@ -1057,9 +994,7 @@ describe("/admin/price-lists", () => {
|
|||||||
|
|
||||||
const response = await api
|
const response = await api
|
||||||
.delete("/admin/price-lists/pl_no_customer_groups/prices/batch", {
|
.delete("/admin/price-lists/pl_no_customer_groups/prices/batch", {
|
||||||
headers: {
|
...adminReqConfig,
|
||||||
Authorization: "Bearer test_token",
|
|
||||||
},
|
|
||||||
data: {
|
data: {
|
||||||
price_ids: ["ma_test_1", "ma_test_2"],
|
price_ids: ["ma_test_1", "ma_test_2"],
|
||||||
},
|
},
|
||||||
@@ -1069,11 +1004,7 @@ describe("/admin/price-lists", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const getPriceListResponse = await api
|
const getPriceListResponse = await api
|
||||||
.get("/admin/price-lists/pl_no_customer_groups", {
|
.get("/admin/price-lists/pl_no_customer_groups", adminReqConfig)
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer test_token",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.warn(err.response.data)
|
console.warn(err.response.data)
|
||||||
})
|
})
|
||||||
@@ -1166,11 +1097,10 @@ describe("/admin/price-lists", () => {
|
|||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
const response = await api
|
const response = await api
|
||||||
.get(`/admin/price-lists/test-list/products?order=-created_at`, {
|
.get(
|
||||||
headers: {
|
`/admin/price-lists/test-list/products?order=-created_at`,
|
||||||
Authorization: "Bearer test_token",
|
adminReqConfig
|
||||||
},
|
)
|
||||||
})
|
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.warn(err.response.data)
|
console.warn(err.response.data)
|
||||||
})
|
})
|
||||||
@@ -1179,28 +1109,6 @@ describe("/admin/price-lists", () => {
|
|||||||
expect(response.data.count).toEqual(2)
|
expect(response.data.count).toEqual(2)
|
||||||
expect(response.data.products).toHaveLength(2)
|
expect(response.data.products).toHaveLength(2)
|
||||||
expect(response.data.products).toEqual([
|
expect(response.data.products).toEqual([
|
||||||
expect.objectContaining({
|
|
||||||
id: "test-prod-1",
|
|
||||||
variants: expect.arrayContaining([
|
|
||||||
expect.objectContaining({
|
|
||||||
id: "test-variant-1",
|
|
||||||
prices: expect.arrayContaining([
|
|
||||||
expect.objectContaining({ currency_code: "usd", amount: 100 }),
|
|
||||||
expect.objectContaining({
|
|
||||||
currency_code: "usd",
|
|
||||||
amount: 150,
|
|
||||||
price_list_id: "test-list",
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
id: "test-variant-2",
|
|
||||||
prices: expect.arrayContaining([
|
|
||||||
expect.objectContaining({ currency_code: "usd", amount: 100 }),
|
|
||||||
]),
|
|
||||||
}),
|
|
||||||
]),
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: "test-prod-2",
|
id: "test-prod-2",
|
||||||
variants: expect.arrayContaining([
|
variants: expect.arrayContaining([
|
||||||
@@ -1223,6 +1131,28 @@ describe("/admin/price-lists", () => {
|
|||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
}),
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-prod-1",
|
||||||
|
variants: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-variant-1",
|
||||||
|
prices: expect.arrayContaining([
|
||||||
|
expect.objectContaining({ currency_code: "usd", amount: 100 }),
|
||||||
|
expect.objectContaining({
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 150,
|
||||||
|
price_list_id: "test-list",
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-variant-2",
|
||||||
|
prices: expect.arrayContaining([
|
||||||
|
expect.objectContaining({ currency_code: "usd", amount: 100 }),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -1230,11 +1160,10 @@ describe("/admin/price-lists", () => {
|
|||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
const response = await api
|
const response = await api
|
||||||
.get(`/admin/price-lists/test-list/products?tags[]=${tag}`, {
|
.get(
|
||||||
headers: {
|
`/admin/price-lists/test-list/products?tags[]=${tag}`,
|
||||||
Authorization: "Bearer test_token",
|
adminReqConfig
|
||||||
},
|
)
|
||||||
})
|
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.warn(err.response.data)
|
console.warn(err.response.data)
|
||||||
})
|
})
|
||||||
@@ -1251,11 +1180,10 @@ describe("/admin/price-lists", () => {
|
|||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
const response = await api
|
const response = await api
|
||||||
.get(`/admin/price-lists/test-list/products?q=Headphones`, {
|
.get(
|
||||||
headers: {
|
`/admin/price-lists/test-list/products?q=Headphones`,
|
||||||
Authorization: "Bearer test_token",
|
adminReqConfig
|
||||||
},
|
)
|
||||||
})
|
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.warn(err.response.data)
|
console.warn(err.response.data)
|
||||||
})
|
})
|
||||||
@@ -1343,22 +1271,14 @@ describe("/admin/price-lists", () => {
|
|||||||
it("should delete all the prices that are part of the price list for the specified product", async () => {
|
it("should delete all the prices that are part of the price list for the specified product", async () => {
|
||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
response = await api.get("/admin/price-lists/test-list", {
|
response = await api.get("/admin/price-lists/test-list", adminReqConfig)
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer test_token",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(response.status).toBe(200)
|
expect(response.status).toBe(200)
|
||||||
expect(response.data.price_list.prices.length).toBe(3)
|
expect(response.data.price_list.prices.length).toBe(3)
|
||||||
|
|
||||||
let response = await api.delete(
|
let response = await api.delete(
|
||||||
`/admin/price-lists/test-list/products/${product1.id}/prices`,
|
`/admin/price-lists/test-list/products/${product1.id}/prices`,
|
||||||
{
|
adminReqConfig
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer test_token",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(response.status).toBe(200)
|
expect(response.status).toBe(200)
|
||||||
@@ -1370,11 +1290,7 @@ describe("/admin/price-lists", () => {
|
|||||||
deleted: true,
|
deleted: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
response = await api.get("/admin/price-lists/test-list", {
|
response = await api.get("/admin/price-lists/test-list", adminReqConfig)
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer test_token",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(response.status).toBe(200)
|
expect(response.status).toBe(200)
|
||||||
expect(response.data.price_list.prices.length).toBe(1)
|
expect(response.data.price_list.prices.length).toBe(1)
|
||||||
@@ -1383,11 +1299,7 @@ describe("/admin/price-lists", () => {
|
|||||||
it("should delete all the prices that are part of the price list for the specified variant", async () => {
|
it("should delete all the prices that are part of the price list for the specified variant", async () => {
|
||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
response = await api.get("/admin/price-lists/test-list", {
|
response = await api.get("/admin/price-lists/test-list", adminReqConfig)
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer test_token",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(response.status).toBe(200)
|
expect(response.status).toBe(200)
|
||||||
expect(response.data.price_list.prices.length).toBe(3)
|
expect(response.data.price_list.prices.length).toBe(3)
|
||||||
@@ -1395,11 +1307,7 @@ describe("/admin/price-lists", () => {
|
|||||||
const variant = product2.variants[0]
|
const variant = product2.variants[0]
|
||||||
let response = await api.delete(
|
let response = await api.delete(
|
||||||
`/admin/price-lists/test-list/variants/${variant.id}/prices`,
|
`/admin/price-lists/test-list/variants/${variant.id}/prices`,
|
||||||
{
|
adminReqConfig
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer test_token",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(response.status).toBe(200)
|
expect(response.status).toBe(200)
|
||||||
@@ -1409,11 +1317,7 @@ describe("/admin/price-lists", () => {
|
|||||||
deleted: true,
|
deleted: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
response = await api.get("/admin/price-lists/test-list", {
|
response = await api.get("/admin/price-lists/test-list", adminReqConfig)
|
||||||
headers: {
|
|
||||||
Authorization: "Bearer test_token",
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
expect(response.status).toBe(200)
|
expect(response.status).toBe(200)
|
||||||
expect(response.data.price_list.prices.length).toBe(2)
|
expect(response.data.price_list.prices.length).toBe(2)
|
||||||
|
|||||||
@@ -647,254 +647,253 @@ describe("/admin/products", () => {
|
|||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
const response = await api
|
const response = await api
|
||||||
.get("/admin/products", adminHeaders)
|
.get("/admin/products?order=created_at", adminHeaders)
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
response.data.products.sort((a, b) =>
|
expect(response.data.products).toHaveLength(5)
|
||||||
a.created_at > b.created_at ? 1 : -1
|
expect(response.data.products).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-product",
|
||||||
|
options: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.stringMatching(/^test-*/),
|
||||||
|
product_id: expect.stringMatching(/^test-*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
images: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.stringMatching(/^test-*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
variants: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-variant",
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
product_id: expect.stringMatching(/^test-*/),
|
||||||
|
prices: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price",
|
||||||
|
variant_id: expect.stringMatching(/^test-variant*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
options: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.stringMatching(/^test-variant-option*/),
|
||||||
|
variant_id: expect.stringMatching(/^test-variant*/),
|
||||||
|
option_id: expect.stringMatching(/^test-opt*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-variant_2",
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
product_id: expect.stringMatching(/^test-*/),
|
||||||
|
prices: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.stringMatching(/^test-price*/),
|
||||||
|
variant_id: "test-variant_2",
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
options: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.stringMatching(/^test-variant-option*/),
|
||||||
|
variant_id: expect.stringMatching(/^test-variant*/),
|
||||||
|
option_id: expect.stringMatching(/^test-opt*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-variant_1",
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
product_id: expect.stringMatching(/^test-*/),
|
||||||
|
prices: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.stringMatching(/^test-price*/),
|
||||||
|
variant_id: expect.stringMatching(/^test-variant*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
options: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.stringMatching(/^test-variant-option*/),
|
||||||
|
variant_id: expect.stringMatching(/^test-variant*/),
|
||||||
|
option_id: expect.stringMatching(/^test-opt*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-variant-sale",
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
product_id: expect.stringMatching(/^test-*/),
|
||||||
|
prices: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price-sale",
|
||||||
|
variant_id: expect.stringMatching(/^test-variant*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
options: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.stringMatching(/^test-variant-option*/),
|
||||||
|
variant_id: expect.stringMatching(/^test-variant*/),
|
||||||
|
option_id: expect.stringMatching(/^test-opt*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
tags: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.stringMatching(/^tag*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
type: expect.objectContaining({
|
||||||
|
id: expect.stringMatching(/^test-*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
collection: expect.objectContaining({
|
||||||
|
id: expect.stringMatching(/^test-*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
profile_id: expect.stringMatching(/^sp_*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-product1",
|
||||||
|
created_at: expect.any(String),
|
||||||
|
options: [],
|
||||||
|
variants: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-variant_4",
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
product_id: expect.stringMatching(/^test-*/),
|
||||||
|
prices: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.stringMatching(/^test-price*/),
|
||||||
|
variant_id: expect.stringMatching(/^test-variant*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
options: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.stringMatching(/^test-variant-option*/),
|
||||||
|
variant_id: expect.stringMatching(/^test-variant*/),
|
||||||
|
option_id: expect.stringMatching(/^test-opt*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-variant_3",
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
product_id: expect.stringMatching(/^test-*/),
|
||||||
|
prices: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.stringMatching(/^test-price*/),
|
||||||
|
variant_id: expect.stringMatching(/^test-variant*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
options: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.stringMatching(/^test-variant-option*/),
|
||||||
|
variant_id: expect.stringMatching(/^test-variant*/),
|
||||||
|
option_id: expect.stringMatching(/^test-opt*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
tags: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: expect.stringMatching(/^tag*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
type: expect.objectContaining({
|
||||||
|
id: expect.stringMatching(/^test-*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
collection: expect.objectContaining({
|
||||||
|
id: expect.stringMatching(/^test-*/),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
profile_id: expect.stringMatching(/^sp_*/),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-product_filtering_1",
|
||||||
|
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),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-product_filtering_2",
|
||||||
|
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),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-product_filtering_3",
|
||||||
|
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),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
])
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(response.data.products).toMatchSnapshot([
|
|
||||||
{
|
|
||||||
id: "test-product",
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
id: expect.stringMatching(/^test-*/),
|
|
||||||
product_id: expect.stringMatching(/^test-*/),
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
images: [
|
|
||||||
{
|
|
||||||
id: expect.stringMatching(/^test-*/),
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
variants: [
|
|
||||||
{
|
|
||||||
id: "test-variant",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
product_id: expect.stringMatching(/^test-*/),
|
|
||||||
prices: [
|
|
||||||
{
|
|
||||||
id: "test-price",
|
|
||||||
variant_id: expect.stringMatching(/^test-variant*/),
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
id: expect.stringMatching(/^test-variant-option*/),
|
|
||||||
variant_id: expect.stringMatching(/^test-variant*/),
|
|
||||||
option_id: expect.stringMatching(/^test-opt*/),
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "test-variant_2",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
product_id: expect.stringMatching(/^test-*/),
|
|
||||||
prices: [
|
|
||||||
{
|
|
||||||
id: expect.stringMatching(/^test-price*/),
|
|
||||||
variant_id: "test-variant_2",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
id: expect.stringMatching(/^test-variant-option*/),
|
|
||||||
variant_id: expect.stringMatching(/^test-variant*/),
|
|
||||||
option_id: expect.stringMatching(/^test-opt*/),
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "test-variant_1",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
product_id: expect.stringMatching(/^test-*/),
|
|
||||||
prices: [
|
|
||||||
{
|
|
||||||
id: expect.stringMatching(/^test-price*/),
|
|
||||||
variant_id: expect.stringMatching(/^test-variant*/),
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
id: expect.stringMatching(/^test-variant-option*/),
|
|
||||||
variant_id: expect.stringMatching(/^test-variant*/),
|
|
||||||
option_id: expect.stringMatching(/^test-opt*/),
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "test-variant-sale",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
product_id: expect.stringMatching(/^test-*/),
|
|
||||||
prices: [
|
|
||||||
{
|
|
||||||
id: "test-price-sale",
|
|
||||||
variant_id: expect.stringMatching(/^test-variant*/),
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
id: expect.stringMatching(/^test-variant-option*/),
|
|
||||||
variant_id: expect.stringMatching(/^test-variant*/),
|
|
||||||
option_id: expect.stringMatching(/^test-opt*/),
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
tags: [
|
|
||||||
{
|
|
||||||
id: expect.stringMatching(/^tag*/),
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
type: {
|
|
||||||
id: expect.stringMatching(/^test-*/),
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
collection: {
|
|
||||||
id: expect.stringMatching(/^test-*/),
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
profile_id: expect.stringMatching(/^sp_*/),
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "test-product1",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
options: [],
|
|
||||||
variants: [
|
|
||||||
{
|
|
||||||
id: "test-variant_4",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
product_id: expect.stringMatching(/^test-*/),
|
|
||||||
prices: [
|
|
||||||
{
|
|
||||||
id: expect.stringMatching(/^test-price*/),
|
|
||||||
variant_id: expect.stringMatching(/^test-variant*/),
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
id: expect.stringMatching(/^test-variant-option*/),
|
|
||||||
variant_id: expect.stringMatching(/^test-variant*/),
|
|
||||||
option_id: expect.stringMatching(/^test-opt*/),
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "test-variant_3",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
product_id: expect.stringMatching(/^test-*/),
|
|
||||||
prices: [
|
|
||||||
{
|
|
||||||
id: expect.stringMatching(/^test-price*/),
|
|
||||||
variant_id: expect.stringMatching(/^test-variant*/),
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
id: expect.stringMatching(/^test-variant-option*/),
|
|
||||||
variant_id: expect.stringMatching(/^test-variant*/),
|
|
||||||
option_id: expect.stringMatching(/^test-opt*/),
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
tags: [
|
|
||||||
{
|
|
||||||
id: expect.stringMatching(/^tag*/),
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
type: {
|
|
||||||
id: expect.stringMatching(/^test-*/),
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
collection: {
|
|
||||||
id: expect.stringMatching(/^test-*/),
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
profile_id: expect.stringMatching(/^sp_*/),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "test-product_filtering_1",
|
|
||||||
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),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "test-product_filtering_2",
|
|
||||||
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),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "test-product_filtering_3",
|
|
||||||
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),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
])
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -1800,11 +1799,11 @@ describe("/admin/products", () => {
|
|||||||
|
|
||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200)
|
||||||
|
|
||||||
expect(response.data.product.variants[1].prices.length).toEqual(
|
expect(response.data.product.variants[0].prices.length).toEqual(
|
||||||
data.prices.length
|
data.prices.length
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(response.data.product.variants[1].prices).toEqual(
|
expect(response.data.product.variants[0].prices).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
amount: 8000,
|
amount: 8000,
|
||||||
|
|||||||
@@ -647,10 +647,10 @@ describe("[MEDUSA_FF_PUBLISHABLE_API_KEYS] Publishable API keys", () => {
|
|||||||
expect(response.data.products).toEqual(
|
expect(response.data.products).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: product1.id,
|
id: product2.id,
|
||||||
}),
|
}),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: product2.id,
|
id: product1.id,
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,450 +0,0 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
||||||
|
|
||||||
exports[`/store/products /store/products/:id includes default relations 1`] = `
|
|
||||||
Object {
|
|
||||||
"product": Object {
|
|
||||||
"collection": Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"handle": "test-collection",
|
|
||||||
"id": "test-collection",
|
|
||||||
"metadata": null,
|
|
||||||
"title": "Test collection",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
},
|
|
||||||
"collection_id": "test-collection",
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"description": "test-product-description",
|
|
||||||
"discountable": true,
|
|
||||||
"external_id": null,
|
|
||||||
"handle": "test-product",
|
|
||||||
"height": null,
|
|
||||||
"hs_code": null,
|
|
||||||
"id": "test-product",
|
|
||||||
"images": Array [
|
|
||||||
Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": "test-image",
|
|
||||||
"metadata": null,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"url": "test-image.png",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"is_giftcard": false,
|
|
||||||
"length": null,
|
|
||||||
"material": null,
|
|
||||||
"metadata": null,
|
|
||||||
"mid_code": null,
|
|
||||||
"options": Array [
|
|
||||||
Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": "test-option",
|
|
||||||
"metadata": null,
|
|
||||||
"product_id": "test-product",
|
|
||||||
"title": "test-option",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"values": Array [
|
|
||||||
Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": "test-variant-option",
|
|
||||||
"metadata": null,
|
|
||||||
"option_id": "test-option",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"value": "Default variant",
|
|
||||||
"variant_id": "test-variant",
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": "test-variant-option-1",
|
|
||||||
"metadata": null,
|
|
||||||
"option_id": "test-option",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"value": "Default variant 1",
|
|
||||||
"variant_id": "test-variant_1",
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": "test-variant-option-2",
|
|
||||||
"metadata": null,
|
|
||||||
"option_id": "test-option",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"value": "Default variant 2",
|
|
||||||
"variant_id": "test-variant_2",
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": "test-variant-option-3",
|
|
||||||
"metadata": null,
|
|
||||||
"option_id": "test-option",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"value": "Default variant 3",
|
|
||||||
"variant_id": "test-variant_3",
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": "test-variant-option-4",
|
|
||||||
"metadata": null,
|
|
||||||
"option_id": "test-option",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"value": "Default variant 4",
|
|
||||||
"variant_id": "test-variant_4",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"origin_country": null,
|
|
||||||
"profile_id": StringMatching /\\^sp_\\*/,
|
|
||||||
"status": "published",
|
|
||||||
"subtitle": null,
|
|
||||||
"tags": Array [
|
|
||||||
Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": "tag1",
|
|
||||||
"metadata": null,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"value": "123",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"thumbnail": null,
|
|
||||||
"title": "Test product",
|
|
||||||
"type": Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": "test-type",
|
|
||||||
"metadata": null,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"value": "test-type",
|
|
||||||
},
|
|
||||||
"type_id": "test-type",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"variants": Array [
|
|
||||||
Object {
|
|
||||||
"allow_backorder": false,
|
|
||||||
"barcode": "test-barcode",
|
|
||||||
"calculated_price": null,
|
|
||||||
"calculated_price_incl_tax": null,
|
|
||||||
"calculated_tax": null,
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"ean": "test-ean",
|
|
||||||
"height": null,
|
|
||||||
"hs_code": null,
|
|
||||||
"id": "test-variant",
|
|
||||||
"inventory_quantity": 10,
|
|
||||||
"length": null,
|
|
||||||
"manage_inventory": true,
|
|
||||||
"material": null,
|
|
||||||
"metadata": null,
|
|
||||||
"mid_code": null,
|
|
||||||
"options": Array [
|
|
||||||
Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": "test-variant-option",
|
|
||||||
"metadata": null,
|
|
||||||
"option_id": "test-option",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"value": "Default variant",
|
|
||||||
"variant_id": "test-variant",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"origin_country": null,
|
|
||||||
"original_price": null,
|
|
||||||
"original_price_incl_tax": null,
|
|
||||||
"original_tax": null,
|
|
||||||
"prices": Array [
|
|
||||||
Object {
|
|
||||||
"amount": 100,
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"currency_code": "usd",
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": "test-price",
|
|
||||||
"max_quantity": null,
|
|
||||||
"min_quantity": null,
|
|
||||||
"price_list": null,
|
|
||||||
"price_list_id": null,
|
|
||||||
"region_id": null,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"variant_id": "test-variant",
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"amount": 80,
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"currency_code": "usd",
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": "test-price-discount",
|
|
||||||
"max_quantity": null,
|
|
||||||
"min_quantity": null,
|
|
||||||
"price_list": Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"description": "Winter sale for VIP customers.",
|
|
||||||
"ends_at": null,
|
|
||||||
"id": "pl",
|
|
||||||
"name": "VIP winter sale",
|
|
||||||
"starts_at": null,
|
|
||||||
"status": "active",
|
|
||||||
"type": "sale",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
},
|
|
||||||
"price_list_id": "pl",
|
|
||||||
"region_id": null,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"variant_id": "test-variant",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"product_id": "test-product",
|
|
||||||
"sku": "test-sku",
|
|
||||||
"tax_rates": null,
|
|
||||||
"title": "Test variant",
|
|
||||||
"upc": "test-upc",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"weight": null,
|
|
||||||
"width": null,
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"allow_backorder": false,
|
|
||||||
"barcode": null,
|
|
||||||
"calculated_price": null,
|
|
||||||
"calculated_price_incl_tax": null,
|
|
||||||
"calculated_tax": null,
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"ean": "test-ean2",
|
|
||||||
"height": null,
|
|
||||||
"hs_code": null,
|
|
||||||
"id": "test-variant_2",
|
|
||||||
"inventory_quantity": 10,
|
|
||||||
"length": null,
|
|
||||||
"manage_inventory": true,
|
|
||||||
"material": null,
|
|
||||||
"metadata": null,
|
|
||||||
"mid_code": null,
|
|
||||||
"options": Array [
|
|
||||||
Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": "test-variant-option-2",
|
|
||||||
"metadata": null,
|
|
||||||
"option_id": "test-option",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"value": "Default variant 2",
|
|
||||||
"variant_id": "test-variant_2",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"origin_country": null,
|
|
||||||
"original_price": null,
|
|
||||||
"original_price_incl_tax": null,
|
|
||||||
"original_tax": null,
|
|
||||||
"prices": Array [
|
|
||||||
Object {
|
|
||||||
"amount": 100,
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"currency_code": "usd",
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": "test-price2",
|
|
||||||
"max_quantity": null,
|
|
||||||
"min_quantity": null,
|
|
||||||
"price_list": null,
|
|
||||||
"price_list_id": null,
|
|
||||||
"region_id": null,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"variant_id": "test-variant_2",
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"amount": 80,
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"currency_code": "usd",
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": "test-price2-discount",
|
|
||||||
"max_quantity": null,
|
|
||||||
"min_quantity": null,
|
|
||||||
"price_list": Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"description": "Winter sale for VIP customers.",
|
|
||||||
"ends_at": null,
|
|
||||||
"id": "pl",
|
|
||||||
"name": "VIP winter sale",
|
|
||||||
"starts_at": null,
|
|
||||||
"status": "active",
|
|
||||||
"type": "sale",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
},
|
|
||||||
"price_list_id": "pl",
|
|
||||||
"region_id": null,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"variant_id": "test-variant_2",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"product_id": "test-product",
|
|
||||||
"sku": "test-sku2",
|
|
||||||
"tax_rates": null,
|
|
||||||
"title": "Test variant rank (2)",
|
|
||||||
"upc": "test-upc2",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"weight": null,
|
|
||||||
"width": null,
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"allow_backorder": false,
|
|
||||||
"barcode": "test-barcode 1",
|
|
||||||
"calculated_price": null,
|
|
||||||
"calculated_price_incl_tax": null,
|
|
||||||
"calculated_tax": null,
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"ean": "test-ean1",
|
|
||||||
"height": null,
|
|
||||||
"hs_code": null,
|
|
||||||
"id": "test-variant_1",
|
|
||||||
"inventory_quantity": 10,
|
|
||||||
"length": null,
|
|
||||||
"manage_inventory": true,
|
|
||||||
"material": null,
|
|
||||||
"metadata": null,
|
|
||||||
"mid_code": null,
|
|
||||||
"options": Array [
|
|
||||||
Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": "test-variant-option-1",
|
|
||||||
"metadata": null,
|
|
||||||
"option_id": "test-option",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"value": "Default variant 1",
|
|
||||||
"variant_id": "test-variant_1",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"origin_country": null,
|
|
||||||
"original_price": null,
|
|
||||||
"original_price_incl_tax": null,
|
|
||||||
"original_tax": null,
|
|
||||||
"prices": Array [
|
|
||||||
Object {
|
|
||||||
"amount": 100,
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"currency_code": "usd",
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": "test-price1",
|
|
||||||
"max_quantity": null,
|
|
||||||
"min_quantity": null,
|
|
||||||
"price_list": null,
|
|
||||||
"price_list_id": null,
|
|
||||||
"region_id": null,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"variant_id": "test-variant_1",
|
|
||||||
},
|
|
||||||
Object {
|
|
||||||
"amount": 80,
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"currency_code": "usd",
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": "test-price1-discount",
|
|
||||||
"max_quantity": null,
|
|
||||||
"min_quantity": null,
|
|
||||||
"price_list": Object {
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"description": "Winter sale for VIP customers.",
|
|
||||||
"ends_at": null,
|
|
||||||
"id": "pl",
|
|
||||||
"name": "VIP winter sale",
|
|
||||||
"starts_at": null,
|
|
||||||
"status": "active",
|
|
||||||
"type": "sale",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
},
|
|
||||||
"price_list_id": "pl",
|
|
||||||
"region_id": null,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"variant_id": "test-variant_1",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"product_id": "test-product",
|
|
||||||
"sku": "test-sku1",
|
|
||||||
"tax_rates": null,
|
|
||||||
"title": "Test variant rank (1)",
|
|
||||||
"upc": "test-upc1",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"weight": null,
|
|
||||||
"width": null,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"weight": null,
|
|
||||||
"width": null,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
exports[`/store/products list params works with expand and fields 1`] = `
|
|
||||||
Object {
|
|
||||||
"count": 2,
|
|
||||||
"limit": 1,
|
|
||||||
"offset": 0,
|
|
||||||
"products": Array [
|
|
||||||
Object {
|
|
||||||
"id": Any<String>,
|
|
||||||
"title": "testprod",
|
|
||||||
"variants": Array [
|
|
||||||
Object {
|
|
||||||
"allow_backorder": false,
|
|
||||||
"barcode": null,
|
|
||||||
"calculated_price": null,
|
|
||||||
"calculated_price_incl_tax": null,
|
|
||||||
"calculated_tax": null,
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"ean": null,
|
|
||||||
"height": null,
|
|
||||||
"hs_code": null,
|
|
||||||
"id": Any<String>,
|
|
||||||
"inventory_quantity": 10,
|
|
||||||
"length": null,
|
|
||||||
"manage_inventory": true,
|
|
||||||
"material": null,
|
|
||||||
"metadata": null,
|
|
||||||
"mid_code": null,
|
|
||||||
"origin_country": null,
|
|
||||||
"original_price": null,
|
|
||||||
"original_price_incl_tax": null,
|
|
||||||
"original_tax": null,
|
|
||||||
"prices": Array [
|
|
||||||
Object {
|
|
||||||
"amount": 100,
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"currency_code": "usd",
|
|
||||||
"deleted_at": null,
|
|
||||||
"id": Any<String>,
|
|
||||||
"max_quantity": null,
|
|
||||||
"min_quantity": null,
|
|
||||||
"price_list": null,
|
|
||||||
"price_list_id": null,
|
|
||||||
"region_id": null,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"variant_id": Any<String>,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
"product_id": Any<String>,
|
|
||||||
"sku": null,
|
|
||||||
"tax_rates": null,
|
|
||||||
"title": "test-variant",
|
|
||||||
"upc": null,
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"weight": null,
|
|
||||||
"width": null,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
@@ -6,12 +6,19 @@ const { initDb, useDb } = require("../../../helpers/use-db")
|
|||||||
const { simpleProductFactory } = require("../../factories")
|
const { simpleProductFactory } = require("../../factories")
|
||||||
const productSeeder = require("../../helpers/store-product-seeder")
|
const productSeeder = require("../../helpers/store-product-seeder")
|
||||||
const adminSeeder = require("../../helpers/admin-seeder")
|
const adminSeeder = require("../../helpers/admin-seeder")
|
||||||
|
|
||||||
jest.setTimeout(30000)
|
jest.setTimeout(30000)
|
||||||
|
|
||||||
describe("/store/products", () => {
|
describe("/store/products", () => {
|
||||||
let medusaProcess
|
let medusaProcess
|
||||||
let dbConnection
|
let dbConnection
|
||||||
|
|
||||||
|
const giftCardId = "giftcard"
|
||||||
|
const testProductId = "test-product"
|
||||||
|
const testProductId1 = "test-product1"
|
||||||
|
const testProductFilteringId1 = "test-product_filtering_1"
|
||||||
|
const testProductFilteringId2 = "test-product_filtering_2"
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const cwd = path.resolve(path.join(__dirname, "..", ".."))
|
const cwd = path.resolve(path.join(__dirname, "..", ".."))
|
||||||
dbConnection = await initDb({ cwd })
|
dbConnection = await initDb({ cwd })
|
||||||
@@ -35,6 +42,190 @@ describe("/store/products", () => {
|
|||||||
await db.teardown()
|
await db.teardown()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("returns a list of ordered products by id ASC", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
const response = await api.get("/store/products?order=id")
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.products).toHaveLength(5)
|
||||||
|
expect(response.data.products[0].id).toEqual(giftCardId)
|
||||||
|
expect(response.data.products[1].id).toEqual(testProductId)
|
||||||
|
expect(response.data.products[2].id).toEqual(testProductId1)
|
||||||
|
expect(response.data.products[3].id).toEqual(testProductFilteringId1)
|
||||||
|
expect(response.data.products[4].id).toEqual(testProductFilteringId2)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a list of ordered products by id DESC", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
const response = await api.get("/store/products?order=-id")
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.products).toHaveLength(5)
|
||||||
|
expect(response.data.products[0].id).toEqual(testProductFilteringId2)
|
||||||
|
expect(response.data.products[1].id).toEqual(testProductFilteringId1)
|
||||||
|
expect(response.data.products[2].id).toEqual(testProductId1)
|
||||||
|
expect(response.data.products[3].id).toEqual(testProductId)
|
||||||
|
expect(response.data.products[4].id).toEqual(giftCardId)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a list of ordered products by variants title DESC", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
const response = await api.get("/store/products?order=-variants.title")
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.products).toHaveLength(5)
|
||||||
|
|
||||||
|
const testProductIndex = response.data.products.indexOf(
|
||||||
|
response.data.products.find((p) => p.id === testProductId)
|
||||||
|
)
|
||||||
|
const testProduct1Index = response.data.products.indexOf(
|
||||||
|
response.data.products.find((p) => p.id === testProductId1)
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(testProductIndex).toBe(3)
|
||||||
|
expect(testProduct1Index).toBe(4)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a list of ordered products by variants title ASC", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
const response = await api.get("/store/products?order=variants.title")
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.products).toHaveLength(5)
|
||||||
|
|
||||||
|
const testProductIndex = response.data.products.indexOf(
|
||||||
|
response.data.products.find((p) => p.id === testProductId)
|
||||||
|
)
|
||||||
|
const testProduct1Index = response.data.products.indexOf(
|
||||||
|
response.data.products.find((p) => p.id === testProductId1)
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(testProductIndex).toBe(0)
|
||||||
|
expect(testProduct1Index).toBe(1)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a list of ordered products by variants prices DESC", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
await simpleProductFactory(dbConnection, {
|
||||||
|
id: "test-product2",
|
||||||
|
status: "published",
|
||||||
|
variants: [
|
||||||
|
{
|
||||||
|
id: "test_variant_5",
|
||||||
|
prices: [
|
||||||
|
{
|
||||||
|
currency: "usd",
|
||||||
|
amount: 200,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
const response = await api.get(
|
||||||
|
"/store/products?order=-variants.prices.amount"
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.products).toHaveLength(6)
|
||||||
|
|
||||||
|
const testProductIndex = response.data.products.indexOf(
|
||||||
|
response.data.products.find((p) => p.id === testProductId)
|
||||||
|
)
|
||||||
|
const testProduct1Index = response.data.products.indexOf(
|
||||||
|
response.data.products.find((p) => p.id === testProductId1)
|
||||||
|
)
|
||||||
|
const testProduct2Index = response.data.products.indexOf(
|
||||||
|
response.data.products.find((p) => p.id === "test-product2")
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(testProduct2Index).toBe(3) // 200
|
||||||
|
expect(testProductIndex).toBe(4) // 100
|
||||||
|
expect(testProduct1Index).toBe(5) // 100
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a list of ordered products by variants prices ASC", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
await simpleProductFactory(dbConnection, {
|
||||||
|
id: "test-product2",
|
||||||
|
status: "published",
|
||||||
|
variants: [
|
||||||
|
{
|
||||||
|
id: "test_variant_5",
|
||||||
|
prices: [
|
||||||
|
{
|
||||||
|
currency: "usd",
|
||||||
|
amount: 200,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
const response = await api.get(
|
||||||
|
"/store/products?order=variants.prices.amount"
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.products).toHaveLength(6)
|
||||||
|
|
||||||
|
const testProductIndex = response.data.products.indexOf(
|
||||||
|
response.data.products.find((p) => p.id === testProductId)
|
||||||
|
)
|
||||||
|
const testProduct1Index = response.data.products.indexOf(
|
||||||
|
response.data.products.find((p) => p.id === testProductId1)
|
||||||
|
)
|
||||||
|
const testProduct2Index = response.data.products.indexOf(
|
||||||
|
response.data.products.find((p) => p.id === "test-product2")
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(testProductIndex).toBe(0) // 100
|
||||||
|
expect(testProduct1Index).toBe(1) // 100
|
||||||
|
expect(testProduct2Index).toBe(2) // 200
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a list of ordered products by id ASC and filtered with free text search", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
const response = await api.get("/store/products?q=filtering&order=id")
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.products).toHaveLength(2)
|
||||||
|
|
||||||
|
expect(response.data.products).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: testProductFilteringId1,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: testProductFilteringId2,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns a list of ordered products by id DESC and filtered with free text search", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
const response = await api.get("/store/products?q=filtering&order=-id")
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.products).toHaveLength(2)
|
||||||
|
|
||||||
|
expect(response.data.products).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: testProductFilteringId2,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: testProductFilteringId1,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
it("returns a list of products in collection", async () => {
|
it("returns a list of products in collection", async () => {
|
||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
@@ -54,7 +245,7 @@ describe("/store/products", () => {
|
|||||||
expect(response.data.products).toEqual(
|
expect(response.data.products).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: "test-product_filtering_2",
|
id: testProductFilteringId2,
|
||||||
collection_id: "test-collection2",
|
collection_id: "test-collection2",
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
@@ -67,7 +258,7 @@ describe("/store/products", () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it("returns a list of products in with a given tag", async () => {
|
it("returns a list of products with a given tag", async () => {
|
||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
const notExpected = [expect.objectContaining({ id: "tag4" })]
|
const notExpected = [expect.objectContaining({ id: "tag4" })]
|
||||||
@@ -83,7 +274,7 @@ describe("/store/products", () => {
|
|||||||
expect(response.data.products).toEqual(
|
expect(response.data.products).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: "test-product_filtering_1",
|
id: testProductFilteringId1,
|
||||||
collection_id: "test-collection1",
|
collection_id: "test-collection1",
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
@@ -110,7 +301,7 @@ describe("/store/products", () => {
|
|||||||
expect(response.data.products).toEqual(
|
expect(response.data.products).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: "giftcard",
|
id: giftCardId,
|
||||||
is_giftcard: true,
|
is_giftcard: true,
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
@@ -151,7 +342,7 @@ describe("/store/products", () => {
|
|||||||
expect(response.data.products).toEqual(
|
expect(response.data.products).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: "test-product_filtering_1",
|
id: testProductFilteringId1,
|
||||||
collection_id: "test-collection1",
|
collection_id: "test-collection1",
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
@@ -168,7 +359,7 @@ describe("/store/products", () => {
|
|||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
const notExpected = [
|
const notExpected = [
|
||||||
expect.objectContaining({ handle: "test-product_filtering_1" }),
|
expect.objectContaining({ handle: testProductFilteringId1 }),
|
||||||
]
|
]
|
||||||
|
|
||||||
const response = await api
|
const response = await api
|
||||||
@@ -182,8 +373,8 @@ describe("/store/products", () => {
|
|||||||
expect(response.data.products).toEqual(
|
expect(response.data.products).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: "test-product_filtering_2",
|
id: testProductFilteringId2,
|
||||||
handle: "test-product_filtering_2",
|
handle: testProductFilteringId2,
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
@@ -231,23 +422,23 @@ describe("/store/products", () => {
|
|||||||
expect(response.data.products).toEqual(
|
expect(response.data.products).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: "test-product1",
|
id: testProductId1,
|
||||||
collection_id: "test-collection",
|
collection_id: "test-collection",
|
||||||
}),
|
}),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: "test-product",
|
id: testProductId,
|
||||||
collection_id: "test-collection",
|
collection_id: "test-collection",
|
||||||
}),
|
}),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: "test-product_filtering_2",
|
id: testProductFilteringId2,
|
||||||
collection_id: "test-collection2",
|
collection_id: "test-collection2",
|
||||||
}),
|
}),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: "test-product_filtering_1",
|
id: testProductFilteringId1,
|
||||||
collection_id: "test-collection1",
|
collection_id: "test-collection1",
|
||||||
}),
|
}),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: "giftcard",
|
id: giftCardId,
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
@@ -284,11 +475,11 @@ describe("/store/products", () => {
|
|||||||
expect(response.data.products).toEqual(
|
expect(response.data.products).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: "test-product1",
|
id: testProductId1,
|
||||||
collection_id: "test-collection",
|
collection_id: "test-collection",
|
||||||
}),
|
}),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: "test-product",
|
id: testProductId,
|
||||||
collection_id: "test-collection",
|
collection_id: "test-collection",
|
||||||
variants: [
|
variants: [
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@@ -307,22 +498,6 @@ describe("/store/products", () => {
|
|||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
expect.objectContaining({
|
|
||||||
original_price: 100,
|
|
||||||
calculated_price: 80,
|
|
||||||
prices: [
|
|
||||||
expect.objectContaining({
|
|
||||||
id: "test-price2",
|
|
||||||
currency_code: "usd",
|
|
||||||
amount: 100,
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
id: "test-price2-discount",
|
|
||||||
currency_code: "usd",
|
|
||||||
amount: 80,
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
original_price: 100,
|
original_price: 100,
|
||||||
calculated_price: 80,
|
calculated_price: 80,
|
||||||
@@ -339,18 +514,34 @@ describe("/store/products", () => {
|
|||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
original_price: 100,
|
||||||
|
calculated_price: 80,
|
||||||
|
prices: [
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price2",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 100,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price2-discount",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 80,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: "test-product_filtering_2",
|
id: testProductFilteringId2,
|
||||||
collection_id: "test-collection2",
|
collection_id: "test-collection2",
|
||||||
}),
|
}),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: "test-product_filtering_1",
|
id: testProductFilteringId1,
|
||||||
collection_id: "test-collection1",
|
collection_id: "test-collection1",
|
||||||
}),
|
}),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: "giftcard",
|
id: giftCardId,
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
@@ -394,29 +585,31 @@ describe("/store/products", () => {
|
|||||||
"/store/products?expand=variants,variants.prices&fields=id,title&limit=1"
|
"/store/products?expand=variants,variants.prices&fields=id,title&limit=1"
|
||||||
)
|
)
|
||||||
|
|
||||||
expect(response.data).toMatchSnapshot({
|
expect(response.data).toEqual(
|
||||||
products: [
|
expect.objectContaining({
|
||||||
{
|
products: expect.arrayContaining([
|
||||||
id: expect.any(String),
|
expect.objectContaining({
|
||||||
variants: [
|
id: expect.any(String),
|
||||||
{
|
variants: expect.arrayContaining([
|
||||||
created_at: expect.any(String),
|
expect.objectContaining({
|
||||||
updated_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
id: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
product_id: expect.any(String),
|
id: expect.any(String),
|
||||||
prices: [
|
product_id: expect.any(String),
|
||||||
{
|
prices: expect.arrayContaining([
|
||||||
created_at: expect.any(String),
|
expect.objectContaining({
|
||||||
updated_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
id: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
variant_id: expect.any(String),
|
id: expect.any(String),
|
||||||
},
|
variant_id: expect.any(String),
|
||||||
],
|
}),
|
||||||
},
|
]),
|
||||||
],
|
}),
|
||||||
},
|
]),
|
||||||
],
|
}),
|
||||||
})
|
]),
|
||||||
|
})
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -436,284 +629,286 @@ describe("/store/products", () => {
|
|||||||
|
|
||||||
const response = await api.get("/store/products/test-product")
|
const response = await api.get("/store/products/test-product")
|
||||||
|
|
||||||
expect(response.data).toMatchSnapshot({
|
expect(response.data).toEqual(
|
||||||
product: {
|
expect.objectContaining({
|
||||||
id: "test-product",
|
product: expect.objectContaining({
|
||||||
variants: [
|
id: testProductId,
|
||||||
{
|
variants: expect.arrayContaining([
|
||||||
id: "test-variant",
|
expect.objectContaining({
|
||||||
inventory_quantity: 10,
|
id: "test-variant",
|
||||||
allow_backorder: false,
|
inventory_quantity: 10,
|
||||||
title: "Test variant",
|
allow_backorder: false,
|
||||||
sku: "test-sku",
|
title: "Test variant",
|
||||||
ean: "test-ean",
|
sku: "test-sku",
|
||||||
upc: "test-upc",
|
ean: "test-ean",
|
||||||
length: null,
|
upc: "test-upc",
|
||||||
manage_inventory: true,
|
length: null,
|
||||||
material: null,
|
manage_inventory: true,
|
||||||
metadata: null,
|
material: null,
|
||||||
mid_code: null,
|
metadata: null,
|
||||||
height: null,
|
mid_code: null,
|
||||||
hs_code: null,
|
height: null,
|
||||||
origin_country: null,
|
hs_code: null,
|
||||||
calculated_price: null,
|
origin_country: null,
|
||||||
original_price: null,
|
calculated_price: null,
|
||||||
barcode: "test-barcode",
|
original_price: null,
|
||||||
product_id: "test-product",
|
barcode: "test-barcode",
|
||||||
created_at: expect.any(String),
|
product_id: testProductId,
|
||||||
updated_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
options: [
|
updated_at: expect.any(String),
|
||||||
{
|
options: expect.arrayContaining([
|
||||||
created_at: expect.any(String),
|
expect.objectContaining({
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
prices: [
|
|
||||||
{
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
amount: 100,
|
|
||||||
currency_code: "usd",
|
|
||||||
deleted_at: null,
|
|
||||||
min_quantity: null,
|
|
||||||
max_quantity: null,
|
|
||||||
price_list_id: null,
|
|
||||||
id: "test-price",
|
|
||||||
region_id: null,
|
|
||||||
variant_id: "test-variant",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "test-price-discount",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
amount: 80,
|
|
||||||
currency_code: "usd",
|
|
||||||
price_list_id: "pl",
|
|
||||||
deleted_at: null,
|
|
||||||
region_id: null,
|
|
||||||
variant_id: "test-variant",
|
|
||||||
price_list: {
|
|
||||||
id: "pl",
|
|
||||||
type: "sale",
|
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
},
|
}),
|
||||||
},
|
]),
|
||||||
],
|
prices: expect.arrayContaining([
|
||||||
},
|
expect.objectContaining({
|
||||||
{
|
|
||||||
id: "test-variant_2",
|
|
||||||
inventory_quantity: 10,
|
|
||||||
allow_backorder: false,
|
|
||||||
title: "Test variant rank (2)",
|
|
||||||
sku: "test-sku2",
|
|
||||||
ean: "test-ean2",
|
|
||||||
upc: "test-upc2",
|
|
||||||
length: null,
|
|
||||||
manage_inventory: true,
|
|
||||||
material: null,
|
|
||||||
metadata: null,
|
|
||||||
mid_code: null,
|
|
||||||
height: null,
|
|
||||||
hs_code: null,
|
|
||||||
origin_country: null,
|
|
||||||
barcode: null,
|
|
||||||
calculated_price: null,
|
|
||||||
original_price: null,
|
|
||||||
product_id: "test-product",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
prices: [
|
|
||||||
{
|
|
||||||
id: "test-price2",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
amount: 100,
|
|
||||||
currency_code: "usd",
|
|
||||||
price_list_id: null,
|
|
||||||
deleted_at: null,
|
|
||||||
region_id: null,
|
|
||||||
variant_id: "test-variant_2",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "test-price2-discount",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
amount: 80,
|
|
||||||
currency_code: "usd",
|
|
||||||
price_list_id: "pl",
|
|
||||||
deleted_at: null,
|
|
||||||
region_id: null,
|
|
||||||
variant_id: "test-variant_2",
|
|
||||||
price_list: {
|
|
||||||
id: "pl",
|
|
||||||
type: "sale",
|
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
},
|
amount: 100,
|
||||||
},
|
currency_code: "usd",
|
||||||
],
|
deleted_at: null,
|
||||||
},
|
min_quantity: null,
|
||||||
{
|
max_quantity: null,
|
||||||
id: "test-variant_1",
|
price_list_id: null,
|
||||||
inventory_quantity: 10,
|
id: "test-price",
|
||||||
allow_backorder: false,
|
region_id: null,
|
||||||
title: "Test variant rank (1)",
|
variant_id: "test-variant",
|
||||||
sku: "test-sku1",
|
}),
|
||||||
ean: "test-ean1",
|
expect.objectContaining({
|
||||||
upc: "test-upc1",
|
id: "test-price-discount",
|
||||||
length: null,
|
|
||||||
manage_inventory: true,
|
|
||||||
material: null,
|
|
||||||
metadata: null,
|
|
||||||
mid_code: null,
|
|
||||||
height: null,
|
|
||||||
hs_code: null,
|
|
||||||
origin_country: null,
|
|
||||||
calculated_price: null,
|
|
||||||
original_price: null,
|
|
||||||
barcode: "test-barcode 1",
|
|
||||||
product_id: "test-product",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
prices: [
|
|
||||||
{
|
|
||||||
id: "test-price1",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
amount: 100,
|
|
||||||
currency_code: "usd",
|
|
||||||
min_quantity: null,
|
|
||||||
max_quantity: null,
|
|
||||||
price_list_id: null,
|
|
||||||
deleted_at: null,
|
|
||||||
region_id: null,
|
|
||||||
variant_id: "test-variant_1",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "test-price1-discount",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
amount: 80,
|
|
||||||
currency_code: "usd",
|
|
||||||
price_list_id: "pl",
|
|
||||||
deleted_at: null,
|
|
||||||
region_id: null,
|
|
||||||
variant_id: "test-variant_1",
|
|
||||||
price_list: {
|
|
||||||
id: "pl",
|
|
||||||
type: "sale",
|
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
},
|
amount: 80,
|
||||||
},
|
currency_code: "usd",
|
||||||
],
|
price_list_id: "pl",
|
||||||
},
|
deleted_at: null,
|
||||||
],
|
region_id: null,
|
||||||
images: [
|
variant_id: "test-variant",
|
||||||
{
|
price_list: expect.objectContaining({
|
||||||
id: "test-image",
|
id: "pl",
|
||||||
|
type: "sale",
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-variant_2",
|
||||||
|
inventory_quantity: 10,
|
||||||
|
allow_backorder: false,
|
||||||
|
title: "Test variant rank (2)",
|
||||||
|
sku: "test-sku2",
|
||||||
|
ean: "test-ean2",
|
||||||
|
upc: "test-upc2",
|
||||||
|
length: null,
|
||||||
|
manage_inventory: true,
|
||||||
|
material: null,
|
||||||
|
metadata: null,
|
||||||
|
mid_code: null,
|
||||||
|
height: null,
|
||||||
|
hs_code: null,
|
||||||
|
origin_country: null,
|
||||||
|
barcode: null,
|
||||||
|
calculated_price: null,
|
||||||
|
original_price: null,
|
||||||
|
product_id: testProductId,
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
options: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
prices: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price2",
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
amount: 100,
|
||||||
|
currency_code: "usd",
|
||||||
|
price_list_id: null,
|
||||||
|
deleted_at: null,
|
||||||
|
region_id: null,
|
||||||
|
variant_id: "test-variant_2",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price2-discount",
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
amount: 80,
|
||||||
|
currency_code: "usd",
|
||||||
|
price_list_id: "pl",
|
||||||
|
deleted_at: null,
|
||||||
|
region_id: null,
|
||||||
|
variant_id: "test-variant_2",
|
||||||
|
price_list: expect.objectContaining({
|
||||||
|
id: "pl",
|
||||||
|
type: "sale",
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-variant_1",
|
||||||
|
inventory_quantity: 10,
|
||||||
|
allow_backorder: false,
|
||||||
|
title: "Test variant rank (1)",
|
||||||
|
sku: "test-sku1",
|
||||||
|
ean: "test-ean1",
|
||||||
|
upc: "test-upc1",
|
||||||
|
length: null,
|
||||||
|
manage_inventory: true,
|
||||||
|
material: null,
|
||||||
|
metadata: null,
|
||||||
|
mid_code: null,
|
||||||
|
height: null,
|
||||||
|
hs_code: null,
|
||||||
|
origin_country: null,
|
||||||
|
calculated_price: null,
|
||||||
|
original_price: null,
|
||||||
|
barcode: "test-barcode 1",
|
||||||
|
product_id: testProductId,
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
options: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
prices: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price1",
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
amount: 100,
|
||||||
|
currency_code: "usd",
|
||||||
|
min_quantity: null,
|
||||||
|
max_quantity: null,
|
||||||
|
price_list_id: null,
|
||||||
|
deleted_at: null,
|
||||||
|
region_id: null,
|
||||||
|
variant_id: "test-variant_1",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price1-discount",
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
amount: 80,
|
||||||
|
currency_code: "usd",
|
||||||
|
price_list_id: "pl",
|
||||||
|
deleted_at: null,
|
||||||
|
region_id: null,
|
||||||
|
variant_id: "test-variant_1",
|
||||||
|
price_list: expect.objectContaining({
|
||||||
|
id: "pl",
|
||||||
|
type: "sale",
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
images: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-image",
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
handle: testProductId,
|
||||||
|
title: "Test product",
|
||||||
|
profile_id: expect.stringMatching(/^sp_*/),
|
||||||
|
description: "test-product-description",
|
||||||
|
collection_id: "test-collection",
|
||||||
|
collection: expect.objectContaining({
|
||||||
|
id: "test-collection",
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
},
|
}),
|
||||||
],
|
type: expect.objectContaining({
|
||||||
handle: "test-product",
|
id: "test-type",
|
||||||
title: "Test product",
|
created_at: expect.any(String),
|
||||||
profile_id: expect.stringMatching(/^sp_*/),
|
updated_at: expect.any(String),
|
||||||
description: "test-product-description",
|
}),
|
||||||
collection_id: "test-collection",
|
tags: expect.arrayContaining([
|
||||||
collection: {
|
expect.objectContaining({
|
||||||
id: "test-collection",
|
id: "tag1",
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
options: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-option",
|
||||||
|
values: expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-variant-option",
|
||||||
|
value: "Default variant",
|
||||||
|
option_id: "test-option",
|
||||||
|
variant_id: "test-variant",
|
||||||
|
metadata: null,
|
||||||
|
deleted_at: null,
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-variant-option-1",
|
||||||
|
value: "Default variant 1",
|
||||||
|
option_id: "test-option",
|
||||||
|
variant_id: "test-variant_1",
|
||||||
|
metadata: null,
|
||||||
|
deleted_at: null,
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-variant-option-2",
|
||||||
|
value: "Default variant 2",
|
||||||
|
option_id: "test-option",
|
||||||
|
variant_id: "test-variant_2",
|
||||||
|
metadata: null,
|
||||||
|
deleted_at: null,
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-variant-option-3",
|
||||||
|
value: "Default variant 3",
|
||||||
|
option_id: "test-option",
|
||||||
|
variant_id: "test-variant_3",
|
||||||
|
metadata: null,
|
||||||
|
deleted_at: null,
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-variant-option-4",
|
||||||
|
value: "Default variant 4",
|
||||||
|
option_id: "test-option",
|
||||||
|
variant_id: "test-variant_4",
|
||||||
|
metadata: null,
|
||||||
|
deleted_at: null,
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
}),
|
||||||
|
]),
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
},
|
}),
|
||||||
type: {
|
})
|
||||||
id: "test-type",
|
)
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
tags: [
|
|
||||||
{
|
|
||||||
id: "tag1",
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
id: "test-option",
|
|
||||||
values: [
|
|
||||||
{
|
|
||||||
id: "test-variant-option",
|
|
||||||
value: "Default variant",
|
|
||||||
option_id: "test-option",
|
|
||||||
variant_id: "test-variant",
|
|
||||||
metadata: null,
|
|
||||||
deleted_at: null,
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "test-variant-option-1",
|
|
||||||
value: "Default variant 1",
|
|
||||||
option_id: "test-option",
|
|
||||||
variant_id: "test-variant_1",
|
|
||||||
metadata: null,
|
|
||||||
deleted_at: null,
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "test-variant-option-2",
|
|
||||||
value: "Default variant 2",
|
|
||||||
option_id: "test-option",
|
|
||||||
variant_id: "test-variant_2",
|
|
||||||
metadata: null,
|
|
||||||
deleted_at: null,
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "test-variant-option-3",
|
|
||||||
value: "Default variant 3",
|
|
||||||
option_id: "test-option",
|
|
||||||
variant_id: "test-variant_3",
|
|
||||||
metadata: null,
|
|
||||||
deleted_at: null,
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "test-variant-option-4",
|
|
||||||
value: "Default variant 4",
|
|
||||||
option_id: "test-option",
|
|
||||||
variant_id: "test-variant_4",
|
|
||||||
metadata: null,
|
|
||||||
deleted_at: null,
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it("lists all published products", async () => {
|
it("lists all published products", async () => {
|
||||||
@@ -742,7 +937,7 @@ describe("/store/products", () => {
|
|||||||
expect(response.data.products).toEqual(
|
expect(response.data.products).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: "test-product",
|
id: testProductId,
|
||||||
status: "published",
|
status: "published",
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ const {
|
|||||||
Image,
|
Image,
|
||||||
Cart,
|
Cart,
|
||||||
PriceList,
|
PriceList,
|
||||||
CustomerGroup,
|
|
||||||
Customer,
|
|
||||||
} = require("@medusajs/medusa")
|
} = require("@medusajs/medusa")
|
||||||
|
|
||||||
module.exports = async (connection, data = {}) => {
|
module.exports = async (connection, data = {}) => {
|
||||||
|
|||||||
@@ -157,6 +157,7 @@ import { FilterableProductProps } from "../../../../types/product"
|
|||||||
* - (query) limit=50 {integer} Limit the number of products returned.
|
* - (query) limit=50 {integer} Limit the number of products returned.
|
||||||
* - (query) expand {string} (Comma separated) Which fields should be expanded in each product of the result.
|
* - (query) expand {string} (Comma separated) Which fields should be expanded in each product of the result.
|
||||||
* - (query) fields {string} (Comma separated) Which fields should be included in each product of the result.
|
* - (query) fields {string} (Comma separated) Which fields should be included in each product of the result.
|
||||||
|
* - (query) order {string} the field used to order the products.
|
||||||
* x-codeSamples:
|
* x-codeSamples:
|
||||||
* - lang: JavaScript
|
* - lang: JavaScript
|
||||||
* label: JS Client
|
* label: JS Client
|
||||||
@@ -258,4 +259,8 @@ export class AdminGetProductsParams extends FilterableProductProps {
|
|||||||
@IsString()
|
@IsString()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
fields?: string
|
fields?: string
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
order?: string
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,10 @@ describe("GET /store/products", () => {
|
|||||||
relations: defaultStoreProductsRelations,
|
relations: defaultStoreProductsRelations,
|
||||||
skip: 0,
|
skip: 0,
|
||||||
take: 100,
|
take: 100,
|
||||||
|
select: undefined,
|
||||||
|
order: {
|
||||||
|
created_at: "DESC",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -50,6 +54,10 @@ describe("GET /store/products", () => {
|
|||||||
relations: defaultStoreProductsRelations,
|
relations: defaultStoreProductsRelations,
|
||||||
skip: 0,
|
skip: 0,
|
||||||
take: 100,
|
take: 100,
|
||||||
|
order: {
|
||||||
|
created_at: "DESC",
|
||||||
|
},
|
||||||
|
select: undefined,
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -2,13 +2,14 @@ import { RequestHandler, Router } from "express"
|
|||||||
import "reflect-metadata"
|
import "reflect-metadata"
|
||||||
|
|
||||||
import { Product } from "../../../.."
|
import { Product } from "../../../.."
|
||||||
import middlewares from "../../../middlewares"
|
import middlewares, { transformQuery } from "../../../middlewares"
|
||||||
import { FlagRouter } from "../../../../utils/flag-router"
|
import { FlagRouter } from "../../../../utils/flag-router"
|
||||||
import { PaginatedResponse } from "../../../../types/common"
|
import { PaginatedResponse } from "../../../../types/common"
|
||||||
import { extendRequestParams } from "../../../middlewares/publishable-api-key/extend-request-params"
|
import { extendRequestParams } from "../../../middlewares/publishable-api-key/extend-request-params"
|
||||||
import PublishableAPIKeysFeatureFlag from "../../../../loaders/feature-flags/publishable-api-keys"
|
import PublishableAPIKeysFeatureFlag from "../../../../loaders/feature-flags/publishable-api-keys"
|
||||||
import { validateProductSalesChannelAssociation } from "../../../middlewares/publishable-api-key/validate-product-sales-channel-association"
|
import { validateProductSalesChannelAssociation } from "../../../middlewares/publishable-api-key/validate-product-sales-channel-association"
|
||||||
import { validateSalesChannelParam } from "../../../middlewares/publishable-api-key/validate-sales-channel-param"
|
import { validateSalesChannelParam } from "../../../middlewares/publishable-api-key/validate-sales-channel-param"
|
||||||
|
import { StoreGetProductsParams } from "./list-products"
|
||||||
|
|
||||||
const route = Router()
|
const route = Router()
|
||||||
|
|
||||||
@@ -24,7 +25,14 @@ export default (app, featureFlagRouter: FlagRouter) => {
|
|||||||
route.use("/:id", validateProductSalesChannelAssociation)
|
route.use("/:id", validateProductSalesChannelAssociation)
|
||||||
}
|
}
|
||||||
|
|
||||||
route.get("/", middlewares.wrap(require("./list-products").default))
|
route.get(
|
||||||
|
"/",
|
||||||
|
transformQuery(StoreGetProductsParams, {
|
||||||
|
defaultRelations: defaultStoreProductsRelations,
|
||||||
|
isList: true,
|
||||||
|
}),
|
||||||
|
middlewares.wrap(require("./list-products").default)
|
||||||
|
)
|
||||||
route.get("/:id", middlewares.wrap(require("./get-product").default))
|
route.get("/:id", middlewares.wrap(require("./get-product").default))
|
||||||
route.post("/search", middlewares.wrap(require("./search").default))
|
route.post("/search", middlewares.wrap(require("./search").default))
|
||||||
|
|
||||||
|
|||||||
@@ -7,21 +7,16 @@ import {
|
|||||||
IsString,
|
IsString,
|
||||||
ValidateNested,
|
ValidateNested,
|
||||||
} from "class-validator"
|
} from "class-validator"
|
||||||
import { omit, pickBy } from "lodash"
|
|
||||||
import {
|
import {
|
||||||
CartService,
|
CartService,
|
||||||
ProductService,
|
ProductService,
|
||||||
RegionService,
|
RegionService,
|
||||||
} from "../../../../services"
|
} from "../../../../services"
|
||||||
import { isDefined } from "medusa-core-utils"
|
|
||||||
import { defaultStoreProductsRelations } from "."
|
|
||||||
import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels"
|
import SalesChannelFeatureFlag from "../../../../loaders/feature-flags/sales-channels"
|
||||||
import { Product } from "../../../../models"
|
|
||||||
import PricingService from "../../../../services/pricing"
|
import PricingService from "../../../../services/pricing"
|
||||||
import { DateComparisonOperator } from "../../../../types/common"
|
import { DateComparisonOperator } from "../../../../types/common"
|
||||||
import { PriceSelectionParams } from "../../../../types/price-selection"
|
import { PriceSelectionParams } from "../../../../types/price-selection"
|
||||||
import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators"
|
import { FeatureFlagDecorators } from "../../../../utils/feature-flag-decorators"
|
||||||
import { validator } from "../../../../utils/validator"
|
|
||||||
import { optionalBooleanMapper } from "../../../../utils/validators/is-boolean"
|
import { optionalBooleanMapper } from "../../../../utils/validators/is-boolean"
|
||||||
import { IsType } from "../../../../utils/validators/is-type"
|
import { IsType } from "../../../../utils/validators/is-type"
|
||||||
import { FlagRouter } from "../../../../utils/flag-router"
|
import { FlagRouter } from "../../../../utils/flag-router"
|
||||||
@@ -133,6 +128,7 @@ import PublishableAPIKeysFeatureFlag from "../../../../loaders/feature-flags/pub
|
|||||||
* - (query) limit=100 {integer} Limit the number of products returned.
|
* - (query) limit=100 {integer} Limit the number of products returned.
|
||||||
* - (query) expand {string} (Comma separated) Which fields should be expanded in each order of the result.
|
* - (query) expand {string} (Comma separated) Which fields should be expanded in each order of the result.
|
||||||
* - (query) fields {string} (Comma separated) Which fields should be included in each order of the result.
|
* - (query) fields {string} (Comma separated) Which fields should be included in each order of the result.
|
||||||
|
* - (query) order {string} the field used to order the products.
|
||||||
* x-codeSamples:
|
* x-codeSamples:
|
||||||
* - lang: JavaScript
|
* - lang: JavaScript
|
||||||
* label: JS Client
|
* label: JS Client
|
||||||
@@ -196,59 +192,34 @@ export default async (req, res) => {
|
|||||||
const cartService: CartService = req.scope.resolve("cartService")
|
const cartService: CartService = req.scope.resolve("cartService")
|
||||||
const regionService: RegionService = req.scope.resolve("regionService")
|
const regionService: RegionService = req.scope.resolve("regionService")
|
||||||
|
|
||||||
const featureFlagRouter: FlagRouter = req.scope.resolve("featureFlagRouter")
|
const validated = req.validatedQuery as StoreGetProductsParams
|
||||||
|
let {
|
||||||
const validated = await validator(StoreGetProductsParams, req.query)
|
cart_id,
|
||||||
|
region_id: regionId,
|
||||||
if (featureFlagRouter.isFeatureEnabled(PublishableAPIKeysFeatureFlag.key)) {
|
currency_code: currencyCode,
|
||||||
if (req.publishableApiKeyScopes?.sales_channel_id.length) {
|
...filterableFields
|
||||||
validated.sales_channel_id =
|
} = req.filterableFields
|
||||||
validated.sales_channel_id ||
|
const listConfig = req.listConfig
|
||||||
req.publishableApiKeyScopes.sales_channel_id
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const filterableFields: StoreGetProductsParams = omit(validated, [
|
|
||||||
"fields",
|
|
||||||
"expand",
|
|
||||||
"limit",
|
|
||||||
"offset",
|
|
||||||
"cart_id",
|
|
||||||
"region_id",
|
|
||||||
"currency_code",
|
|
||||||
])
|
|
||||||
|
|
||||||
// get only published products for store endpoint
|
// get only published products for store endpoint
|
||||||
filterableFields["status"] = ["published"]
|
filterableFields["status"] = ["published"]
|
||||||
|
|
||||||
let includeFields: (keyof Product)[] = []
|
const featureFlagRouter: FlagRouter = req.scope.resolve("featureFlagRouter")
|
||||||
if (validated.fields) {
|
if (featureFlagRouter.isFeatureEnabled(PublishableAPIKeysFeatureFlag.key)) {
|
||||||
const set = new Set(validated.fields.split(",")) as Set<keyof Product>
|
if (req.publishableApiKeyScopes?.sales_channel_id.length) {
|
||||||
set.add("id")
|
filterableFields.sales_channel_id =
|
||||||
includeFields = [...set]
|
filterableFields.sales_channel_id ||
|
||||||
}
|
req.publishableApiKeyScopes.sales_channel_id
|
||||||
|
|
||||||
let expandFields: string[] = []
|
listConfig.relations.push("sales_channels")
|
||||||
if (validated.expand) {
|
}
|
||||||
expandFields = validated.expand.split(",")
|
|
||||||
}
|
|
||||||
|
|
||||||
const listConfig = {
|
|
||||||
select: includeFields.length ? includeFields : undefined,
|
|
||||||
relations: expandFields.length
|
|
||||||
? expandFields
|
|
||||||
: defaultStoreProductsRelations,
|
|
||||||
skip: validated.offset,
|
|
||||||
take: validated.limit,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const [rawProducts, count] = await productService.listAndCount(
|
const [rawProducts, count] = await productService.listAndCount(
|
||||||
pickBy(filterableFields, (val) => isDefined(val)),
|
filterableFields,
|
||||||
listConfig
|
listConfig
|
||||||
)
|
)
|
||||||
|
|
||||||
let regionId = validated.region_id
|
|
||||||
let currencyCode = validated.currency_code
|
|
||||||
if (validated.cart_id) {
|
if (validated.cart_id) {
|
||||||
const cart = await cartService.retrieve(validated.cart_id, {
|
const cart = await cartService.retrieve(validated.cart_id, {
|
||||||
select: ["id", "region_id"],
|
select: ["id", "region_id"],
|
||||||
@@ -261,7 +232,7 @@ export default async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const products = await pricingService.setProductPrices(rawProducts, {
|
const products = await pricingService.setProductPrices(rawProducts, {
|
||||||
cart_id: validated.cart_id,
|
cart_id: cart_id,
|
||||||
region_id: regionId,
|
region_id: regionId,
|
||||||
currency_code: currencyCode,
|
currency_code: currencyCode,
|
||||||
customer_id: req.user?.customer_id,
|
customer_id: req.user?.customer_id,
|
||||||
@@ -294,6 +265,10 @@ export class StoreGetProductsPaginationParams extends PriceSelectionParams {
|
|||||||
@IsOptional()
|
@IsOptional()
|
||||||
@Type(() => Number)
|
@Type(() => Number)
|
||||||
limit?: number = 100
|
limit?: number = 100
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
order?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export class StoreGetProductsParams extends StoreGetProductsPaginationParams {
|
export class StoreGetProductsParams extends StoreGetProductsPaginationParams {
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { IdMap } from "medusa-test-utils"
|
import { IdMap } from "medusa-test-utils"
|
||||||
import { request } from "../../../../../helpers/test-request"
|
import { request } from "../../../../../helpers/test-request"
|
||||||
import { ProductVariantServiceMock } from "../../../../../services/__mocks__/product-variant"
|
|
||||||
|
|
||||||
describe("List variants", () => {
|
describe("List variants", () => {
|
||||||
describe("list variants successfull", () => {
|
describe("list variants successfull", () => {
|
||||||
|
|||||||
@@ -1,17 +1,8 @@
|
|||||||
import { flatten, groupBy, map, merge } from "lodash"
|
import { flatten, groupBy, map, merge } from "lodash"
|
||||||
import {
|
import { Brackets, EntityRepository, FindOperator, In, Repository, } from "typeorm"
|
||||||
Brackets,
|
|
||||||
EntityRepository,
|
|
||||||
FindOperator,
|
|
||||||
In,
|
|
||||||
Repository,
|
|
||||||
} from "typeorm"
|
|
||||||
import { PriceList, Product, SalesChannel } from "../models"
|
import { PriceList, Product, SalesChannel } from "../models"
|
||||||
import {
|
import { ExtendedFindConfig, Selector, WithRequiredProperty, } from "../types/common"
|
||||||
ExtendedFindConfig,
|
import { applyOrdering } from "../utils/repository"
|
||||||
Selector,
|
|
||||||
WithRequiredProperty,
|
|
||||||
} from "../types/common"
|
|
||||||
|
|
||||||
export type ProductSelector = Omit<Selector<Product>, "tags"> & {
|
export type ProductSelector = Omit<Selector<Product>, "tags"> & {
|
||||||
tags: FindOperator<string[]>
|
tags: FindOperator<string[]>
|
||||||
@@ -45,6 +36,8 @@ export class ProductRepository extends Repository<Product> {
|
|||||||
optionsWithoutRelations: FindWithoutRelationsOptions,
|
optionsWithoutRelations: FindWithoutRelationsOptions,
|
||||||
shouldCount = false
|
shouldCount = false
|
||||||
): Promise<[Product[], number]> {
|
): Promise<[Product[], number]> {
|
||||||
|
const productAlias = "product"
|
||||||
|
|
||||||
const tags = optionsWithoutRelations?.where?.tags
|
const tags = optionsWithoutRelations?.where?.tags
|
||||||
delete optionsWithoutRelations?.where?.tags
|
delete optionsWithoutRelations?.where?.tags
|
||||||
|
|
||||||
@@ -58,8 +51,8 @@ export class ProductRepository extends Repository<Product> {
|
|||||||
optionsWithoutRelations?.where?.discount_condition_id
|
optionsWithoutRelations?.where?.discount_condition_id
|
||||||
delete optionsWithoutRelations?.where?.discount_condition_id
|
delete optionsWithoutRelations?.where?.discount_condition_id
|
||||||
|
|
||||||
const qb = this.createQueryBuilder("product")
|
const qb = this.createQueryBuilder(productAlias)
|
||||||
.select(["product.id"])
|
.select([`${productAlias}.id`])
|
||||||
.skip(optionsWithoutRelations.skip)
|
.skip(optionsWithoutRelations.skip)
|
||||||
.take(optionsWithoutRelations.take)
|
.take(optionsWithoutRelations.take)
|
||||||
|
|
||||||
@@ -67,38 +60,26 @@ export class ProductRepository extends Repository<Product> {
|
|||||||
qb.where(optionsWithoutRelations.where)
|
qb.where(optionsWithoutRelations.where)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (optionsWithoutRelations.order) {
|
|
||||||
const toSelect: string[] = []
|
|
||||||
const parsed = Object.entries(optionsWithoutRelations.order).reduce(
|
|
||||||
(acc, [k, v]) => {
|
|
||||||
const key = `product.${k}`
|
|
||||||
toSelect.push(key)
|
|
||||||
acc[key] = v
|
|
||||||
return acc
|
|
||||||
},
|
|
||||||
{}
|
|
||||||
)
|
|
||||||
qb.addSelect(toSelect)
|
|
||||||
qb.orderBy(parsed)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tags) {
|
if (tags) {
|
||||||
qb.leftJoin("product.tags", "tags").andWhere(`tags.id IN (:...tag_ids)`, {
|
qb.leftJoin(`${productAlias}.tags`, "tags").andWhere(
|
||||||
tag_ids: tags.value,
|
`tags.id IN (:...tag_ids)`,
|
||||||
})
|
{
|
||||||
|
tag_ids: tags.value,
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (price_lists) {
|
if (price_lists) {
|
||||||
qb.leftJoin("product.variants", "variants")
|
qb.leftJoin(`${productAlias}.variants`, "variants")
|
||||||
.leftJoin("variants.prices", "ma")
|
.leftJoin("variants.prices", "prices")
|
||||||
.andWhere("ma.price_list_id IN (:...price_list_ids)", {
|
.andWhere("prices.price_list_id IN (:...price_list_ids)", {
|
||||||
price_list_ids: price_lists.value,
|
price_list_ids: price_lists.value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sales_channels) {
|
if (sales_channels) {
|
||||||
qb.innerJoin(
|
qb.innerJoin(
|
||||||
"product.sales_channels",
|
`${productAlias}.sales_channels`,
|
||||||
"sales_channels",
|
"sales_channels",
|
||||||
"sales_channels.id IN (:...sales_channels_ids)",
|
"sales_channels.id IN (:...sales_channels_ids)",
|
||||||
{ sales_channels_ids: sales_channels.value }
|
{ sales_channels_ids: sales_channels.value }
|
||||||
@@ -109,11 +90,20 @@ export class ProductRepository extends Repository<Product> {
|
|||||||
qb.innerJoin(
|
qb.innerJoin(
|
||||||
"discount_condition_product",
|
"discount_condition_product",
|
||||||
"dc_product",
|
"dc_product",
|
||||||
`dc_product.product_id = product.id AND dc_product.condition_id = :dcId`,
|
`dc_product.product_id = ${productAlias}.id AND dc_product.condition_id = :dcId`,
|
||||||
{ dcId: discount_condition_id }
|
{ dcId: discount_condition_id }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const joinedWithPriceLists = !!price_lists
|
||||||
|
applyOrdering({
|
||||||
|
repository: this,
|
||||||
|
order: optionsWithoutRelations.order ?? {},
|
||||||
|
qb,
|
||||||
|
alias: productAlias,
|
||||||
|
shouldJoin: (relation) => relation !== "prices" || !joinedWithPriceLists,
|
||||||
|
})
|
||||||
|
|
||||||
if (optionsWithoutRelations.withDeleted) {
|
if (optionsWithoutRelations.withDeleted) {
|
||||||
qb.withDeleted()
|
qb.withDeleted()
|
||||||
}
|
}
|
||||||
@@ -151,7 +141,8 @@ export class ProductRepository extends Repository<Product> {
|
|||||||
entityIds: string[],
|
entityIds: string[],
|
||||||
groupedRelations: { [toplevel: string]: string[] },
|
groupedRelations: { [toplevel: string]: string[] },
|
||||||
withDeleted = false,
|
withDeleted = false,
|
||||||
select: (keyof Product)[] = []
|
select: (keyof Product)[] = [],
|
||||||
|
order: { [column: string]: "ASC" | "DESC" } = {}
|
||||||
): Promise<Product[]> {
|
): Promise<Product[]> {
|
||||||
const entitiesIdsWithRelations = await Promise.all(
|
const entitiesIdsWithRelations = await Promise.all(
|
||||||
Object.entries(groupedRelations).map(async ([toplevel, rels]) => {
|
Object.entries(groupedRelations).map(async ([toplevel, rels]) => {
|
||||||
@@ -162,15 +153,13 @@ export class ProductRepository extends Repository<Product> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (toplevel === "variants") {
|
if (toplevel === "variants") {
|
||||||
querybuilder = querybuilder
|
querybuilder = querybuilder.leftJoinAndSelect(
|
||||||
.leftJoinAndSelect(
|
`products.${toplevel}`,
|
||||||
`products.${toplevel}`,
|
toplevel,
|
||||||
toplevel,
|
"variants.deleted_at IS NULL"
|
||||||
"variants.deleted_at IS NULL"
|
)
|
||||||
)
|
|
||||||
.orderBy({
|
order["variants.variant_rank"] = "ASC"
|
||||||
"variants.variant_rank": "ASC",
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
querybuilder = querybuilder.leftJoinAndSelect(
|
querybuilder = querybuilder.leftJoinAndSelect(
|
||||||
`products.${toplevel}`,
|
`products.${toplevel}`,
|
||||||
@@ -251,12 +240,14 @@ export class ProductRepository extends Repository<Product> {
|
|||||||
entitiesIds,
|
entitiesIds,
|
||||||
groupedRelations,
|
groupedRelations,
|
||||||
idsOrOptionsWithoutRelations.withDeleted,
|
idsOrOptionsWithoutRelations.withDeleted,
|
||||||
idsOrOptionsWithoutRelations.select
|
idsOrOptionsWithoutRelations.select,
|
||||||
|
idsOrOptionsWithoutRelations.order
|
||||||
)
|
)
|
||||||
|
|
||||||
const entitiesAndRelations = entitiesIdsWithRelations.concat(entities)
|
const entitiesAndRelations = groupBy(entitiesIdsWithRelations, "id")
|
||||||
const entitiesToReturn =
|
const entitiesToReturn = map(entitiesIds, (id) =>
|
||||||
this.mergeEntitiesWithRelations(entitiesAndRelations)
|
merge({}, ...entitiesAndRelations[id])
|
||||||
|
)
|
||||||
|
|
||||||
return [entitiesToReturn, count]
|
return [entitiesToReturn, count]
|
||||||
}
|
}
|
||||||
@@ -353,6 +344,12 @@ export class ProductRepository extends Repository<Product> {
|
|||||||
options: FindWithoutRelationsOptions = { where: {} },
|
options: FindWithoutRelationsOptions = { where: {} },
|
||||||
relations: string[] = []
|
relations: string[] = []
|
||||||
): Promise<[Product[], number]> {
|
): Promise<[Product[], number]> {
|
||||||
|
const productAlias = "product"
|
||||||
|
const pricesAlias = "prices"
|
||||||
|
const variantsAlias = "variants"
|
||||||
|
const collectionAlias = "collection"
|
||||||
|
const tagsAlias = "tags"
|
||||||
|
|
||||||
const tags = options.where.tags
|
const tags = options.where.tags
|
||||||
delete options.where.tags
|
delete options.where.tags
|
||||||
|
|
||||||
@@ -367,18 +364,18 @@ export class ProductRepository extends Repository<Product> {
|
|||||||
|
|
||||||
const cleanedOptions = this._cleanOptions(options)
|
const cleanedOptions = this._cleanOptions(options)
|
||||||
|
|
||||||
let qb = this.createQueryBuilder("product")
|
let qb = this.createQueryBuilder(`${productAlias}`)
|
||||||
.leftJoinAndSelect("product.variants", "variant")
|
.leftJoinAndSelect(`${productAlias}.variants`, variantsAlias)
|
||||||
.leftJoinAndSelect("product.collection", "collection")
|
.leftJoinAndSelect(`${productAlias}.collection`, `${collectionAlias}`)
|
||||||
.select(["product.id"])
|
.select([`${productAlias}.id`])
|
||||||
.where(cleanedOptions.where)
|
.where(cleanedOptions.where)
|
||||||
.andWhere(
|
.andWhere(
|
||||||
new Brackets((qb) => {
|
new Brackets((qb) => {
|
||||||
qb.where(`product.description ILIKE :q`, { q: `%${q}%` })
|
qb.where(`${productAlias}.description ILIKE :q`, { q: `%${q}%` })
|
||||||
.orWhere(`product.title ILIKE :q`, { q: `%${q}%` })
|
.orWhere(`${productAlias}.title ILIKE :q`, { q: `%${q}%` })
|
||||||
.orWhere(`variant.title ILIKE :q`, { q: `%${q}%` })
|
.orWhere(`${variantsAlias}.title ILIKE :q`, { q: `%${q}%` })
|
||||||
.orWhere(`variant.sku ILIKE :q`, { q: `%${q}%` })
|
.orWhere(`${variantsAlias}.sku ILIKE :q`, { q: `%${q}%` })
|
||||||
.orWhere(`collection.title ILIKE :q`, { q: `%${q}%` })
|
.orWhere(`${collectionAlias}.title ILIKE :q`, { q: `%${q}%` })
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.skip(cleanedOptions.skip)
|
.skip(cleanedOptions.skip)
|
||||||
@@ -388,47 +385,72 @@ export class ProductRepository extends Repository<Product> {
|
|||||||
qb.innerJoin(
|
qb.innerJoin(
|
||||||
"discount_condition_product",
|
"discount_condition_product",
|
||||||
"dc_product",
|
"dc_product",
|
||||||
`dc_product.product_id = product.id AND dc_product.condition_id = :dcId`,
|
`dc_product.product_id = ${productAlias}.id AND dc_product.condition_id = :dcId`,
|
||||||
{ dcId: discount_condition_id }
|
{ dcId: discount_condition_id }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tags) {
|
if (tags) {
|
||||||
qb.leftJoin("product.tags", "tags").andWhere(`tags.id IN (:...tag_ids)`, {
|
qb.leftJoin(`${productAlias}.tags`, tagsAlias).andWhere(
|
||||||
tag_ids: tags.value,
|
`${tagsAlias}.id IN (:...tag_ids)`,
|
||||||
})
|
{
|
||||||
|
tag_ids: tags.value,
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (price_lists) {
|
if (price_lists) {
|
||||||
qb.leftJoin("product.variants", "variants")
|
const variantPricesAlias = `${variantsAlias}_prices`
|
||||||
.leftJoin("variants.prices", "ma")
|
qb.leftJoin(`${productAlias}.variants`, variantPricesAlias)
|
||||||
.andWhere("ma.price_list_id IN (:...price_list_ids)", {
|
.leftJoin(`${variantPricesAlias}.prices`, pricesAlias)
|
||||||
|
.andWhere(`${pricesAlias}.price_list_id IN (:...price_list_ids)`, {
|
||||||
price_list_ids: price_lists.value,
|
price_list_ids: price_lists.value,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sales_channels) {
|
if (sales_channels) {
|
||||||
qb.innerJoin(
|
qb.innerJoin(
|
||||||
"product.sales_channels",
|
`${productAlias}.sales_channels`,
|
||||||
"sales_channels",
|
"sales_channels",
|
||||||
"sales_channels.id IN (:...sales_channels_ids)",
|
"sales_channels.id IN (:...sales_channels_ids)",
|
||||||
{ sales_channels_ids: sales_channels.value }
|
{ sales_channels_ids: sales_channels.value }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const joinedWithTags = !!tags
|
||||||
|
const joinedWithPriceLists = !!price_lists
|
||||||
|
applyOrdering({
|
||||||
|
repository: this,
|
||||||
|
order: options.order ?? {},
|
||||||
|
qb,
|
||||||
|
alias: productAlias,
|
||||||
|
shouldJoin: (relation) =>
|
||||||
|
relation !== variantsAlias &&
|
||||||
|
(relation !== pricesAlias || !joinedWithPriceLists) &&
|
||||||
|
(relation !== tagsAlias || !joinedWithTags),
|
||||||
|
})
|
||||||
|
|
||||||
if (cleanedOptions.withDeleted) {
|
if (cleanedOptions.withDeleted) {
|
||||||
qb = qb.withDeleted()
|
qb = qb.withDeleted()
|
||||||
}
|
}
|
||||||
|
|
||||||
const [results, count] = await qb.getManyAndCount()
|
const [results, count] = await qb.getManyAndCount()
|
||||||
|
const orderedResultsSet = new Set(results.map((p) => p.id))
|
||||||
|
|
||||||
const products = await this.findWithRelations(
|
const products = await this.findWithRelations(
|
||||||
relations,
|
relations,
|
||||||
results.map((r) => r.id),
|
[...orderedResultsSet],
|
||||||
cleanedOptions.withDeleted
|
cleanedOptions.withDeleted
|
||||||
)
|
)
|
||||||
|
const productsMap = new Map(products.map((p) => [p.id, p]))
|
||||||
|
|
||||||
return [products, count]
|
// Looping through the orderedResultsSet in order to maintain the original order and assign the data returned by findWithRelations
|
||||||
|
const orderedProducts: Product[] = []
|
||||||
|
orderedResultsSet.forEach((id) => {
|
||||||
|
orderedProducts.push(productsMap.get(id)!)
|
||||||
|
})
|
||||||
|
|
||||||
|
return [orderedProducts, count]
|
||||||
}
|
}
|
||||||
|
|
||||||
public async isProductInSalesChannels(
|
public async isProductInSalesChannels(
|
||||||
|
|||||||
@@ -3,10 +3,7 @@ import { IdMap, MockManager } from "medusa-test-utils"
|
|||||||
import { User } from "../../../../models"
|
import { User } from "../../../../models"
|
||||||
import { BatchJobStatus } from "../../../../types/batch-job"
|
import { BatchJobStatus } from "../../../../types/batch-job"
|
||||||
import { productsToExport } from "../../../__fixtures__/product-export-data"
|
import { productsToExport } from "../../../__fixtures__/product-export-data"
|
||||||
import {
|
import { AdminPostBatchesReq, defaultAdminProductRelations, } from "../../../../api"
|
||||||
AdminPostBatchesReq,
|
|
||||||
defaultAdminProductRelations,
|
|
||||||
} from "../../../../api"
|
|
||||||
import { ProductExportBatchJob } from "../../../batch-jobs/product/types"
|
import { ProductExportBatchJob } from "../../../batch-jobs/product/types"
|
||||||
import { Request } from "express"
|
import { Request } from "express"
|
||||||
import { FlagRouter } from "../../../../utils/flag-router"
|
import { FlagRouter } from "../../../../utils/flag-router"
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ export function getListConfig<TModel extends BaseEntity>(
|
|||||||
expand?: string[],
|
expand?: string[],
|
||||||
limit = 50,
|
limit = 50,
|
||||||
offset = 0,
|
offset = 0,
|
||||||
order?: { [k: symbol]: "DESC" | "ASC" }
|
order: { [k: string | symbol]: "DESC" | "ASC" } = {}
|
||||||
): FindConfig<TModel> {
|
): FindConfig<TModel> {
|
||||||
let includeFields: (keyof TModel)[] = []
|
let includeFields: (keyof TModel)[] = []
|
||||||
if (isDefined(fields)) {
|
if (isDefined(fields)) {
|
||||||
@@ -66,8 +66,10 @@ export function getListConfig<TModel extends BaseEntity>(
|
|||||||
expandFields = expand
|
expandFields = expand
|
||||||
}
|
}
|
||||||
|
|
||||||
const orderBy: Record<string, "DESC" | "ASC"> = order ?? {
|
const orderBy = order
|
||||||
created_at: "DESC",
|
|
||||||
|
if (!Object.keys(order).length) {
|
||||||
|
orderBy["created_at"] = "DESC"
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import { flatten, groupBy, map, merge } from "lodash"
|
import { flatten, groupBy, map, merge } from "lodash"
|
||||||
import { Repository, SelectQueryBuilder } from "typeorm"
|
import { EntityMetadata, Repository, SelectQueryBuilder } from "typeorm"
|
||||||
import { FindWithoutRelationsOptions } from "../repositories/customer-group"
|
import { FindWithoutRelationsOptions } from "../repositories/customer-group"
|
||||||
|
|
||||||
|
// TODO: All the utilities except applyOrdering needs to be re worked depending on the outcome of the product repository
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom query entity, it is part of the creation of a custom findWithRelationsAndCount needs.
|
* Custom query entity, it is part of the creation of a custom findWithRelationsAndCount needs.
|
||||||
* Allow to query the relations for the specified entity ids
|
* Allow to query the relations for the specified entity ids
|
||||||
@@ -163,3 +165,80 @@ export function mergeEntitiesWithRelations<T>(
|
|||||||
merge({}, ...entityAndRelations)
|
merge({}, ...entityAndRelations)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply the appropriate order depending on the requirements
|
||||||
|
* @param repository
|
||||||
|
* @param order The field on which to apply the order (e.g { "variants.prices.amount": "DESC" })
|
||||||
|
* @param qb
|
||||||
|
* @param alias
|
||||||
|
* @param shouldJoin In case a join is already applied elsewhere and therefore you want to avoid to re joining the data in that case you can return false for specific relations
|
||||||
|
*/
|
||||||
|
export function applyOrdering<T>({
|
||||||
|
repository,
|
||||||
|
order,
|
||||||
|
qb,
|
||||||
|
alias,
|
||||||
|
shouldJoin,
|
||||||
|
}: {
|
||||||
|
repository: Repository<T>
|
||||||
|
order: Record<string, "ASC" | "DESC">
|
||||||
|
qb: SelectQueryBuilder<T>
|
||||||
|
alias: string
|
||||||
|
shouldJoin: (relation: string) => boolean
|
||||||
|
}) {
|
||||||
|
const toSelect: string[] = []
|
||||||
|
|
||||||
|
const parsed = Object.entries(order).reduce(
|
||||||
|
(acc, [orderPath, orderDirection]) => {
|
||||||
|
// If the orderPath (e.g variants.prices.amount) includes a point it means that it is to access
|
||||||
|
// a child relation of an unknown depth
|
||||||
|
if (orderPath.includes(".")) {
|
||||||
|
// We are spliting the path and separating the relations from the property to order. (e.g relations ["variants", "prices"] and property "amount"
|
||||||
|
const relationsToJoin = orderPath.split(".")
|
||||||
|
const propToOrder = relationsToJoin.pop()
|
||||||
|
|
||||||
|
// For each relation we will retrieve the metadata in order to use the right property name from the relation registered in the entity.
|
||||||
|
// Each time we will return the child (i.e the relation) and the inverse metadata (corresponding to the child metadata from the parent point of view)
|
||||||
|
// In order for the next child to know its parent
|
||||||
|
relationsToJoin.reduce(
|
||||||
|
([parent, parentMetadata], child) => {
|
||||||
|
// Find the relation metadata from the parent entity
|
||||||
|
const relationMetadata = (
|
||||||
|
parentMetadata as EntityMetadata
|
||||||
|
).relations.find(
|
||||||
|
(relationMetadata) => relationMetadata.propertyName === child
|
||||||
|
)
|
||||||
|
|
||||||
|
// The consumer can refuse to apply a join on a relation if the join has already been applied before calling this util
|
||||||
|
const shouldApplyJoin = shouldJoin(child)
|
||||||
|
if (shouldApplyJoin) {
|
||||||
|
qb.leftJoin(`${parent}.${relationMetadata!.propertyPath}`, child)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the child relation to be the parent for the next one, as well as the metadata corresponding the child in order
|
||||||
|
// to find the next relation metadata for the next child
|
||||||
|
return [child, relationMetadata!.inverseEntityMetadata]
|
||||||
|
},
|
||||||
|
[alias, repository.metadata]
|
||||||
|
)
|
||||||
|
|
||||||
|
// The key for variants.prices.amount will be "prices.amount" since we are ordering on the join added to its parent "variants" in this example
|
||||||
|
const key = `${
|
||||||
|
relationsToJoin[relationsToJoin.length - 1]
|
||||||
|
}.${propToOrder}`
|
||||||
|
acc[key] = orderDirection
|
||||||
|
toSelect.push(key)
|
||||||
|
return acc
|
||||||
|
}
|
||||||
|
|
||||||
|
const key = `${alias}.${orderPath}`
|
||||||
|
toSelect.push(key)
|
||||||
|
acc[key] = orderDirection
|
||||||
|
return acc
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
)
|
||||||
|
qb.addSelect(toSelect)
|
||||||
|
qb.orderBy(parsed)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user