Feat: use price selection strategy (#1165)
* init * add query params * added buld id validation to repo * admin done * updated price reqs * initial price selection strategy * update customer seeder * format models * price selection strategy * price selection testing * update price selection tests * update price selection strategy * remove console.warn * update price seleciton strategy * use price selection strategy in "get-product" * price selection strategy integration testing * update integration tests * update price selection strat * remove console.log * fix unit tests * update product snapshot integration tests * fix failing unit tests * update variant test snapshots * update variant test snapshots * fix failing unit tests * update product snapshot integration tests * intial implementation of PriceList * add price selection strategy test to list-products * add price selection to list products * add price selection strategy to getRegionPrice * add price selection strategy to get variant * update product snapshot test * store testing of price selection * variant services * update cart service * update product tests * update test * unit testing with price selection strategy * integration tests for price lists * update sort prices for consistent results * update snapshot * update product snapshot with product ids * this time pipelines work * swap tests * redo ordering * updated admin/product integration tests * update updateVariantPrices method * remove comment from error handler * add integration test for batch deleting prices associated with price list * named ids * run with verbose * add console.log * sort products in integration test * remove verbose flag * make update to prices through variant service limited to default prices * update store/products.js snapshot * update comment * add todo * lift existing price calculations to variant level * remove unused import * add api unit tests and update product integration tests to validate that prices from Price List are ignored * fix product test * update integration tests * pre merge commit * requested changes * cascade * ensure delete variant cascades to MoneyAmount * fetch variants correctly * use find options * add pricelist to relevant seeders * update integration tests * update price selection with "includeDiscountPrices" * use transaction with price selection strategy * add await to prevent store test errors * remove verbose * addresses PR feedback * removed unused endpoint * remove unused repository from constructor * remove from constructor argument * update mock * update unit tests * fix failing store integration tests * remove medusajs ressource * re add env.template * price selection strategy methods * fix integration tests * update unit tests * remove commented out code * update jsdoc * update price selection strategy parameter * update snapshots * integration tests cleanup * pr feedback * update integration tests * pr feedback * price selection unit tests * add calculated price type to results * cleanup include discount prices and price selection configs * refactor price selection params to a separate file * update tests and refactor price selection seeder * remove prices from variant update * rename result * pr feedback * remove unused import * create getRegionPriceContext * remove from params in search * remove unused import Co-authored-by: Kasper <kasper@medusajs.com> Co-authored-by: Kasper Fabricius Kristensen <45367945+kasperkristensen@users.noreply.github.com>
This commit is contained in:
36 files changed
+3794
-533
No files matched your search
@@ -21,7 +21,7 @@ Array [
|
|||||||
"handle": "test-product",
|
"handle": "test-product",
|
||||||
"height": null,
|
"height": null,
|
||||||
"hs_code": null,
|
"hs_code": null,
|
||||||
"id": StringMatching /\\^test-\\*/,
|
"id": "test-product",
|
||||||
"images": Array [
|
"images": Array [
|
||||||
Object {
|
Object {
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
@@ -78,6 +78,7 @@ Array [
|
|||||||
Object {
|
Object {
|
||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": "test-barcode",
|
"barcode": "test-barcode",
|
||||||
|
"calculated_price": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": "test-ean",
|
"ean": "test-ean",
|
||||||
@@ -103,15 +104,17 @@ Array [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
|
"original_price": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"currency_code": "usd",
|
"currency_code": "usd",
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"id": StringMatching /\\^test-price\\*/,
|
"id": "test-price",
|
||||||
"max_quantity": null,
|
"max_quantity": null,
|
||||||
"min_quantity": null,
|
"min_quantity": null,
|
||||||
|
"price_list": null,
|
||||||
"price_list_id": null,
|
"price_list_id": null,
|
||||||
"region_id": null,
|
"region_id": null,
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
@@ -129,6 +132,7 @@ Array [
|
|||||||
Object {
|
Object {
|
||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": null,
|
"barcode": null,
|
||||||
|
"calculated_price": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": "test-ean2",
|
"ean": "test-ean2",
|
||||||
@@ -154,6 +158,7 @@ Array [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
|
"original_price": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -163,10 +168,11 @@ Array [
|
|||||||
"id": StringMatching /\\^test-price\\*/,
|
"id": StringMatching /\\^test-price\\*/,
|
||||||
"max_quantity": null,
|
"max_quantity": null,
|
||||||
"min_quantity": null,
|
"min_quantity": null,
|
||||||
|
"price_list": null,
|
||||||
"price_list_id": null,
|
"price_list_id": null,
|
||||||
"region_id": null,
|
"region_id": null,
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
"variant_id": StringMatching /\\^test-variant\\*/,
|
"variant_id": "test-variant_2",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
"product_id": StringMatching /\\^test-\\*/,
|
"product_id": StringMatching /\\^test-\\*/,
|
||||||
@@ -180,6 +186,7 @@ Array [
|
|||||||
Object {
|
Object {
|
||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": "test-barcode 1",
|
"barcode": "test-barcode 1",
|
||||||
|
"calculated_price": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": "test-ean1",
|
"ean": "test-ean1",
|
||||||
@@ -205,6 +212,7 @@ Array [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
|
"original_price": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -214,6 +222,7 @@ Array [
|
|||||||
"id": StringMatching /\\^test-price\\*/,
|
"id": StringMatching /\\^test-price\\*/,
|
||||||
"max_quantity": null,
|
"max_quantity": null,
|
||||||
"min_quantity": null,
|
"min_quantity": null,
|
||||||
|
"price_list": null,
|
||||||
"price_list_id": null,
|
"price_list_id": null,
|
||||||
"region_id": null,
|
"region_id": null,
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
@@ -228,6 +237,60 @@ Array [
|
|||||||
"weight": null,
|
"weight": null,
|
||||||
"width": null,
|
"width": null,
|
||||||
},
|
},
|
||||||
|
Object {
|
||||||
|
"allow_backorder": false,
|
||||||
|
"barcode": "test-barcode-sale",
|
||||||
|
"calculated_price": 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,
|
||||||
|
"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",
|
||||||
|
"title": "Test variant",
|
||||||
|
"upc": "test-upc-sale",
|
||||||
|
"updated_at": Any<String>,
|
||||||
|
"weight": null,
|
||||||
|
"width": null,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
"weight": null,
|
"weight": null,
|
||||||
"width": null,
|
"width": null,
|
||||||
@@ -251,7 +314,7 @@ Array [
|
|||||||
"handle": "test-product1",
|
"handle": "test-product1",
|
||||||
"height": null,
|
"height": null,
|
||||||
"hs_code": null,
|
"hs_code": null,
|
||||||
"id": StringMatching /\\^test-\\*/,
|
"id": "test-product1",
|
||||||
"images": Array [],
|
"images": Array [],
|
||||||
"is_giftcard": false,
|
"is_giftcard": false,
|
||||||
"length": null,
|
"length": null,
|
||||||
@@ -289,6 +352,7 @@ Array [
|
|||||||
Object {
|
Object {
|
||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": null,
|
"barcode": null,
|
||||||
|
"calculated_price": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": "test-ean4",
|
"ean": "test-ean4",
|
||||||
@@ -314,6 +378,7 @@ Array [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
|
"original_price": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -323,6 +388,7 @@ Array [
|
|||||||
"id": StringMatching /\\^test-price\\*/,
|
"id": StringMatching /\\^test-price\\*/,
|
||||||
"max_quantity": null,
|
"max_quantity": null,
|
||||||
"min_quantity": null,
|
"min_quantity": null,
|
||||||
|
"price_list": null,
|
||||||
"price_list_id": null,
|
"price_list_id": null,
|
||||||
"region_id": null,
|
"region_id": null,
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
@@ -340,6 +406,7 @@ Array [
|
|||||||
Object {
|
Object {
|
||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": null,
|
"barcode": null,
|
||||||
|
"calculated_price": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": "test-ean3",
|
"ean": "test-ean3",
|
||||||
@@ -365,6 +432,7 @@ Array [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
|
"original_price": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -374,6 +442,7 @@ Array [
|
|||||||
"id": StringMatching /\\^test-price\\*/,
|
"id": StringMatching /\\^test-price\\*/,
|
||||||
"max_quantity": null,
|
"max_quantity": null,
|
||||||
"min_quantity": null,
|
"min_quantity": null,
|
||||||
|
"price_list": null,
|
||||||
"price_list_id": null,
|
"price_list_id": null,
|
||||||
"region_id": "test-region",
|
"region_id": "test-region",
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
@@ -392,39 +461,6 @@ Array [
|
|||||||
"weight": null,
|
"weight": null,
|
||||||
"width": null,
|
"width": null,
|
||||||
},
|
},
|
||||||
Object {
|
|
||||||
"collection": Any<Object>,
|
|
||||||
"collection_id": "test-collection1",
|
|
||||||
"created_at": Any<String>,
|
|
||||||
"deleted_at": null,
|
|
||||||
"description": "test-product-description",
|
|
||||||
"discountable": true,
|
|
||||||
"external_id": null,
|
|
||||||
"handle": "test-product_filtering_3",
|
|
||||||
"height": null,
|
|
||||||
"hs_code": null,
|
|
||||||
"id": StringMatching /\\^test-\\*/,
|
|
||||||
"images": Array [],
|
|
||||||
"is_giftcard": false,
|
|
||||||
"length": null,
|
|
||||||
"material": null,
|
|
||||||
"metadata": null,
|
|
||||||
"mid_code": null,
|
|
||||||
"options": Any<Array>,
|
|
||||||
"origin_country": null,
|
|
||||||
"profile_id": StringMatching /\\^sp_\\*/,
|
|
||||||
"status": "draft",
|
|
||||||
"subtitle": null,
|
|
||||||
"tags": Any<Array>,
|
|
||||||
"thumbnail": null,
|
|
||||||
"title": "Test product filtering 3",
|
|
||||||
"type": Any<Object>,
|
|
||||||
"type_id": "test-type",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"variants": Any<Array>,
|
|
||||||
"weight": null,
|
|
||||||
"width": null,
|
|
||||||
},
|
|
||||||
Object {
|
Object {
|
||||||
"collection": Any<Object>,
|
"collection": Any<Object>,
|
||||||
"collection_id": "test-collection1",
|
"collection_id": "test-collection1",
|
||||||
@@ -436,7 +472,7 @@ Array [
|
|||||||
"handle": "test-product_filtering_1",
|
"handle": "test-product_filtering_1",
|
||||||
"height": null,
|
"height": null,
|
||||||
"hs_code": null,
|
"hs_code": null,
|
||||||
"id": StringMatching /\\^test-\\*/,
|
"id": "test-product_filtering_1",
|
||||||
"images": Array [],
|
"images": Array [],
|
||||||
"is_giftcard": false,
|
"is_giftcard": false,
|
||||||
"length": null,
|
"length": null,
|
||||||
@@ -469,7 +505,7 @@ Array [
|
|||||||
"handle": "test-product_filtering_2",
|
"handle": "test-product_filtering_2",
|
||||||
"height": null,
|
"height": null,
|
||||||
"hs_code": null,
|
"hs_code": null,
|
||||||
"id": StringMatching /\\^test-\\*/,
|
"id": "test-product_filtering_2",
|
||||||
"images": Array [],
|
"images": Array [],
|
||||||
"is_giftcard": false,
|
"is_giftcard": false,
|
||||||
"length": null,
|
"length": null,
|
||||||
@@ -491,6 +527,39 @@ Array [
|
|||||||
"weight": null,
|
"weight": null,
|
||||||
"width": null,
|
"width": null,
|
||||||
},
|
},
|
||||||
|
Object {
|
||||||
|
"collection": Any<Object>,
|
||||||
|
"collection_id": "test-collection1",
|
||||||
|
"created_at": Any<String>,
|
||||||
|
"deleted_at": null,
|
||||||
|
"description": "test-product-description",
|
||||||
|
"discountable": true,
|
||||||
|
"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,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -539,6 +608,7 @@ Array [
|
|||||||
Object {
|
Object {
|
||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": null,
|
"barcode": null,
|
||||||
|
"calculated_price": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": null,
|
"ean": null,
|
||||||
@@ -564,6 +634,7 @@ Array [
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
|
"original_price": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -573,6 +644,7 @@ Array [
|
|||||||
"id": Any<String>,
|
"id": Any<String>,
|
||||||
"max_quantity": null,
|
"max_quantity": null,
|
||||||
"min_quantity": null,
|
"min_quantity": null,
|
||||||
|
"price_list": null,
|
||||||
"price_list_id": null,
|
"price_list_id": null,
|
||||||
"region_id": null,
|
"region_id": null,
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
@@ -696,6 +768,7 @@ Object {
|
|||||||
Object {
|
Object {
|
||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": null,
|
"barcode": null,
|
||||||
|
"calculated_price": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": null,
|
"ean": null,
|
||||||
@@ -731,6 +804,7 @@ Object {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
|
"original_price": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -740,6 +814,7 @@ Object {
|
|||||||
"id": StringMatching /\\^ma_\\*/,
|
"id": StringMatching /\\^ma_\\*/,
|
||||||
"max_quantity": null,
|
"max_quantity": null,
|
||||||
"min_quantity": null,
|
"min_quantity": null,
|
||||||
|
"price_list": null,
|
||||||
"price_list_id": null,
|
"price_list_id": null,
|
||||||
"region_id": null,
|
"region_id": null,
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
@@ -753,6 +828,7 @@ Object {
|
|||||||
"id": StringMatching /\\^ma_\\*/,
|
"id": StringMatching /\\^ma_\\*/,
|
||||||
"max_quantity": null,
|
"max_quantity": null,
|
||||||
"min_quantity": null,
|
"min_quantity": null,
|
||||||
|
"price_list": null,
|
||||||
"price_list_id": null,
|
"price_list_id": null,
|
||||||
"region_id": null,
|
"region_id": null,
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
@@ -766,6 +842,7 @@ Object {
|
|||||||
"id": StringMatching /\\^ma_\\*/,
|
"id": StringMatching /\\^ma_\\*/,
|
||||||
"max_quantity": null,
|
"max_quantity": null,
|
||||||
"min_quantity": null,
|
"min_quantity": null,
|
||||||
|
"price_list": null,
|
||||||
"price_list_id": null,
|
"price_list_id": null,
|
||||||
"region_id": null,
|
"region_id": null,
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
@@ -855,6 +932,7 @@ Object {
|
|||||||
Object {
|
Object {
|
||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": "test-barcode",
|
"barcode": "test-barcode",
|
||||||
|
"calculated_price": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": "test-ean",
|
"ean": "test-ean",
|
||||||
@@ -880,6 +958,7 @@ Object {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
|
"original_price": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 75,
|
"amount": 75,
|
||||||
@@ -889,6 +968,7 @@ Object {
|
|||||||
"id": "test-price",
|
"id": "test-price",
|
||||||
"max_quantity": null,
|
"max_quantity": null,
|
||||||
"min_quantity": null,
|
"min_quantity": null,
|
||||||
|
"price_list": null,
|
||||||
"price_list_id": null,
|
"price_list_id": null,
|
||||||
"region_id": null,
|
"region_id": null,
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
|
|||||||
@@ -522,10 +522,13 @@ describe("/admin/products", () => {
|
|||||||
console.log(err)
|
console.log(err)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
response.data.products.sort((a, b) =>
|
||||||
|
a.created_at > b.created_at ? 1 : -1
|
||||||
|
)
|
||||||
|
|
||||||
expect(response.data.products).toMatchSnapshot([
|
expect(response.data.products).toMatchSnapshot([
|
||||||
{
|
{
|
||||||
id: expect.stringMatching(/^test-*/),
|
id: "test-product",
|
||||||
created_at: expect.any(String),
|
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
id: expect.stringMatching(/^test-*/),
|
id: expect.stringMatching(/^test-*/),
|
||||||
@@ -543,7 +546,53 @@ describe("/admin/products", () => {
|
|||||||
],
|
],
|
||||||
variants: [
|
variants: [
|
||||||
{
|
{
|
||||||
id: "test-variant", // expect.stringMatching(/^test-variant*/),
|
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),
|
created_at: expect.any(String),
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
product_id: expect.stringMatching(/^test-*/),
|
product_id: expect.stringMatching(/^test-*/),
|
||||||
@@ -566,36 +615,13 @@ describe("/admin/products", () => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "test-variant_2", // expect.stringMatching(/^test-variant*/),
|
id: "test-variant-sale",
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
product_id: expect.stringMatching(/^test-*/),
|
product_id: expect.stringMatching(/^test-*/),
|
||||||
prices: [
|
prices: [
|
||||||
{
|
{
|
||||||
id: expect.stringMatching(/^test-price*/),
|
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),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: "test-variant_1", // expect.stringMatching(/^test-variant*/),
|
|
||||||
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*/),
|
variant_id: expect.stringMatching(/^test-variant*/),
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
@@ -634,12 +660,12 @@ describe("/admin/products", () => {
|
|||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: expect.stringMatching(/^test-*/),
|
id: "test-product1",
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
options: [],
|
options: [],
|
||||||
variants: [
|
variants: [
|
||||||
{
|
{
|
||||||
id: "test-variant_4", // expect.stringMatching(/^test-variant*/),
|
id: "test-variant_4",
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
product_id: expect.stringMatching(/^test-*/),
|
product_id: expect.stringMatching(/^test-*/),
|
||||||
@@ -662,7 +688,7 @@ describe("/admin/products", () => {
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "test-variant_3", // expect.stringMatching(/^test-variant*/),
|
id: "test-variant_3",
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
product_id: expect.stringMatching(/^test-*/),
|
product_id: expect.stringMatching(/^test-*/),
|
||||||
@@ -703,11 +729,10 @@ describe("/admin/products", () => {
|
|||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
},
|
},
|
||||||
profile_id: expect.stringMatching(/^sp_*/),
|
profile_id: expect.stringMatching(/^sp_*/),
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: expect.stringMatching(/^test-*/),
|
id: "test-product_filtering_1",
|
||||||
profile_id: expect.stringMatching(/^sp_*/),
|
profile_id: expect.stringMatching(/^sp_*/),
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
type: expect.any(Object),
|
type: expect.any(Object),
|
||||||
@@ -718,7 +743,7 @@ describe("/admin/products", () => {
|
|||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: expect.stringMatching(/^test-*/),
|
id: "test-product_filtering_2",
|
||||||
profile_id: expect.stringMatching(/^sp_*/),
|
profile_id: expect.stringMatching(/^sp_*/),
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
type: expect.any(Object),
|
type: expect.any(Object),
|
||||||
@@ -729,7 +754,7 @@ describe("/admin/products", () => {
|
|||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: expect.stringMatching(/^test-*/),
|
id: "test-product_filtering_3",
|
||||||
profile_id: expect.stringMatching(/^sp_*/),
|
profile_id: expect.stringMatching(/^sp_*/),
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
type: expect.any(Object),
|
type: expect.any(Object),
|
||||||
@@ -1357,7 +1382,6 @@ describe("/admin/products", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200)
|
||||||
|
|
||||||
expect(response.data).toEqual({
|
expect(response.data).toEqual({
|
||||||
product: expect.objectContaining({
|
product: expect.objectContaining({
|
||||||
id: "test-product",
|
id: "test-product",
|
||||||
@@ -1369,33 +1393,6 @@ describe("/admin/products", () => {
|
|||||||
amount: 1500,
|
amount: 1500,
|
||||||
currency_code: "usd",
|
currency_code: "usd",
|
||||||
}),
|
}),
|
||||||
expect.objectContaining({
|
|
||||||
id: "ma_test_1",
|
|
||||||
amount: 100,
|
|
||||||
currency_code: "usd",
|
|
||||||
min_quantity: 1,
|
|
||||||
max_quantity: 100,
|
|
||||||
variant_id: "test-variant",
|
|
||||||
price_list_id: "pl_no_customer_groups",
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
id: "ma_test_2",
|
|
||||||
amount: 80,
|
|
||||||
currency_code: "usd",
|
|
||||||
min_quantity: 101,
|
|
||||||
max_quantity: 500,
|
|
||||||
variant_id: "test-variant",
|
|
||||||
price_list_id: "pl_no_customer_groups",
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
id: "ma_test_3",
|
|
||||||
amount: 50,
|
|
||||||
currency_code: "usd",
|
|
||||||
min_quantity: 501,
|
|
||||||
max_quantity: 1000,
|
|
||||||
variant_id: "test-variant",
|
|
||||||
price_list_id: "pl_no_customer_groups",
|
|
||||||
}),
|
|
||||||
]),
|
]),
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
@@ -1451,8 +1448,9 @@ describe("/admin/products", () => {
|
|||||||
prices: [
|
prices: [
|
||||||
// usd price coming from the product seeder
|
// usd price coming from the product seeder
|
||||||
{
|
{
|
||||||
currency_code: "usd",
|
id: "test-price",
|
||||||
amount: 100,
|
amount: 100,
|
||||||
|
currency_code: "usd",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
currency_code: "eur",
|
currency_code: "eur",
|
||||||
@@ -1489,33 +1487,6 @@ describe("/admin/products", () => {
|
|||||||
amount: 4500,
|
amount: 4500,
|
||||||
currency_code: "eur",
|
currency_code: "eur",
|
||||||
}),
|
}),
|
||||||
expect.objectContaining({
|
|
||||||
id: "ma_test_1",
|
|
||||||
amount: 100,
|
|
||||||
currency_code: "usd",
|
|
||||||
min_quantity: 1,
|
|
||||||
max_quantity: 100,
|
|
||||||
variant_id: "test-variant",
|
|
||||||
price_list_id: "pl_no_customer_groups",
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
id: "ma_test_2",
|
|
||||||
amount: 80,
|
|
||||||
currency_code: "usd",
|
|
||||||
min_quantity: 101,
|
|
||||||
max_quantity: 500,
|
|
||||||
variant_id: "test-variant",
|
|
||||||
price_list_id: "pl_no_customer_groups",
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
id: "ma_test_3",
|
|
||||||
amount: 50,
|
|
||||||
currency_code: "usd",
|
|
||||||
min_quantity: 501,
|
|
||||||
max_quantity: 1000,
|
|
||||||
variant_id: "test-variant",
|
|
||||||
price_list_id: "pl_no_customer_groups",
|
|
||||||
}),
|
|
||||||
]),
|
]),
|
||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
@@ -1547,42 +1518,13 @@ describe("/admin/products", () => {
|
|||||||
|
|
||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200)
|
||||||
|
|
||||||
expect(response.data.product.variants[0].prices.length).toEqual(
|
expect(response.data.product.variants[0].prices.length).toEqual(1)
|
||||||
4 // 3 prices from Price List + 1 default price
|
|
||||||
)
|
|
||||||
expect(response.data.product.variants[0].prices).toEqual(
|
expect(response.data.product.variants[0].prices).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
amount: 4500,
|
amount: 4500,
|
||||||
currency_code: "usd",
|
currency_code: "usd",
|
||||||
}),
|
}),
|
||||||
expect.objectContaining({
|
|
||||||
id: "ma_test_1",
|
|
||||||
amount: 100,
|
|
||||||
currency_code: "usd",
|
|
||||||
min_quantity: 1,
|
|
||||||
max_quantity: 100,
|
|
||||||
variant_id: "test-variant",
|
|
||||||
price_list_id: "pl_no_customer_groups",
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
id: "ma_test_2",
|
|
||||||
amount: 80,
|
|
||||||
currency_code: "usd",
|
|
||||||
min_quantity: 101,
|
|
||||||
max_quantity: 500,
|
|
||||||
variant_id: "test-variant",
|
|
||||||
price_list_id: "pl_no_customer_groups",
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
id: "ma_test_3",
|
|
||||||
amount: 50,
|
|
||||||
currency_code: "usd",
|
|
||||||
min_quantity: 501,
|
|
||||||
max_quantity: 1000,
|
|
||||||
variant_id: "test-variant",
|
|
||||||
price_list_id: "pl_no_customer_groups",
|
|
||||||
}),
|
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -1614,9 +1556,8 @@ describe("/admin/products", () => {
|
|||||||
|
|
||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200)
|
||||||
|
|
||||||
expect(response.data.product.variants[0].prices.length).toEqual(
|
expect(response.data.product.variants[0].prices.length).toEqual(2)
|
||||||
5 // 2 default prices + 3 prices from Price List
|
|
||||||
)
|
|
||||||
expect(response.data.product.variants[0].prices).toEqual(
|
expect(response.data.product.variants[0].prices).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@@ -1627,33 +1568,6 @@ describe("/admin/products", () => {
|
|||||||
amount: 900,
|
amount: 900,
|
||||||
currency_code: "eur",
|
currency_code: "eur",
|
||||||
}),
|
}),
|
||||||
expect.objectContaining({
|
|
||||||
id: "ma_test_1",
|
|
||||||
amount: 100,
|
|
||||||
currency_code: "usd",
|
|
||||||
min_quantity: 1,
|
|
||||||
max_quantity: 100,
|
|
||||||
variant_id: "test-variant",
|
|
||||||
price_list_id: "pl_no_customer_groups",
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
id: "ma_test_2",
|
|
||||||
amount: 80,
|
|
||||||
currency_code: "usd",
|
|
||||||
min_quantity: 101,
|
|
||||||
max_quantity: 500,
|
|
||||||
variant_id: "test-variant",
|
|
||||||
price_list_id: "pl_no_customer_groups",
|
|
||||||
}),
|
|
||||||
expect.objectContaining({
|
|
||||||
id: "ma_test_3",
|
|
||||||
amount: 50,
|
|
||||||
currency_code: "usd",
|
|
||||||
min_quantity: 501,
|
|
||||||
max_quantity: 1000,
|
|
||||||
variant_id: "test-variant",
|
|
||||||
price_list_id: "pl_no_customer_groups",
|
|
||||||
}),
|
|
||||||
])
|
])
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -1951,7 +1865,7 @@ describe("/admin/products", () => {
|
|||||||
it("successfully creates soft-deleted product variant", async () => {
|
it("successfully creates soft-deleted product variant", async () => {
|
||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
const product = await api
|
await api
|
||||||
.get("/admin/products/test-product", {
|
.get("/admin/products/test-product", {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: "bearer test_token",
|
Authorization: "bearer test_token",
|
||||||
|
|||||||
@@ -0,0 +1,659 @@
|
|||||||
|
const path = require("path")
|
||||||
|
|
||||||
|
const setupServer = require("../../../helpers/setup-server")
|
||||||
|
const { useApi } = require("../../../helpers/use-api")
|
||||||
|
const { useDb, initDb } = require("../../../helpers/use-db")
|
||||||
|
|
||||||
|
const adminSeeder = require("../../helpers/admin-seeder")
|
||||||
|
const promotionsSeeder = require("../../helpers/price-selection-seeder")
|
||||||
|
|
||||||
|
jest.setTimeout(30000)
|
||||||
|
|
||||||
|
describe("Promotions", () => {
|
||||||
|
let medusaProcess
|
||||||
|
let dbConnection
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
const cwd = path.resolve(path.join(__dirname, "..", ".."))
|
||||||
|
dbConnection = await initDb({ cwd })
|
||||||
|
medusaProcess = await setupServer({ cwd })
|
||||||
|
})
|
||||||
|
|
||||||
|
afterAll(async () => {
|
||||||
|
const db = useDb()
|
||||||
|
await db.shutdown()
|
||||||
|
|
||||||
|
medusaProcess.kill()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("Money amount", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
try {
|
||||||
|
await adminSeeder(dbConnection)
|
||||||
|
await promotionsSeeder(dbConnection)
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
const db = useDb()
|
||||||
|
await db.teardown()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("calculated_price contains lowest price", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
const res = await api
|
||||||
|
.get("/store/products/test-product?region_id=test-region")
|
||||||
|
.catch((error) => console.log(error))
|
||||||
|
|
||||||
|
const variant = res.data.product.variants[0]
|
||||||
|
|
||||||
|
const lowestPrice = variant.prices.reduce(
|
||||||
|
(prev, curr) => (curr.amount < prev ? curr.amount : prev),
|
||||||
|
Infinity
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(variant.calculated_price).toEqual(lowestPrice)
|
||||||
|
|
||||||
|
expect(variant).toEqual(
|
||||||
|
expect.objectContaining({ original_price: 120, calculated_price: 110 })
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("returns no money amounts belonging to customer groups without login", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
const res = await api
|
||||||
|
.get("/store/products/test-product?cart_id=test-cart")
|
||||||
|
.catch((error) => console.log(error))
|
||||||
|
|
||||||
|
const variant = res.data.product.variants[0]
|
||||||
|
|
||||||
|
expect(variant.prices.length).toEqual(2)
|
||||||
|
variant.prices.forEach((price) => {
|
||||||
|
if (price.price_list) {
|
||||||
|
expect(price.price_list.customer_groups).toEqual(undefined)
|
||||||
|
} else {
|
||||||
|
expect(price.price_list).toEqual(null)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
expect(variant.prices).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price1",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 120,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price3",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
price_list_id: "pl",
|
||||||
|
amount: 110,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("sets default price as original price", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
const res = await api
|
||||||
|
.get("/store/products/test-product?cart_id=test-cart")
|
||||||
|
.catch((error) => console.log(error))
|
||||||
|
|
||||||
|
const variant = res.data.product.variants[0]
|
||||||
|
|
||||||
|
expect(variant.original_price).toEqual(
|
||||||
|
variant.prices.find((p) => p.price_list_id === null).amount
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("gets prices for currency if no region prices exist", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
const res = await api
|
||||||
|
.get("/store/products/test-product?cart_id=test-cart-2")
|
||||||
|
.catch((error) => console.log(error))
|
||||||
|
|
||||||
|
const variant = res.data.product.variants[0]
|
||||||
|
|
||||||
|
expect(variant.original_price).toEqual(
|
||||||
|
variant.prices.find((p) => p.price_list_id === null).amount
|
||||||
|
)
|
||||||
|
expect(variant.prices.length).toEqual(2)
|
||||||
|
variant.prices.forEach((price) => {
|
||||||
|
if (price.price_list) {
|
||||||
|
expect(price.price_list.customer_groups).toEqual(undefined)
|
||||||
|
} else {
|
||||||
|
expect(price.price_list).toEqual(null)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
variant.prices.forEach((price) => {
|
||||||
|
expect(price.region_id).toEqual("test-region")
|
||||||
|
expect(price.currency_code).toEqual("usd")
|
||||||
|
})
|
||||||
|
expect(variant.prices).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price1",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 120,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price3",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
price_list_id: "pl",
|
||||||
|
amount: 110,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("gets prices for cart region for multi region product", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
const res = await api
|
||||||
|
.get("/store/products/test-product-multi-region?cart_id=test-cart-1")
|
||||||
|
.catch((error) => console.log(error))
|
||||||
|
|
||||||
|
const variant = res.data.product.variants[0]
|
||||||
|
|
||||||
|
expect(variant).toEqual(
|
||||||
|
expect.objectContaining({ original_price: 130, calculated_price: 110 })
|
||||||
|
)
|
||||||
|
expect(variant.original_price).toEqual(
|
||||||
|
variant.prices.find((p) => p.price_list_id === null).amount
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(variant.prices.length).toEqual(2)
|
||||||
|
|
||||||
|
expect(variant.prices).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price1-region-2",
|
||||||
|
region_id: "test-region-2",
|
||||||
|
currency_code: "dkk",
|
||||||
|
amount: 130,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price3-region-2",
|
||||||
|
region_id: "test-region-2",
|
||||||
|
currency_code: "dkk",
|
||||||
|
price_list_id: "pl",
|
||||||
|
amount: 110,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("gets prices for multi region product", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
const res = await api
|
||||||
|
.get(
|
||||||
|
"/store/products/test-product-multi-region?region_id=test-region-2"
|
||||||
|
)
|
||||||
|
.catch((error) => console.log(error))
|
||||||
|
|
||||||
|
const variant = res.data.product.variants[0]
|
||||||
|
|
||||||
|
expect(variant).toEqual(
|
||||||
|
expect.objectContaining({ original_price: 130, calculated_price: 110 })
|
||||||
|
)
|
||||||
|
expect(variant.original_price).toEqual(
|
||||||
|
variant.prices.find((p) => p.price_list_id === null).amount
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(variant.prices.length).toEqual(2)
|
||||||
|
|
||||||
|
expect(variant.prices).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price1-region-2",
|
||||||
|
region_id: "test-region-2",
|
||||||
|
currency_code: "dkk",
|
||||||
|
amount: 130,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price3-region-2",
|
||||||
|
region_id: "test-region-2",
|
||||||
|
currency_code: "dkk",
|
||||||
|
price_list_id: "pl",
|
||||||
|
amount: 110,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("gets prices for multi currency product", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
const res = await api
|
||||||
|
.get("/store/products/test-product-multi-region?currency_code=dkk")
|
||||||
|
.catch((error) => console.log(error))
|
||||||
|
|
||||||
|
const variant = res.data.product.variants[0]
|
||||||
|
|
||||||
|
expect(variant).toEqual(
|
||||||
|
expect.objectContaining({ original_price: 130, calculated_price: 110 })
|
||||||
|
)
|
||||||
|
expect(variant.original_price).toEqual(
|
||||||
|
variant.prices.find((p) => p.price_list_id === null).amount
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(variant.prices.length).toEqual(2)
|
||||||
|
|
||||||
|
expect(variant.prices).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price1-region-2",
|
||||||
|
region_id: "test-region-2",
|
||||||
|
currency_code: "dkk",
|
||||||
|
amount: 130,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price3-region-2",
|
||||||
|
region_id: "test-region-2",
|
||||||
|
currency_code: "dkk",
|
||||||
|
price_list_id: "pl",
|
||||||
|
amount: 110,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("gets moneyamounts only with valid date interval", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
const res = await api
|
||||||
|
.get("/store/products/test-product-sale?cart_id=test-cart")
|
||||||
|
.catch((error) => console.log(error))
|
||||||
|
|
||||||
|
const variant = res.data.product.variants[0]
|
||||||
|
|
||||||
|
const date = new Date()
|
||||||
|
|
||||||
|
expect(variant.prices.length).toEqual(2)
|
||||||
|
variant.prices.forEach((price) => {
|
||||||
|
if (price.starts_at) {
|
||||||
|
expect(new Date(price.starts_at).getTime()).toBeLessThan(
|
||||||
|
date.getTime()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (price.ends_at) {
|
||||||
|
expect(new Date(price.ends_at).getTime()).toBeGreaterThan(
|
||||||
|
date.getTime()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("gets moneyamounts with valid date intervals and finds lowest price with overlapping intervals", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
const res = await api
|
||||||
|
.get("/store/products/test-product-sale-overlap?cart_id=test-cart")
|
||||||
|
.catch((error) => console.log(error))
|
||||||
|
|
||||||
|
const variant = res.data.product.variants[0]
|
||||||
|
|
||||||
|
const date = new Date()
|
||||||
|
|
||||||
|
expect(variant).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
original_price: 150,
|
||||||
|
calculated_price: 120,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
expect(variant.prices.length).toEqual(3)
|
||||||
|
variant.prices.forEach((price) => {
|
||||||
|
if (price.starts_at) {
|
||||||
|
expect(new Date(price.starts_at).getTime()).toBeLessThan(
|
||||||
|
date.getTime()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (price.ends_at) {
|
||||||
|
expect(new Date(price.ends_at).getTime()).toBeGreaterThan(
|
||||||
|
date.getTime()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(variant.prices).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price-sale-overlap-1",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 140,
|
||||||
|
price_list_id: "pl_current_1",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price1-sale-overlap",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 120,
|
||||||
|
price_list_id: "pl_current",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price2-sale-overlap-default",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 150,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("gets all prices with varying quantity limits with no quantity", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
const res = await api
|
||||||
|
.get("/store/products/test-product-quantity?cart_id=test-cart")
|
||||||
|
.catch((error) => console.log(error))
|
||||||
|
|
||||||
|
const variant = res.data.product.variants[0]
|
||||||
|
|
||||||
|
expect(variant.prices.length).toEqual(5)
|
||||||
|
expect(variant.prices).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price-quantity",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 100,
|
||||||
|
price_list_id: "pl",
|
||||||
|
min_quantity: 10,
|
||||||
|
max_quantity: 100,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price1-quantity",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 120,
|
||||||
|
price_list_id: "pl",
|
||||||
|
min_quantity: 101,
|
||||||
|
max_quantity: 1000,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price2-quantity",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 130,
|
||||||
|
price_list_id: "pl",
|
||||||
|
max_quantity: 9,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price3-quantity-now",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 140,
|
||||||
|
price_list_id: "pl_current",
|
||||||
|
min_quantity: 101,
|
||||||
|
max_quantity: 1000,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price3-quantity-default",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 150,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(variant.calculated_price).toEqual(130)
|
||||||
|
expect(variant.original_price).toEqual(150)
|
||||||
|
expect(variant.original_price).toEqual(
|
||||||
|
variant.prices.find((p) => p.price_list_id === null).amount
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("fetches product with groups in money amounts with login", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
// customer with customer-group 5
|
||||||
|
const authResponse = await api.post("/store/auth", {
|
||||||
|
email: "test5@email.com",
|
||||||
|
password: "test",
|
||||||
|
})
|
||||||
|
|
||||||
|
const [authCookie] = authResponse.headers["set-cookie"][0].split(";")
|
||||||
|
|
||||||
|
const res = await api
|
||||||
|
.get("/store/products/test-product?cart_id=test-cart", {
|
||||||
|
headers: {
|
||||||
|
Cookie: authCookie,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.catch((error) => console.log(error))
|
||||||
|
|
||||||
|
const variant = res.data.product.variants[0]
|
||||||
|
|
||||||
|
expect(variant.prices.length).toEqual(3)
|
||||||
|
|
||||||
|
expect(variant.prices).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price1",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 120,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price3",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
price_list_id: "pl",
|
||||||
|
amount: 110,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 100,
|
||||||
|
price_list: expect.objectContaining({}),
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("fetches product with groups and quantities in money amounts with login", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
// customer with customer-group 5
|
||||||
|
const authResponse = await api.post("/store/auth", {
|
||||||
|
email: "test5@email.com",
|
||||||
|
password: "test",
|
||||||
|
})
|
||||||
|
|
||||||
|
const [authCookie] = authResponse.headers["set-cookie"][0].split(";")
|
||||||
|
|
||||||
|
const res = await api
|
||||||
|
.get(
|
||||||
|
"/store/products/test-product-quantity-customer?cart_id=test-cart",
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Cookie: authCookie,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((error) => console.log(error))
|
||||||
|
|
||||||
|
const variant = res.data.product.variants[0]
|
||||||
|
|
||||||
|
expect(variant.prices.length).toEqual(6)
|
||||||
|
expect(variant.prices).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price-quantity-customer",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 100,
|
||||||
|
min_quantity: 10,
|
||||||
|
max_quantity: 100,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price1-quantity-customer",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 120,
|
||||||
|
min_quantity: 101,
|
||||||
|
max_quantity: 1000,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price2-quantity-customer",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 130,
|
||||||
|
max_quantity: 9,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price2-quantity-customer-group",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 100,
|
||||||
|
max_quantity: 9,
|
||||||
|
price_list: expect.objectContaining({}),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price3-quantity-customer-now",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 140,
|
||||||
|
min_quantity: 101,
|
||||||
|
max_quantity: 1000,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price3-quantity-customer-default",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 150,
|
||||||
|
price_list_id: null,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(variant.calculated_price).toEqual(100)
|
||||||
|
expect(variant.original_price).toEqual(150)
|
||||||
|
expect(variant.original_price).toEqual(
|
||||||
|
variant.prices.find((p) => p.price_list_id === null).amount
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("gets moneyamounts only with valid date interval for customer", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
// customer with customer-group 5
|
||||||
|
const authResponse = await api.post("/store/auth", {
|
||||||
|
email: "test5@email.com",
|
||||||
|
password: "test",
|
||||||
|
})
|
||||||
|
|
||||||
|
const [authCookie] = authResponse.headers["set-cookie"][0].split(";")
|
||||||
|
|
||||||
|
const res = await api
|
||||||
|
.get("/store/products/test-product-sale-customer?cart_id=test-cart", {
|
||||||
|
headers: {
|
||||||
|
Cookie: authCookie,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.catch((error) => console.log(error))
|
||||||
|
|
||||||
|
const variant = res.data.product.variants[0]
|
||||||
|
|
||||||
|
const date = new Date()
|
||||||
|
|
||||||
|
expect(variant).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
original_price: 150,
|
||||||
|
calculated_price: 100,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(variant.prices.length).toEqual(2)
|
||||||
|
variant.prices.forEach((price) => {
|
||||||
|
if (price.starts_at) {
|
||||||
|
expect(new Date(price.starts_at).getTime()).toBeLessThan(
|
||||||
|
date.getTime()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (price.ends_at) {
|
||||||
|
expect(new Date(price.ends_at).getTime()).toBeGreaterThan(
|
||||||
|
date.getTime()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("gets moneyamounts only with valid date interval for customer regardless of quantity limits", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
// customer with customer-group 5
|
||||||
|
const authResponse = await api.post("/store/auth", {
|
||||||
|
email: "test5@email.com",
|
||||||
|
password: "test",
|
||||||
|
})
|
||||||
|
|
||||||
|
const [authCookie] = authResponse.headers["set-cookie"][0].split(";")
|
||||||
|
|
||||||
|
const res = await api
|
||||||
|
.get(
|
||||||
|
"/store/products/test-product-sale-customer-quantity?cart_id=test-cart",
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Cookie: authCookie,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.catch((error) => console.log(error))
|
||||||
|
|
||||||
|
const variant = res.data.product.variants[0]
|
||||||
|
|
||||||
|
const date = new Date()
|
||||||
|
|
||||||
|
expect(variant).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
original_price: 150,
|
||||||
|
calculated_price: 100,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(variant.prices.length).toEqual(3)
|
||||||
|
variant.prices.forEach((price) => {
|
||||||
|
if (price.starts_at) {
|
||||||
|
expect(new Date(price.starts_at).getTime()).toBeLessThan(
|
||||||
|
date.getTime()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
if (price.ends_at) {
|
||||||
|
expect(new Date(price.ends_at).getTime()).toBeGreaterThan(
|
||||||
|
date.getTime()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(variant.prices).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price1-sale-customer-quantity-groups",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 100,
|
||||||
|
max_quantity: 99,
|
||||||
|
price_list: expect.objectContaining({}),
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price2-sale-customer-quantity-default",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 150,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price1-sale-customer-quantity",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 110,
|
||||||
|
max_quantity: 99,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`/store/variants /test-variant 1`] = `
|
exports[`/store/variants GET /store/variants /test-variant 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"variant": Object {
|
"variant": Object {
|
||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": "test-barcode",
|
"barcode": "test-barcode",
|
||||||
|
"calculated_price": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": "test-ean",
|
"ean": "test-ean",
|
||||||
@@ -30,6 +31,7 @@ Object {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
|
"original_price": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -39,6 +41,7 @@ Object {
|
|||||||
"id": "test-price",
|
"id": "test-price",
|
||||||
"max_quantity": null,
|
"max_quantity": null,
|
||||||
"min_quantity": null,
|
"min_quantity": null,
|
||||||
|
"price_list": null,
|
||||||
"price_list_id": null,
|
"price_list_id": null,
|
||||||
"region_id": null,
|
"region_id": null,
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
@@ -57,71 +60,99 @@ Object {
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`/store/variants includes default relations 1`] = `
|
exports[`/store/variants GET /store/variants advanced pricing /test-variant with currency code 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"variants": Array [
|
"variant": Object {
|
||||||
Object {
|
"allow_backorder": false,
|
||||||
"allow_backorder": false,
|
"barcode": "test-barcode",
|
||||||
"barcode": "test-barcode",
|
"calculated_price": 80,
|
||||||
"created_at": Any<String>,
|
"calculated_price_type": "sale",
|
||||||
"deleted_at": null,
|
"created_at": Any<String>,
|
||||||
"ean": "test-ean",
|
"deleted_at": null,
|
||||||
"height": null,
|
"ean": "test-ean",
|
||||||
"hs_code": null,
|
"height": null,
|
||||||
"id": "test-variant",
|
"hs_code": null,
|
||||||
"inventory_quantity": 10,
|
"id": "test-variant",
|
||||||
"length": null,
|
"inventory_quantity": 10,
|
||||||
"manage_inventory": true,
|
"length": null,
|
||||||
"material": null,
|
"manage_inventory": true,
|
||||||
"metadata": null,
|
"material": null,
|
||||||
"mid_code": null,
|
"metadata": null,
|
||||||
"options": Array [
|
"mid_code": null,
|
||||||
Object {
|
"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": 100,
|
||||||
|
"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>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"id": "test-variant-option",
|
"description": "Winter sale for VIP customers.",
|
||||||
"metadata": null,
|
"ends_at": null,
|
||||||
"option_id": "test-option",
|
"id": "pl",
|
||||||
|
"name": "VIP winter sale",
|
||||||
|
"starts_at": null,
|
||||||
|
"status": "active",
|
||||||
|
"type": "sale",
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
"value": "Default variant",
|
|
||||||
"variant_id": "test-variant",
|
|
||||||
},
|
},
|
||||||
],
|
"price_list_id": "pl",
|
||||||
"origin_country": null,
|
"region_id": null,
|
||||||
"prices": Array [
|
"updated_at": Any<String>,
|
||||||
Object {
|
"variant_id": "test-variant",
|
||||||
"amount": 100,
|
},
|
||||||
"created_at": Any<String>,
|
],
|
||||||
"currency_code": "usd",
|
"product": Any<Object>,
|
||||||
"deleted_at": null,
|
"product_id": "test-product",
|
||||||
"id": "test-price",
|
"sku": "test-sku",
|
||||||
"max_quantity": null,
|
"title": "Test variant",
|
||||||
"min_quantity": null,
|
"upc": "test-upc",
|
||||||
"price_list_id": null,
|
"updated_at": Any<String>,
|
||||||
"region_id": null,
|
"weight": null,
|
||||||
"updated_at": Any<String>,
|
"width": null,
|
||||||
"variant_id": "test-variant",
|
},
|
||||||
},
|
|
||||||
],
|
|
||||||
"product": Any<Object>,
|
|
||||||
"product_id": "test-product",
|
|
||||||
"sku": "test-sku",
|
|
||||||
"title": "Test variant",
|
|
||||||
"upc": "test-upc",
|
|
||||||
"updated_at": Any<String>,
|
|
||||||
"weight": null,
|
|
||||||
"width": null,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`/store/variants lists by title 1`] = `
|
exports[`/store/variants GET /store/variants advanced pricing lists by title 1`] = `
|
||||||
Object {
|
Object {
|
||||||
"variants": Array [
|
"variants": Array [
|
||||||
Object {
|
Object {
|
||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": null,
|
"barcode": null,
|
||||||
|
"calculated_price": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": null,
|
"ean": null,
|
||||||
@@ -147,6 +178,7 @@ Object {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
|
"original_price": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -156,6 +188,7 @@ Object {
|
|||||||
"id": Any<String>,
|
"id": Any<String>,
|
||||||
"max_quantity": null,
|
"max_quantity": null,
|
||||||
"min_quantity": null,
|
"min_quantity": null,
|
||||||
|
"price_list": null,
|
||||||
"price_list_id": null,
|
"price_list_id": null,
|
||||||
"region_id": null,
|
"region_id": null,
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
@@ -174,3 +207,151 @@ Object {
|
|||||||
],
|
],
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`/store/variants GET /store/variants advanced pricing sets additional prices correctly when querying a variant 1`] = `
|
||||||
|
Object {
|
||||||
|
"variant": Object {
|
||||||
|
"allow_backorder": false,
|
||||||
|
"barcode": "test-barcode",
|
||||||
|
"calculated_price": 80,
|
||||||
|
"calculated_price_type": "sale",
|
||||||
|
"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": 100,
|
||||||
|
"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": Any<Object>,
|
||||||
|
"product_id": "test-product",
|
||||||
|
"sku": "test-sku",
|
||||||
|
"title": "Test variant",
|
||||||
|
"upc": "test-upc",
|
||||||
|
"updated_at": Any<String>,
|
||||||
|
"weight": null,
|
||||||
|
"width": null,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`/store/variants GET /store/variants includes default relations 1`] = `
|
||||||
|
Object {
|
||||||
|
"variants": Array [
|
||||||
|
Object {
|
||||||
|
"allow_backorder": false,
|
||||||
|
"barcode": "test-barcode",
|
||||||
|
"calculated_price": 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,
|
||||||
|
"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",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"product": Any<Object>,
|
||||||
|
"product_id": "test-product",
|
||||||
|
"sku": "test-sku",
|
||||||
|
"title": "Test variant",
|
||||||
|
"upc": "test-upc",
|
||||||
|
"updated_at": Any<String>,
|
||||||
|
"weight": null,
|
||||||
|
"width": null,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`;
|
||||||
@@ -102,7 +102,7 @@ Object {
|
|||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
"profile_id": StringMatching /\\^sp_\\*/,
|
"profile_id": StringMatching /\\^sp_\\*/,
|
||||||
"status": "draft",
|
"status": "published",
|
||||||
"subtitle": null,
|
"subtitle": null,
|
||||||
"tags": Array [
|
"tags": Array [
|
||||||
Object {
|
Object {
|
||||||
@@ -130,6 +130,7 @@ Object {
|
|||||||
Object {
|
Object {
|
||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": "test-barcode",
|
"barcode": "test-barcode",
|
||||||
|
"calculated_price": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": "test-ean",
|
"ean": "test-ean",
|
||||||
@@ -155,6 +156,7 @@ Object {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
|
"original_price": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -164,11 +166,37 @@ Object {
|
|||||||
"id": "test-price",
|
"id": "test-price",
|
||||||
"max_quantity": null,
|
"max_quantity": null,
|
||||||
"min_quantity": null,
|
"min_quantity": null,
|
||||||
|
"price_list": null,
|
||||||
"price_list_id": null,
|
"price_list_id": null,
|
||||||
"region_id": null,
|
"region_id": null,
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
"variant_id": "test-variant",
|
"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",
|
"product_id": "test-product",
|
||||||
"sku": "test-sku",
|
"sku": "test-sku",
|
||||||
@@ -181,6 +209,7 @@ Object {
|
|||||||
Object {
|
Object {
|
||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": null,
|
"barcode": null,
|
||||||
|
"calculated_price": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": "test-ean2",
|
"ean": "test-ean2",
|
||||||
@@ -206,6 +235,7 @@ Object {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
|
"original_price": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -215,11 +245,37 @@ Object {
|
|||||||
"id": "test-price2",
|
"id": "test-price2",
|
||||||
"max_quantity": null,
|
"max_quantity": null,
|
||||||
"min_quantity": null,
|
"min_quantity": null,
|
||||||
|
"price_list": null,
|
||||||
"price_list_id": null,
|
"price_list_id": null,
|
||||||
"region_id": null,
|
"region_id": null,
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
"variant_id": "test-variant_2",
|
"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",
|
"product_id": "test-product",
|
||||||
"sku": "test-sku2",
|
"sku": "test-sku2",
|
||||||
@@ -232,6 +288,7 @@ Object {
|
|||||||
Object {
|
Object {
|
||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": "test-barcode 1",
|
"barcode": "test-barcode 1",
|
||||||
|
"calculated_price": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": "test-ean1",
|
"ean": "test-ean1",
|
||||||
@@ -257,6 +314,7 @@ Object {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
|
"original_price": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -266,11 +324,37 @@ Object {
|
|||||||
"id": "test-price1",
|
"id": "test-price1",
|
||||||
"max_quantity": null,
|
"max_quantity": null,
|
||||||
"min_quantity": null,
|
"min_quantity": null,
|
||||||
|
"price_list": null,
|
||||||
"price_list_id": null,
|
"price_list_id": null,
|
||||||
"region_id": null,
|
"region_id": null,
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
"variant_id": "test-variant_1",
|
"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",
|
"product_id": "test-product",
|
||||||
"sku": "test-sku1",
|
"sku": "test-sku1",
|
||||||
@@ -300,6 +384,7 @@ Object {
|
|||||||
Object {
|
Object {
|
||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": null,
|
"barcode": null,
|
||||||
|
"calculated_price": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": null,
|
"ean": null,
|
||||||
@@ -313,6 +398,7 @@ Object {
|
|||||||
"metadata": null,
|
"metadata": null,
|
||||||
"mid_code": null,
|
"mid_code": null,
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
|
"original_price": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -322,6 +408,7 @@ Object {
|
|||||||
"id": Any<String>,
|
"id": Any<String>,
|
||||||
"max_quantity": null,
|
"max_quantity": null,
|
||||||
"min_quantity": null,
|
"min_quantity": null,
|
||||||
|
"price_list": null,
|
||||||
"price_list_id": null,
|
"price_list_id": null,
|
||||||
"region_id": null,
|
"region_id": null,
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ const {
|
|||||||
GiftCard,
|
GiftCard,
|
||||||
Cart,
|
Cart,
|
||||||
CustomShippingOption,
|
CustomShippingOption,
|
||||||
|
PriceList,
|
||||||
|
MoneyAmount,
|
||||||
} = require("@medusajs/medusa")
|
} = require("@medusajs/medusa")
|
||||||
|
|
||||||
const setupServer = require("../../../helpers/setup-server")
|
const setupServer = require("../../../helpers/setup-server")
|
||||||
@@ -90,20 +92,51 @@ describe("/store/carts", () => {
|
|||||||
|
|
||||||
it("creates a cart with items", async () => {
|
it("creates a cart with items", async () => {
|
||||||
await productSeeder(dbConnection)
|
await productSeeder(dbConnection)
|
||||||
|
|
||||||
|
const yesterday = ((today) =>
|
||||||
|
new Date(today.setDate(today.getDate() - 1)))(new Date())
|
||||||
|
const tomorrow = ((today) =>
|
||||||
|
new Date(today.setDate(today.getDate() + 1)))(new Date())
|
||||||
|
|
||||||
|
const priceList1 = await dbConnection.manager.create(PriceList, {
|
||||||
|
id: "pl_current",
|
||||||
|
name: "Past winter sale",
|
||||||
|
description: "Winter sale for key accounts.",
|
||||||
|
type: "sale",
|
||||||
|
status: "active",
|
||||||
|
starts_at: yesterday,
|
||||||
|
ends_at: tomorrow,
|
||||||
|
})
|
||||||
|
|
||||||
|
await dbConnection.manager.save(priceList1)
|
||||||
|
|
||||||
|
const ma_sale_1 = dbConnection.manager.create(MoneyAmount, {
|
||||||
|
variant_id: "test-variant-sale",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 800,
|
||||||
|
price_list_id: "pl_current",
|
||||||
|
})
|
||||||
|
|
||||||
|
await dbConnection.manager.save(ma_sale_1)
|
||||||
|
|
||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
const response = await api.post("/store/carts", {
|
const response = await api
|
||||||
items: [
|
.post("/store/carts", {
|
||||||
{
|
items: [
|
||||||
variant_id: "test-variant_1",
|
{
|
||||||
quantity: 1,
|
variant_id: "test-variant_1",
|
||||||
},
|
quantity: 1,
|
||||||
{
|
},
|
||||||
variant_id: "test-variant_2",
|
{
|
||||||
quantity: 2,
|
variant_id: "test-variant-sale",
|
||||||
},
|
quantity: 2,
|
||||||
],
|
},
|
||||||
})
|
],
|
||||||
|
})
|
||||||
|
.catch((err) => console.log(err))
|
||||||
|
|
||||||
|
response.data.cart.items.sort((a, b) => a.quantity - b.quantity)
|
||||||
|
|
||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200)
|
||||||
expect(response.data.cart.items).toEqual([
|
expect(response.data.cart.items).toEqual([
|
||||||
@@ -112,8 +145,9 @@ describe("/store/carts", () => {
|
|||||||
quantity: 1,
|
quantity: 1,
|
||||||
}),
|
}),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
variant_id: "test-variant_2",
|
variant_id: "test-variant-sale",
|
||||||
quantity: 2,
|
quantity: 2,
|
||||||
|
unit_price: 800,
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -155,6 +189,122 @@ describe("/store/carts", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("POST /store/carts/:id/line-items", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
try {
|
||||||
|
await cartSeeder(dbConnection)
|
||||||
|
await swapSeeder(dbConnection)
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await doAfterEach()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("adds line item to cart", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
// Add standard line item to cart
|
||||||
|
const response = await api
|
||||||
|
.post(
|
||||||
|
"/store/carts/test-cart/line-items",
|
||||||
|
{
|
||||||
|
variant_id: "test-variant-quantity",
|
||||||
|
quantity: 1,
|
||||||
|
},
|
||||||
|
{ withCredentials: true }
|
||||||
|
)
|
||||||
|
.catch((err) => console.log(err))
|
||||||
|
|
||||||
|
expect(response.data.cart.items).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
cart_id: "test-cart",
|
||||||
|
unit_price: 1000,
|
||||||
|
variant_id: "test-variant-quantity",
|
||||||
|
quantity: 1,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it("adds line item to cart time limited sale", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
// Add standard line item to cart
|
||||||
|
const response = await api
|
||||||
|
.post(
|
||||||
|
"/store/carts/test-cart/line-items",
|
||||||
|
{
|
||||||
|
variant_id: "test-variant-sale",
|
||||||
|
quantity: 1,
|
||||||
|
},
|
||||||
|
{ withCredentials: true }
|
||||||
|
)
|
||||||
|
.catch((err) => console.log(err))
|
||||||
|
|
||||||
|
expect(response.data.cart.items).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
cart_id: "test-cart",
|
||||||
|
unit_price: 800,
|
||||||
|
variant_id: "test-variant-sale",
|
||||||
|
quantity: 1,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it("adds line item with quantity to cart with quantity discount", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
// Add standard line item to cart
|
||||||
|
const response = await api
|
||||||
|
.post(
|
||||||
|
"/store/carts/test-cart/line-items",
|
||||||
|
{
|
||||||
|
variant_id: "test-variant-quantity",
|
||||||
|
quantity: 90,
|
||||||
|
},
|
||||||
|
{ withCredentials: true }
|
||||||
|
)
|
||||||
|
.catch((err) => console.log(err))
|
||||||
|
|
||||||
|
expect(response.data.cart.items).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
cart_id: "test-cart",
|
||||||
|
unit_price: 800,
|
||||||
|
variant_id: "test-variant-quantity",
|
||||||
|
quantity: 90,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
})
|
||||||
|
|
||||||
|
it("adds line item with quantity to cart with quantity discount no ceiling", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
// Add standard line item to cart
|
||||||
|
const response = await api
|
||||||
|
.post(
|
||||||
|
"/store/carts/test-cart/line-items",
|
||||||
|
{
|
||||||
|
variant_id: "test-variant-quantity",
|
||||||
|
quantity: 900,
|
||||||
|
},
|
||||||
|
{ withCredentials: true }
|
||||||
|
)
|
||||||
|
.catch((err) => console.log(err))
|
||||||
|
|
||||||
|
expect(response.data.cart.items).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
cart_id: "test-cart",
|
||||||
|
unit_price: 700,
|
||||||
|
variant_id: "test-variant-quantity",
|
||||||
|
quantity: 900,
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe("POST /store/carts/:id", () => {
|
describe("POST /store/carts/:id", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
try {
|
try {
|
||||||
@@ -270,6 +420,46 @@ describe("/store/carts", () => {
|
|||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("updates prices when cart customer id is updated", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
const beforeUpdate = await api
|
||||||
|
.get(`/store/carts/test-cart-3`)
|
||||||
|
.catch((error) => console.log(error))
|
||||||
|
|
||||||
|
expect(beforeUpdate.data.cart.items[0].unit_price).toEqual(8000)
|
||||||
|
|
||||||
|
const response = await api
|
||||||
|
.post("/store/carts/test-cart-3", {
|
||||||
|
customer_id: "test-customer-2",
|
||||||
|
})
|
||||||
|
.catch((error) => console.log(error))
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.cart.items[0].unit_price).toEqual(500)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("updates prices when cart region id is updated", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
const beforeUpdate = await api
|
||||||
|
.get(`/store/carts/test-cart-3`)
|
||||||
|
.catch((error) => console.log(error))
|
||||||
|
|
||||||
|
expect(beforeUpdate.data.cart.items[0].unit_price).toEqual(8000)
|
||||||
|
expect(beforeUpdate.data.cart.region_id).toEqual("test-region")
|
||||||
|
|
||||||
|
const response = await api
|
||||||
|
.post("/store/carts/test-cart-3", {
|
||||||
|
region_id: "test-region-multiple",
|
||||||
|
})
|
||||||
|
.catch((error) => console.log(error))
|
||||||
|
|
||||||
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.cart.region_id).toEqual("test-region-multiple")
|
||||||
|
expect(response.data.cart.items[0].unit_price).toEqual(700)
|
||||||
|
})
|
||||||
|
|
||||||
it("updates address using string id", async () => {
|
it("updates address using string id", async () => {
|
||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
@@ -377,7 +567,7 @@ describe("/store/carts", () => {
|
|||||||
await api.post(`/store/carts/test-cart-2/complete-cart`)
|
await api.post(`/store/carts/test-cart-2/complete-cart`)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
expect(error.response.data).toMatchSnapshot({
|
expect(error.response.data).toMatchSnapshot({
|
||||||
code: "not_allowed",
|
type: "not_allowed",
|
||||||
message: "Cart has already been completed",
|
message: "Cart has already been completed",
|
||||||
code: "cart_incompatible_state",
|
code: "cart_incompatible_state",
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
const { ProductVariant } = require("@medusajs/medusa")
|
||||||
const path = require("path")
|
const path = require("path")
|
||||||
const setupServer = require("../../../helpers/setup-server")
|
const setupServer = require("../../../helpers/setup-server")
|
||||||
const { useApi } = require("../../../helpers/use-api")
|
const { useApi } = require("../../../helpers/use-api")
|
||||||
@@ -5,6 +6,7 @@ const { initDb, useDb } = require("../../../helpers/use-db")
|
|||||||
const { simpleProductFactory } = require("../../factories")
|
const { simpleProductFactory } = require("../../factories")
|
||||||
|
|
||||||
const productSeeder = require("../../helpers/product-seeder")
|
const productSeeder = require("../../helpers/product-seeder")
|
||||||
|
const storeProductSeeder = require("../../helpers/store-product-seeder")
|
||||||
jest.setTimeout(30000)
|
jest.setTimeout(30000)
|
||||||
describe("/store/variants", () => {
|
describe("/store/variants", () => {
|
||||||
let medusaProcess
|
let medusaProcess
|
||||||
@@ -22,46 +24,100 @@ describe("/store/variants", () => {
|
|||||||
medusaProcess.kill()
|
medusaProcess.kill()
|
||||||
})
|
})
|
||||||
|
|
||||||
beforeEach(async () => {
|
describe("GET /store/variants", () => {
|
||||||
try {
|
beforeEach(async () => {
|
||||||
await productSeeder(dbConnection)
|
try {
|
||||||
|
await productSeeder(dbConnection)
|
||||||
|
|
||||||
await simpleProductFactory(
|
await simpleProductFactory(
|
||||||
dbConnection,
|
dbConnection,
|
||||||
{
|
{
|
||||||
title: "prod",
|
title: "prod",
|
||||||
variants: [
|
variants: [
|
||||||
{
|
{
|
||||||
title: "test1",
|
title: "test1",
|
||||||
inventory_quantity: 10,
|
inventory_quantity: 10,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: "test2",
|
title: "test2",
|
||||||
inventory_quantity: 12,
|
inventory_quantity: 12,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
100
|
100
|
||||||
)
|
)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err)
|
console.log(err)
|
||||||
throw err
|
throw err
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
const db = useDb()
|
const db = useDb()
|
||||||
await db.teardown()
|
await db.teardown()
|
||||||
})
|
})
|
||||||
|
|
||||||
it("includes default relations", async () => {
|
it("includes default relations", async () => {
|
||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
const response = await api.get("/store/variants?ids=test-variant")
|
const response = await api.get("/store/variants?ids=test-variant")
|
||||||
|
|
||||||
expect(response.data).toMatchSnapshot({
|
expect(response.data).toMatchSnapshot({
|
||||||
variants: [
|
variants: [
|
||||||
{
|
{
|
||||||
|
allow_backorder: false,
|
||||||
|
barcode: "test-barcode",
|
||||||
|
created_at: expect.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,
|
||||||
|
origin_country: null,
|
||||||
|
product_id: "test-product",
|
||||||
|
sku: "test-sku",
|
||||||
|
title: "Test variant",
|
||||||
|
upc: "test-upc",
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
weight: null,
|
||||||
|
width: null,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
prices: [
|
||||||
|
{
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
amount: 100,
|
||||||
|
currency_code: "usd",
|
||||||
|
deleted_at: null,
|
||||||
|
id: "test-price",
|
||||||
|
region_id: null,
|
||||||
|
variant_id: "test-variant",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
product: expect.any(Object),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("/test-variant", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
const response = await api.get("/store/variants/test-variant")
|
||||||
|
|
||||||
|
expect(response.data).toMatchSnapshot({
|
||||||
|
variant: {
|
||||||
allow_backorder: false,
|
allow_backorder: false,
|
||||||
barcode: "test-barcode",
|
barcode: "test-barcode",
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
@@ -106,103 +162,230 @@ describe("/store/variants", () => {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
product: expect.any(Object),
|
product: expect.any(Object),
|
||||||
options: [
|
|
||||||
{ created_at: expect.any(String), updated_at: expect.any(String) },
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
],
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it("lists by title", async () => {
|
describe("GET /store/variants advanced pricing", () => {
|
||||||
const api = useApi()
|
beforeEach(async () => {
|
||||||
|
try {
|
||||||
|
await storeProductSeeder(dbConnection)
|
||||||
|
|
||||||
const response = await api.get(
|
await simpleProductFactory(
|
||||||
"/store/variants?title[]=test1&title[]=test2&inventory_quantity[gt]=10"
|
dbConnection,
|
||||||
)
|
{
|
||||||
expect(response.data).toMatchSnapshot({
|
title: "prod",
|
||||||
variants: [
|
variants: [
|
||||||
{
|
{
|
||||||
id: expect.any(String),
|
title: "test1",
|
||||||
title: "test2",
|
inventory_quantity: 10,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: "test2",
|
||||||
|
inventory_quantity: 12,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
100
|
||||||
|
)
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
const db = useDb()
|
||||||
|
await db.teardown()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("/test-variant with currency code", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
const response = await api.get(
|
||||||
|
"/store/variants/test-variant?currency_code=usd"
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(response.data).toMatchSnapshot({
|
||||||
|
variant: {
|
||||||
|
allow_backorder: false,
|
||||||
|
barcode: "test-barcode",
|
||||||
created_at: expect.any(String),
|
created_at: expect.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,
|
||||||
|
origin_country: null,
|
||||||
|
product_id: "test-product",
|
||||||
|
sku: "test-sku",
|
||||||
|
title: "Test variant",
|
||||||
|
upc: "test-upc",
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
|
weight: null,
|
||||||
|
width: null,
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
id: expect.any(String),
|
|
||||||
option_id: expect.any(String),
|
|
||||||
variant_id: expect.any(String),
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
prices: [
|
prices: [
|
||||||
{
|
{
|
||||||
id: expect.any(String),
|
created_at: expect.any(String),
|
||||||
variant_id: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
|
amount: 100,
|
||||||
|
currency_code: "usd",
|
||||||
|
deleted_at: null,
|
||||||
|
id: "test-price",
|
||||||
|
region_id: null,
|
||||||
|
min_quantity: null,
|
||||||
|
max_quantity: null,
|
||||||
|
price_list_id: null,
|
||||||
|
variant_id: "test-variant",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
amount: 80,
|
||||||
|
currency_code: "usd",
|
||||||
|
deleted_at: null,
|
||||||
|
price_list_id: "pl",
|
||||||
|
id: "test-price-discount",
|
||||||
|
region_id: null,
|
||||||
|
variant_id: "test-variant",
|
||||||
|
price_list: {
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
id: "pl",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
product: expect.any(Object),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it("sets additional prices correctly when querying a variant", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
const response = await api
|
||||||
|
.get("/store/variants/test-variant?cart_id=test-cart")
|
||||||
|
.catch((error) => console.log(error))
|
||||||
|
|
||||||
|
expect(response.data).toMatchSnapshot({
|
||||||
|
variant: {
|
||||||
|
id: "test-variant",
|
||||||
|
inventory_quantity: 10,
|
||||||
|
title: "Test variant",
|
||||||
|
sku: "test-sku",
|
||||||
|
ean: "test-ean",
|
||||||
|
upc: "test-upc",
|
||||||
|
barcode: "test-barcode",
|
||||||
|
product_id: "test-product",
|
||||||
|
allow_backorder: false,
|
||||||
|
created_at: expect.any(String),
|
||||||
|
deleted_at: null,
|
||||||
|
height: null,
|
||||||
|
hs_code: null,
|
||||||
|
length: null,
|
||||||
|
manage_inventory: true,
|
||||||
|
material: null,
|
||||||
|
metadata: null,
|
||||||
|
mid_code: null,
|
||||||
|
origin_country: null,
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
weight: null,
|
||||||
|
width: null,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
id: "test-variant-option",
|
||||||
|
value: "Default variant",
|
||||||
|
option_id: "test-option",
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
original_price: 100,
|
||||||
|
calculated_price: 80,
|
||||||
|
prices: [
|
||||||
|
{
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
amount: 100,
|
||||||
|
currency_code: "usd",
|
||||||
|
deleted_at: null,
|
||||||
|
id: "test-price",
|
||||||
|
region_id: null,
|
||||||
|
variant_id: "test-variant",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
amount: 80,
|
||||||
|
currency_code: "usd",
|
||||||
|
deleted_at: null,
|
||||||
|
price_list_id: "pl",
|
||||||
|
id: "test-price-discount",
|
||||||
|
region_id: null,
|
||||||
|
variant_id: "test-variant",
|
||||||
|
price_list: {
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
id: "pl",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
product: expect.any(Object),
|
product: expect.any(Object),
|
||||||
product_id: expect.any(String),
|
|
||||||
},
|
},
|
||||||
],
|
})
|
||||||
})
|
})
|
||||||
})
|
|
||||||
|
|
||||||
it("/test-variant", async () => {
|
it("lists by title", async () => {
|
||||||
const api = useApi()
|
const api = useApi()
|
||||||
|
|
||||||
const response = await api.get("/store/variants/test-variant")
|
const response = await api
|
||||||
|
.get(
|
||||||
|
"/store/variants?title[]=test1&title[]=test2&inventory_quantity[gt]=10"
|
||||||
|
)
|
||||||
|
.catch((err) => console.log(err))
|
||||||
|
|
||||||
expect(response.data).toMatchSnapshot({
|
expect(response.data).toMatchSnapshot({
|
||||||
variant: {
|
variants: [
|
||||||
allow_backorder: false,
|
|
||||||
barcode: "test-barcode",
|
|
||||||
created_at: expect.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,
|
|
||||||
origin_country: null,
|
|
||||||
product_id: "test-product",
|
|
||||||
sku: "test-sku",
|
|
||||||
title: "Test variant",
|
|
||||||
upc: "test-upc",
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
weight: null,
|
|
||||||
width: null,
|
|
||||||
options: [
|
|
||||||
{
|
{
|
||||||
|
id: expect.any(String),
|
||||||
|
title: "test2",
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
id: expect.any(String),
|
||||||
|
option_id: expect.any(String),
|
||||||
|
variant_id: expect.any(String),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
prices: [
|
||||||
|
{
|
||||||
|
id: expect.any(String),
|
||||||
|
variant_id: expect.any(String),
|
||||||
|
created_at: expect.any(String),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
product: expect.any(Object),
|
||||||
|
product_id: expect.any(String),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
prices: [
|
})
|
||||||
{
|
|
||||||
created_at: expect.any(String),
|
|
||||||
updated_at: expect.any(String),
|
|
||||||
amount: 100,
|
|
||||||
currency_code: "usd",
|
|
||||||
deleted_at: null,
|
|
||||||
id: "test-price",
|
|
||||||
region_id: null,
|
|
||||||
min_quantity: null,
|
|
||||||
max_quantity: null,
|
|
||||||
price_list_id: null,
|
|
||||||
variant_id: "test-variant",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
product: expect.any(Object),
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -1,4 +1,3 @@
|
|||||||
const { Product } = require("@medusajs/medusa")
|
|
||||||
const path = require("path")
|
const path = require("path")
|
||||||
const setupServer = require("../../../helpers/setup-server")
|
const setupServer = require("../../../helpers/setup-server")
|
||||||
const { useApi } = require("../../../helpers/use-api")
|
const { useApi } = require("../../../helpers/use-api")
|
||||||
@@ -201,17 +200,26 @@ describe("/store/products", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
expect(response.status).toEqual(200)
|
expect(response.status).toEqual(200)
|
||||||
|
expect(response.data.products.length).toEqual(5)
|
||||||
expect(response.data.products).toEqual([
|
expect(response.data.products).toEqual([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: "giftcard",
|
id: "test-product1",
|
||||||
|
collection_id: "test-collection",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-product",
|
||||||
|
collection_id: "test-collection",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-product_filtering_2",
|
||||||
|
collection_id: "test-collection2",
|
||||||
}),
|
}),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: "test-product_filtering_1",
|
id: "test-product_filtering_1",
|
||||||
collection_id: "test-collection1",
|
collection_id: "test-collection1",
|
||||||
}),
|
}),
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
id: "test-product_filtering_2",
|
id: "giftcard",
|
||||||
collection_id: "test-collection2",
|
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
|
|
||||||
@@ -223,12 +231,111 @@ describe("/store/products", () => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe("list params", () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
try {
|
||||||
|
await productSeeder(dbConnection)
|
||||||
|
await adminSeeder(dbConnection)
|
||||||
|
} catch (err) {
|
||||||
|
console.log(err)
|
||||||
|
throw err
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
const db = useDb()
|
||||||
|
await db.teardown()
|
||||||
|
})
|
||||||
|
|
||||||
|
it("Includes Additional prices when queried with a cart id", async () => {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
const response = await api
|
||||||
|
.get("/store/products?cart_id=test-cart")
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err)
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(response.data.products).toEqual([
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-product1",
|
||||||
|
collection_id: "test-collection",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-product",
|
||||||
|
collection_id: "test-collection",
|
||||||
|
variants: [
|
||||||
|
expect.objectContaining({
|
||||||
|
original_price: 100,
|
||||||
|
calculated_price: 80,
|
||||||
|
prices: [
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 100,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price-discount",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 80,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
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({
|
||||||
|
original_price: 100,
|
||||||
|
calculated_price: 80,
|
||||||
|
prices: [
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price1",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 100,
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-price1-discount",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 80,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-product_filtering_2",
|
||||||
|
collection_id: "test-collection2",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "test-product_filtering_1",
|
||||||
|
collection_id: "test-collection1",
|
||||||
|
}),
|
||||||
|
expect.objectContaining({
|
||||||
|
id: "giftcard",
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe("list params", () => {
|
describe("list params", () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
try {
|
try {
|
||||||
await adminSeeder(dbConnection)
|
await adminSeeder(dbConnection)
|
||||||
|
|
||||||
const p1 = await simpleProductFactory(
|
await simpleProductFactory(
|
||||||
dbConnection,
|
dbConnection,
|
||||||
{
|
{
|
||||||
title: "testprod",
|
title: "testprod",
|
||||||
@@ -238,7 +345,7 @@ describe("/store/products", () => {
|
|||||||
11
|
11
|
||||||
)
|
)
|
||||||
|
|
||||||
const p2 = await simpleProductFactory(
|
await simpleProductFactory(
|
||||||
dbConnection,
|
dbConnection,
|
||||||
{
|
{
|
||||||
title: "testprod3",
|
title: "testprod3",
|
||||||
@@ -332,6 +439,8 @@ describe("/store/products", () => {
|
|||||||
height: null,
|
height: null,
|
||||||
hs_code: null,
|
hs_code: null,
|
||||||
origin_country: null,
|
origin_country: null,
|
||||||
|
calculated_price: null,
|
||||||
|
original_price: null,
|
||||||
barcode: "test-barcode",
|
barcode: "test-barcode",
|
||||||
product_id: "test-product",
|
product_id: "test-product",
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
@@ -349,13 +458,30 @@ describe("/store/products", () => {
|
|||||||
amount: 100,
|
amount: 100,
|
||||||
currency_code: "usd",
|
currency_code: "usd",
|
||||||
deleted_at: null,
|
deleted_at: null,
|
||||||
id: "test-price",
|
|
||||||
region_id: null,
|
|
||||||
min_quantity: null,
|
min_quantity: null,
|
||||||
max_quantity: null,
|
max_quantity: null,
|
||||||
price_list_id: null,
|
price_list_id: null,
|
||||||
|
id: "test-price",
|
||||||
|
region_id: null,
|
||||||
variant_id: "test-variant",
|
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),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -375,6 +501,8 @@ describe("/store/products", () => {
|
|||||||
hs_code: null,
|
hs_code: null,
|
||||||
origin_country: null,
|
origin_country: null,
|
||||||
barcode: null,
|
barcode: null,
|
||||||
|
calculated_price: null,
|
||||||
|
original_price: null,
|
||||||
product_id: "test-product",
|
product_id: "test-product",
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
@@ -386,18 +514,33 @@ describe("/store/products", () => {
|
|||||||
],
|
],
|
||||||
prices: [
|
prices: [
|
||||||
{
|
{
|
||||||
|
id: "test-price2",
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
amount: 100,
|
amount: 100,
|
||||||
currency_code: "usd",
|
currency_code: "usd",
|
||||||
deleted_at: null,
|
|
||||||
id: "test-price2",
|
|
||||||
region_id: null,
|
|
||||||
min_quantity: null,
|
|
||||||
max_quantity: null,
|
|
||||||
price_list_id: null,
|
price_list_id: null,
|
||||||
|
deleted_at: null,
|
||||||
|
region_id: null,
|
||||||
variant_id: "test-variant_2",
|
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),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -416,6 +559,8 @@ describe("/store/products", () => {
|
|||||||
height: null,
|
height: null,
|
||||||
hs_code: null,
|
hs_code: null,
|
||||||
origin_country: null,
|
origin_country: null,
|
||||||
|
calculated_price: null,
|
||||||
|
original_price: null,
|
||||||
barcode: "test-barcode 1",
|
barcode: "test-barcode 1",
|
||||||
product_id: "test-product",
|
product_id: "test-product",
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
@@ -428,18 +573,35 @@ describe("/store/products", () => {
|
|||||||
],
|
],
|
||||||
prices: [
|
prices: [
|
||||||
{
|
{
|
||||||
|
id: "test-price1",
|
||||||
created_at: expect.any(String),
|
created_at: expect.any(String),
|
||||||
updated_at: expect.any(String),
|
updated_at: expect.any(String),
|
||||||
amount: 100,
|
amount: 100,
|
||||||
currency_code: "usd",
|
currency_code: "usd",
|
||||||
deleted_at: null,
|
|
||||||
id: "test-price1",
|
|
||||||
region_id: null,
|
|
||||||
min_quantity: null,
|
min_quantity: null,
|
||||||
max_quantity: null,
|
max_quantity: null,
|
||||||
price_list_id: null,
|
price_list_id: null,
|
||||||
|
deleted_at: null,
|
||||||
|
region_id: null,
|
||||||
variant_id: "test-variant_1",
|
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),
|
||||||
|
updated_at: expect.any(String),
|
||||||
|
},
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ const {
|
|||||||
LineItem,
|
LineItem,
|
||||||
Payment,
|
Payment,
|
||||||
PaymentSession,
|
PaymentSession,
|
||||||
|
CustomerGroup,
|
||||||
|
PriceList,
|
||||||
} = require("@medusajs/medusa")
|
} = require("@medusajs/medusa")
|
||||||
|
|
||||||
module.exports = async (connection, data = {}) => {
|
module.exports = async (connection, data = {}) => {
|
||||||
@@ -52,6 +54,8 @@ module.exports = async (connection, data = {}) => {
|
|||||||
tax_rate: 0,
|
tax_rate: 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
await manager.save(r)
|
||||||
|
|
||||||
// Region with multiple countries
|
// Region with multiple countries
|
||||||
const regionWithMultipleCoutries = manager.create(Region, {
|
const regionWithMultipleCoutries = manager.create(Region, {
|
||||||
id: "test-region-multiple",
|
id: "test-region-multiple",
|
||||||
@@ -240,7 +244,7 @@ module.exports = async (connection, data = {}) => {
|
|||||||
is_disabled: false,
|
is_disabled: false,
|
||||||
starts_at: tenDaysAgo,
|
starts_at: tenDaysAgo,
|
||||||
ends_at: tenDaysFromToday,
|
ends_at: tenDaysFromToday,
|
||||||
valid_duration: "P1M", //one month
|
valid_duration: "P1M", // one month
|
||||||
})
|
})
|
||||||
|
|
||||||
DynamicDiscount.regions = [r]
|
DynamicDiscount.regions = [r]
|
||||||
@@ -256,11 +260,21 @@ module.exports = async (connection, data = {}) => {
|
|||||||
email: "test@email.com",
|
email: "test@email.com",
|
||||||
})
|
})
|
||||||
|
|
||||||
await manager.insert(Customer, {
|
const c2 = await manager.create(Customer, {
|
||||||
id: "test-customer-2",
|
id: "test-customer-2",
|
||||||
email: "test-2@email.com",
|
email: "test-2@email.com",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const cg = await manager.create(CustomerGroup, {
|
||||||
|
id: "cgroup",
|
||||||
|
name: "customer group",
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(cg)
|
||||||
|
|
||||||
|
c2.groups = [cg]
|
||||||
|
await manager.save(c2)
|
||||||
|
|
||||||
await manager.insert(Customer, {
|
await manager.insert(Customer, {
|
||||||
id: "some-customer",
|
id: "some-customer",
|
||||||
email: "some-customer@email.com",
|
email: "some-customer@email.com",
|
||||||
@@ -299,6 +313,28 @@ module.exports = async (connection, data = {}) => {
|
|||||||
data: {},
|
data: {},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const priceList = await manager.create(PriceList, {
|
||||||
|
id: "pl",
|
||||||
|
name: "VIP winter sale",
|
||||||
|
description: "Winter sale for VIP customers.",
|
||||||
|
type: "sale",
|
||||||
|
status: "active",
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(priceList)
|
||||||
|
|
||||||
|
const priceList1 = await manager.create(PriceList, {
|
||||||
|
id: "pl_current",
|
||||||
|
name: "Past winter sale",
|
||||||
|
description: "Winter sale for key accounts.",
|
||||||
|
type: "sale",
|
||||||
|
status: "active",
|
||||||
|
starts_at: tenDaysAgo,
|
||||||
|
ends_at: tenDaysFromToday,
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(priceList1)
|
||||||
|
|
||||||
await manager.insert(Product, {
|
await manager.insert(Product, {
|
||||||
id: "giftcard-product",
|
id: "giftcard-product",
|
||||||
title: "Giftcard",
|
title: "Giftcard",
|
||||||
@@ -328,6 +364,32 @@ module.exports = async (connection, data = {}) => {
|
|||||||
options: [{ id: "test-option", title: "Size" }],
|
options: [{ id: "test-option", title: "Size" }],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
await manager.insert(ProductVariant, {
|
||||||
|
id: "test-variant-quantity",
|
||||||
|
title: "test variant",
|
||||||
|
product_id: "test-product",
|
||||||
|
inventory_quantity: 1000,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
option_id: "test-option",
|
||||||
|
value: "Size",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.insert(ProductVariant, {
|
||||||
|
id: "test-variant-sale",
|
||||||
|
title: "test variant",
|
||||||
|
product_id: "test-product",
|
||||||
|
inventory_quantity: 1000,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
option_id: "test-option",
|
||||||
|
value: "Size",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
await manager.insert(ProductVariant, {
|
await manager.insert(ProductVariant, {
|
||||||
id: "test-variant",
|
id: "test-variant",
|
||||||
title: "test variant",
|
title: "test variant",
|
||||||
@@ -357,14 +419,60 @@ module.exports = async (connection, data = {}) => {
|
|||||||
const ma = manager.create(MoneyAmount, {
|
const ma = manager.create(MoneyAmount, {
|
||||||
variant_id: "test-variant",
|
variant_id: "test-variant",
|
||||||
currency_code: "usd",
|
currency_code: "usd",
|
||||||
|
type: "default",
|
||||||
amount: 1000,
|
amount: 1000,
|
||||||
})
|
})
|
||||||
|
|
||||||
await manager.save(ma)
|
await manager.save(ma)
|
||||||
|
|
||||||
|
const ma_sale = manager.create(MoneyAmount, {
|
||||||
|
variant_id: "test-variant-sale",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 1000,
|
||||||
|
})
|
||||||
|
await manager.save(ma_sale)
|
||||||
|
|
||||||
|
const ma_sale_1 = manager.create(MoneyAmount, {
|
||||||
|
variant_id: "test-variant-sale",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 800,
|
||||||
|
price_list_id: "pl_current",
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(ma_sale_1)
|
||||||
|
|
||||||
|
const ma_quantity = manager.create(MoneyAmount, {
|
||||||
|
variant_id: "test-variant-quantity",
|
||||||
|
currency_code: "usd",
|
||||||
|
type: "default",
|
||||||
|
amount: 1000,
|
||||||
|
})
|
||||||
|
await manager.save(ma_quantity)
|
||||||
|
|
||||||
|
const ma_quantity_1 = manager.create(MoneyAmount, {
|
||||||
|
variant_id: "test-variant-quantity",
|
||||||
|
currency_code: "usd",
|
||||||
|
type: "sale",
|
||||||
|
min_quantity: 10,
|
||||||
|
max_quantity: 100,
|
||||||
|
amount: 800,
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(ma_quantity_1)
|
||||||
|
|
||||||
|
const ma_quantity_2 = manager.create(MoneyAmount, {
|
||||||
|
variant_id: "test-variant-quantity",
|
||||||
|
currency_code: "usd",
|
||||||
|
type: "sale",
|
||||||
|
min_quantity: 100,
|
||||||
|
amount: 700,
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(ma_quantity_2)
|
||||||
|
|
||||||
const ma2 = manager.create(MoneyAmount, {
|
const ma2 = manager.create(MoneyAmount, {
|
||||||
variant_id: "test-variant-2",
|
variant_id: "test-variant-2",
|
||||||
currency_code: "usd",
|
currency_code: "usd",
|
||||||
|
type: "default",
|
||||||
amount: 8000,
|
amount: 8000,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -373,6 +481,7 @@ module.exports = async (connection, data = {}) => {
|
|||||||
const ma3 = manager.create(MoneyAmount, {
|
const ma3 = manager.create(MoneyAmount, {
|
||||||
variant_id: "giftcard-denom",
|
variant_id: "giftcard-denom",
|
||||||
currency_code: "usd",
|
currency_code: "usd",
|
||||||
|
type: "default",
|
||||||
amount: 1000,
|
amount: 1000,
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -533,4 +642,67 @@ module.exports = async (connection, data = {}) => {
|
|||||||
cart_id: "test-cart-3",
|
cart_id: "test-cart-3",
|
||||||
})
|
})
|
||||||
await manager.save(li2)
|
await manager.save(li2)
|
||||||
|
|
||||||
|
const cart4 = manager.create(Cart, {
|
||||||
|
id: "test-cart-3",
|
||||||
|
email: "some-customer@email.com",
|
||||||
|
shipping_address: {
|
||||||
|
id: "test-shipping-address",
|
||||||
|
first_name: "lebron",
|
||||||
|
country_code: "us",
|
||||||
|
},
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
completed_at: null,
|
||||||
|
items: [],
|
||||||
|
})
|
||||||
|
await manager.save(cart4)
|
||||||
|
|
||||||
|
await manager.insert(ProductVariant, {
|
||||||
|
id: "test-variant-sale-cg",
|
||||||
|
title: "test variant",
|
||||||
|
product_id: "test-product",
|
||||||
|
inventory_quantity: 1000,
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
option_id: "test-option",
|
||||||
|
value: "Size",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
const ma_cg = manager.create(MoneyAmount, {
|
||||||
|
variant_id: "test-variant-sale-cg",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 1000,
|
||||||
|
})
|
||||||
|
await manager.save(ma_cg)
|
||||||
|
|
||||||
|
const ma_sale_cg = manager.create(MoneyAmount, {
|
||||||
|
variant_id: "test-variant-sale-cg",
|
||||||
|
currency_code: "usd",
|
||||||
|
price_list_id: "pl",
|
||||||
|
amount: 500,
|
||||||
|
})
|
||||||
|
await manager.save(ma_sale_cg)
|
||||||
|
|
||||||
|
const ma_sale_cg_new_region = manager.create(MoneyAmount, {
|
||||||
|
variant_id: "test-variant-sale-cg",
|
||||||
|
region_id: "test-region-multiple",
|
||||||
|
currency_code: "eur",
|
||||||
|
amount: 700,
|
||||||
|
})
|
||||||
|
await manager.save(ma_sale_cg_new_region)
|
||||||
|
|
||||||
|
const li3 = await manager.create(LineItem, {
|
||||||
|
id: "test-item3",
|
||||||
|
title: "Line Item",
|
||||||
|
description: "Line Item Desc",
|
||||||
|
thumbnail: "https://test.js/1234",
|
||||||
|
unit_price: 8000,
|
||||||
|
quantity: 1,
|
||||||
|
variant_id: "test-variant-sale-cg",
|
||||||
|
cart_id: "test-cart-3",
|
||||||
|
})
|
||||||
|
await manager.save(li3)
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,883 @@
|
|||||||
|
const {
|
||||||
|
Customer,
|
||||||
|
CustomerGroup,
|
||||||
|
ShippingProfile,
|
||||||
|
Product,
|
||||||
|
ProductVariant,
|
||||||
|
ProductCollection,
|
||||||
|
ProductOption,
|
||||||
|
Region,
|
||||||
|
Cart,
|
||||||
|
PriceList,
|
||||||
|
} = require("@medusajs/medusa")
|
||||||
|
|
||||||
|
module.exports = async (connection, data = {}) => {
|
||||||
|
const yesterday = ((today) => new Date(today.setDate(today.getDate() - 1)))(
|
||||||
|
new Date()
|
||||||
|
)
|
||||||
|
const tomorrow = ((today) => new Date(today.setDate(today.getDate() + 1)))(
|
||||||
|
new Date()
|
||||||
|
)
|
||||||
|
const tenDaysAgo = ((today) => new Date(today.setDate(today.getDate() - 10)))(
|
||||||
|
new Date()
|
||||||
|
)
|
||||||
|
const tenDaysFromToday = ((today) =>
|
||||||
|
new Date(today.setDate(today.getDate() + 10)))(new Date())
|
||||||
|
|
||||||
|
const manager = connection.manager
|
||||||
|
|
||||||
|
const defaultProfile = await manager.findOne(ShippingProfile, {
|
||||||
|
type: "default",
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.insert(Region, {
|
||||||
|
id: "test-region",
|
||||||
|
name: "Test Region",
|
||||||
|
currency_code: "usd",
|
||||||
|
tax_rate: 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.insert(Region, {
|
||||||
|
id: "test-region-1",
|
||||||
|
name: "Test Region no prices",
|
||||||
|
currency_code: "usd",
|
||||||
|
tax_rate: 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.insert(Region, {
|
||||||
|
id: "test-region-2",
|
||||||
|
name: "Test Region no prices",
|
||||||
|
currency_code: "dkk",
|
||||||
|
tax_rate: 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
const coll = manager.create(ProductCollection, {
|
||||||
|
id: "test-collection",
|
||||||
|
handle: "test-collection",
|
||||||
|
title: "Test collection",
|
||||||
|
})
|
||||||
|
await manager.save(coll)
|
||||||
|
|
||||||
|
const customer5 = await manager.create(Customer, {
|
||||||
|
id: "test-customer-5",
|
||||||
|
email: "test5@email.com",
|
||||||
|
first_name: "John",
|
||||||
|
last_name: "Deere",
|
||||||
|
password_hash:
|
||||||
|
"c2NyeXB0AAEAAAABAAAAAVMdaddoGjwU1TafDLLlBKnOTQga7P2dbrfgf3fB+rCD/cJOMuGzAvRdKutbYkVpuJWTU39P7OpuWNkUVoEETOVLMJafbI8qs8Qx/7jMQXkN", // password matching "test"
|
||||||
|
has_account: true,
|
||||||
|
})
|
||||||
|
await manager.save(customer5)
|
||||||
|
|
||||||
|
const customer6 = await manager.create(Customer, {
|
||||||
|
id: "test-customer-6",
|
||||||
|
password_hash:
|
||||||
|
"c2NyeXB0AAEAAAABAAAAAVMdaddoGjwU1TafDLLlBKnOTQga7P2dbrfgf3fB+rCD/cJOMuGzAvRdKutbYkVpuJWTU39P7OpuWNkUVoEETOVLMJafbI8qs8Qx/7jMQXkN", // password matching "test"
|
||||||
|
email: "test6@email.com",
|
||||||
|
has_account: true,
|
||||||
|
})
|
||||||
|
await manager.save(customer6)
|
||||||
|
|
||||||
|
const customer7 = await manager.create(Customer, {
|
||||||
|
id: "test-customer-7",
|
||||||
|
password_hash:
|
||||||
|
"c2NyeXB0AAEAAAABAAAAAVMdaddoGjwU1TafDLLlBKnOTQga7P2dbrfgf3fB+rCD/cJOMuGzAvRdKutbYkVpuJWTU39P7OpuWNkUVoEETOVLMJafbI8qs8Qx/7jMQXkN", // password matching "test"
|
||||||
|
email: "test7@email.com",
|
||||||
|
has_account: true,
|
||||||
|
})
|
||||||
|
await manager.save(customer7)
|
||||||
|
|
||||||
|
const c_group_5 = await manager.create(CustomerGroup, {
|
||||||
|
id: "test-group-5",
|
||||||
|
name: "test-group-5",
|
||||||
|
})
|
||||||
|
await manager.save(c_group_5)
|
||||||
|
|
||||||
|
const c_group_6 = await manager.create(CustomerGroup, {
|
||||||
|
id: "test-group-6",
|
||||||
|
name: "test-group-6",
|
||||||
|
})
|
||||||
|
await manager.save(c_group_6)
|
||||||
|
|
||||||
|
customer5.groups = [c_group_5]
|
||||||
|
await manager.save(customer5)
|
||||||
|
|
||||||
|
customer6.groups = [c_group_6]
|
||||||
|
await manager.save(customer6)
|
||||||
|
|
||||||
|
customer7.groups = [c_group_5, c_group_6]
|
||||||
|
await manager.save(customer7)
|
||||||
|
|
||||||
|
const priceList = await manager.create(PriceList, {
|
||||||
|
id: "pl",
|
||||||
|
name: "VIP winter sale",
|
||||||
|
description: "Winter sale for VIP customers.",
|
||||||
|
type: "sale",
|
||||||
|
status: "active",
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(priceList)
|
||||||
|
|
||||||
|
const priceList1 = await manager.create(PriceList, {
|
||||||
|
id: "pl_1",
|
||||||
|
name: "VIP winter sale",
|
||||||
|
description: "Winter sale for VIP customers.",
|
||||||
|
type: "sale",
|
||||||
|
status: "active",
|
||||||
|
})
|
||||||
|
|
||||||
|
priceList1.customer_groups = [c_group_5]
|
||||||
|
|
||||||
|
await manager.save(priceList1)
|
||||||
|
|
||||||
|
const priceList2 = await manager.create(PriceList, {
|
||||||
|
id: "pl_2",
|
||||||
|
name: "VVIP winter sale",
|
||||||
|
description: "Winter sale for key accounts.",
|
||||||
|
type: "sale",
|
||||||
|
status: "active",
|
||||||
|
})
|
||||||
|
|
||||||
|
priceList2.customer_groups = [c_group_6]
|
||||||
|
|
||||||
|
await manager.save(priceList2)
|
||||||
|
|
||||||
|
const priceList3 = await manager.create(PriceList, {
|
||||||
|
id: "pl_expired",
|
||||||
|
name: "Past winter sale",
|
||||||
|
description: "Winter sale for key accounts.",
|
||||||
|
type: "sale",
|
||||||
|
status: "active",
|
||||||
|
starts_at: tenDaysAgo,
|
||||||
|
ends_at: yesterday,
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(priceList3)
|
||||||
|
|
||||||
|
const priceList4 = await manager.create(PriceList, {
|
||||||
|
id: "pl_upcoming",
|
||||||
|
name: "Past winter sale",
|
||||||
|
description: "Winter sale for key accounts.",
|
||||||
|
type: "sale",
|
||||||
|
status: "active",
|
||||||
|
starts_at: tomorrow,
|
||||||
|
ends_at: tenDaysFromToday,
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(priceList4)
|
||||||
|
|
||||||
|
const priceList5 = await manager.create(PriceList, {
|
||||||
|
id: "pl_current",
|
||||||
|
name: "Past winter sale",
|
||||||
|
description: "Winter sale for key accounts.",
|
||||||
|
type: "sale",
|
||||||
|
status: "active",
|
||||||
|
starts_at: tenDaysAgo,
|
||||||
|
ends_at: tenDaysFromToday,
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(priceList5)
|
||||||
|
|
||||||
|
const priceList6 = await manager.create(PriceList, {
|
||||||
|
id: "pl_current_1",
|
||||||
|
name: "Past winter sale",
|
||||||
|
description: "Winter sale for key accounts.",
|
||||||
|
type: "sale",
|
||||||
|
status: "active",
|
||||||
|
starts_at: tenDaysAgo,
|
||||||
|
ends_at: tomorrow,
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(priceList6)
|
||||||
|
|
||||||
|
const priceList7 = await manager.create(PriceList, {
|
||||||
|
id: "pl_upcoming-customer",
|
||||||
|
name: "Past winter sale",
|
||||||
|
description: "Winter sale for key accounts.",
|
||||||
|
type: "sale",
|
||||||
|
status: "active",
|
||||||
|
starts_at: tomorrow,
|
||||||
|
ends_at: tenDaysFromToday,
|
||||||
|
})
|
||||||
|
|
||||||
|
priceList7.customer_groups = [c_group_5]
|
||||||
|
|
||||||
|
await manager.save(priceList7)
|
||||||
|
|
||||||
|
const priceList8 = await manager.create(PriceList, {
|
||||||
|
id: "pl_current-customer",
|
||||||
|
name: "Past winter sale",
|
||||||
|
description: "Winter sale for key accounts.",
|
||||||
|
type: "sale",
|
||||||
|
status: "active",
|
||||||
|
starts_at: tenDaysAgo,
|
||||||
|
ends_at: tenDaysFromToday,
|
||||||
|
})
|
||||||
|
|
||||||
|
priceList8.customer_groups = [c_group_5]
|
||||||
|
|
||||||
|
await manager.save(priceList8)
|
||||||
|
|
||||||
|
const priceList9 = await manager.create(PriceList, {
|
||||||
|
id: "pl_expired-customer",
|
||||||
|
name: "Past winter sale",
|
||||||
|
description: "Winter sale for key accounts.",
|
||||||
|
type: "sale",
|
||||||
|
status: "active",
|
||||||
|
starts_at: tenDaysAgo,
|
||||||
|
ends_at: yesterday,
|
||||||
|
})
|
||||||
|
|
||||||
|
priceList9.customer_groups = [c_group_5]
|
||||||
|
|
||||||
|
await manager.save(priceList9)
|
||||||
|
|
||||||
|
const p1 = await manager.create(Product, {
|
||||||
|
id: "test-product",
|
||||||
|
handle: "test-product",
|
||||||
|
title: "Test product",
|
||||||
|
profile_id: defaultProfile.id,
|
||||||
|
description: "test-product-description1",
|
||||||
|
collection_id: "test-collection",
|
||||||
|
tags: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(p1)
|
||||||
|
|
||||||
|
await manager.save(ProductOption, {
|
||||||
|
id: "test-option",
|
||||||
|
title: "test-option",
|
||||||
|
product_id: "test-product",
|
||||||
|
})
|
||||||
|
|
||||||
|
const variant4 = await manager.create(ProductVariant, {
|
||||||
|
id: "test-variant",
|
||||||
|
inventory_quantity: 10,
|
||||||
|
title: "Test variant",
|
||||||
|
sku: "test-sku",
|
||||||
|
ean: "test-ean",
|
||||||
|
status: "published",
|
||||||
|
upc: "test-upc",
|
||||||
|
product_id: "test-product",
|
||||||
|
prices: [
|
||||||
|
{
|
||||||
|
id: "test-price",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 100,
|
||||||
|
price_list_id: "pl_1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price1",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price2",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 130,
|
||||||
|
price_list_id: "pl_2",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price3",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 110,
|
||||||
|
price_list_id: "pl",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
id: "test-variant-option",
|
||||||
|
value: "Default variant",
|
||||||
|
option_id: "test-option",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(variant4)
|
||||||
|
|
||||||
|
const p2 = await manager.create(Product, {
|
||||||
|
id: "test-product-quantity",
|
||||||
|
handle: "test-product-quantity",
|
||||||
|
title: "Test product",
|
||||||
|
profile_id: defaultProfile.id,
|
||||||
|
description: "test-product-description1",
|
||||||
|
collection_id: "test-collection",
|
||||||
|
tags: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(p2)
|
||||||
|
|
||||||
|
await manager.save(ProductOption, {
|
||||||
|
id: "test-option",
|
||||||
|
title: "test-option",
|
||||||
|
product_id: "test-product-quantity",
|
||||||
|
})
|
||||||
|
|
||||||
|
const variant_quantity = await manager.create(ProductVariant, {
|
||||||
|
id: "test-variant-quantity",
|
||||||
|
inventory_quantity: 10,
|
||||||
|
title: "Test variant",
|
||||||
|
sku: "test-sku-quantity",
|
||||||
|
ean: "test-ean-quantity",
|
||||||
|
status: "published",
|
||||||
|
upc: "test-upc-quantity",
|
||||||
|
product_id: "test-product-quantity",
|
||||||
|
prices: [
|
||||||
|
{
|
||||||
|
id: "test-price-quantity",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 100,
|
||||||
|
price_list_id: "pl",
|
||||||
|
min_quantity: 10,
|
||||||
|
max_quantity: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price1-quantity",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 120,
|
||||||
|
price_list_id: "pl",
|
||||||
|
min_quantity: 101,
|
||||||
|
max_quantity: 1000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price1-quantity-group",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 120,
|
||||||
|
min_quantity: 101,
|
||||||
|
max_quantity: 1000,
|
||||||
|
price_list_id: "pl_1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price2-quantity",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 130,
|
||||||
|
price_list_id: "pl",
|
||||||
|
max_quantity: 9,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price3-quantity-expired",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 120,
|
||||||
|
min_quantity: 101,
|
||||||
|
max_quantity: 1000,
|
||||||
|
price_list_id: "pl_expired",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price3-quantity-future",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 120,
|
||||||
|
min_quantity: 101,
|
||||||
|
max_quantity: 1000,
|
||||||
|
price_list_id: "pl_upcoming",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price3-quantity-now",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 140,
|
||||||
|
min_quantity: 101,
|
||||||
|
max_quantity: 1000,
|
||||||
|
price_list_id: "pl_current",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price3-quantity-default",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 150,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
id: "test-variant-option",
|
||||||
|
value: "Default variant",
|
||||||
|
option_id: "test-option",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(variant_quantity)
|
||||||
|
|
||||||
|
const p3 = await manager.create(Product, {
|
||||||
|
id: "test-product-sale",
|
||||||
|
handle: "test-product-sale",
|
||||||
|
title: "Test product sale",
|
||||||
|
profile_id: defaultProfile.id,
|
||||||
|
description: "test-product-description1",
|
||||||
|
collection_id: "test-collection",
|
||||||
|
tags: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(p3)
|
||||||
|
|
||||||
|
await manager.save(ProductOption, {
|
||||||
|
id: "test-option-sale",
|
||||||
|
title: "test-option sale",
|
||||||
|
product_id: "test-product-sale",
|
||||||
|
})
|
||||||
|
|
||||||
|
const variant_sale = await manager.create(ProductVariant, {
|
||||||
|
id: "test-variant-sale",
|
||||||
|
inventory_quantity: 10,
|
||||||
|
title: "Test variant",
|
||||||
|
sku: "test-sku-sale",
|
||||||
|
ean: "test-ean-sale",
|
||||||
|
status: "published",
|
||||||
|
upc: "test-upc-sale",
|
||||||
|
product_id: "test-product-sale",
|
||||||
|
prices: [
|
||||||
|
{
|
||||||
|
id: "test-price-sale",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 100,
|
||||||
|
price_list_id: "pl_expired",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price1-sale",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 120,
|
||||||
|
price_list_id: "pl_current",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price2-sale",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 130,
|
||||||
|
price_list_id: "pl_upcoming",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price2-sale-default",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 150,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
id: "test-variant-option",
|
||||||
|
value: "Default variant",
|
||||||
|
option_id: "test-option",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(variant_sale)
|
||||||
|
|
||||||
|
const p4 = await manager.create(Product, {
|
||||||
|
id: "test-product-sale-overlap",
|
||||||
|
handle: "test-product-sale-overlap",
|
||||||
|
title: "Test product sale",
|
||||||
|
profile_id: defaultProfile.id,
|
||||||
|
description: "test-product-description1",
|
||||||
|
collection_id: "test-collection",
|
||||||
|
tags: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(p4)
|
||||||
|
|
||||||
|
await manager.save(ProductOption, {
|
||||||
|
id: "test-option-sale-overlap",
|
||||||
|
title: "test-option sale",
|
||||||
|
product_id: "test-product-sale-overlap",
|
||||||
|
})
|
||||||
|
|
||||||
|
const variant_sale_overlap = await manager.create(ProductVariant, {
|
||||||
|
id: "test-variant-sale-overlap",
|
||||||
|
inventory_quantity: 10,
|
||||||
|
title: "Test variant",
|
||||||
|
sku: "test-sku-sale-overlap",
|
||||||
|
ean: "test-ean-sale-overlap",
|
||||||
|
status: "published",
|
||||||
|
upc: "test-upc-sale-overlap",
|
||||||
|
product_id: "test-product-sale-overlap",
|
||||||
|
prices: [
|
||||||
|
{
|
||||||
|
id: "test-price-sale-overlap-1",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 140,
|
||||||
|
price_list_id: "pl_current_1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price1-sale-overlap",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 120,
|
||||||
|
price_list_id: "pl_current",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price2-sale-overlap-default",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 150,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
id: "test-variant-option-overlap",
|
||||||
|
value: "Default variant",
|
||||||
|
option_id: "test-option-sale-overlap",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(variant_sale_overlap)
|
||||||
|
|
||||||
|
const multiRegionProduct = await manager.create(Product, {
|
||||||
|
id: "test-product-multi-region",
|
||||||
|
handle: "test-product-multi-region",
|
||||||
|
title: "Test product",
|
||||||
|
profile_id: defaultProfile.id,
|
||||||
|
description: "test-product-multi-region-description1",
|
||||||
|
collection_id: "test-collection",
|
||||||
|
tags: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(multiRegionProduct)
|
||||||
|
|
||||||
|
await manager.save(ProductOption, {
|
||||||
|
id: "test-option-multi-region",
|
||||||
|
title: "test-option",
|
||||||
|
product_id: "test-product-multi-region",
|
||||||
|
})
|
||||||
|
|
||||||
|
const variant_multi_region = await manager.create(ProductVariant, {
|
||||||
|
id: "test-variant-multi-region",
|
||||||
|
inventory_quantity: 10,
|
||||||
|
title: "Test variant",
|
||||||
|
sku: "test-sku-multi-region",
|
||||||
|
ean: "test-ean-multi-region",
|
||||||
|
status: "published",
|
||||||
|
upc: "test-upc-multi-region",
|
||||||
|
product_id: "test-product-multi-region",
|
||||||
|
prices: [
|
||||||
|
{
|
||||||
|
id: "test-price-region-1",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 100,
|
||||||
|
price_list_id: "pl",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price1-region-1",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 120,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price1-region-2",
|
||||||
|
region_id: "test-region-2",
|
||||||
|
currency_code: "dkk",
|
||||||
|
amount: 130,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price3-region-2",
|
||||||
|
region_id: "test-region-2",
|
||||||
|
currency_code: "dkk",
|
||||||
|
price_list_id: "pl",
|
||||||
|
amount: 110,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
id: "test-variant-option-multi-region",
|
||||||
|
value: "Default variant",
|
||||||
|
option_id: "test-option-multi-region",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(variant_multi_region)
|
||||||
|
|
||||||
|
const p5 = await manager.create(Product, {
|
||||||
|
id: "test-product-quantity-customer",
|
||||||
|
handle: "test-product-quantity-customer",
|
||||||
|
title: "Test product",
|
||||||
|
profile_id: defaultProfile.id,
|
||||||
|
description: "test-product-description1",
|
||||||
|
collection_id: "test-collection",
|
||||||
|
tags: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(p5)
|
||||||
|
|
||||||
|
await manager.save(ProductOption, {
|
||||||
|
id: "test-option-quantity-customer",
|
||||||
|
title: "test-option",
|
||||||
|
product_id: "test-product-quantity-customer",
|
||||||
|
})
|
||||||
|
|
||||||
|
const variant_quantity_customer = await manager.create(ProductVariant, {
|
||||||
|
id: "test-variant-quantity-customer",
|
||||||
|
inventory_quantity: 10,
|
||||||
|
title: "Test variant",
|
||||||
|
sku: "test-sku-quantity-customer",
|
||||||
|
ean: "test-ean-quantity-customer",
|
||||||
|
status: "published",
|
||||||
|
upc: "test-upc-quantity-customer",
|
||||||
|
product_id: "test-product-quantity-customer",
|
||||||
|
prices: [
|
||||||
|
{
|
||||||
|
id: "test-price-quantity-customer",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 100,
|
||||||
|
price_list_id: "pl",
|
||||||
|
min_quantity: 10,
|
||||||
|
max_quantity: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price1-quantity-customer",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 120,
|
||||||
|
price_list_id: "pl",
|
||||||
|
min_quantity: 101,
|
||||||
|
max_quantity: 1000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price2-quantity-customer",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 130,
|
||||||
|
price_list_id: "pl",
|
||||||
|
max_quantity: 9,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price2-quantity-customer-group",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 100,
|
||||||
|
max_quantity: 9,
|
||||||
|
price_list_id: "pl_1",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price3-quantity-customer-expired",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 120,
|
||||||
|
min_quantity: 101,
|
||||||
|
max_quantity: 1000,
|
||||||
|
price_list_id: "pl_expired",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price3-quantity-customer-future",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 120,
|
||||||
|
min_quantity: 101,
|
||||||
|
max_quantity: 1000,
|
||||||
|
price_list_id: "pl_upcoming",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price3-quantity-customer-now",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 140,
|
||||||
|
min_quantity: 101,
|
||||||
|
max_quantity: 1000,
|
||||||
|
price_list_id: "pl_current",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price3-quantity-customer-default",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 150,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
id: "test-variant-option",
|
||||||
|
value: "Default variant",
|
||||||
|
option_id: "test-option-quantity-customer",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(variant_quantity_customer)
|
||||||
|
|
||||||
|
const p6 = await manager.create(Product, {
|
||||||
|
id: "test-product-sale-customer",
|
||||||
|
handle: "test-product-sale-customer",
|
||||||
|
title: "Test product sale",
|
||||||
|
profile_id: defaultProfile.id,
|
||||||
|
description: "test-product-description1",
|
||||||
|
collection_id: "test-collection",
|
||||||
|
tags: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(p6)
|
||||||
|
|
||||||
|
await manager.save(ProductOption, {
|
||||||
|
id: "test-option-sale",
|
||||||
|
title: "test-option sale",
|
||||||
|
product_id: "test-product-sale-customer",
|
||||||
|
})
|
||||||
|
|
||||||
|
const variant_sale_customer = await manager.create(ProductVariant, {
|
||||||
|
id: "test-variant-sale-customer",
|
||||||
|
inventory_quantity: 10,
|
||||||
|
title: "Test variant",
|
||||||
|
sku: "test-sku-sale-customer",
|
||||||
|
ean: "test-ean-sale-customer",
|
||||||
|
status: "published",
|
||||||
|
upc: "test-upc-sale-customer",
|
||||||
|
product_id: "test-product-sale-customer",
|
||||||
|
prices: [
|
||||||
|
{
|
||||||
|
id: "test-price-sale-customer",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 120,
|
||||||
|
price_list_id: "pl_expired-customer",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price1-sale-customer",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 100,
|
||||||
|
price_list_id: "pl_current-customer",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price2-sale-customer",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 130,
|
||||||
|
price_list_id: "pl_upcoming-customer",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price2-sale-customer-default",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 150,
|
||||||
|
type: "default",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
id: "test-variant-option",
|
||||||
|
value: "Default variant",
|
||||||
|
option_id: "test-option",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(variant_sale_customer)
|
||||||
|
|
||||||
|
const p7 = await manager.create(Product, {
|
||||||
|
id: "test-product-sale-customer-quantity",
|
||||||
|
handle: "test-product-sale-customer-quantity",
|
||||||
|
title: "Test product sale",
|
||||||
|
profile_id: defaultProfile.id,
|
||||||
|
description: "test-product-description1",
|
||||||
|
collection_id: "test-collection",
|
||||||
|
tags: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(p7)
|
||||||
|
|
||||||
|
await manager.save(ProductOption, {
|
||||||
|
id: "test-option-sale",
|
||||||
|
title: "test-option sale",
|
||||||
|
product_id: "test-product-sale-customer-quantity",
|
||||||
|
})
|
||||||
|
|
||||||
|
const variant_sale_customer_quantity = await manager.create(ProductVariant, {
|
||||||
|
id: "test-variant-sale-customer-quantity",
|
||||||
|
inventory_quantity: 10,
|
||||||
|
title: "Test variant",
|
||||||
|
sku: "test-sku-sale-customer-quantity",
|
||||||
|
ean: "test-ean-sale-customer-quantity",
|
||||||
|
status: "published",
|
||||||
|
upc: "test-upc-sale-customer-quantity",
|
||||||
|
product_id: "test-product-sale-customer-quantity",
|
||||||
|
prices: [
|
||||||
|
{
|
||||||
|
id: "test-price-sale-customer-quantity",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 120,
|
||||||
|
min_quantity: 100,
|
||||||
|
max_quantity: 1000,
|
||||||
|
price_list_id: "pl_expired-customer",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price1-sale-customer-quantity-groups",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 100,
|
||||||
|
max_quantity: 99,
|
||||||
|
price_list_id: "pl_current-customer",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price2-sale-customer-quantity",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 130,
|
||||||
|
min_quantity: 500,
|
||||||
|
max_quantity: 900,
|
||||||
|
price_list_id: "pl_upcoming-customer",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price2-sale-customer-quantity-default",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 150,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price1-sale-customer-quantity",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 110,
|
||||||
|
max_quantity: 99,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
id: "test-variant-option",
|
||||||
|
value: "Default variant",
|
||||||
|
option_id: "test-option",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(variant_sale_customer_quantity)
|
||||||
|
|
||||||
|
const cart = await manager.create(Cart, {
|
||||||
|
id: "test-cart",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
items: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(cart)
|
||||||
|
|
||||||
|
const cart_region2 = await manager.create(Cart, {
|
||||||
|
id: "test-cart-1",
|
||||||
|
region_id: "test-region-2",
|
||||||
|
currency_code: "dkk",
|
||||||
|
items: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(cart_region2)
|
||||||
|
|
||||||
|
const cart_region1 = await manager.create(Cart, {
|
||||||
|
id: "test-cart-2",
|
||||||
|
region_id: "test-region-1",
|
||||||
|
currency_code: "usd",
|
||||||
|
items: [],
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(cart_region1)
|
||||||
|
}
|
||||||
@@ -17,7 +17,7 @@ module.exports = async (connection, data = {}) => {
|
|||||||
type: "default",
|
type: "default",
|
||||||
})
|
})
|
||||||
|
|
||||||
const coll = manager.create(ProductCollection, {
|
const coll = await manager.create(ProductCollection, {
|
||||||
id: "test-collection",
|
id: "test-collection",
|
||||||
handle: "test-collection",
|
handle: "test-collection",
|
||||||
title: "Test collection",
|
title: "Test collection",
|
||||||
@@ -25,7 +25,7 @@ module.exports = async (connection, data = {}) => {
|
|||||||
|
|
||||||
await manager.save(coll)
|
await manager.save(coll)
|
||||||
|
|
||||||
const coll1 = manager.create(ProductCollection, {
|
const coll1 = await manager.create(ProductCollection, {
|
||||||
id: "test-collection1",
|
id: "test-collection1",
|
||||||
handle: "test-collection1",
|
handle: "test-collection1",
|
||||||
title: "Test collection 1",
|
title: "Test collection 1",
|
||||||
@@ -33,7 +33,7 @@ module.exports = async (connection, data = {}) => {
|
|||||||
|
|
||||||
await manager.save(coll1)
|
await manager.save(coll1)
|
||||||
|
|
||||||
const coll2 = manager.create(ProductCollection, {
|
const coll2 = await manager.create(ProductCollection, {
|
||||||
id: "test-collection2",
|
id: "test-collection2",
|
||||||
handle: "test-collection2",
|
handle: "test-collection2",
|
||||||
title: "Test collection 2",
|
title: "Test collection 2",
|
||||||
@@ -41,28 +41,28 @@ module.exports = async (connection, data = {}) => {
|
|||||||
|
|
||||||
await manager.save(coll2)
|
await manager.save(coll2)
|
||||||
|
|
||||||
const tag = manager.create(ProductTag, {
|
const tag = await manager.create(ProductTag, {
|
||||||
id: "tag1",
|
id: "tag1",
|
||||||
value: "123",
|
value: "123",
|
||||||
})
|
})
|
||||||
|
|
||||||
await manager.save(tag)
|
await manager.save(tag)
|
||||||
|
|
||||||
const tag3 = manager.create(ProductTag, {
|
const tag3 = await manager.create(ProductTag, {
|
||||||
id: "tag3",
|
id: "tag3",
|
||||||
value: "123",
|
value: "123",
|
||||||
})
|
})
|
||||||
|
|
||||||
await manager.save(tag3)
|
await manager.save(tag3)
|
||||||
|
|
||||||
const tag4 = manager.create(ProductTag, {
|
const tag4 = await manager.create(ProductTag, {
|
||||||
id: "tag4",
|
id: "tag4",
|
||||||
value: "123",
|
value: "123",
|
||||||
})
|
})
|
||||||
|
|
||||||
await manager.save(tag4)
|
await manager.save(tag4)
|
||||||
|
|
||||||
const type = manager.create(ProductType, {
|
const type = await manager.create(ProductType, {
|
||||||
id: "test-type",
|
id: "test-type",
|
||||||
value: "test-type",
|
value: "test-type",
|
||||||
})
|
})
|
||||||
@@ -83,7 +83,7 @@ module.exports = async (connection, data = {}) => {
|
|||||||
tax_rate: 0,
|
tax_rate: 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
const p = manager.create(Product, {
|
const p = await manager.create(Product, {
|
||||||
id: "test-product",
|
id: "test-product",
|
||||||
handle: "test-product",
|
handle: "test-product",
|
||||||
title: "Test product",
|
title: "Test product",
|
||||||
@@ -129,6 +129,34 @@ module.exports = async (connection, data = {}) => {
|
|||||||
|
|
||||||
await manager.save(variant1)
|
await manager.save(variant1)
|
||||||
|
|
||||||
|
const sale = await manager.create(ProductVariant, {
|
||||||
|
id: "test-variant-sale",
|
||||||
|
inventory_quantity: 10,
|
||||||
|
title: "Test variant",
|
||||||
|
variant_rank: 3,
|
||||||
|
sku: "test-sku-sale",
|
||||||
|
ean: "test-ean-sale",
|
||||||
|
upc: "test-upc-sale",
|
||||||
|
barcode: "test-barcode-sale",
|
||||||
|
product_id: "test-product",
|
||||||
|
prices: [
|
||||||
|
{
|
||||||
|
id: "test-price-sale",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 1000,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
id: "test-variant-option-sale",
|
||||||
|
value: "Default variant",
|
||||||
|
option_id: "test-option",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(sale)
|
||||||
|
|
||||||
const variant2 = await manager.create(ProductVariant, {
|
const variant2 = await manager.create(ProductVariant, {
|
||||||
id: "test-variant_1",
|
id: "test-variant_1",
|
||||||
inventory_quantity: 10,
|
inventory_quantity: 10,
|
||||||
@@ -172,7 +200,7 @@ module.exports = async (connection, data = {}) => {
|
|||||||
|
|
||||||
await manager.save(variant3)
|
await manager.save(variant3)
|
||||||
|
|
||||||
const p1 = manager.create(Product, {
|
const p1 = await manager.create(Product, {
|
||||||
id: "test-product1",
|
id: "test-product1",
|
||||||
handle: "test-product1",
|
handle: "test-product1",
|
||||||
title: "Test product1",
|
title: "Test product1",
|
||||||
@@ -203,6 +231,7 @@ module.exports = async (connection, data = {}) => {
|
|||||||
region_id: "test-region",
|
region_id: "test-region",
|
||||||
currency_code: "usd",
|
currency_code: "usd",
|
||||||
amount: 100,
|
amount: 100,
|
||||||
|
type: "default",
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
options: [
|
options: [
|
||||||
@@ -225,7 +254,9 @@ module.exports = async (connection, data = {}) => {
|
|||||||
ean: "test-ean4",
|
ean: "test-ean4",
|
||||||
upc: "test-upc4",
|
upc: "test-upc4",
|
||||||
product_id: "test-product1",
|
product_id: "test-product1",
|
||||||
prices: [{ id: "test-price4", currency_code: "usd", amount: 100 }],
|
prices: [
|
||||||
|
{ id: "test-price4", currency_code: "usd", amount: 100, type: "default" },
|
||||||
|
],
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
id: "test-variant-option-4",
|
id: "test-variant-option-4",
|
||||||
@@ -237,7 +268,7 @@ module.exports = async (connection, data = {}) => {
|
|||||||
|
|
||||||
await manager.save(variant5)
|
await manager.save(variant5)
|
||||||
|
|
||||||
const product1 = manager.create(Product, {
|
const product1 = await manager.create(Product, {
|
||||||
id: "test-product_filtering_1",
|
id: "test-product_filtering_1",
|
||||||
handle: "test-product_filtering_1",
|
handle: "test-product_filtering_1",
|
||||||
title: "Test product filtering 1",
|
title: "Test product filtering 1",
|
||||||
@@ -251,7 +282,7 @@ module.exports = async (connection, data = {}) => {
|
|||||||
|
|
||||||
await manager.save(product1)
|
await manager.save(product1)
|
||||||
|
|
||||||
const product2 = manager.create(Product, {
|
const product2 = await manager.create(Product, {
|
||||||
id: "test-product_filtering_2",
|
id: "test-product_filtering_2",
|
||||||
handle: "test-product_filtering_2",
|
handle: "test-product_filtering_2",
|
||||||
title: "Test product filtering 2",
|
title: "Test product filtering 2",
|
||||||
@@ -265,7 +296,7 @@ module.exports = async (connection, data = {}) => {
|
|||||||
|
|
||||||
await manager.save(product2)
|
await manager.save(product2)
|
||||||
|
|
||||||
const product3 = manager.create(Product, {
|
const product3 = await manager.create(Product, {
|
||||||
id: "test-product_filtering_3",
|
id: "test-product_filtering_3",
|
||||||
handle: "test-product_filtering_3",
|
handle: "test-product_filtering_3",
|
||||||
title: "Test product filtering 3",
|
title: "Test product filtering 3",
|
||||||
@@ -279,7 +310,7 @@ module.exports = async (connection, data = {}) => {
|
|||||||
|
|
||||||
await manager.save(product3)
|
await manager.save(product3)
|
||||||
|
|
||||||
const product4 = manager.create(Product, {
|
const product4 = await manager.create(Product, {
|
||||||
id: "test-product_filtering_4",
|
id: "test-product_filtering_4",
|
||||||
handle: "test-product_filtering_4",
|
handle: "test-product_filtering_4",
|
||||||
title: "Test product filtering 4",
|
title: "Test product filtering 4",
|
||||||
|
|||||||
@@ -8,11 +8,45 @@ const {
|
|||||||
ShippingProfile,
|
ShippingProfile,
|
||||||
ProductVariant,
|
ProductVariant,
|
||||||
Image,
|
Image,
|
||||||
|
Cart,
|
||||||
|
PriceList,
|
||||||
} = require("@medusajs/medusa")
|
} = require("@medusajs/medusa")
|
||||||
|
|
||||||
module.exports = async (connection, data = {}) => {
|
module.exports = async (connection, data = {}) => {
|
||||||
const manager = connection.manager
|
const manager = connection.manager
|
||||||
|
|
||||||
|
const yesterday = ((today) => new Date(today.setDate(today.getDate() - 1)))(
|
||||||
|
new Date()
|
||||||
|
)
|
||||||
|
const tomorrow = ((today) => new Date(today.setDate(today.getDate() + 1)))(
|
||||||
|
new Date()
|
||||||
|
)
|
||||||
|
const tenDaysAgo = ((today) => new Date(today.setDate(today.getDate() - 10)))(
|
||||||
|
new Date()
|
||||||
|
)
|
||||||
|
|
||||||
|
const priceList = await manager.create(PriceList, {
|
||||||
|
id: "pl",
|
||||||
|
name: "VIP winter sale",
|
||||||
|
description: "Winter sale for VIP customers.",
|
||||||
|
type: "sale",
|
||||||
|
status: "active",
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(priceList)
|
||||||
|
|
||||||
|
const priceList1 = await manager.create(PriceList, {
|
||||||
|
id: "pl_expired",
|
||||||
|
name: "Past winter sale",
|
||||||
|
description: "Winter sale for key accounts.",
|
||||||
|
type: "sale",
|
||||||
|
status: "active",
|
||||||
|
starts_at: tenDaysAgo,
|
||||||
|
ends_at: yesterday,
|
||||||
|
})
|
||||||
|
|
||||||
|
await manager.save(priceList1)
|
||||||
|
|
||||||
const defaultProfile = await manager.findOne(ShippingProfile, {
|
const defaultProfile = await manager.findOne(ShippingProfile, {
|
||||||
type: "default",
|
type: "default",
|
||||||
})
|
})
|
||||||
@@ -83,12 +117,20 @@ module.exports = async (connection, data = {}) => {
|
|||||||
tax_rate: 0,
|
tax_rate: 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
await manager.insert(Cart, {
|
||||||
|
id: "test-cart",
|
||||||
|
region_id: "test-region",
|
||||||
|
currency_code: "usd",
|
||||||
|
items: [],
|
||||||
|
})
|
||||||
|
|
||||||
const p = manager.create(Product, {
|
const p = manager.create(Product, {
|
||||||
id: "test-product",
|
id: "test-product",
|
||||||
handle: "test-product",
|
handle: "test-product",
|
||||||
title: "Test product",
|
title: "Test product",
|
||||||
profile_id: defaultProfile.id,
|
profile_id: defaultProfile.id,
|
||||||
description: "test-product-description",
|
description: "test-product-description",
|
||||||
|
status: "published",
|
||||||
collection_id: "test-collection",
|
collection_id: "test-collection",
|
||||||
type: { id: "test-type", value: "test-type" },
|
type: { id: "test-type", value: "test-type" },
|
||||||
tags: [
|
tags: [
|
||||||
@@ -117,7 +159,21 @@ module.exports = async (connection, data = {}) => {
|
|||||||
upc: "test-upc",
|
upc: "test-upc",
|
||||||
barcode: "test-barcode",
|
barcode: "test-barcode",
|
||||||
product_id: "test-product",
|
product_id: "test-product",
|
||||||
prices: [{ id: "test-price", currency_code: "usd", amount: 100 }],
|
prices: [
|
||||||
|
{ id: "test-price", currency_code: "usd", type: "default", amount: 100 },
|
||||||
|
{
|
||||||
|
id: "test-price-discount",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 80,
|
||||||
|
price_list_id: "pl",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price-discount-expired",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 70,
|
||||||
|
price_list_id: "pl_expired",
|
||||||
|
},
|
||||||
|
],
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
id: "test-variant-option",
|
id: "test-variant-option",
|
||||||
@@ -139,7 +195,21 @@ module.exports = async (connection, data = {}) => {
|
|||||||
upc: "test-upc1",
|
upc: "test-upc1",
|
||||||
barcode: "test-barcode 1",
|
barcode: "test-barcode 1",
|
||||||
product_id: "test-product",
|
product_id: "test-product",
|
||||||
prices: [{ id: "test-price1", currency_code: "usd", amount: 100 }],
|
prices: [
|
||||||
|
{ id: "test-price1", currency_code: "usd", type: "default", amount: 100 },
|
||||||
|
{
|
||||||
|
id: "test-price1-discount",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 80,
|
||||||
|
price_list_id: "pl",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price1-discount-expired",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 70,
|
||||||
|
price_list_id: "pl_expired",
|
||||||
|
},
|
||||||
|
],
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
id: "test-variant-option-1",
|
id: "test-variant-option-1",
|
||||||
@@ -160,7 +230,21 @@ module.exports = async (connection, data = {}) => {
|
|||||||
ean: "test-ean2",
|
ean: "test-ean2",
|
||||||
upc: "test-upc2",
|
upc: "test-upc2",
|
||||||
product_id: "test-product",
|
product_id: "test-product",
|
||||||
prices: [{ id: "test-price2", currency_code: "usd", amount: 100 }],
|
prices: [
|
||||||
|
{ id: "test-price2", currency_code: "usd", type: "default", amount: 100 },
|
||||||
|
{
|
||||||
|
id: "test-price2-discount",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 80,
|
||||||
|
price_list_id: "pl",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "test-price2-discount-expired",
|
||||||
|
currency_code: "usd",
|
||||||
|
amount: 70,
|
||||||
|
price_list_id: "pl_expired",
|
||||||
|
},
|
||||||
|
],
|
||||||
options: [
|
options: [
|
||||||
{
|
{
|
||||||
id: "test-variant-option-2",
|
id: "test-variant-option-2",
|
||||||
@@ -176,6 +260,7 @@ module.exports = async (connection, data = {}) => {
|
|||||||
id: "test-product1",
|
id: "test-product1",
|
||||||
handle: "test-product1",
|
handle: "test-product1",
|
||||||
title: "Test product1",
|
title: "Test product1",
|
||||||
|
status: "published",
|
||||||
profile_id: defaultProfile.id,
|
profile_id: defaultProfile.id,
|
||||||
description: "test-product-description1",
|
description: "test-product-description1",
|
||||||
collection_id: "test-collection",
|
collection_id: "test-collection",
|
||||||
|
|||||||
@@ -74,9 +74,9 @@ export const ProductVariantServiceMock = {
|
|||||||
}
|
}
|
||||||
return Promise.resolve(undefined)
|
return Promise.resolve(undefined)
|
||||||
}),
|
}),
|
||||||
getRegionPrice: jest.fn().mockImplementation((variantId, regionId) => {
|
getRegionPrice: jest.fn().mockImplementation((variantId, context) => {
|
||||||
if (variantId === IdMap.getId("test-variant-1")) {
|
if (variantId === IdMap.getId("test-variant-1")) {
|
||||||
if (regionId === IdMap.getId("world")) {
|
if (context.regionId === IdMap.getId("world")) {
|
||||||
return Promise.resolve(10)
|
return Promise.resolve(10)
|
||||||
} else {
|
} else {
|
||||||
return Promise.resolve(20)
|
return Promise.resolve(20)
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ class AddOnLineItemService extends BaseService {
|
|||||||
|
|
||||||
let unitPrice = await this.productVariantService_.getRegionPrice(
|
let unitPrice = await this.productVariantService_.getRegionPrice(
|
||||||
variant._id,
|
variant._id,
|
||||||
region._id
|
{regionId: region._id}
|
||||||
)
|
)
|
||||||
|
|
||||||
const addOnPrices = await Promise.all(
|
const addOnPrices = await Promise.all(
|
||||||
|
|||||||
@@ -8,8 +8,10 @@ import {
|
|||||||
IsString,
|
IsString,
|
||||||
ValidateNested,
|
ValidateNested,
|
||||||
} from "class-validator"
|
} from "class-validator"
|
||||||
|
import { MedusaError } from "medusa-core-utils"
|
||||||
import { defaultAdminProductFields, defaultAdminProductRelations } from "."
|
import { defaultAdminProductFields, defaultAdminProductRelations } from "."
|
||||||
import { ProductService, ProductVariantService } from "../../../../services"
|
import { ProductService, ProductVariantService } from "../../../../services"
|
||||||
|
import { PriceSelectionParams } from "../../../../types/price-selection"
|
||||||
import { ProductVariantPricesUpdateReq } from "../../../../types/product-variant"
|
import { ProductVariantPricesUpdateReq } from "../../../../types/product-variant"
|
||||||
import { validator } from "../../../../utils/validator"
|
import { validator } from "../../../../utils/validator"
|
||||||
|
|
||||||
@@ -130,6 +132,8 @@ export default async (req, res) => {
|
|||||||
req.body
|
req.body
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const validatedQueryParams = await validator(PriceSelectionParams, req.query)
|
||||||
|
|
||||||
const productService: ProductService = req.scope.resolve("productService")
|
const productService: ProductService = req.scope.resolve("productService")
|
||||||
const productVariantService: ProductVariantService = req.scope.resolve(
|
const productVariantService: ProductVariantService = req.scope.resolve(
|
||||||
"productVariantService"
|
"productVariantService"
|
||||||
@@ -140,9 +144,12 @@ export default async (req, res) => {
|
|||||||
...validated,
|
...validated,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
await productVariantService.retrieve(variant_id)
|
||||||
|
|
||||||
const product = await productService.retrieve(id, {
|
const product = await productService.retrieve(id, {
|
||||||
select: defaultAdminProductFields,
|
select: defaultAdminProductFields,
|
||||||
relations: defaultAdminProductRelations,
|
relations: defaultAdminProductRelations,
|
||||||
|
...validatedQueryParams,
|
||||||
})
|
})
|
||||||
|
|
||||||
res.json({ product })
|
res.json({ product })
|
||||||
|
|||||||
@@ -21,7 +21,13 @@ describe("Get product by id", () => {
|
|||||||
expect(ProductServiceMock.retrieve).toHaveBeenCalledTimes(1)
|
expect(ProductServiceMock.retrieve).toHaveBeenCalledTimes(1)
|
||||||
expect(ProductServiceMock.retrieve).toHaveBeenCalledWith(
|
expect(ProductServiceMock.retrieve).toHaveBeenCalledWith(
|
||||||
IdMap.getId("product1"),
|
IdMap.getId("product1"),
|
||||||
{ relations: defaultStoreProductsRelations }
|
{
|
||||||
|
relations: defaultStoreProductsRelations,
|
||||||
|
cart_id: undefined,
|
||||||
|
currency_code: undefined,
|
||||||
|
region_id: undefined,
|
||||||
|
include_discount_prices: true,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -51,7 +57,13 @@ describe("Get product by id", () => {
|
|||||||
it("endpoint called with defaultRelations", () => {
|
it("endpoint called with defaultRelations", () => {
|
||||||
expect(ProductServiceMock.retrieve).toHaveBeenCalledWith(
|
expect(ProductServiceMock.retrieve).toHaveBeenCalledWith(
|
||||||
IdMap.getId("variantsWithPrices"),
|
IdMap.getId("variantsWithPrices"),
|
||||||
{ relations: defaultStoreProductsRelations }
|
{
|
||||||
|
relations: defaultStoreProductsRelations,
|
||||||
|
cart_id: undefined,
|
||||||
|
currency_code: undefined,
|
||||||
|
region_id: undefined,
|
||||||
|
include_discount_prices: true,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,15 @@ describe("GET /store/products", () => {
|
|||||||
expect(ProductServiceMock.listAndCount).toHaveBeenCalledTimes(1)
|
expect(ProductServiceMock.listAndCount).toHaveBeenCalledTimes(1)
|
||||||
expect(ProductServiceMock.listAndCount).toHaveBeenCalledWith(
|
expect(ProductServiceMock.listAndCount).toHaveBeenCalledWith(
|
||||||
{ status: ["published"] },
|
{ status: ["published"] },
|
||||||
{ relations: defaultStoreProductsRelations, skip: 0, take: 100 }
|
{
|
||||||
|
relations: defaultStoreProductsRelations,
|
||||||
|
skip: 0,
|
||||||
|
take: 100,
|
||||||
|
cart_id: undefined,
|
||||||
|
currency_code: undefined,
|
||||||
|
region_id: undefined,
|
||||||
|
include_discount_prices: true,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -42,7 +50,15 @@ describe("GET /store/products", () => {
|
|||||||
expect(ProductServiceMock.listAndCount).toHaveBeenCalledTimes(1)
|
expect(ProductServiceMock.listAndCount).toHaveBeenCalledTimes(1)
|
||||||
expect(ProductServiceMock.listAndCount).toHaveBeenCalledWith(
|
expect(ProductServiceMock.listAndCount).toHaveBeenCalledWith(
|
||||||
{ is_giftcard: true, status: ["published"] },
|
{ is_giftcard: true, status: ["published"] },
|
||||||
{ relations: defaultStoreProductsRelations, skip: 0, take: 100 }
|
{
|
||||||
|
relations: defaultStoreProductsRelations,
|
||||||
|
skip: 0,
|
||||||
|
take: 100,
|
||||||
|
cart_id: undefined,
|
||||||
|
currency_code: undefined,
|
||||||
|
region_id: undefined,
|
||||||
|
include_discount_prices: true,
|
||||||
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { defaultStoreProductsRelations } from "."
|
import { defaultStoreProductsRelations } from "."
|
||||||
import { ProductService } from "../../../../services"
|
import { ProductService } from "../../../../services"
|
||||||
|
import { PriceSelectionParams } from "../../../../types/price-selection"
|
||||||
|
import { validator } from "../../../../utils/validator"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @oas [get] /products/{id}
|
* @oas [get] /products/{id}
|
||||||
@@ -23,9 +25,18 @@ import { ProductService } from "../../../../services"
|
|||||||
export default async (req, res) => {
|
export default async (req, res) => {
|
||||||
const { id } = req.params
|
const { id } = req.params
|
||||||
|
|
||||||
|
const validated = await validator(PriceSelectionParams, req.query)
|
||||||
|
|
||||||
|
const customer_id = req.user?.customer_id
|
||||||
|
|
||||||
const productService: ProductService = req.scope.resolve("productService")
|
const productService: ProductService = req.scope.resolve("productService")
|
||||||
const product = await productService.retrieve(id, {
|
const product = await productService.retrieve(id, {
|
||||||
relations: defaultStoreProductsRelations,
|
relations: defaultStoreProductsRelations,
|
||||||
|
cart_id: validated.cart_id,
|
||||||
|
customer_id: customer_id,
|
||||||
|
region_id: validated.region_id,
|
||||||
|
currency_code: validated.currency_code,
|
||||||
|
include_discount_prices: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
res.json({ product })
|
res.json({ product })
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { omit, pickBy } from "lodash"
|
|||||||
import { defaultStoreProductsRelations } from "."
|
import { defaultStoreProductsRelations } from "."
|
||||||
import { ProductService } from "../../../../services"
|
import { ProductService } from "../../../../services"
|
||||||
import { DateComparisonOperator } from "../../../../types/common"
|
import { DateComparisonOperator } from "../../../../types/common"
|
||||||
|
import { PriceSelectionParams } from "../../../../types/price-selection"
|
||||||
import { validator } from "../../../../utils/validator"
|
import { validator } from "../../../../utils/validator"
|
||||||
import { IsType } from "../../../../utils/validators/is-type"
|
import { IsType } from "../../../../utils/validators/is-type"
|
||||||
import { optionalBooleanMapper } from "../../../../utils/validators/is-boolean"
|
import { optionalBooleanMapper } from "../../../../utils/validators/is-boolean"
|
||||||
@@ -68,6 +69,9 @@ export default async (req, res) => {
|
|||||||
"expand",
|
"expand",
|
||||||
"limit",
|
"limit",
|
||||||
"offset",
|
"offset",
|
||||||
|
"cart_id",
|
||||||
|
"region_id",
|
||||||
|
"currency_code",
|
||||||
])
|
])
|
||||||
|
|
||||||
// get only published products for store endpoint
|
// get only published products for store endpoint
|
||||||
@@ -92,6 +96,11 @@ export default async (req, res) => {
|
|||||||
: defaultStoreProductsRelations,
|
: defaultStoreProductsRelations,
|
||||||
skip: validated.offset,
|
skip: validated.offset,
|
||||||
take: validated.limit,
|
take: validated.limit,
|
||||||
|
cart_id: validated.cart_id,
|
||||||
|
region_id: validated.region_id,
|
||||||
|
currency_code: validated.currency_code,
|
||||||
|
customer_id: req.user?.customer_id,
|
||||||
|
include_discount_prices: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
const [products, count] = await productService.listAndCount(
|
const [products, count] = await productService.listAndCount(
|
||||||
@@ -107,7 +116,7 @@ export default async (req, res) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export class StoreGetProductsPaginationParams {
|
export class StoreGetProductsPaginationParams extends PriceSelectionParams {
|
||||||
@IsString()
|
@IsString()
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
fields?: string
|
fields?: string
|
||||||
|
|||||||
@@ -16,6 +16,10 @@ describe("Get variant by id", () => {
|
|||||||
expect(ProductVariantServiceMock.retrieve).toHaveBeenCalledTimes(1)
|
expect(ProductVariantServiceMock.retrieve).toHaveBeenCalledTimes(1)
|
||||||
expect(ProductVariantServiceMock.retrieve).toHaveBeenCalledWith("1", {
|
expect(ProductVariantServiceMock.retrieve).toHaveBeenCalledWith("1", {
|
||||||
relations: ["prices", "options"],
|
relations: ["prices", "options"],
|
||||||
|
cart_id: undefined,
|
||||||
|
currency_code: undefined,
|
||||||
|
region_id: undefined,
|
||||||
|
include_discount_prices: true,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
import { defaultStoreVariantRelations } from "."
|
import { defaultStoreVariantRelations } from "."
|
||||||
import ProductVariantService from "../../../../services/product-variant"
|
import ProductVariantService from "../../../../services/product-variant"
|
||||||
|
import { PriceSelectionParams } from "../../../../types/price-selection"
|
||||||
|
import { validator } from "../../../../utils/validator"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @oas [get] /variants/{variant_id}
|
* @oas [get] /variants/{variant_id}
|
||||||
@@ -23,12 +25,21 @@ import ProductVariantService from "../../../../services/product-variant"
|
|||||||
export default async (req, res) => {
|
export default async (req, res) => {
|
||||||
const { id } = req.params
|
const { id } = req.params
|
||||||
|
|
||||||
|
const validated = await validator(PriceSelectionParams, req.query)
|
||||||
|
|
||||||
const variantService: ProductVariantService = req.scope.resolve(
|
const variantService: ProductVariantService = req.scope.resolve(
|
||||||
"productVariantService"
|
"productVariantService"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const customer_id = req.user?.customer_id
|
||||||
|
|
||||||
const variant = await variantService.retrieve(id, {
|
const variant = await variantService.retrieve(id, {
|
||||||
relations: defaultStoreVariantRelations,
|
relations: defaultStoreVariantRelations,
|
||||||
|
cart_id: validated.cart_id,
|
||||||
|
customer_id: customer_id,
|
||||||
|
region_id: validated.region_id,
|
||||||
|
currency_code: validated.currency_code,
|
||||||
|
include_discount_prices: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
res.json({ variant })
|
res.json({ variant })
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import ProductVariantService from "../../../../services/product-variant"
|
|||||||
import { validator } from "../../../../utils/validator"
|
import { validator } from "../../../../utils/validator"
|
||||||
import { IsType } from "../../../../utils/validators/is-type"
|
import { IsType } from "../../../../utils/validators/is-type"
|
||||||
import { NumericalComparisonOperator } from "../../../../types/common"
|
import { NumericalComparisonOperator } from "../../../../types/common"
|
||||||
|
import { PriceSelectionParams } from "../../../../types/price-selection"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @oas [get] /variants
|
* @oas [get] /variants
|
||||||
@@ -41,12 +42,19 @@ export default async (req, res) => {
|
|||||||
expandFields = expand.split(",")
|
expandFields = expand.split(",")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const customer_id = req.user?.customer_id
|
||||||
|
|
||||||
const listConfig = {
|
const listConfig = {
|
||||||
relations: expandFields.length
|
relations: expandFields.length
|
||||||
? expandFields
|
? expandFields
|
||||||
: defaultStoreVariantRelations,
|
: defaultStoreVariantRelations,
|
||||||
skip: offset,
|
skip: offset,
|
||||||
take: limit,
|
take: limit,
|
||||||
|
cart_id: validated.cart_id,
|
||||||
|
region_id: validated.region_id,
|
||||||
|
currency_code: validated.currency_code,
|
||||||
|
customer_id: customer_id,
|
||||||
|
include_discount_prices: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterableFields: FilterableProductVariantProps = omit(validated, [
|
const filterableFields: FilterableProductVariantProps = omit(validated, [
|
||||||
@@ -54,6 +62,9 @@ export default async (req, res) => {
|
|||||||
"limit",
|
"limit",
|
||||||
"offset",
|
"offset",
|
||||||
"expand",
|
"expand",
|
||||||
|
"cart_id",
|
||||||
|
"region_id",
|
||||||
|
"currency_code",
|
||||||
])
|
])
|
||||||
|
|
||||||
if (validated.ids) {
|
if (validated.ids) {
|
||||||
@@ -68,7 +79,7 @@ export default async (req, res) => {
|
|||||||
res.json({ variants })
|
res.json({ variants })
|
||||||
}
|
}
|
||||||
|
|
||||||
export class StoreGetVariantsParams {
|
export class StoreGetVariantsParams extends PriceSelectionParams {
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsInt()
|
@IsInt()
|
||||||
@Type(() => Number)
|
@Type(() => Number)
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { EntityManager } from "typeorm"
|
import { EntityManager } from "typeorm"
|
||||||
import { MoneyAmount } from ".."
|
import { MoneyAmount } from ".."
|
||||||
import { MoneyAmountRepository } from "../repositories/money-amount"
|
|
||||||
import { PriceListType } from "../types/price-list"
|
import { PriceListType } from "../types/price-list"
|
||||||
|
|
||||||
export interface IPriceSelectionStrategy {
|
export interface IPriceSelectionStrategy {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
JoinColumn,
|
JoinColumn,
|
||||||
ManyToOne,
|
ManyToOne,
|
||||||
PrimaryColumn,
|
PrimaryColumn,
|
||||||
UpdateDateColumn
|
UpdateDateColumn,
|
||||||
} from "typeorm"
|
} from "typeorm"
|
||||||
import { ulid } from "ulid"
|
import { ulid } from "ulid"
|
||||||
import { resolveDbType } from "../utils/db-aware-column"
|
import { resolveDbType } from "../utils/db-aware-column"
|
||||||
@@ -41,11 +41,10 @@ export class MoneyAmount {
|
|||||||
@Column({ nullable: true })
|
@Column({ nullable: true })
|
||||||
price_list_id: string | null
|
price_list_id: string | null
|
||||||
|
|
||||||
@ManyToOne(
|
@ManyToOne(() => PriceList, (priceList) => priceList.prices, {
|
||||||
() => PriceList,
|
cascade: true,
|
||||||
(priceList) => priceList.prices,
|
onDelete: "CASCADE",
|
||||||
{ cascade: true, onDelete: "CASCADE" }
|
})
|
||||||
)
|
|
||||||
@JoinColumn({ name: "price_list_id" })
|
@JoinColumn({ name: "price_list_id" })
|
||||||
price_list: PriceList | null
|
price_list: PriceList | null
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
ManyToMany,
|
ManyToMany,
|
||||||
OneToMany,
|
OneToMany,
|
||||||
PrimaryColumn,
|
PrimaryColumn,
|
||||||
UpdateDateColumn
|
UpdateDateColumn,
|
||||||
} from "typeorm"
|
} from "typeorm"
|
||||||
import { ulid } from "ulid"
|
import { ulid } from "ulid"
|
||||||
import { PriceListStatus, PriceListType } from "../types/price-list"
|
import { PriceListStatus, PriceListType } from "../types/price-list"
|
||||||
@@ -53,18 +53,14 @@ export class PriceList {
|
|||||||
referencedColumnName: "id",
|
referencedColumnName: "id",
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@ManyToMany(
|
@ManyToMany(() => CustomerGroup, (cg) => cg.price_lists, {
|
||||||
() => CustomerGroup,
|
onDelete: "CASCADE",
|
||||||
(cg) => cg.price_lists,
|
})
|
||||||
{ onDelete: "CASCADE" }
|
|
||||||
)
|
|
||||||
customer_groups: CustomerGroup[]
|
customer_groups: CustomerGroup[]
|
||||||
|
|
||||||
@OneToMany(
|
@OneToMany(() => MoneyAmount, (moneyAmount) => moneyAmount.price_list, {
|
||||||
() => MoneyAmount,
|
onDelete: "CASCADE",
|
||||||
(moneyAmount) => moneyAmount.price_list,
|
})
|
||||||
{ onDelete: "CASCADE" }
|
|
||||||
)
|
|
||||||
prices: MoneyAmount[]
|
prices: MoneyAmount[]
|
||||||
|
|
||||||
@CreateDateColumn({ type: resolveDbType("timestamptz") })
|
@CreateDateColumn({ type: resolveDbType("timestamptz") })
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import partition from "lodash/partition"
|
import partition from "lodash/partition"
|
||||||
|
import { MedusaError } from "medusa-core-utils"
|
||||||
import {
|
import {
|
||||||
Brackets,
|
Brackets,
|
||||||
EntityRepository,
|
EntityRepository,
|
||||||
@@ -130,7 +131,7 @@ export class MoneyAmountRepository extends Repository<MoneyAmount> {
|
|||||||
"price_list",
|
"price_list",
|
||||||
"ma.price_list_id = price_list.id "
|
"ma.price_list_id = price_list.id "
|
||||||
)
|
)
|
||||||
.where({ variant_id: variant_id }) // "ma.variant_id = :variant_id",
|
.where({ variant_id: variant_id })
|
||||||
.andWhere("(ma.price_list_id is null or price_list.status = 'active')")
|
.andWhere("(ma.price_list_id is null or price_list.status = 'active')")
|
||||||
.andWhere(
|
.andWhere(
|
||||||
"(price_list is null or price_list.ends_at is null OR price_list.ends_at > :date) ",
|
"(price_list is null or price_list.ends_at is null OR price_list.ends_at > :date) ",
|
||||||
|
|||||||
@@ -1040,6 +1040,19 @@ describe("CartService", () => {
|
|||||||
return this
|
return this
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const priceSelectionStrat = {
|
||||||
|
calculateVariantPrice: async (variantId, context) => {
|
||||||
|
if (variantId === IdMap.getId("fail")) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.NOT_FOUND,
|
||||||
|
`Money amount for variant with id ${variantId} in region ${context.region_id} does not exist`
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
return { calculatedPrice: 100 }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
const cartService = new CartService({
|
const cartService = new CartService({
|
||||||
manager: MockManager,
|
manager: MockManager,
|
||||||
paymentProviderService,
|
paymentProviderService,
|
||||||
@@ -1050,6 +1063,7 @@ describe("CartService", () => {
|
|||||||
lineItemService,
|
lineItemService,
|
||||||
productVariantService,
|
productVariantService,
|
||||||
eventBusService,
|
eventBusService,
|
||||||
|
priceSelectionStrategy: priceSelectionStrat,
|
||||||
})
|
})
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@@ -1316,7 +1330,7 @@ describe("CartService", () => {
|
|||||||
jest.clearAllMocks()
|
jest.clearAllMocks()
|
||||||
})
|
})
|
||||||
|
|
||||||
let cartService = new CartService({})
|
const cartService = new CartService({})
|
||||||
|
|
||||||
it("given a cart with custom shipping options and a shipping option id corresponding to a custom shipping option, then it should return a custom shipping option", async () => {
|
it("given a cart with custom shipping options and a shipping option id corresponding to a custom shipping option, then it should return a custom shipping option", async () => {
|
||||||
const cartCSO = [
|
const cartCSO = [
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import ProductVariantService from "../product-variant"
|
|||||||
|
|
||||||
const eventBusService = {
|
const eventBusService = {
|
||||||
emit: jest.fn(),
|
emit: jest.fn(),
|
||||||
withTransaction: function() {
|
withTransaction: function () {
|
||||||
return this
|
return this
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -18,9 +18,33 @@ describe("ProductVariantService", () => {
|
|||||||
return Promise.resolve({ id: IdMap.getId("ironman") })
|
return Promise.resolve({ id: IdMap.getId("ironman") })
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const cartRepository = MockRepository({
|
||||||
|
findOne: (data) => {
|
||||||
|
return Promise.resolve({})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const priceSelectionStrat = {
|
||||||
|
calculateVariantPrice: (variantId, context) => {
|
||||||
|
return {
|
||||||
|
originalPrice: null,
|
||||||
|
calculatedPrice: null,
|
||||||
|
prices: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
const priceSelectionStrategy = {
|
||||||
|
withTransaction: (manager) => {
|
||||||
|
return priceSelectionStrat
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
const productVariantService = new ProductVariantService({
|
const productVariantService = new ProductVariantService({
|
||||||
manager: MockManager,
|
manager: MockManager,
|
||||||
productVariantRepository,
|
productVariantRepository,
|
||||||
|
cartRepository,
|
||||||
|
priceSelectionStrategy,
|
||||||
})
|
})
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
@@ -227,6 +251,29 @@ describe("ProductVariantService", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe("update", () => {
|
describe("update", () => {
|
||||||
|
const cartRepository = MockRepository({
|
||||||
|
findOne: (data) => {
|
||||||
|
return Promise.resolve({})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const priceSelectionStrat = {
|
||||||
|
calculateVariantPrice: (variantId, context) => {
|
||||||
|
return {
|
||||||
|
originalPrice: null,
|
||||||
|
calculatedPrice: null,
|
||||||
|
calculatedPriceType: undefined,
|
||||||
|
prices: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const priceSelectionStrategy = {
|
||||||
|
withTransaction: (manager) => {
|
||||||
|
return priceSelectionStrat
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
const productVariantRepository = MockRepository({
|
const productVariantRepository = MockRepository({
|
||||||
findOne: (query) => Promise.resolve({ id: IdMap.getId("ironman") }),
|
findOne: (query) => Promise.resolve({ id: IdMap.getId("ironman") }),
|
||||||
})
|
})
|
||||||
@@ -246,6 +293,8 @@ describe("ProductVariantService", () => {
|
|||||||
moneyAmountRepository,
|
moneyAmountRepository,
|
||||||
productVariantRepository,
|
productVariantRepository,
|
||||||
productOptionValueRepository,
|
productOptionValueRepository,
|
||||||
|
cartRepository,
|
||||||
|
priceSelectionStrategy,
|
||||||
})
|
})
|
||||||
|
|
||||||
productVariantService.updateOptionValue = jest
|
productVariantService.updateOptionValue = jest
|
||||||
@@ -464,13 +513,13 @@ describe("ProductVariantService", () => {
|
|||||||
|
|
||||||
describe("getRegionPrice", () => {
|
describe("getRegionPrice", () => {
|
||||||
const regionService = {
|
const regionService = {
|
||||||
retrieve: function() {
|
retrieve: function () {
|
||||||
return Promise.resolve({
|
return Promise.resolve({
|
||||||
id: IdMap.getId("california"),
|
id: IdMap.getId("california"),
|
||||||
name: "California",
|
name: "California",
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
withTransaction: function() {
|
withTransaction: function () {
|
||||||
return this
|
return this
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -498,11 +547,35 @@ describe("ProductVariantService", () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const cartRepository = MockRepository({
|
||||||
|
findOne: (data) => {
|
||||||
|
return Promise.resolve({})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const priceSelectionStrat = {
|
||||||
|
calculateVariantPrice: (variantId, context) => {
|
||||||
|
return Promise.resolve({
|
||||||
|
originalPrice: null,
|
||||||
|
calculatedPrice: 1000,
|
||||||
|
prices: [],
|
||||||
|
})
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const priceSelectionStrategy = {
|
||||||
|
withTransaction: (manager) => {
|
||||||
|
return priceSelectionStrat
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
const productVariantService = new ProductVariantService({
|
const productVariantService = new ProductVariantService({
|
||||||
manager: MockManager,
|
manager: MockManager,
|
||||||
eventBusService,
|
eventBusService,
|
||||||
regionService,
|
regionService,
|
||||||
moneyAmountRepository,
|
moneyAmountRepository,
|
||||||
|
cartRepository,
|
||||||
|
priceSelectionStrategy,
|
||||||
})
|
})
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import ProductService from "../product"
|
|||||||
|
|
||||||
const eventBusService = {
|
const eventBusService = {
|
||||||
emit: jest.fn(),
|
emit: jest.fn(),
|
||||||
withTransaction: function() {
|
withTransaction: function () {
|
||||||
return this
|
return this
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -54,7 +54,7 @@ describe("ProductService", () => {
|
|||||||
|
|
||||||
describe("create", () => {
|
describe("create", () => {
|
||||||
const productRepository = MockRepository({
|
const productRepository = MockRepository({
|
||||||
create: product => ({
|
create: (product) => ({
|
||||||
id: IdMap.getId("ironman"),
|
id: IdMap.getId("ironman"),
|
||||||
title: "Suit",
|
title: "Suit",
|
||||||
options: [],
|
options: [],
|
||||||
@@ -71,7 +71,7 @@ describe("ProductService", () => {
|
|||||||
|
|
||||||
const productTagRepository = MockRepository({
|
const productTagRepository = MockRepository({
|
||||||
findOne: () => Promise.resolve(undefined),
|
findOne: () => Promise.resolve(undefined),
|
||||||
create: data => {
|
create: (data) => {
|
||||||
if (data.value === "title") {
|
if (data.value === "title") {
|
||||||
return { id: "tag-1", value: "title" }
|
return { id: "tag-1", value: "title" }
|
||||||
}
|
}
|
||||||
@@ -83,16 +83,16 @@ describe("ProductService", () => {
|
|||||||
})
|
})
|
||||||
const productTypeRepository = MockRepository({
|
const productTypeRepository = MockRepository({
|
||||||
findOne: () => Promise.resolve(undefined),
|
findOne: () => Promise.resolve(undefined),
|
||||||
create: data => {
|
create: (data) => {
|
||||||
return { id: "type", value: "type1" }
|
return { id: "type", value: "type1" }
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
const productCollectionService = {
|
const productCollectionService = {
|
||||||
withTransaction: function() {
|
withTransaction: function () {
|
||||||
return this
|
return this
|
||||||
},
|
},
|
||||||
retrieve: id =>
|
retrieve: (id) =>
|
||||||
Promise.resolve({ id: IdMap.getId("cat"), title: "Suits" }),
|
Promise.resolve({ id: IdMap.getId("cat"), title: "Suits" }),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,7 +223,7 @@ describe("ProductService", () => {
|
|||||||
|
|
||||||
const productTypeRepository = MockRepository({
|
const productTypeRepository = MockRepository({
|
||||||
findOne: () => Promise.resolve(undefined),
|
findOne: () => Promise.resolve(undefined),
|
||||||
create: data => {
|
create: (data) => {
|
||||||
return { id: "type", value: "type1" }
|
return { id: "type", value: "type1" }
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -231,7 +231,7 @@ describe("ProductService", () => {
|
|||||||
const productVariantRepository = MockRepository()
|
const productVariantRepository = MockRepository()
|
||||||
|
|
||||||
const productVariantService = {
|
const productVariantService = {
|
||||||
withTransaction: function() {
|
withTransaction: function () {
|
||||||
return this
|
return this
|
||||||
},
|
},
|
||||||
update: (variant, update) => {
|
update: (variant, update) => {
|
||||||
@@ -243,7 +243,7 @@ describe("ProductService", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const productTagRepository = MockRepository({
|
const productTagRepository = MockRepository({
|
||||||
findOne: data => {
|
findOne: (data) => {
|
||||||
if (data.where.value === "test") {
|
if (data.where.value === "test") {
|
||||||
return Promise.resolve({ id: IdMap.getId("test"), value: "test" })
|
return Promise.resolve({ id: IdMap.getId("test"), value: "test" })
|
||||||
}
|
}
|
||||||
@@ -253,6 +253,25 @@ describe("ProductService", () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const cartRepository = MockRepository({
|
||||||
|
findOne: (data) => {
|
||||||
|
return Promise.resolve({})
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const priceSelectionStrategy = {
|
||||||
|
withTransaction: (manager) => {
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
calculateVariantPrice: (variantId, context) => {
|
||||||
|
return {
|
||||||
|
originalPrice: null,
|
||||||
|
calculatedPrice: null,
|
||||||
|
prices: [],
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
const productService = new ProductService({
|
const productService = new ProductService({
|
||||||
manager: MockManager,
|
manager: MockManager,
|
||||||
productRepository,
|
productRepository,
|
||||||
@@ -261,6 +280,8 @@ describe("ProductService", () => {
|
|||||||
productTagRepository,
|
productTagRepository,
|
||||||
productTypeRepository,
|
productTypeRepository,
|
||||||
eventBusService,
|
eventBusService,
|
||||||
|
cartRepository,
|
||||||
|
priceSelectionStrategy,
|
||||||
})
|
})
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@@ -440,7 +461,7 @@ describe("ProductService", () => {
|
|||||||
|
|
||||||
describe("addOption", () => {
|
describe("addOption", () => {
|
||||||
const productRepository = MockRepository({
|
const productRepository = MockRepository({
|
||||||
findOneWithRelations: query =>
|
findOneWithRelations: (query) =>
|
||||||
Promise.resolve({
|
Promise.resolve({
|
||||||
id: IdMap.getId("ironman"),
|
id: IdMap.getId("ironman"),
|
||||||
options: [{ title: "Color" }],
|
options: [{ title: "Color" }],
|
||||||
@@ -449,7 +470,7 @@ describe("ProductService", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const productVariantService = {
|
const productVariantService = {
|
||||||
withTransaction: function() {
|
withTransaction: function () {
|
||||||
return this
|
return this
|
||||||
},
|
},
|
||||||
addOptionValue: jest.fn(),
|
addOptionValue: jest.fn(),
|
||||||
@@ -513,7 +534,7 @@ describe("ProductService", () => {
|
|||||||
|
|
||||||
describe("reorderVariants", () => {
|
describe("reorderVariants", () => {
|
||||||
const productRepository = MockRepository({
|
const productRepository = MockRepository({
|
||||||
findOneWithRelations: query =>
|
findOneWithRelations: (query) =>
|
||||||
Promise.resolve({
|
Promise.resolve({
|
||||||
id: IdMap.getId("ironman"),
|
id: IdMap.getId("ironman"),
|
||||||
variants: [{ id: IdMap.getId("green") }, { id: IdMap.getId("blue") }],
|
variants: [{ id: IdMap.getId("green") }, { id: IdMap.getId("blue") }],
|
||||||
@@ -571,7 +592,7 @@ describe("ProductService", () => {
|
|||||||
|
|
||||||
describe("reorderOptions", () => {
|
describe("reorderOptions", () => {
|
||||||
const productRepository = MockRepository({
|
const productRepository = MockRepository({
|
||||||
findOneWithRelations: query =>
|
findOneWithRelations: (query) =>
|
||||||
Promise.resolve({
|
Promise.resolve({
|
||||||
id: IdMap.getId("ironman"),
|
id: IdMap.getId("ironman"),
|
||||||
options: [
|
options: [
|
||||||
@@ -637,7 +658,7 @@ describe("ProductService", () => {
|
|||||||
|
|
||||||
describe("updateOption", () => {
|
describe("updateOption", () => {
|
||||||
const productRepository = MockRepository({
|
const productRepository = MockRepository({
|
||||||
findOneWithRelations: query =>
|
findOneWithRelations: (query) =>
|
||||||
Promise.resolve({
|
Promise.resolve({
|
||||||
id: IdMap.getId("ironman"),
|
id: IdMap.getId("ironman"),
|
||||||
options: [
|
options: [
|
||||||
@@ -712,7 +733,7 @@ describe("ProductService", () => {
|
|||||||
|
|
||||||
describe("deleteOption", () => {
|
describe("deleteOption", () => {
|
||||||
const productRepository = MockRepository({
|
const productRepository = MockRepository({
|
||||||
findOneWithRelations: query =>
|
findOneWithRelations: (query) =>
|
||||||
Promise.resolve({
|
Promise.resolve({
|
||||||
id: IdMap.getId("ironman"),
|
id: IdMap.getId("ironman"),
|
||||||
variants: [
|
variants: [
|
||||||
@@ -751,7 +772,7 @@ describe("ProductService", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const productOptionRepository = MockRepository({
|
const productOptionRepository = MockRepository({
|
||||||
findOne: query => {
|
findOne: (query) => {
|
||||||
if (query.where.id === IdMap.getId("material")) {
|
if (query.where.id === IdMap.getId("material")) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
import _ from "lodash"
|
import _ from "lodash"
|
||||||
import { EntityManager, DeepPartial } from "typeorm"
|
import {
|
||||||
|
EntityManager,
|
||||||
|
DeepPartial,
|
||||||
|
AlreadyHasActiveConnectionError,
|
||||||
|
} from "typeorm"
|
||||||
import { MedusaError, Validator } from "medusa-core-utils"
|
import { MedusaError, Validator } from "medusa-core-utils"
|
||||||
import { BaseService } from "medusa-interfaces"
|
import { BaseService } from "medusa-interfaces"
|
||||||
|
|
||||||
@@ -38,6 +42,7 @@ import GiftCardService from "./gift-card"
|
|||||||
import TotalsService from "./totals"
|
import TotalsService from "./totals"
|
||||||
import InventoryService from "./inventory"
|
import InventoryService from "./inventory"
|
||||||
import CustomShippingOptionService from "./custom-shipping-option"
|
import CustomShippingOptionService from "./custom-shipping-option"
|
||||||
|
import { IPriceSelectionStrategy } from "../interfaces/price-selection-strategy"
|
||||||
|
|
||||||
type CartConstructorProps = {
|
type CartConstructorProps = {
|
||||||
manager: EntityManager
|
manager: EntityManager
|
||||||
@@ -59,6 +64,7 @@ type CartConstructorProps = {
|
|||||||
totalsService: TotalsService
|
totalsService: TotalsService
|
||||||
inventoryService: InventoryService
|
inventoryService: InventoryService
|
||||||
customShippingOptionService: CustomShippingOptionService
|
customShippingOptionService: CustomShippingOptionService
|
||||||
|
priceSelectionStrategy: IPriceSelectionStrategy
|
||||||
}
|
}
|
||||||
|
|
||||||
type TotalsConfig = {
|
type TotalsConfig = {
|
||||||
@@ -94,6 +100,7 @@ class CartService extends BaseService {
|
|||||||
private paymentSessionRepository_: typeof PaymentSessionRepository
|
private paymentSessionRepository_: typeof PaymentSessionRepository
|
||||||
private inventoryService_: InventoryService
|
private inventoryService_: InventoryService
|
||||||
private customShippingOptionService_: CustomShippingOptionService
|
private customShippingOptionService_: CustomShippingOptionService
|
||||||
|
private priceSelectionStrategy_: IPriceSelectionStrategy
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
manager,
|
manager,
|
||||||
@@ -115,6 +122,7 @@ class CartService extends BaseService {
|
|||||||
paymentSessionRepository,
|
paymentSessionRepository,
|
||||||
inventoryService,
|
inventoryService,
|
||||||
customShippingOptionService,
|
customShippingOptionService,
|
||||||
|
priceSelectionStrategy,
|
||||||
}: CartConstructorProps) {
|
}: CartConstructorProps) {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
@@ -137,6 +145,7 @@ class CartService extends BaseService {
|
|||||||
this.inventoryService_ = inventoryService
|
this.inventoryService_ = inventoryService
|
||||||
this.customShippingOptionService_ = customShippingOptionService
|
this.customShippingOptionService_ = customShippingOptionService
|
||||||
this.taxProviderService_ = taxProviderService
|
this.taxProviderService_ = taxProviderService
|
||||||
|
this.priceSelectionStrategy_ = priceSelectionStrategy
|
||||||
}
|
}
|
||||||
|
|
||||||
withTransaction(transactionManager: EntityManager): CartService {
|
withTransaction(transactionManager: EntityManager): CartService {
|
||||||
@@ -164,6 +173,7 @@ class CartService extends BaseService {
|
|||||||
giftCardService: this.giftCardService_,
|
giftCardService: this.giftCardService_,
|
||||||
inventoryService: this.inventoryService_,
|
inventoryService: this.inventoryService_,
|
||||||
customShippingOptionService: this.customShippingOptionService_,
|
customShippingOptionService: this.customShippingOptionService_,
|
||||||
|
priceSelectionStrategy: this.priceSelectionStrategy_,
|
||||||
})
|
})
|
||||||
|
|
||||||
cloned.transactionManager_ = transactionManager
|
cloned.transactionManager_ = transactionManager
|
||||||
@@ -701,12 +711,6 @@ class CartService extends BaseService {
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
if (typeof update.region_id !== "undefined") {
|
|
||||||
const countryCode =
|
|
||||||
(update.country_code || update.shipping_address?.country_code) ?? null
|
|
||||||
await this.setRegion_(cart, update.region_id, countryCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof update.customer_id !== "undefined") {
|
if (typeof update.customer_id !== "undefined") {
|
||||||
await this.updateCustomerId_(cart, update.customer_id)
|
await this.updateCustomerId_(cart, update.customer_id)
|
||||||
} else {
|
} else {
|
||||||
@@ -718,6 +722,19 @@ class CartService extends BaseService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof update.region_id !== "undefined") {
|
||||||
|
const countryCode =
|
||||||
|
(update.country_code || update.shipping_address?.country_code) ?? null
|
||||||
|
await this.setRegion_(cart, update.region_id, countryCode)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof update.customer_id !== "undefined" ||
|
||||||
|
typeof update.region_id !== "undefined"
|
||||||
|
) {
|
||||||
|
await this.updateUnitPrices(cart, update.region_id, update.customer_id)
|
||||||
|
}
|
||||||
|
|
||||||
const addrRepo = manager.getCustomRepository(this.addressRepository_)
|
const addrRepo = manager.getCustomRepository(this.addressRepository_)
|
||||||
if ("shipping_address_id" in update || "shipping_address" in update) {
|
if ("shipping_address_id" in update || "shipping_address" in update) {
|
||||||
let address: string | Partial<Address> | undefined
|
let address: string | Partial<Address> | undefined
|
||||||
@@ -1169,7 +1186,10 @@ class CartService extends BaseService {
|
|||||||
* this could be IP address or similar for fraud handling.
|
* this could be IP address or similar for fraud handling.
|
||||||
* @return the resulting cart
|
* @return the resulting cart
|
||||||
*/
|
*/
|
||||||
async authorizePayment(cartId: string, context: Record<string, any> = {}): Promise<Cart> {
|
async authorizePayment(
|
||||||
|
cartId: string,
|
||||||
|
context: Record<string, any> = {}
|
||||||
|
): Promise<Cart> {
|
||||||
return this.atomicPhase_(async (manager: EntityManager) => {
|
return this.atomicPhase_(async (manager: EntityManager) => {
|
||||||
const cartRepository = manager.getCustomRepository(this.cartRepository_)
|
const cartRepository = manager.getCustomRepository(this.cartRepository_)
|
||||||
|
|
||||||
@@ -1592,6 +1612,57 @@ class CartService extends BaseService {
|
|||||||
return customOption
|
return customOption
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updateUnitPrices(
|
||||||
|
cart: Cart,
|
||||||
|
regionId?: string,
|
||||||
|
customer_id?: string
|
||||||
|
): Promise<void> {
|
||||||
|
// If the cart contains items, we update the price of the items
|
||||||
|
// to match the updated region or customer id (keeping the old
|
||||||
|
// value if it exists)
|
||||||
|
if (cart.items.length) {
|
||||||
|
const region = await this.regionService_.retrieve(
|
||||||
|
regionId || cart.region_id,
|
||||||
|
{
|
||||||
|
relations: ["countries"],
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
cart.items = await Promise.all(
|
||||||
|
cart.items
|
||||||
|
.map(async (item) => {
|
||||||
|
const availablePrice = await this.priceSelectionStrategy_
|
||||||
|
.calculateVariantPrice(item.variant_id, {
|
||||||
|
region_id: region.id,
|
||||||
|
currency_code: region.currency_code,
|
||||||
|
quantity: item.quantity,
|
||||||
|
customer_id: customer_id || cart.customer_id,
|
||||||
|
include_discount_prices: true,
|
||||||
|
})
|
||||||
|
.catch(() => undefined)
|
||||||
|
|
||||||
|
if (
|
||||||
|
availablePrice !== undefined &&
|
||||||
|
availablePrice.calculatedPrice !== null
|
||||||
|
) {
|
||||||
|
return this.lineItemService_
|
||||||
|
.withTransaction(this.transactionManager_)
|
||||||
|
.update(item.id, {
|
||||||
|
has_shipping: false,
|
||||||
|
unit_price: availablePrice.calculatedPrice,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
await this.lineItemService_
|
||||||
|
.withTransaction(this.transactionManager_)
|
||||||
|
.delete(item.id)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.filter(Boolean)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set's the region of a cart.
|
* Set's the region of a cart.
|
||||||
* @param cart - the cart to set region on
|
* @param cart - the cart to set region on
|
||||||
@@ -1619,34 +1690,6 @@ class CartService extends BaseService {
|
|||||||
cart.region = region
|
cart.region = region
|
||||||
cart.region_id = region.id
|
cart.region_id = region.id
|
||||||
|
|
||||||
// If the cart contains items we want to change the unit_price field of each
|
|
||||||
// item to correspond to the price given in the region
|
|
||||||
if (cart.items.length) {
|
|
||||||
cart.items = await Promise.all(
|
|
||||||
cart.items
|
|
||||||
.map(async (item) => {
|
|
||||||
const availablePrice = await this.productVariantService_
|
|
||||||
.getRegionPrice(item.variant_id, regionId)
|
|
||||||
.catch(() => undefined)
|
|
||||||
|
|
||||||
if (availablePrice !== undefined) {
|
|
||||||
return this.lineItemService_
|
|
||||||
.withTransaction(this.transactionManager_)
|
|
||||||
.update(item.id, {
|
|
||||||
has_shipping: false,
|
|
||||||
unit_price: availablePrice,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
await this.lineItemService_
|
|
||||||
.withTransaction(this.transactionManager_)
|
|
||||||
.delete(item.id)
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.filter(Boolean)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When changing the region you are changing the set of countries that your
|
* When changing the region you are changing the set of countries that your
|
||||||
* cart can be shipped to so we need to make sure that the current shipping
|
* cart can be shipped to so we need to make sure that the current shipping
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ class LineItemService extends BaseService {
|
|||||||
.withTransaction(manager)
|
.withTransaction(manager)
|
||||||
.retrieve(variantId, {
|
.retrieve(variantId, {
|
||||||
relations: ["product"],
|
relations: ["product"],
|
||||||
|
include_discount_prices: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
const region = await this.regionService_
|
const region = await this.regionService_
|
||||||
@@ -164,7 +165,12 @@ class LineItemService extends BaseService {
|
|||||||
} else {
|
} else {
|
||||||
price = await this.productVariantService_
|
price = await this.productVariantService_
|
||||||
.withTransaction(manager)
|
.withTransaction(manager)
|
||||||
.getRegionPrice(variant.id, region.id)
|
.getRegionPrice(variant.id, {
|
||||||
|
regionId: region.id,
|
||||||
|
quantity: quantity,
|
||||||
|
customer_id: undefined,
|
||||||
|
include_discount_prices: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const toCreate = {
|
const toCreate = {
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
|
import { JsonWebTokenError } from "jsonwebtoken"
|
||||||
import { MedusaError } from "medusa-core-utils"
|
import { MedusaError } from "medusa-core-utils"
|
||||||
import { BaseService } from "medusa-interfaces"
|
import { BaseService } from "medusa-interfaces"
|
||||||
import { Brackets, EntityManager, ILike, SelectQueryBuilder } from "typeorm"
|
import { Brackets, EntityManager, ILike, SelectQueryBuilder } from "typeorm"
|
||||||
import { MoneyAmount } from ".."
|
import {
|
||||||
|
IPriceSelectionStrategy,
|
||||||
|
PriceSelectionContext,
|
||||||
|
} from "../interfaces/price-selection-strategy"
|
||||||
|
import { MoneyAmount } from "../models/money-amount"
|
||||||
import { Product } from "../models/product"
|
import { Product } from "../models/product"
|
||||||
import { ProductOptionValue } from "../models/product-option-value"
|
import { ProductOptionValue } from "../models/product-option-value"
|
||||||
import { ProductVariant } from "../models/product-variant"
|
import { ProductVariant } from "../models/product-variant"
|
||||||
|
import { CartRepository } from "../repositories/cart"
|
||||||
import { MoneyAmountRepository } from "../repositories/money-amount"
|
import { MoneyAmountRepository } from "../repositories/money-amount"
|
||||||
import { ProductRepository } from "../repositories/product"
|
import { ProductRepository } from "../repositories/product"
|
||||||
import { ProductOptionValueRepository } from "../repositories/product-option-value"
|
import { ProductOptionValueRepository } from "../repositories/product-option-value"
|
||||||
@@ -18,6 +24,7 @@ import { FindConfig } from "../types/common"
|
|||||||
import {
|
import {
|
||||||
CreateProductVariantInput,
|
CreateProductVariantInput,
|
||||||
FilterableProductVariantProps,
|
FilterableProductVariantProps,
|
||||||
|
GetRegionPriceContext,
|
||||||
ProductVariantPrice,
|
ProductVariantPrice,
|
||||||
UpdateProductVariantInput,
|
UpdateProductVariantInput,
|
||||||
} from "../types/product-variant"
|
} from "../types/product-variant"
|
||||||
@@ -38,8 +45,10 @@ class ProductVariantService extends BaseService {
|
|||||||
private productRepository_: typeof ProductRepository
|
private productRepository_: typeof ProductRepository
|
||||||
private eventBus_: EventBusService
|
private eventBus_: EventBusService
|
||||||
private regionService_: RegionService
|
private regionService_: RegionService
|
||||||
|
private priceSelectionStrategy_: IPriceSelectionStrategy
|
||||||
private moneyAmountRepository_: typeof MoneyAmountRepository
|
private moneyAmountRepository_: typeof MoneyAmountRepository
|
||||||
private productOptionValueRepository_: typeof ProductOptionValueRepository
|
private productOptionValueRepository_: typeof ProductOptionValueRepository
|
||||||
|
private cartRepository_: typeof CartRepository
|
||||||
|
|
||||||
constructor({
|
constructor({
|
||||||
manager,
|
manager,
|
||||||
@@ -49,6 +58,8 @@ class ProductVariantService extends BaseService {
|
|||||||
regionService,
|
regionService,
|
||||||
moneyAmountRepository,
|
moneyAmountRepository,
|
||||||
productOptionValueRepository,
|
productOptionValueRepository,
|
||||||
|
cartRepository,
|
||||||
|
priceSelectionStrategy,
|
||||||
}) {
|
}) {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
@@ -70,6 +81,10 @@ class ProductVariantService extends BaseService {
|
|||||||
this.moneyAmountRepository_ = moneyAmountRepository
|
this.moneyAmountRepository_ = moneyAmountRepository
|
||||||
|
|
||||||
this.productOptionValueRepository_ = productOptionValueRepository
|
this.productOptionValueRepository_ = productOptionValueRepository
|
||||||
|
|
||||||
|
this.cartRepository_ = cartRepository
|
||||||
|
|
||||||
|
this.priceSelectionStrategy_ = priceSelectionStrategy
|
||||||
}
|
}
|
||||||
|
|
||||||
withTransaction(transactionManager: EntityManager): ProductVariantService {
|
withTransaction(transactionManager: EntityManager): ProductVariantService {
|
||||||
@@ -85,6 +100,8 @@ class ProductVariantService extends BaseService {
|
|||||||
regionService: this.regionService_,
|
regionService: this.regionService_,
|
||||||
moneyAmountRepository: this.moneyAmountRepository_,
|
moneyAmountRepository: this.moneyAmountRepository_,
|
||||||
productOptionValueRepository: this.productOptionValueRepository_,
|
productOptionValueRepository: this.productOptionValueRepository_,
|
||||||
|
cartRepository: this.cartRepository_,
|
||||||
|
priceSelectionStrategy: this.priceSelectionStrategy_,
|
||||||
})
|
})
|
||||||
|
|
||||||
cloned.transactionManager_ = transactionManager
|
cloned.transactionManager_ = transactionManager
|
||||||
@@ -100,12 +117,21 @@ class ProductVariantService extends BaseService {
|
|||||||
*/
|
*/
|
||||||
async retrieve(
|
async retrieve(
|
||||||
variantId: string,
|
variantId: string,
|
||||||
config: FindConfig<ProductVariant> = {}
|
config: FindConfig<ProductVariant> & PriceSelectionContext = {
|
||||||
|
include_discount_prices: false,
|
||||||
|
}
|
||||||
): Promise<ProductVariant> {
|
): Promise<ProductVariant> {
|
||||||
const variantRepo = this.manager_.getCustomRepository(
|
const variantRepo = this.manager_.getCustomRepository(
|
||||||
this.productVariantRepository_
|
this.productVariantRepository_
|
||||||
)
|
)
|
||||||
const validatedId = this.validateId_(variantId)
|
const validatedId = this.validateId_(variantId)
|
||||||
|
|
||||||
|
const priceIndex = config.relations?.indexOf("prices") ?? -1
|
||||||
|
if (priceIndex >= 0 && config.relations) {
|
||||||
|
config.relations = [...config.relations]
|
||||||
|
config.relations.splice(priceIndex, 1)
|
||||||
|
}
|
||||||
|
|
||||||
const query = this.buildQuery_({ id: validatedId }, config)
|
const query = this.buildQuery_({ id: validatedId }, config)
|
||||||
const variant = await variantRepo.findOne(query)
|
const variant = await variantRepo.findOne(query)
|
||||||
|
|
||||||
@@ -116,7 +142,16 @@ class ProductVariantService extends BaseService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return variant
|
return priceIndex >= 0
|
||||||
|
? ((await this.setAdditionalPrices(
|
||||||
|
variant,
|
||||||
|
config.currency_code,
|
||||||
|
config.region_id,
|
||||||
|
config.cart_id,
|
||||||
|
config.customer_id,
|
||||||
|
config.include_discount_prices
|
||||||
|
)) as ProductVariant)
|
||||||
|
: variant
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -127,11 +162,20 @@ class ProductVariantService extends BaseService {
|
|||||||
*/
|
*/
|
||||||
async retrieveBySKU(
|
async retrieveBySKU(
|
||||||
sku: string,
|
sku: string,
|
||||||
config: FindConfig<ProductVariant> = {}
|
config: FindConfig<ProductVariant> & PriceSelectionContext = {
|
||||||
|
include_discount_prices: false,
|
||||||
|
}
|
||||||
): Promise<ProductVariant> {
|
): Promise<ProductVariant> {
|
||||||
const variantRepo = this.manager_.getCustomRepository(
|
const variantRepo = this.manager_.getCustomRepository(
|
||||||
this.productVariantRepository_
|
this.productVariantRepository_
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const priceIndex = config.relations?.indexOf("prices") ?? -1
|
||||||
|
if (priceIndex >= 0 && config.relations) {
|
||||||
|
config.relations = [...config.relations]
|
||||||
|
config.relations.splice(priceIndex, 1)
|
||||||
|
}
|
||||||
|
|
||||||
const query = this.buildQuery_({ sku }, config)
|
const query = this.buildQuery_({ sku }, config)
|
||||||
const variant = await variantRepo.findOne(query)
|
const variant = await variantRepo.findOne(query)
|
||||||
|
|
||||||
@@ -142,7 +186,16 @@ class ProductVariantService extends BaseService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return variant
|
return priceIndex >= 0
|
||||||
|
? ((await this.setAdditionalPrices(
|
||||||
|
variant,
|
||||||
|
config.currency_code,
|
||||||
|
config.region_id,
|
||||||
|
config.cart_id,
|
||||||
|
config.customer_id,
|
||||||
|
config.include_discount_prices
|
||||||
|
)) as ProductVariant)
|
||||||
|
: variant
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -254,6 +307,7 @@ class ProductVariantService extends BaseService {
|
|||||||
* The function will throw, if price updates are attempted.
|
* The function will throw, if price updates are attempted.
|
||||||
* @param {string | ProductVariant} variantOrVariantId - variant or id of a variant.
|
* @param {string | ProductVariant} variantOrVariantId - variant or id of a variant.
|
||||||
* @param {object} update - an object with the update values.
|
* @param {object} update - an object with the update values.
|
||||||
|
* @param {object} config - an object with the config values for returning the variant.
|
||||||
* @return {Promise} resolves to the update result.
|
* @return {Promise} resolves to the update result.
|
||||||
*/
|
*/
|
||||||
async update(
|
async update(
|
||||||
@@ -267,7 +321,17 @@ class ProductVariantService extends BaseService {
|
|||||||
|
|
||||||
let variant = variantOrVariantId as ProductVariant
|
let variant = variantOrVariantId as ProductVariant
|
||||||
if (typeof variant === `string`) {
|
if (typeof variant === `string`) {
|
||||||
variant = await this.retrieve(variantOrVariantId as string)
|
const variantRes = await variantRepo.findOne({
|
||||||
|
where: { id: variantOrVariantId as string },
|
||||||
|
})
|
||||||
|
if (typeof variant === "undefined") {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.NOT_FOUND,
|
||||||
|
`Variant with id ${variantOrVariantId} was not found`
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
variant = variantRes as ProductVariant
|
||||||
|
}
|
||||||
} else if (!variant.id) {
|
} else if (!variant.id) {
|
||||||
throw new MedusaError(
|
throw new MedusaError(
|
||||||
MedusaError.Types.INVALID_DATA,
|
MedusaError.Types.INVALID_DATA,
|
||||||
@@ -291,12 +355,12 @@ class ProductVariantService extends BaseService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (metadata) {
|
if (typeof metadata === "object") {
|
||||||
variant.metadata = this.setMetadata_(variant, metadata)
|
variant.metadata = this.setMetadata_(variant, metadata as object)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof inventory_quantity === "number") {
|
if (typeof inventory_quantity === "number") {
|
||||||
variant.inventory_quantity = inventory_quantity
|
variant.inventory_quantity = inventory_quantity as number
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [key, value] of Object.entries(rest)) {
|
for (const [key, value] of Object.entries(rest)) {
|
||||||
@@ -312,6 +376,7 @@ class ProductVariantService extends BaseService {
|
|||||||
product_id: result.product_id,
|
product_id: result.product_id,
|
||||||
fields: Object.keys(update),
|
fields: Object.keys(update),
|
||||||
})
|
})
|
||||||
|
|
||||||
return result
|
return result
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -358,41 +423,29 @@ class ProductVariantService extends BaseService {
|
|||||||
* exists the function will try to use a currency price. If no default
|
* exists the function will try to use a currency price. If no default
|
||||||
* currency price exists the function will throw an error.
|
* currency price exists the function will throw an error.
|
||||||
* @param {string} variantId - the id of the variant to get price from
|
* @param {string} variantId - the id of the variant to get price from
|
||||||
* @param {string} regionId - the id of the region to get price for
|
* @param {GetRegionPriceContext} context - context for getting region price
|
||||||
* @return {number} the price specific to the region
|
* @return {number} the price specific to the region
|
||||||
*/
|
*/
|
||||||
async getRegionPrice(variantId: string, regionId: string): Promise<number> {
|
async getRegionPrice(
|
||||||
|
variantId: string,
|
||||||
|
context: GetRegionPriceContext
|
||||||
|
): Promise<number> {
|
||||||
return this.atomicPhase_(async (manager: EntityManager) => {
|
return this.atomicPhase_(async (manager: EntityManager) => {
|
||||||
const moneyAmountRepo = manager.getCustomRepository(
|
|
||||||
this.moneyAmountRepository_
|
|
||||||
)
|
|
||||||
|
|
||||||
const region = await this.regionService_
|
const region = await this.regionService_
|
||||||
.withTransaction(manager)
|
.withTransaction(manager)
|
||||||
.retrieve(regionId)
|
.retrieve(context.regionId)
|
||||||
|
|
||||||
// Find region price based on region id
|
const prices = await this.priceSelectionStrategy_
|
||||||
let moneyAmount = await moneyAmountRepo.findOne({
|
.withTransaction(manager)
|
||||||
where: { region_id: regionId, variant_id: variantId },
|
.calculateVariantPrice(variantId, {
|
||||||
})
|
region_id: context.regionId,
|
||||||
|
currency_code: region.currency_code,
|
||||||
// If no price could be find based on region id, we try to fetch
|
quantity: context.quantity,
|
||||||
// based on the region currency code
|
customer_id: context.customer_id,
|
||||||
if (!moneyAmount) {
|
include_discount_prices: !!context.include_discount_prices,
|
||||||
moneyAmount = await moneyAmountRepo.findOne({
|
|
||||||
where: { variant_id: variantId, currency_code: region.currency_code },
|
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
// Still, if no price is found, we throw
|
return prices.calculatedPrice
|
||||||
if (!moneyAmount) {
|
|
||||||
throw new MedusaError(
|
|
||||||
MedusaError.Types.NOT_FOUND,
|
|
||||||
`A price for region: ${region.name} could not be found`
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return moneyAmount.amount
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -554,12 +607,23 @@ class ProductVariantService extends BaseService {
|
|||||||
*/
|
*/
|
||||||
async listAndCount(
|
async listAndCount(
|
||||||
selector: FilterableProductVariantProps,
|
selector: FilterableProductVariantProps,
|
||||||
config: FindConfig<ProductVariant> = { relations: [], skip: 0, take: 20 }
|
config: FindConfig<ProductVariant> & PriceSelectionContext = {
|
||||||
|
relations: [],
|
||||||
|
skip: 0,
|
||||||
|
take: 20,
|
||||||
|
include_discount_prices: false,
|
||||||
|
}
|
||||||
): Promise<[ProductVariant[], number]> {
|
): Promise<[ProductVariant[], number]> {
|
||||||
const variantRepo = this.manager_.getCustomRepository(
|
const variantRepo = this.manager_.getCustomRepository(
|
||||||
this.productVariantRepository_
|
this.productVariantRepository_
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const priceIndex = config.relations?.indexOf("prices") ?? -1
|
||||||
|
if (priceIndex >= 0 && config.relations) {
|
||||||
|
config.relations = [...config.relations]
|
||||||
|
config.relations.splice(priceIndex, 1)
|
||||||
|
}
|
||||||
|
|
||||||
const { q, query, relations } = this.prepareListQuery_(selector, config)
|
const { q, query, relations } = this.prepareListQuery_(selector, config)
|
||||||
|
|
||||||
if (q) {
|
if (q) {
|
||||||
@@ -571,10 +635,39 @@ class ProductVariantService extends BaseService {
|
|||||||
raw.map((i) => i.id),
|
raw.map((i) => i.id),
|
||||||
query.withDeleted ?? false
|
query.withDeleted ?? false
|
||||||
)
|
)
|
||||||
|
if (priceIndex >= 0) {
|
||||||
|
const res = await this.setAdditionalPrices(
|
||||||
|
variants,
|
||||||
|
config.currency_code,
|
||||||
|
config.region_id,
|
||||||
|
config.cart_id,
|
||||||
|
config.customer_id,
|
||||||
|
config.include_discount_prices
|
||||||
|
)
|
||||||
|
return [res as ProductVariant[], count]
|
||||||
|
}
|
||||||
|
|
||||||
return [variants, count]
|
return [variants, count]
|
||||||
}
|
}
|
||||||
|
|
||||||
return await variantRepo.findWithRelationsAndCount(relations, query)
|
const [variants, count] = await variantRepo.findWithRelationsAndCount(
|
||||||
|
relations,
|
||||||
|
query
|
||||||
|
)
|
||||||
|
|
||||||
|
if (priceIndex >= 0) {
|
||||||
|
const res = await this.setAdditionalPrices(
|
||||||
|
variants,
|
||||||
|
config.currency_code,
|
||||||
|
config.region_id,
|
||||||
|
config.cart_id,
|
||||||
|
config.customer_id,
|
||||||
|
config.include_discount_prices
|
||||||
|
)
|
||||||
|
return [res as ProductVariant[], count]
|
||||||
|
}
|
||||||
|
|
||||||
|
return [variants, count]
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -584,12 +677,22 @@ class ProductVariantService extends BaseService {
|
|||||||
*/
|
*/
|
||||||
async list(
|
async list(
|
||||||
selector: FilterableProductVariantProps,
|
selector: FilterableProductVariantProps,
|
||||||
config: FindConfig<ProductVariant> = { relations: [], skip: 0, take: 20 }
|
config: FindConfig<ProductVariant> & PriceSelectionContext = {
|
||||||
|
relations: [],
|
||||||
|
skip: 0,
|
||||||
|
take: 20,
|
||||||
|
}
|
||||||
): Promise<ProductVariant[]> {
|
): Promise<ProductVariant[]> {
|
||||||
const productVariantRepo = this.manager_.getCustomRepository(
|
const productVariantRepo = this.manager_.getCustomRepository(
|
||||||
this.productVariantRepository_
|
this.productVariantRepository_
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const priceIndex = config.relations?.indexOf("prices") ?? -1
|
||||||
|
if (priceIndex >= 0 && config.relations) {
|
||||||
|
config.relations = [...config.relations]
|
||||||
|
config.relations.splice(priceIndex, 1)
|
||||||
|
}
|
||||||
|
|
||||||
let q: string | undefined
|
let q: string | undefined
|
||||||
if ("q" in selector) {
|
if ("q" in selector) {
|
||||||
q = selector.q
|
q = selector.q
|
||||||
@@ -620,7 +723,18 @@ class ProductVariantService extends BaseService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return await productVariantRepo.find(query)
|
const variants = await productVariantRepo.find(query)
|
||||||
|
|
||||||
|
return priceIndex >= 0
|
||||||
|
? ((await this.setAdditionalPrices(
|
||||||
|
variants,
|
||||||
|
config.currency_code,
|
||||||
|
config.region_id,
|
||||||
|
config.cart_id,
|
||||||
|
config.customer_id,
|
||||||
|
config.include_discount_prices
|
||||||
|
)) as ProductVariant[])
|
||||||
|
: variants
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -770,6 +884,72 @@ class ProductVariantService extends BaseService {
|
|||||||
|
|
||||||
return qb
|
return qb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set additional prices on a list of variants.
|
||||||
|
* @param {ProductVariant | ProductVariant[] } variant variant on which to set additional prices
|
||||||
|
* @param {string} currency_code currency code to fetch prices for
|
||||||
|
* @param {string} region_id region to fetch prices for
|
||||||
|
* @param {string} cart_id string of cart to use as a basis for getting currency and region
|
||||||
|
* @param {string} customer_id id of potentially logged in customer, used to get prices valid for their customer groups
|
||||||
|
* @param {boolean} include_discount_prices should result include discount pricing
|
||||||
|
* @return {Promise<ProductVariant | ProductVariant[]>} A list of variants with variants decorated with "additional_prices"
|
||||||
|
*/
|
||||||
|
async setAdditionalPrices(
|
||||||
|
variant,
|
||||||
|
currency_code,
|
||||||
|
region_id,
|
||||||
|
cart_id,
|
||||||
|
customer_id,
|
||||||
|
include_discount_prices = false
|
||||||
|
): Promise<ProductVariant | ProductVariant[]> {
|
||||||
|
return this.atomicPhase_(async (manager) => {
|
||||||
|
const cartRepo = manager.getCustomRepository(this.cartRepository_)
|
||||||
|
|
||||||
|
let regionId = region_id
|
||||||
|
let currencyCode = currency_code
|
||||||
|
|
||||||
|
if (cart_id) {
|
||||||
|
const cart = await cartRepo.findOne({
|
||||||
|
where: { id: cart_id },
|
||||||
|
relations: ["region"],
|
||||||
|
})
|
||||||
|
|
||||||
|
regionId = cart.region.id
|
||||||
|
currencyCode = cart.region.currency_code
|
||||||
|
}
|
||||||
|
|
||||||
|
const variantArray = Array.isArray(variant) ? variant : [variant]
|
||||||
|
|
||||||
|
const priceSelectionStrategy =
|
||||||
|
this.priceSelectionStrategy_.withTransaction(manager)
|
||||||
|
|
||||||
|
const variantsWithPrices = await Promise.all(
|
||||||
|
variantArray.map(async (v) => {
|
||||||
|
const prices = await priceSelectionStrategy.calculateVariantPrice(
|
||||||
|
v.id,
|
||||||
|
{
|
||||||
|
region_id: regionId,
|
||||||
|
currency_code: currencyCode,
|
||||||
|
cart_id: cart_id,
|
||||||
|
customer_id: customer_id,
|
||||||
|
include_discount_prices: include_discount_prices,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
...v,
|
||||||
|
prices: prices.prices,
|
||||||
|
original_price: prices.originalPrice,
|
||||||
|
calculated_price: prices.calculatedPrice,
|
||||||
|
calculated_price_type: prices.calculatedPriceType,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
return Array.isArray(variant) ? variantsWithPrices : variantsWithPrices[0]
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ProductVariantService
|
export default ProductVariantService
|
||||||
@@ -27,6 +27,8 @@ class ProductService extends BaseService {
|
|||||||
productTagRepository,
|
productTagRepository,
|
||||||
imageRepository,
|
imageRepository,
|
||||||
searchService,
|
searchService,
|
||||||
|
cartRepository,
|
||||||
|
priceSelectionStrategy,
|
||||||
}) {
|
}) {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
@@ -62,6 +64,12 @@ class ProductService extends BaseService {
|
|||||||
|
|
||||||
/** @private @const {SearchService} */
|
/** @private @const {SearchService} */
|
||||||
this.searchService_ = searchService
|
this.searchService_ = searchService
|
||||||
|
|
||||||
|
/** @private @const {CartRepository} */
|
||||||
|
this.cartRepository_ = cartRepository
|
||||||
|
|
||||||
|
/** @private @const {IPriceSelectionStrategy} */
|
||||||
|
this.priceSelectionStrategy_ = priceSelectionStrategy
|
||||||
}
|
}
|
||||||
|
|
||||||
withTransaction(transactionManager) {
|
withTransaction(transactionManager) {
|
||||||
@@ -80,6 +88,8 @@ class ProductService extends BaseService {
|
|||||||
productTagRepository: this.productTagRepository_,
|
productTagRepository: this.productTagRepository_,
|
||||||
productTypeRepository: this.productTypeRepository_,
|
productTypeRepository: this.productTypeRepository_,
|
||||||
imageRepository: this.imageRepository_,
|
imageRepository: this.imageRepository_,
|
||||||
|
cartRepository: this.cartRepository_,
|
||||||
|
priceSelectionStrategy: this.priceSelectionStrategy_,
|
||||||
})
|
})
|
||||||
|
|
||||||
cloned.transactionManager_ = transactionManager
|
cloned.transactionManager_ = transactionManager
|
||||||
@@ -95,10 +105,23 @@ class ProductService extends BaseService {
|
|||||||
* returned
|
* returned
|
||||||
* @return {Promise<Product[]>} the result of the find operation
|
* @return {Promise<Product[]>} the result of the find operation
|
||||||
*/
|
*/
|
||||||
async list(selector = {}, config = { relations: [], skip: 0, take: 20 }) {
|
async list(
|
||||||
|
selector = {},
|
||||||
|
config = {
|
||||||
|
relations: [],
|
||||||
|
skip: 0,
|
||||||
|
take: 20,
|
||||||
|
include_discount_prices: false,
|
||||||
|
}
|
||||||
|
) {
|
||||||
const productRepo = this.manager_.getCustomRepository(
|
const productRepo = this.manager_.getCustomRepository(
|
||||||
this.productRepository_
|
this.productRepository_
|
||||||
)
|
)
|
||||||
|
const priceIndex = config.relations?.indexOf("variants.prices") ?? -1
|
||||||
|
if (priceIndex >= 0 && config.relations) {
|
||||||
|
config.relations = [...config.relations]
|
||||||
|
config.relations.splice(priceIndex, 1)
|
||||||
|
}
|
||||||
|
|
||||||
const { q, query, relations } = this.prepareListQuery_(selector, config)
|
const { q, query, relations } = this.prepareListQuery_(selector, config)
|
||||||
|
|
||||||
@@ -112,7 +135,18 @@ class ProductService extends BaseService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return productRepo.findWithRelations(relations, query)
|
const products = productRepo.findWithRelations(relations, query)
|
||||||
|
|
||||||
|
return priceIndex > -1
|
||||||
|
? await this.setAdditionalPrices(
|
||||||
|
products,
|
||||||
|
config.currency_code,
|
||||||
|
config.region_id,
|
||||||
|
config.cart_id,
|
||||||
|
config.customer_id,
|
||||||
|
config.include_discount_prices
|
||||||
|
)
|
||||||
|
: products
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -128,12 +162,23 @@ class ProductService extends BaseService {
|
|||||||
*/
|
*/
|
||||||
async listAndCount(
|
async listAndCount(
|
||||||
selector = {},
|
selector = {},
|
||||||
config = { relations: [], skip: 0, take: 20 }
|
config = {
|
||||||
|
relations: [],
|
||||||
|
skip: 0,
|
||||||
|
take: 20,
|
||||||
|
include_discount_prices: false,
|
||||||
|
}
|
||||||
) {
|
) {
|
||||||
const productRepo = this.manager_.getCustomRepository(
|
const productRepo = this.manager_.getCustomRepository(
|
||||||
this.productRepository_
|
this.productRepository_
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const priceIndex = config.relations?.indexOf("variants.prices") ?? -1
|
||||||
|
if (priceIndex >= 0 && config.relations) {
|
||||||
|
config.relations = [...config.relations]
|
||||||
|
config.relations.splice(priceIndex, 1)
|
||||||
|
}
|
||||||
|
|
||||||
const { q, query, relations } = this.prepareListQuery_(selector, config)
|
const { q, query, relations } = this.prepareListQuery_(selector, config)
|
||||||
|
|
||||||
if (q) {
|
if (q) {
|
||||||
@@ -148,7 +193,25 @@ class ProductService extends BaseService {
|
|||||||
return [products, count]
|
return [products, count]
|
||||||
}
|
}
|
||||||
|
|
||||||
return await productRepo.findWithRelationsAndCount(relations, query)
|
const [products, count] = await productRepo.findWithRelationsAndCount(
|
||||||
|
relations,
|
||||||
|
query
|
||||||
|
)
|
||||||
|
|
||||||
|
if (priceIndex > -1) {
|
||||||
|
const productsWithAdditionalPrices = await this.setAdditionalPrices(
|
||||||
|
products,
|
||||||
|
config.currency_code,
|
||||||
|
config.region_id,
|
||||||
|
config.cart_id,
|
||||||
|
config.customer_id,
|
||||||
|
config.include_discount_prices
|
||||||
|
)
|
||||||
|
|
||||||
|
return [productsWithAdditionalPrices, count]
|
||||||
|
} else {
|
||||||
|
return [products, count]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -172,12 +235,18 @@ class ProductService extends BaseService {
|
|||||||
* query response
|
* query response
|
||||||
* @return {Promise<Product>} the result of the find one operation.
|
* @return {Promise<Product>} the result of the find one operation.
|
||||||
*/
|
*/
|
||||||
async retrieve(productId, config = {}) {
|
async retrieve(productId, config = { include_discount_prices: false }) {
|
||||||
const productRepo = this.manager_.getCustomRepository(
|
const productRepo = this.manager_.getCustomRepository(
|
||||||
this.productRepository_
|
this.productRepository_
|
||||||
)
|
)
|
||||||
const validatedId = this.validateId_(productId)
|
const validatedId = this.validateId_(productId)
|
||||||
|
|
||||||
|
const priceIndex = config.relations?.indexOf("variants.prices") ?? -1
|
||||||
|
if (priceIndex >= 0 && config.relations) {
|
||||||
|
config.relations = [...config.relations]
|
||||||
|
config.relations.splice(priceIndex, 1)
|
||||||
|
}
|
||||||
|
|
||||||
const query = { where: { id: validatedId } }
|
const query = { where: { id: validatedId } }
|
||||||
|
|
||||||
if (config.relations && config.relations.length > 0) {
|
if (config.relations && config.relations.length > 0) {
|
||||||
@@ -199,7 +268,16 @@ class ProductService extends BaseService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return product
|
return priceIndex > -1
|
||||||
|
? await this.setAdditionalPrices(
|
||||||
|
product,
|
||||||
|
config.currency_code,
|
||||||
|
config.region_id,
|
||||||
|
config.cart_id,
|
||||||
|
config.customer_id,
|
||||||
|
config.include_discount_prices
|
||||||
|
)
|
||||||
|
: product
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -214,6 +292,12 @@ class ProductService extends BaseService {
|
|||||||
this.productRepository_
|
this.productRepository_
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const priceIndex = config.relations?.indexOf("variants.prices") ?? -1
|
||||||
|
if (priceIndex >= 0 && config.relations) {
|
||||||
|
config.relations = [...config.relations]
|
||||||
|
config.relations.splice(priceIndex, 1)
|
||||||
|
}
|
||||||
|
|
||||||
const query = { where: { handle: productHandle } }
|
const query = { where: { handle: productHandle } }
|
||||||
|
|
||||||
if (config.relations && config.relations.length > 0) {
|
if (config.relations && config.relations.length > 0) {
|
||||||
@@ -235,7 +319,16 @@ class ProductService extends BaseService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return product
|
return priceIndex > -1
|
||||||
|
? await this.setAdditionalPrices(
|
||||||
|
product,
|
||||||
|
config.currency_code,
|
||||||
|
config.region_id,
|
||||||
|
config.cart_id,
|
||||||
|
config.customer_id,
|
||||||
|
config.include_discount_prices
|
||||||
|
)
|
||||||
|
: product
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -250,6 +343,12 @@ class ProductService extends BaseService {
|
|||||||
this.productRepository_
|
this.productRepository_
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const priceIndex = config.relations?.indexOf("variants.prices") ?? -1
|
||||||
|
if (priceIndex >= 0 && config.relations) {
|
||||||
|
config.relations = [...config.relations]
|
||||||
|
config.relations.splice(priceIndex, 1)
|
||||||
|
}
|
||||||
|
|
||||||
const query = { where: { external_id: externalId } }
|
const query = { where: { external_id: externalId } }
|
||||||
|
|
||||||
if (config.relations && config.relations.length > 0) {
|
if (config.relations && config.relations.length > 0) {
|
||||||
@@ -271,7 +370,16 @@ class ProductService extends BaseService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return product
|
return priceIndex > -1
|
||||||
|
? await this.setAdditionalPrices(
|
||||||
|
product,
|
||||||
|
config.currency_code,
|
||||||
|
config.region_id,
|
||||||
|
config.cart_id,
|
||||||
|
config.customer_id,
|
||||||
|
config.include_discount_prices
|
||||||
|
)
|
||||||
|
: product
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -535,6 +643,7 @@ class ProductService extends BaseService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const result = await productRepo.save(product)
|
const result = await productRepo.save(product)
|
||||||
|
|
||||||
await this.eventBus_
|
await this.eventBus_
|
||||||
.withTransaction(manager)
|
.withTransaction(manager)
|
||||||
.emit(ProductService.Events.UPDATED, {
|
.emit(ProductService.Events.UPDATED, {
|
||||||
@@ -821,11 +930,18 @@ class ProductService extends BaseService {
|
|||||||
* @param {string} productId - the productId to decorate.
|
* @param {string} productId - the productId to decorate.
|
||||||
* @param {string[]} fields - the fields to include.
|
* @param {string[]} fields - the fields to include.
|
||||||
* @param {string[]} expandFields - fields to expand.
|
* @param {string[]} expandFields - fields to expand.
|
||||||
|
* @param {object} config - retrieve config for price calculation.
|
||||||
* @return {Product} return the decorated product.
|
* @return {Product} return the decorated product.
|
||||||
*/
|
*/
|
||||||
async decorate(productId, fields = [], expandFields = []) {
|
async decorate(productId, fields = [], expandFields = [], config = {}) {
|
||||||
const requiredFields = ["id", "metadata"]
|
const requiredFields = ["id", "metadata"]
|
||||||
|
|
||||||
|
const priceIndex = expandFields.indexOf("variants.prices") ?? -1
|
||||||
|
if (priceIndex >= 0 && expandFields.length) {
|
||||||
|
expandFields = [...expandFields]
|
||||||
|
expandFields.splice(priceIndex, 1)
|
||||||
|
}
|
||||||
|
|
||||||
fields = fields.concat(requiredFields)
|
fields = fields.concat(requiredFields)
|
||||||
|
|
||||||
const product = await this.retrieve(productId, {
|
const product = await this.retrieve(productId, {
|
||||||
@@ -833,8 +949,16 @@ class ProductService extends BaseService {
|
|||||||
relations: expandFields,
|
relations: expandFields,
|
||||||
})
|
})
|
||||||
|
|
||||||
// const final = await this.runDecorators_(decorated)
|
return priceIndex > -1
|
||||||
return product
|
? await this.setAdditionalPrices(
|
||||||
|
product,
|
||||||
|
config.currency_code,
|
||||||
|
config.region_id,
|
||||||
|
config.cart_id,
|
||||||
|
config.customer_id,
|
||||||
|
config.include_discount_prices
|
||||||
|
)
|
||||||
|
: product
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -908,6 +1032,80 @@ class ProductService extends BaseService {
|
|||||||
|
|
||||||
return qb
|
return qb
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set additional prices on a list of products.
|
||||||
|
* @param {Product[] | Product} products list of products on which to set additional prices
|
||||||
|
* @param {string} currency_code currency code to fetch prices for
|
||||||
|
* @param {string} region_id region to fetch prices for
|
||||||
|
* @param {string} cart_id string of cart to use as a basis for getting currency and region
|
||||||
|
* @param {string} customer_id id of potentially logged in customer, used to get prices valid for their customer groups
|
||||||
|
* @param {boolean} include_discount_prices indication wether or not to include sales prices in result
|
||||||
|
* @return {Promise<Product[]>} A list of products with variants decorated with "additional_prices"
|
||||||
|
*/
|
||||||
|
async setAdditionalPrices(
|
||||||
|
products,
|
||||||
|
currency_code,
|
||||||
|
region_id,
|
||||||
|
cart_id,
|
||||||
|
customer_id,
|
||||||
|
include_discount_prices = false
|
||||||
|
) {
|
||||||
|
return this.atomicPhase_(async (manager) => {
|
||||||
|
const cartRepo = this.manager_.getCustomRepository(this.cartRepository_)
|
||||||
|
|
||||||
|
let regionId = region_id
|
||||||
|
let currencyCode = currency_code
|
||||||
|
|
||||||
|
if (cart_id) {
|
||||||
|
const cart = await cartRepo.findOne({
|
||||||
|
where: { id: cart_id },
|
||||||
|
relations: ["region"],
|
||||||
|
})
|
||||||
|
|
||||||
|
regionId = cart.region.id
|
||||||
|
currencyCode = cart.region.currency_code
|
||||||
|
}
|
||||||
|
|
||||||
|
const productArray = Array.isArray(products) ? products : [products]
|
||||||
|
|
||||||
|
const priceSelectionStrategy =
|
||||||
|
this.priceSelectionStrategy_.withTransaction(manager)
|
||||||
|
|
||||||
|
const productsWithPrices = await Promise.all(
|
||||||
|
productArray.map(async (p) => {
|
||||||
|
if (p.variants?.length) {
|
||||||
|
p.variants = await Promise.all(
|
||||||
|
p.variants.map(async (v) => {
|
||||||
|
const prices =
|
||||||
|
await priceSelectionStrategy.calculateVariantPrice(v.id, {
|
||||||
|
region_id: regionId,
|
||||||
|
currency_code: currencyCode,
|
||||||
|
cart_id: cart_id,
|
||||||
|
customer_id: customer_id,
|
||||||
|
include_discount_prices,
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
...v,
|
||||||
|
prices: prices.prices,
|
||||||
|
original_price: prices.originalPrice,
|
||||||
|
calculated_price: prices.calculatedPrice,
|
||||||
|
calculated_price_type: prices.calculatedPriceType,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return p
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
return Array.isArray(products)
|
||||||
|
? productsWithPrices
|
||||||
|
: productsWithPrices[0]
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ProductService
|
export default ProductService
|
||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
} from "../interfaces/price-selection-strategy"
|
} from "../interfaces/price-selection-strategy"
|
||||||
import { MoneyAmountRepository } from "../repositories/money-amount"
|
import { MoneyAmountRepository } from "../repositories/money-amount"
|
||||||
import { EntityManager } from "typeorm"
|
import { EntityManager } from "typeorm"
|
||||||
|
import { MedusaError } from "medusa-core-utils"
|
||||||
|
|
||||||
class PriceSelectionStrategy extends AbstractPriceSelectionStrategy {
|
class PriceSelectionStrategy extends AbstractPriceSelectionStrategy {
|
||||||
private moneyAmountRepository_: typeof MoneyAmountRepository
|
private moneyAmountRepository_: typeof MoneyAmountRepository
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
import { IsOptional, IsString } from "class-validator"
|
||||||
|
|
||||||
|
export class PriceSelectionParams {
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
cart_id?: string
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
region_id?: string
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
currency_code?: string
|
||||||
|
}
|
||||||
@@ -25,6 +25,13 @@ export type ProductVariantPrice = {
|
|||||||
max_quantity?: number
|
max_quantity?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type GetRegionPriceContext = {
|
||||||
|
regionId: string
|
||||||
|
quantity?: number
|
||||||
|
customer_id?: string
|
||||||
|
include_discount_prices?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
export type ProductVariantOption = {
|
export type ProductVariantOption = {
|
||||||
option_id: string
|
option_id: string
|
||||||
value: string
|
value: string
|
||||||
|
|||||||
Reference in new issue
Block a user