fix: adds tax calculation to product pricing (#1354)
* fix: adds tax calculation to product pricing * fix: dedupe * fix: merge inconsistencies * fix: merge inconsistencies
This commit is contained in:
1 parent
9a3ff32b42
commit
14366f536d
31 files changed
+781
-423
No files matched your search
@@ -79,6 +79,8 @@ Array [
|
|||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": "test-barcode",
|
"barcode": "test-barcode",
|
||||||
"calculated_price": null,
|
"calculated_price": null,
|
||||||
|
"calculated_price_incl_tax": null,
|
||||||
|
"calculated_tax": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": "test-ean",
|
"ean": "test-ean",
|
||||||
@@ -105,6 +107,8 @@ Array [
|
|||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
"original_price": null,
|
"original_price": null,
|
||||||
|
"original_price_incl_tax": null,
|
||||||
|
"original_tax": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -123,6 +127,7 @@ Array [
|
|||||||
],
|
],
|
||||||
"product_id": StringMatching /\\^test-\\*/,
|
"product_id": StringMatching /\\^test-\\*/,
|
||||||
"sku": "test-sku",
|
"sku": "test-sku",
|
||||||
|
"tax_rates": null,
|
||||||
"title": "Test variant",
|
"title": "Test variant",
|
||||||
"upc": "test-upc",
|
"upc": "test-upc",
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
@@ -133,6 +138,8 @@ Array [
|
|||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": null,
|
"barcode": null,
|
||||||
"calculated_price": null,
|
"calculated_price": null,
|
||||||
|
"calculated_price_incl_tax": null,
|
||||||
|
"calculated_tax": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": "test-ean2",
|
"ean": "test-ean2",
|
||||||
@@ -159,6 +166,8 @@ Array [
|
|||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
"original_price": null,
|
"original_price": null,
|
||||||
|
"original_price_incl_tax": null,
|
||||||
|
"original_tax": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -177,6 +186,7 @@ Array [
|
|||||||
],
|
],
|
||||||
"product_id": StringMatching /\\^test-\\*/,
|
"product_id": StringMatching /\\^test-\\*/,
|
||||||
"sku": "test-sku2",
|
"sku": "test-sku2",
|
||||||
|
"tax_rates": null,
|
||||||
"title": "Test variant rank (2)",
|
"title": "Test variant rank (2)",
|
||||||
"upc": "test-upc2",
|
"upc": "test-upc2",
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
@@ -187,6 +197,8 @@ Array [
|
|||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": "test-barcode 1",
|
"barcode": "test-barcode 1",
|
||||||
"calculated_price": null,
|
"calculated_price": null,
|
||||||
|
"calculated_price_incl_tax": null,
|
||||||
|
"calculated_tax": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": "test-ean1",
|
"ean": "test-ean1",
|
||||||
@@ -213,6 +225,8 @@ Array [
|
|||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
"original_price": null,
|
"original_price": null,
|
||||||
|
"original_price_incl_tax": null,
|
||||||
|
"original_tax": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -231,6 +245,7 @@ Array [
|
|||||||
],
|
],
|
||||||
"product_id": StringMatching /\\^test-\\*/,
|
"product_id": StringMatching /\\^test-\\*/,
|
||||||
"sku": "test-sku1",
|
"sku": "test-sku1",
|
||||||
|
"tax_rates": null,
|
||||||
"title": "Test variant rank (1)",
|
"title": "Test variant rank (1)",
|
||||||
"upc": "test-upc1",
|
"upc": "test-upc1",
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
@@ -241,6 +256,8 @@ Array [
|
|||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": "test-barcode-sale",
|
"barcode": "test-barcode-sale",
|
||||||
"calculated_price": null,
|
"calculated_price": null,
|
||||||
|
"calculated_price_incl_tax": null,
|
||||||
|
"calculated_tax": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": "test-ean-sale",
|
"ean": "test-ean-sale",
|
||||||
@@ -267,6 +284,8 @@ Array [
|
|||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
"original_price": null,
|
"original_price": null,
|
||||||
|
"original_price_incl_tax": null,
|
||||||
|
"original_tax": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 1000,
|
"amount": 1000,
|
||||||
@@ -285,6 +304,7 @@ Array [
|
|||||||
],
|
],
|
||||||
"product_id": StringMatching /\\^test-\\*/,
|
"product_id": StringMatching /\\^test-\\*/,
|
||||||
"sku": "test-sku-sale",
|
"sku": "test-sku-sale",
|
||||||
|
"tax_rates": null,
|
||||||
"title": "Test variant",
|
"title": "Test variant",
|
||||||
"upc": "test-upc-sale",
|
"upc": "test-upc-sale",
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
@@ -353,6 +373,8 @@ Array [
|
|||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": null,
|
"barcode": null,
|
||||||
"calculated_price": null,
|
"calculated_price": null,
|
||||||
|
"calculated_price_incl_tax": null,
|
||||||
|
"calculated_tax": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": "test-ean4",
|
"ean": "test-ean4",
|
||||||
@@ -379,6 +401,8 @@ Array [
|
|||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
"original_price": null,
|
"original_price": null,
|
||||||
|
"original_price_incl_tax": null,
|
||||||
|
"original_tax": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -397,6 +421,7 @@ Array [
|
|||||||
],
|
],
|
||||||
"product_id": StringMatching /\\^test-\\*/,
|
"product_id": StringMatching /\\^test-\\*/,
|
||||||
"sku": "test-sku4",
|
"sku": "test-sku4",
|
||||||
|
"tax_rates": null,
|
||||||
"title": "Test variant rank (2)",
|
"title": "Test variant rank (2)",
|
||||||
"upc": "test-upc4",
|
"upc": "test-upc4",
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
@@ -407,6 +432,8 @@ Array [
|
|||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": null,
|
"barcode": null,
|
||||||
"calculated_price": null,
|
"calculated_price": null,
|
||||||
|
"calculated_price_incl_tax": null,
|
||||||
|
"calculated_tax": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": "test-ean3",
|
"ean": "test-ean3",
|
||||||
@@ -433,6 +460,8 @@ Array [
|
|||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
"original_price": null,
|
"original_price": null,
|
||||||
|
"original_price_incl_tax": null,
|
||||||
|
"original_tax": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -451,6 +480,7 @@ Array [
|
|||||||
],
|
],
|
||||||
"product_id": StringMatching /\\^test-\\*/,
|
"product_id": StringMatching /\\^test-\\*/,
|
||||||
"sku": "test-sku3",
|
"sku": "test-sku3",
|
||||||
|
"tax_rates": null,
|
||||||
"title": "Test variant rank (2)",
|
"title": "Test variant rank (2)",
|
||||||
"upc": "test-upc3",
|
"upc": "test-upc3",
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
@@ -609,6 +639,8 @@ Array [
|
|||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": null,
|
"barcode": null,
|
||||||
"calculated_price": null,
|
"calculated_price": null,
|
||||||
|
"calculated_price_incl_tax": null,
|
||||||
|
"calculated_tax": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": null,
|
"ean": null,
|
||||||
@@ -635,6 +667,8 @@ Array [
|
|||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
"original_price": null,
|
"original_price": null,
|
||||||
|
"original_price_incl_tax": null,
|
||||||
|
"original_tax": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -653,6 +687,7 @@ Array [
|
|||||||
],
|
],
|
||||||
"product_id": StringMatching /\\^prod_\\*/,
|
"product_id": StringMatching /\\^prod_\\*/,
|
||||||
"sku": null,
|
"sku": null,
|
||||||
|
"tax_rates": null,
|
||||||
"title": "Test variant",
|
"title": "Test variant",
|
||||||
"upc": null,
|
"upc": null,
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
@@ -769,6 +804,8 @@ Object {
|
|||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": null,
|
"barcode": null,
|
||||||
"calculated_price": null,
|
"calculated_price": null,
|
||||||
|
"calculated_price_incl_tax": null,
|
||||||
|
"calculated_tax": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": null,
|
"ean": null,
|
||||||
@@ -805,6 +842,8 @@ Object {
|
|||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
"original_price": null,
|
"original_price": null,
|
||||||
|
"original_price_incl_tax": null,
|
||||||
|
"original_tax": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -851,6 +890,7 @@ Object {
|
|||||||
],
|
],
|
||||||
"product_id": StringMatching /\\^prod_\\*/,
|
"product_id": StringMatching /\\^prod_\\*/,
|
||||||
"sku": null,
|
"sku": null,
|
||||||
|
"tax_rates": null,
|
||||||
"title": "Test variant",
|
"title": "Test variant",
|
||||||
"upc": null,
|
"upc": null,
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
@@ -933,6 +973,8 @@ Object {
|
|||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": "test-barcode",
|
"barcode": "test-barcode",
|
||||||
"calculated_price": null,
|
"calculated_price": null,
|
||||||
|
"calculated_price_incl_tax": null,
|
||||||
|
"calculated_tax": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": "test-ean",
|
"ean": "test-ean",
|
||||||
@@ -959,6 +1001,8 @@ Object {
|
|||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
"original_price": null,
|
"original_price": null,
|
||||||
|
"original_price_incl_tax": null,
|
||||||
|
"original_tax": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 75,
|
"amount": 75,
|
||||||
@@ -977,6 +1021,7 @@ Object {
|
|||||||
],
|
],
|
||||||
"product_id": "test-product",
|
"product_id": "test-product",
|
||||||
"sku": "test-sku",
|
"sku": "test-sku",
|
||||||
|
"tax_rates": null,
|
||||||
"title": "Test variant",
|
"title": "Test variant",
|
||||||
"upc": "test-upc",
|
"upc": "test-upc",
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ describe("/admin/products", () => {
|
|||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const cwd = path.resolve(path.join(__dirname, "..", ".."))
|
const cwd = path.resolve(path.join(__dirname, "..", ".."))
|
||||||
dbConnection = await initDb({ cwd })
|
dbConnection = await initDb({ cwd })
|
||||||
medusaProcess = await setupServer({ cwd })
|
medusaProcess = await setupServer({ cwd, verbose: false })
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
|
|||||||
@@ -6,6 +6,8 @@ Object {
|
|||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": "test-barcode",
|
"barcode": "test-barcode",
|
||||||
"calculated_price": null,
|
"calculated_price": null,
|
||||||
|
"calculated_price_incl_tax": null,
|
||||||
|
"calculated_tax": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": "test-ean",
|
"ean": "test-ean",
|
||||||
@@ -32,6 +34,8 @@ Object {
|
|||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
"original_price": null,
|
"original_price": null,
|
||||||
|
"original_price_incl_tax": null,
|
||||||
|
"original_tax": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -51,6 +55,7 @@ Object {
|
|||||||
"product": Any<Object>,
|
"product": Any<Object>,
|
||||||
"product_id": "test-product",
|
"product_id": "test-product",
|
||||||
"sku": "test-sku",
|
"sku": "test-sku",
|
||||||
|
"tax_rates": null,
|
||||||
"title": "Test variant",
|
"title": "Test variant",
|
||||||
"upc": "test-upc",
|
"upc": "test-upc",
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
@@ -66,7 +71,9 @@ Object {
|
|||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": "test-barcode",
|
"barcode": "test-barcode",
|
||||||
"calculated_price": 80,
|
"calculated_price": 80,
|
||||||
|
"calculated_price_incl_tax": null,
|
||||||
"calculated_price_type": "sale",
|
"calculated_price_type": "sale",
|
||||||
|
"calculated_tax": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": "test-ean",
|
"ean": "test-ean",
|
||||||
@@ -93,6 +100,8 @@ Object {
|
|||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
"original_price": 100,
|
"original_price": 100,
|
||||||
|
"original_price_incl_tax": null,
|
||||||
|
"original_tax": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -137,6 +146,7 @@ Object {
|
|||||||
"product": Any<Object>,
|
"product": Any<Object>,
|
||||||
"product_id": "test-product",
|
"product_id": "test-product",
|
||||||
"sku": "test-sku",
|
"sku": "test-sku",
|
||||||
|
"tax_rates": null,
|
||||||
"title": "Test variant",
|
"title": "Test variant",
|
||||||
"upc": "test-upc",
|
"upc": "test-upc",
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
@@ -153,6 +163,8 @@ Object {
|
|||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": null,
|
"barcode": null,
|
||||||
"calculated_price": null,
|
"calculated_price": null,
|
||||||
|
"calculated_price_incl_tax": null,
|
||||||
|
"calculated_tax": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": null,
|
"ean": null,
|
||||||
@@ -179,6 +191,8 @@ Object {
|
|||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
"original_price": null,
|
"original_price": null,
|
||||||
|
"original_price_incl_tax": null,
|
||||||
|
"original_tax": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -198,6 +212,7 @@ Object {
|
|||||||
"product": Any<Object>,
|
"product": Any<Object>,
|
||||||
"product_id": Any<String>,
|
"product_id": Any<String>,
|
||||||
"sku": null,
|
"sku": null,
|
||||||
|
"tax_rates": null,
|
||||||
"title": "test2",
|
"title": "test2",
|
||||||
"upc": null,
|
"upc": null,
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
@@ -214,7 +229,9 @@ Object {
|
|||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": "test-barcode",
|
"barcode": "test-barcode",
|
||||||
"calculated_price": 80,
|
"calculated_price": 80,
|
||||||
|
"calculated_price_incl_tax": 80,
|
||||||
"calculated_price_type": "sale",
|
"calculated_price_type": "sale",
|
||||||
|
"calculated_tax": 0,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": "test-ean",
|
"ean": "test-ean",
|
||||||
@@ -241,6 +258,8 @@ Object {
|
|||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
"original_price": 100,
|
"original_price": 100,
|
||||||
|
"original_price_incl_tax": 100,
|
||||||
|
"original_tax": 0,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -285,6 +304,13 @@ Object {
|
|||||||
"product": Any<Object>,
|
"product": Any<Object>,
|
||||||
"product_id": "test-product",
|
"product_id": "test-product",
|
||||||
"sku": "test-sku",
|
"sku": "test-sku",
|
||||||
|
"tax_rates": Array [
|
||||||
|
Object {
|
||||||
|
"code": "default",
|
||||||
|
"name": "default",
|
||||||
|
"rate": 0,
|
||||||
|
},
|
||||||
|
],
|
||||||
"title": "Test variant",
|
"title": "Test variant",
|
||||||
"upc": "test-upc",
|
"upc": "test-upc",
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
@@ -301,6 +327,8 @@ Object {
|
|||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": "test-barcode",
|
"barcode": "test-barcode",
|
||||||
"calculated_price": null,
|
"calculated_price": null,
|
||||||
|
"calculated_price_incl_tax": null,
|
||||||
|
"calculated_tax": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": "test-ean",
|
"ean": "test-ean",
|
||||||
@@ -327,6 +355,8 @@ Object {
|
|||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
"original_price": null,
|
"original_price": null,
|
||||||
|
"original_price_incl_tax": null,
|
||||||
|
"original_tax": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -346,6 +376,7 @@ Object {
|
|||||||
"product": Any<Object>,
|
"product": Any<Object>,
|
||||||
"product_id": "test-product",
|
"product_id": "test-product",
|
||||||
"sku": "test-sku",
|
"sku": "test-sku",
|
||||||
|
"tax_rates": null,
|
||||||
"title": "Test variant",
|
"title": "Test variant",
|
||||||
"upc": "test-upc",
|
"upc": "test-upc",
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
|
|||||||
@@ -131,6 +131,8 @@ Object {
|
|||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": "test-barcode",
|
"barcode": "test-barcode",
|
||||||
"calculated_price": null,
|
"calculated_price": null,
|
||||||
|
"calculated_price_incl_tax": null,
|
||||||
|
"calculated_tax": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": "test-ean",
|
"ean": "test-ean",
|
||||||
@@ -157,6 +159,8 @@ Object {
|
|||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
"original_price": null,
|
"original_price": null,
|
||||||
|
"original_price_incl_tax": null,
|
||||||
|
"original_tax": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -200,6 +204,7 @@ Object {
|
|||||||
],
|
],
|
||||||
"product_id": "test-product",
|
"product_id": "test-product",
|
||||||
"sku": "test-sku",
|
"sku": "test-sku",
|
||||||
|
"tax_rates": null,
|
||||||
"title": "Test variant",
|
"title": "Test variant",
|
||||||
"upc": "test-upc",
|
"upc": "test-upc",
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
@@ -210,6 +215,8 @@ Object {
|
|||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": null,
|
"barcode": null,
|
||||||
"calculated_price": null,
|
"calculated_price": null,
|
||||||
|
"calculated_price_incl_tax": null,
|
||||||
|
"calculated_tax": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": "test-ean2",
|
"ean": "test-ean2",
|
||||||
@@ -236,6 +243,8 @@ Object {
|
|||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
"original_price": null,
|
"original_price": null,
|
||||||
|
"original_price_incl_tax": null,
|
||||||
|
"original_tax": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -279,6 +288,7 @@ Object {
|
|||||||
],
|
],
|
||||||
"product_id": "test-product",
|
"product_id": "test-product",
|
||||||
"sku": "test-sku2",
|
"sku": "test-sku2",
|
||||||
|
"tax_rates": null,
|
||||||
"title": "Test variant rank (2)",
|
"title": "Test variant rank (2)",
|
||||||
"upc": "test-upc2",
|
"upc": "test-upc2",
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
@@ -289,6 +299,8 @@ Object {
|
|||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": "test-barcode 1",
|
"barcode": "test-barcode 1",
|
||||||
"calculated_price": null,
|
"calculated_price": null,
|
||||||
|
"calculated_price_incl_tax": null,
|
||||||
|
"calculated_tax": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": "test-ean1",
|
"ean": "test-ean1",
|
||||||
@@ -315,6 +327,8 @@ Object {
|
|||||||
],
|
],
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
"original_price": null,
|
"original_price": null,
|
||||||
|
"original_price_incl_tax": null,
|
||||||
|
"original_tax": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -358,6 +372,7 @@ Object {
|
|||||||
],
|
],
|
||||||
"product_id": "test-product",
|
"product_id": "test-product",
|
||||||
"sku": "test-sku1",
|
"sku": "test-sku1",
|
||||||
|
"tax_rates": null,
|
||||||
"title": "Test variant rank (1)",
|
"title": "Test variant rank (1)",
|
||||||
"upc": "test-upc1",
|
"upc": "test-upc1",
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
@@ -385,6 +400,8 @@ Object {
|
|||||||
"allow_backorder": false,
|
"allow_backorder": false,
|
||||||
"barcode": null,
|
"barcode": null,
|
||||||
"calculated_price": null,
|
"calculated_price": null,
|
||||||
|
"calculated_price_incl_tax": null,
|
||||||
|
"calculated_tax": null,
|
||||||
"created_at": Any<String>,
|
"created_at": Any<String>,
|
||||||
"deleted_at": null,
|
"deleted_at": null,
|
||||||
"ean": null,
|
"ean": null,
|
||||||
@@ -399,6 +416,8 @@ Object {
|
|||||||
"mid_code": null,
|
"mid_code": null,
|
||||||
"origin_country": null,
|
"origin_country": null,
|
||||||
"original_price": null,
|
"original_price": null,
|
||||||
|
"original_price_incl_tax": null,
|
||||||
|
"original_tax": null,
|
||||||
"prices": Array [
|
"prices": Array [
|
||||||
Object {
|
Object {
|
||||||
"amount": 100,
|
"amount": 100,
|
||||||
@@ -417,6 +436,7 @@ Object {
|
|||||||
],
|
],
|
||||||
"product_id": Any<String>,
|
"product_id": Any<String>,
|
||||||
"sku": null,
|
"sku": null,
|
||||||
|
"tax_rates": null,
|
||||||
"title": "test-variant",
|
"title": "test-variant",
|
||||||
"upc": null,
|
"upc": null,
|
||||||
"updated_at": Any<String>,
|
"updated_at": Any<String>,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ describe("/store/variants", () => {
|
|||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const cwd = path.resolve(path.join(__dirname, "..", ".."))
|
const cwd = path.resolve(path.join(__dirname, "..", ".."))
|
||||||
dbConnection = await initDb({ cwd })
|
dbConnection = await initDb({ cwd })
|
||||||
medusaProcess = await setupServer({ cwd })
|
medusaProcess = await setupServer({ cwd, verbose: false })
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { IsString } from "class-validator"
|
import { IsString } from "class-validator"
|
||||||
import { defaultAdminProductFields, defaultAdminProductRelations } from "."
|
import { defaultAdminProductFields, defaultAdminProductRelations } from "."
|
||||||
import { ProductService } from "../../../../services"
|
import { ProductService, PricingService } from "../../../../services"
|
||||||
import { validator } from "../../../../utils/validator"
|
import { validator } from "../../../../utils/validator"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,13 +42,16 @@ export default async (req, res) => {
|
|||||||
)
|
)
|
||||||
|
|
||||||
const productService: ProductService = req.scope.resolve("productService")
|
const productService: ProductService = req.scope.resolve("productService")
|
||||||
|
const pricingService: PricingService = req.scope.resolve("pricingService")
|
||||||
|
|
||||||
await productService.addOption(id, validated.title)
|
await productService.addOption(id, validated.title)
|
||||||
const product = await productService.retrieve(id, {
|
const rawProduct = await productService.retrieve(id, {
|
||||||
select: defaultAdminProductFields,
|
select: defaultAdminProductFields,
|
||||||
relations: defaultAdminProductRelations,
|
relations: defaultAdminProductRelations,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const [product] = await pricingService.setProductPrices([rawProduct])
|
||||||
|
|
||||||
res.json({ product })
|
res.json({ product })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { EntityManager } from "typeorm"
|
|||||||
import { defaultAdminProductFields, defaultAdminProductRelations } from "."
|
import { defaultAdminProductFields, defaultAdminProductRelations } from "."
|
||||||
import {
|
import {
|
||||||
ProductService,
|
ProductService,
|
||||||
|
PricingService,
|
||||||
ProductVariantService,
|
ProductVariantService,
|
||||||
ShippingProfileService,
|
ShippingProfileService,
|
||||||
} from "../../../../services"
|
} from "../../../../services"
|
||||||
@@ -211,6 +212,7 @@ export default async (req, res) => {
|
|||||||
const validated = await validator(AdminPostProductsReq, req.body)
|
const validated = await validator(AdminPostProductsReq, req.body)
|
||||||
|
|
||||||
const productService: ProductService = req.scope.resolve("productService")
|
const productService: ProductService = req.scope.resolve("productService")
|
||||||
|
const pricingService: PricingService = req.scope.resolve("pricingService")
|
||||||
const productVariantService: ProductVariantService = req.scope.resolve(
|
const productVariantService: ProductVariantService = req.scope.resolve(
|
||||||
"productVariantService"
|
"productVariantService"
|
||||||
)
|
)
|
||||||
@@ -270,11 +272,13 @@ export default async (req, res) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
const product = await productService.retrieve(newProduct.id, {
|
const rawProduct = await productService.retrieve(newProduct.id, {
|
||||||
select: defaultAdminProductFields,
|
select: defaultAdminProductFields,
|
||||||
relations: defaultAdminProductRelations,
|
relations: defaultAdminProductRelations,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const [product] = await pricingService.setProductPrices([rawProduct])
|
||||||
|
|
||||||
res.json({ product })
|
res.json({ product })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
import { defaultAdminProductFields, defaultAdminProductRelations } from "."
|
import { defaultAdminProductFields, defaultAdminProductRelations } from "."
|
||||||
import { ProductService, ProductVariantService } from "../../../../services"
|
import {
|
||||||
|
ProductService,
|
||||||
|
PricingService,
|
||||||
|
ProductVariantService,
|
||||||
|
} from "../../../../services"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @oas [delete] /products/{id}/variants/{variant_id}
|
* @oas [delete] /products/{id}/variants/{variant_id}
|
||||||
@@ -35,6 +39,7 @@ export default async (req, res) => {
|
|||||||
"productVariantService"
|
"productVariantService"
|
||||||
)
|
)
|
||||||
const productService: ProductService = req.scope.resolve("productService")
|
const productService: ProductService = req.scope.resolve("productService")
|
||||||
|
const pricingService: PricingService = req.scope.resolve("pricingService")
|
||||||
|
|
||||||
await productVariantService.delete(variant_id)
|
await productVariantService.delete(variant_id)
|
||||||
|
|
||||||
@@ -42,11 +47,12 @@ export default async (req, res) => {
|
|||||||
select: defaultAdminProductFields,
|
select: defaultAdminProductFields,
|
||||||
relations: defaultAdminProductRelations,
|
relations: defaultAdminProductRelations,
|
||||||
})
|
})
|
||||||
|
const [product] = await pricingService.setProductPrices([data])
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
variant_id,
|
variant_id,
|
||||||
object: "product-variant",
|
object: "product-variant",
|
||||||
deleted: true,
|
deleted: true,
|
||||||
product: data,
|
product,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { defaultAdminProductFields, defaultAdminProductRelations } from "."
|
import { defaultAdminProductFields, defaultAdminProductRelations } from "."
|
||||||
import { ProductService } from "../../../../services"
|
import { ProductService, PricingService } from "../../../../services"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @oas [get] /products/{id}
|
* @oas [get] /products/{id}
|
||||||
@@ -25,11 +25,14 @@ export default async (req, res) => {
|
|||||||
const { id } = req.params
|
const { id } = req.params
|
||||||
|
|
||||||
const productService: ProductService = req.scope.resolve("productService")
|
const productService: ProductService = req.scope.resolve("productService")
|
||||||
|
const pricingService: PricingService = req.scope.resolve("pricingService")
|
||||||
|
|
||||||
const product = await productService.retrieve(id, {
|
const rawProduct = await productService.retrieve(id, {
|
||||||
select: defaultAdminProductFields,
|
select: defaultAdminProductFields,
|
||||||
relations: defaultAdminProductRelations,
|
relations: defaultAdminProductRelations,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const [product] = await pricingService.setProductPrices([rawProduct])
|
||||||
|
|
||||||
res.json({ product })
|
res.json({ product })
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import { Router } from "express"
|
import { Router } from "express"
|
||||||
import "reflect-metadata"
|
import "reflect-metadata"
|
||||||
|
import { PricedProduct } from "../../../../types/pricing"
|
||||||
import { Product, ProductTag, ProductType } from "../../../.."
|
import { Product, ProductTag, ProductType } from "../../../.."
|
||||||
import { PaginatedResponse } from "../../../../types/common"
|
import { PaginatedResponse } from "../../../../types/common"
|
||||||
import middlewares from "../../../middlewares"
|
import middlewares from "../../../middlewares"
|
||||||
@@ -102,10 +103,7 @@ export const defaultAdminProductFields = [
|
|||||||
"metadata",
|
"metadata",
|
||||||
]
|
]
|
||||||
|
|
||||||
export const defaultAdminGetProductsVariantsFields = [
|
export const defaultAdminGetProductsVariantsFields = ["id", "product_id"]
|
||||||
"id",
|
|
||||||
"product_id"
|
|
||||||
]
|
|
||||||
|
|
||||||
export const allowedAdminProductFields = [
|
export const allowedAdminProductFields = [
|
||||||
"id",
|
"id",
|
||||||
@@ -166,7 +164,7 @@ export type AdminProductsDeleteRes = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type AdminProductsListRes = PaginatedResponse & {
|
export type AdminProductsListRes = PaginatedResponse & {
|
||||||
products: Product[]
|
products: (PricedProduct | Product)[]
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AdminProductsListTypesRes = {
|
export type AdminProductsListTypesRes = {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import {
|
|||||||
defaultAdminProductRelations,
|
defaultAdminProductRelations,
|
||||||
ProductStatus,
|
ProductStatus,
|
||||||
} from "."
|
} from "."
|
||||||
import { ProductService } from "../../../../services"
|
import { ProductService, PricingService } from "../../../../services"
|
||||||
import { ProductVariantPricesUpdateReq } from "../../../../types/product-variant"
|
import { ProductVariantPricesUpdateReq } from "../../../../types/product-variant"
|
||||||
import { validator } from "../../../../utils/validator"
|
import { validator } from "../../../../utils/validator"
|
||||||
|
|
||||||
@@ -210,13 +210,15 @@ export default async (req, res) => {
|
|||||||
const validated = await validator(AdminPostProductsProductReq, req.body)
|
const validated = await validator(AdminPostProductsProductReq, req.body)
|
||||||
|
|
||||||
const productService: ProductService = req.scope.resolve("productService")
|
const productService: ProductService = req.scope.resolve("productService")
|
||||||
|
const pricingService: PricingService = req.scope.resolve("pricingService")
|
||||||
|
|
||||||
await productService.update(id, validated)
|
await productService.update(id, validated)
|
||||||
|
|
||||||
const product = await productService.retrieve(id, {
|
const rawProduct = await productService.retrieve(id, {
|
||||||
select: defaultAdminProductFields,
|
select: defaultAdminProductFields,
|
||||||
relations: defaultAdminProductRelations,
|
relations: defaultAdminProductRelations,
|
||||||
})
|
})
|
||||||
|
const [product] = await pricingService.setProductPrices([rawProduct])
|
||||||
|
|
||||||
res.json({ product })
|
res.json({ product })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,11 @@ import {
|
|||||||
ValidateNested,
|
ValidateNested,
|
||||||
} from "class-validator"
|
} from "class-validator"
|
||||||
import { defaultAdminProductFields, defaultAdminProductRelations } from "."
|
import { defaultAdminProductFields, defaultAdminProductRelations } from "."
|
||||||
import { ProductService, ProductVariantService } from "../../../../services"
|
import {
|
||||||
|
ProductService,
|
||||||
|
PricingService,
|
||||||
|
ProductVariantService,
|
||||||
|
} from "../../../../services"
|
||||||
import { PriceSelectionParams } from "../../../../types/price-selection"
|
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"
|
||||||
@@ -134,6 +138,7 @@ export default async (req, res) => {
|
|||||||
const validatedQueryParams = await validator(PriceSelectionParams, req.query)
|
const validatedQueryParams = await validator(PriceSelectionParams, req.query)
|
||||||
|
|
||||||
const productService: ProductService = req.scope.resolve("productService")
|
const productService: ProductService = req.scope.resolve("productService")
|
||||||
|
const pricingService: PricingService = req.scope.resolve("pricingService")
|
||||||
const productVariantService: ProductVariantService = req.scope.resolve(
|
const productVariantService: ProductVariantService = req.scope.resolve(
|
||||||
"productVariantService"
|
"productVariantService"
|
||||||
)
|
)
|
||||||
@@ -143,14 +148,14 @@ export default async (req, res) => {
|
|||||||
...validated,
|
...validated,
|
||||||
})
|
})
|
||||||
|
|
||||||
await productVariantService.retrieve(variant_id)
|
const rawProduct = await productService.retrieve(id, {
|
||||||
|
|
||||||
const product = await productService.retrieve(id, {
|
|
||||||
select: defaultAdminProductFields,
|
select: defaultAdminProductFields,
|
||||||
relations: defaultAdminProductRelations,
|
relations: defaultAdminProductRelations,
|
||||||
...validatedQueryParams,
|
...validatedQueryParams,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const [product] = await pricingService.setProductPrices([rawProduct])
|
||||||
|
|
||||||
res.json({ product })
|
res.json({ product })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,10 +23,6 @@ describe("Get product by id", () => {
|
|||||||
IdMap.getId("product1"),
|
IdMap.getId("product1"),
|
||||||
{
|
{
|
||||||
relations: defaultStoreProductsRelations,
|
relations: defaultStoreProductsRelations,
|
||||||
cart_id: undefined,
|
|
||||||
currency_code: undefined,
|
|
||||||
region_id: undefined,
|
|
||||||
include_discount_prices: true,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -59,10 +55,6 @@ describe("Get product by id", () => {
|
|||||||
IdMap.getId("variantsWithPrices"),
|
IdMap.getId("variantsWithPrices"),
|
||||||
{
|
{
|
||||||
relations: defaultStoreProductsRelations,
|
relations: defaultStoreProductsRelations,
|
||||||
cart_id: undefined,
|
|
||||||
currency_code: undefined,
|
|
||||||
region_id: undefined,
|
|
||||||
include_discount_prices: true,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -23,10 +23,6 @@ describe("GET /store/products", () => {
|
|||||||
relations: defaultStoreProductsRelations,
|
relations: defaultStoreProductsRelations,
|
||||||
skip: 0,
|
skip: 0,
|
||||||
take: 100,
|
take: 100,
|
||||||
cart_id: undefined,
|
|
||||||
currency_code: undefined,
|
|
||||||
region_id: undefined,
|
|
||||||
include_discount_prices: true,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@@ -54,10 +50,6 @@ describe("GET /store/products", () => {
|
|||||||
relations: defaultStoreProductsRelations,
|
relations: defaultStoreProductsRelations,
|
||||||
skip: 0,
|
skip: 0,
|
||||||
take: 100,
|
take: 100,
|
||||||
cart_id: undefined,
|
|
||||||
currency_code: undefined,
|
|
||||||
region_id: undefined,
|
|
||||||
include_discount_prices: true,
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
import { defaultStoreProductsRelations } from "."
|
import { defaultStoreProductsRelations } from "."
|
||||||
import { ProductService } from "../../../../services"
|
import {
|
||||||
|
ProductService,
|
||||||
|
PricingService,
|
||||||
|
CartService,
|
||||||
|
RegionService,
|
||||||
|
} from "../../../../services"
|
||||||
import { PriceSelectionParams } from "../../../../types/price-selection"
|
import { PriceSelectionParams } from "../../../../types/price-selection"
|
||||||
import { validator } from "../../../../utils/validator"
|
import { validator } from "../../../../utils/validator"
|
||||||
|
|
||||||
@@ -30,12 +35,31 @@ export default async (req, res) => {
|
|||||||
const customer_id = req.user?.customer_id
|
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 pricingService: PricingService = req.scope.resolve("pricingService")
|
||||||
|
const cartService: CartService = req.scope.resolve("cartService")
|
||||||
|
const regionService: RegionService = req.scope.resolve("regionService")
|
||||||
|
const rawProduct = await productService.retrieve(id, {
|
||||||
relations: defaultStoreProductsRelations,
|
relations: defaultStoreProductsRelations,
|
||||||
|
})
|
||||||
|
|
||||||
|
let regionId = validated.region_id
|
||||||
|
let currencyCode = validated.currency_code
|
||||||
|
if (validated.cart_id) {
|
||||||
|
const cart = await cartService.retrieve(validated.cart_id, {
|
||||||
|
select: ["id", "region_id"],
|
||||||
|
})
|
||||||
|
const region = await regionService.retrieve(cart.region_id, {
|
||||||
|
select: ["id", "currency_code"],
|
||||||
|
})
|
||||||
|
regionId = region.id
|
||||||
|
currencyCode = region.currency_code
|
||||||
|
}
|
||||||
|
|
||||||
|
const [product] = await pricingService.setProductPrices([rawProduct], {
|
||||||
cart_id: validated.cart_id,
|
cart_id: validated.cart_id,
|
||||||
customer_id: customer_id,
|
customer_id: customer_id,
|
||||||
region_id: validated.region_id,
|
region_id: regionId,
|
||||||
currency_code: validated.currency_code,
|
currency_code: currencyCode,
|
||||||
include_discount_prices: true,
|
include_discount_prices: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,12 @@ import {
|
|||||||
} from "class-validator"
|
} from "class-validator"
|
||||||
import { omit, pickBy } from "lodash"
|
import { omit, pickBy } from "lodash"
|
||||||
import { defaultStoreProductsRelations } from "."
|
import { defaultStoreProductsRelations } from "."
|
||||||
import { ProductService } from "../../../../services"
|
import {
|
||||||
|
ProductService,
|
||||||
|
RegionService,
|
||||||
|
CartService,
|
||||||
|
} from "../../../../services"
|
||||||
|
import PricingService from "../../../../services/pricing"
|
||||||
import { DateComparisonOperator } from "../../../../types/common"
|
import { DateComparisonOperator } from "../../../../types/common"
|
||||||
import { PriceSelectionParams } from "../../../../types/price-selection"
|
import { PriceSelectionParams } from "../../../../types/price-selection"
|
||||||
import { validator } from "../../../../utils/validator"
|
import { validator } from "../../../../utils/validator"
|
||||||
@@ -61,6 +66,9 @@ import { optionalBooleanMapper } from "../../../../utils/validators/is-boolean"
|
|||||||
*/
|
*/
|
||||||
export default async (req, res) => {
|
export default async (req, res) => {
|
||||||
const productService: ProductService = req.scope.resolve("productService")
|
const productService: ProductService = req.scope.resolve("productService")
|
||||||
|
const pricingService: PricingService = req.scope.resolve("pricingService")
|
||||||
|
const cartService: CartService = req.scope.resolve("cartService")
|
||||||
|
const regionService: RegionService = req.scope.resolve("regionService")
|
||||||
|
|
||||||
const validated = await validator(StoreGetProductsParams, req.query)
|
const validated = await validator(StoreGetProductsParams, req.query)
|
||||||
|
|
||||||
@@ -96,18 +104,34 @@ 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 [rawProducts, count] = await productService.listAndCount(
|
||||||
pickBy(filterableFields, (val) => typeof val !== "undefined"),
|
pickBy(filterableFields, (val) => typeof val !== "undefined"),
|
||||||
listConfig
|
listConfig
|
||||||
)
|
)
|
||||||
|
|
||||||
|
let regionId = validated.region_id
|
||||||
|
let currencyCode = validated.currency_code
|
||||||
|
if (validated.cart_id) {
|
||||||
|
const cart = await cartService.retrieve(validated.cart_id, {
|
||||||
|
select: ["id", "region_id"],
|
||||||
|
})
|
||||||
|
const region = await regionService.retrieve(cart.region_id, {
|
||||||
|
select: ["id", "currency_code"],
|
||||||
|
})
|
||||||
|
regionId = region.id
|
||||||
|
currencyCode = region.currency_code
|
||||||
|
}
|
||||||
|
|
||||||
|
const products = await pricingService.setProductPrices(rawProducts, {
|
||||||
|
cart_id: validated.cart_id,
|
||||||
|
region_id: regionId,
|
||||||
|
currency_code: currencyCode,
|
||||||
|
customer_id: req.user?.customer_id,
|
||||||
|
include_discount_prices: true,
|
||||||
|
})
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
products,
|
products,
|
||||||
count,
|
count,
|
||||||
|
|||||||
@@ -16,10 +16,6 @@ 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,10 @@
|
|||||||
import { defaultStoreVariantRelations } from "."
|
import { defaultStoreVariantRelations } from "."
|
||||||
import ProductVariantService from "../../../../services/product-variant"
|
import {
|
||||||
|
CartService,
|
||||||
|
RegionService,
|
||||||
|
ProductVariantService,
|
||||||
|
PricingService,
|
||||||
|
} from "../../../../services"
|
||||||
import { PriceSelectionParams } from "../../../../types/price-selection"
|
import { PriceSelectionParams } from "../../../../types/price-selection"
|
||||||
import { validator } from "../../../../utils/validator"
|
import { validator } from "../../../../utils/validator"
|
||||||
|
|
||||||
@@ -30,15 +35,34 @@ export default async (req, res) => {
|
|||||||
const variantService: ProductVariantService = req.scope.resolve(
|
const variantService: ProductVariantService = req.scope.resolve(
|
||||||
"productVariantService"
|
"productVariantService"
|
||||||
)
|
)
|
||||||
|
const pricingService: PricingService = req.scope.resolve("pricingService")
|
||||||
|
const cartService: CartService = req.scope.resolve("cartService")
|
||||||
|
const regionService: RegionService = req.scope.resolve("regionService")
|
||||||
|
|
||||||
const customer_id = req.user?.customer_id
|
const customer_id = req.user?.customer_id
|
||||||
|
|
||||||
const variant = await variantService.retrieve(id, {
|
const rawVariant = await variantService.retrieve(id, {
|
||||||
relations: defaultStoreVariantRelations,
|
relations: defaultStoreVariantRelations,
|
||||||
|
})
|
||||||
|
|
||||||
|
let regionId = validated.region_id
|
||||||
|
let currencyCode = validated.currency_code
|
||||||
|
if (validated.cart_id) {
|
||||||
|
const cart = await cartService.retrieve(validated.cart_id, {
|
||||||
|
select: ["id", "region_id"],
|
||||||
|
})
|
||||||
|
const region = await regionService.retrieve(cart.region_id, {
|
||||||
|
select: ["id", "currency_code"],
|
||||||
|
})
|
||||||
|
regionId = region.id
|
||||||
|
currencyCode = region.currency_code
|
||||||
|
}
|
||||||
|
|
||||||
|
const [variant] = await pricingService.setVariantPrices([rawVariant], {
|
||||||
cart_id: validated.cart_id,
|
cart_id: validated.cart_id,
|
||||||
customer_id: customer_id,
|
customer_id: customer_id,
|
||||||
region_id: validated.region_id,
|
region_id: regionId,
|
||||||
currency_code: validated.currency_code,
|
currency_code: currencyCode,
|
||||||
include_discount_prices: true,
|
include_discount_prices: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,12 @@ import { omit } from "lodash"
|
|||||||
import { IsInt, IsOptional, IsString } from "class-validator"
|
import { IsInt, IsOptional, IsString } from "class-validator"
|
||||||
import { defaultStoreVariantRelations } from "."
|
import { defaultStoreVariantRelations } from "."
|
||||||
import { FilterableProductVariantProps } from "../../../../types/product-variant"
|
import { FilterableProductVariantProps } from "../../../../types/product-variant"
|
||||||
import ProductVariantService from "../../../../services/product-variant"
|
import {
|
||||||
|
CartService,
|
||||||
|
RegionService,
|
||||||
|
ProductVariantService,
|
||||||
|
PricingService,
|
||||||
|
} from "../../../../services"
|
||||||
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"
|
||||||
@@ -50,11 +55,6 @@ export default async (req, res) => {
|
|||||||
: 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, [
|
||||||
@@ -71,10 +71,35 @@ export default async (req, res) => {
|
|||||||
filterableFields.id = validated.ids.split(",")
|
filterableFields.id = validated.ids.split(",")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const pricingService: PricingService = req.scope.resolve("pricingService")
|
||||||
const variantService: ProductVariantService = req.scope.resolve(
|
const variantService: ProductVariantService = req.scope.resolve(
|
||||||
"productVariantService"
|
"productVariantService"
|
||||||
)
|
)
|
||||||
const variants = await variantService.list(filterableFields, listConfig)
|
const cartService: CartService = req.scope.resolve("cartService")
|
||||||
|
const regionService: RegionService = req.scope.resolve("regionService")
|
||||||
|
|
||||||
|
const rawVariants = await variantService.list(filterableFields, listConfig)
|
||||||
|
|
||||||
|
let regionId = validated.region_id
|
||||||
|
let currencyCode = validated.currency_code
|
||||||
|
if (validated.cart_id) {
|
||||||
|
const cart = await cartService.retrieve(validated.cart_id, {
|
||||||
|
select: ["id", "region_id"],
|
||||||
|
})
|
||||||
|
const region = await regionService.retrieve(cart.region_id, {
|
||||||
|
select: ["id", "currency_code"],
|
||||||
|
})
|
||||||
|
regionId = region.id
|
||||||
|
currencyCode = region.currency_code
|
||||||
|
}
|
||||||
|
|
||||||
|
const variants = await pricingService.setVariantPrices(rawVariants, {
|
||||||
|
cart_id: validated.cart_id,
|
||||||
|
region_id: regionId,
|
||||||
|
currency_code: currencyCode,
|
||||||
|
customer_id: customer_id,
|
||||||
|
include_discount_prices: true,
|
||||||
|
})
|
||||||
|
|
||||||
res.json({ variants })
|
res.json({ variants })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import { AdminProductsListRes } from "../../api"
|
|||||||
import { pickBy } from "lodash"
|
import { pickBy } from "lodash"
|
||||||
import { MedusaError } from "medusa-core-utils"
|
import { MedusaError } from "medusa-core-utils"
|
||||||
import { Product } from "../../models/product"
|
import { Product } from "../../models/product"
|
||||||
import { ProductService } from "../../services"
|
import { ProductService, PricingService } from "../../services"
|
||||||
import { getListConfig } from "../../utils/get-query-config"
|
import { getListConfig } from "../../utils/get-query-config"
|
||||||
import { FilterableProductProps } from "../../types/product"
|
import { FilterableProductProps } from "../../types/product"
|
||||||
|
|
||||||
@@ -24,10 +24,11 @@ const listAndCount = async (
|
|||||||
body?: object,
|
body?: object,
|
||||||
context: ListContext = { limit: 50, offset: 0 }
|
context: ListContext = { limit: 50, offset: 0 }
|
||||||
): Promise<AdminProductsListRes> => {
|
): Promise<AdminProductsListRes> => {
|
||||||
const productService: ProductService = scope.resolve("productService")
|
|
||||||
const { limit, offset, allowedFields, defaultFields, defaultRelations } =
|
const { limit, offset, allowedFields, defaultFields, defaultRelations } =
|
||||||
context
|
context
|
||||||
|
|
||||||
|
const productService: ProductService = scope.resolve("productService")
|
||||||
|
const pricingService: PricingService = scope.resolve("pricingService")
|
||||||
let includeFields: (keyof Product)[] | undefined
|
let includeFields: (keyof Product)[] | undefined
|
||||||
if (context.fields) {
|
if (context.fields) {
|
||||||
includeFields = context.fields.split(",") as (keyof Product)[]
|
includeFields = context.fields.split(",") as (keyof Product)[]
|
||||||
@@ -67,11 +68,20 @@ const listAndCount = async (
|
|||||||
orderBy
|
orderBy
|
||||||
)
|
)
|
||||||
|
|
||||||
const [products, count] = await productService.listAndCount(
|
const [rawProducts, count] = await productService.listAndCount(
|
||||||
pickBy(query, (val) => typeof val !== "undefined"),
|
pickBy(query, (val) => typeof val !== "undefined"),
|
||||||
listConfig
|
listConfig
|
||||||
)
|
)
|
||||||
|
|
||||||
|
let products = rawProducts
|
||||||
|
|
||||||
|
const includesPricing = ["variants", "variants.prices"].every((relation) =>
|
||||||
|
listConfig?.relations?.includes(relation)
|
||||||
|
)
|
||||||
|
if (includesPricing) {
|
||||||
|
products = await pricingService.setProductPrices(rawProducts)
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
products,
|
products,
|
||||||
count,
|
count,
|
||||||
|
|||||||
@@ -82,8 +82,7 @@ export class ProductVariantRepository extends Repository<ProductVariant> {
|
|||||||
): Promise<ProductVariant[]> {
|
): Promise<ProductVariant[]> {
|
||||||
const entitiesIdsWithRelations = await Promise.all(
|
const entitiesIdsWithRelations = await Promise.all(
|
||||||
Object.entries(groupedRelations).map(([toplevel, rels]) => {
|
Object.entries(groupedRelations).map(([toplevel, rels]) => {
|
||||||
let querybuilder = this.createQueryBuilder("pv")
|
let querybuilder = this.createQueryBuilder("pv").leftJoinAndSelect(
|
||||||
querybuilder = querybuilder.leftJoinAndSelect(
|
|
||||||
`pv.${toplevel}`,
|
`pv.${toplevel}`,
|
||||||
toplevel
|
toplevel
|
||||||
)
|
)
|
||||||
@@ -94,20 +93,20 @@ export class ProductVariantRepository extends Repository<ProductVariant> {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Regex matches all '.' except the rightmost
|
// Regex matches all '.' except the rightmost
|
||||||
querybuilder = querybuilder.leftJoinAndSelect(
|
querybuilder.leftJoinAndSelect(
|
||||||
rel.replace(/\.(?=[^.]*\.)/g, "__"),
|
rel.replace(/\.(?=[^.]*\.)/g, "__"),
|
||||||
rel.replace(".", "__")
|
rel.replace(".", "__")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (withDeleted) {
|
if (withDeleted) {
|
||||||
querybuilder = querybuilder
|
querybuilder
|
||||||
.where("pv.id IN (:...entitiesIds)", {
|
.where("pv.id IN (:...entitiesIds)", {
|
||||||
entitiesIds: entityIds,
|
entitiesIds: entityIds,
|
||||||
})
|
})
|
||||||
.withDeleted()
|
.withDeleted()
|
||||||
} else {
|
} else {
|
||||||
querybuilder = querybuilder.where(
|
querybuilder.where(
|
||||||
"pv.deleted_at IS NULL AND pv.id IN (:...entitiesIds)",
|
"pv.deleted_at IS NULL AND pv.id IN (:...entitiesIds)",
|
||||||
{
|
{
|
||||||
entitiesIds: entityIds,
|
entitiesIds: entityIds,
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
export const PricingServiceMock = {
|
||||||
|
withTransaction: function () {
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
setProductPrices: jest.fn().mockImplementation((prod) => {
|
||||||
|
return Promise.resolve(prod)
|
||||||
|
}),
|
||||||
|
setVariantPrices: jest.fn().mockImplementation((variant) => {
|
||||||
|
return Promise.resolve(variant)
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
|
||||||
|
const mock = jest.fn().mockImplementation(() => {
|
||||||
|
return PricingServiceMock
|
||||||
|
})
|
||||||
|
|
||||||
|
export default mock
|
||||||
@@ -4,7 +4,7 @@ import LineItemService from "../line-item"
|
|||||||
describe("LineItemService", () => {
|
describe("LineItemService", () => {
|
||||||
describe("create", () => {
|
describe("create", () => {
|
||||||
const lineItemRepository = MockRepository({
|
const lineItemRepository = MockRepository({
|
||||||
create: (data) => data
|
create: (data) => data,
|
||||||
})
|
})
|
||||||
|
|
||||||
const cartRepository = MockRepository({
|
const cartRepository = MockRepository({
|
||||||
@@ -15,7 +15,7 @@ describe("LineItemService", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const regionService = {
|
const regionService = {
|
||||||
withTransaction: function() {
|
withTransaction: function () {
|
||||||
return this
|
return this
|
||||||
},
|
},
|
||||||
retrieve: () => {
|
retrieve: () => {
|
||||||
@@ -26,10 +26,10 @@ describe("LineItemService", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const productVariantService = {
|
const productVariantService = {
|
||||||
withTransaction: function() {
|
withTransaction: function () {
|
||||||
return this
|
return this
|
||||||
},
|
},
|
||||||
retrieve: query => {
|
retrieve: (query) => {
|
||||||
if (query === IdMap.getId("test-giftcard")) {
|
if (query === IdMap.getId("test-giftcard")) {
|
||||||
return {
|
return {
|
||||||
id: IdMap.getId("test-giftcard"),
|
id: IdMap.getId("test-giftcard"),
|
||||||
@@ -54,8 +54,25 @@ describe("LineItemService", () => {
|
|||||||
getRegionPrice: () => 100,
|
getRegionPrice: () => 100,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const pricingService = {
|
||||||
|
withTransaction: function () {
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
getProductVariantPricingById: () => {
|
||||||
|
return {
|
||||||
|
calculated_price: 100,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
getProductVariantPricing: () => {
|
||||||
|
return {
|
||||||
|
calculated_price: 100,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
const lineItemService = new LineItemService({
|
const lineItemService = new LineItemService({
|
||||||
manager: MockManager,
|
manager: MockManager,
|
||||||
|
pricingService,
|
||||||
lineItemRepository,
|
lineItemRepository,
|
||||||
productVariantService,
|
productVariantService,
|
||||||
regionService,
|
regionService,
|
||||||
@@ -119,7 +136,9 @@ describe("LineItemService", () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
expect(lineItemRepository.create).toHaveBeenCalledTimes(2)
|
expect(lineItemRepository.create).toHaveBeenCalledTimes(2)
|
||||||
expect(lineItemRepository.create).toHaveBeenNthCalledWith(2, expect.objectContaining({
|
expect(lineItemRepository.create).toHaveBeenNthCalledWith(
|
||||||
|
2,
|
||||||
|
expect.objectContaining({
|
||||||
allow_discounts: false,
|
allow_discounts: false,
|
||||||
variant_id: IdMap.getId("test-giftcard"),
|
variant_id: IdMap.getId("test-giftcard"),
|
||||||
cart_id: IdMap.getId("test-cart"),
|
cart_id: IdMap.getId("test-cart"),
|
||||||
@@ -131,7 +150,8 @@ describe("LineItemService", () => {
|
|||||||
is_giftcard: true,
|
is_giftcard: true,
|
||||||
should_merge: true,
|
should_merge: true,
|
||||||
metadata: {},
|
metadata: {},
|
||||||
}))
|
})
|
||||||
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -39,3 +39,4 @@ export { default as UserService } from "./user"
|
|||||||
export { default as TaxRateService } from "./tax-rate"
|
export { default as TaxRateService } from "./tax-rate"
|
||||||
export { default as TaxProviderService } from "./tax-provider"
|
export { default as TaxProviderService } from "./tax-provider"
|
||||||
export { default as ProductTypeService } from "./product-type"
|
export { default as ProductTypeService } from "./product-type"
|
||||||
|
export { default as PricingService } from "./pricing"
|
||||||
@@ -3,7 +3,12 @@ import { BaseService } from "medusa-interfaces"
|
|||||||
import { EntityManager } from "typeorm"
|
import { EntityManager } from "typeorm"
|
||||||
import { LineItemRepository } from "../repositories/line-item"
|
import { LineItemRepository } from "../repositories/line-item"
|
||||||
import { LineItemTaxLineRepository } from "../repositories/line-item-tax-line"
|
import { LineItemTaxLineRepository } from "../repositories/line-item-tax-line"
|
||||||
import { ProductService, RegionService, ProductVariantService } from "./index"
|
import {
|
||||||
|
PricingService,
|
||||||
|
ProductService,
|
||||||
|
RegionService,
|
||||||
|
ProductVariantService,
|
||||||
|
} from "./index"
|
||||||
import { CartRepository } from "../repositories/cart"
|
import { CartRepository } from "../repositories/cart"
|
||||||
import { LineItem } from "../models/line-item"
|
import { LineItem } from "../models/line-item"
|
||||||
import LineItemAdjustmentService from "./line-item-adjustment"
|
import LineItemAdjustmentService from "./line-item-adjustment"
|
||||||
@@ -17,6 +22,7 @@ type InjectedDependencies = {
|
|||||||
cartRepository: typeof CartRepository
|
cartRepository: typeof CartRepository
|
||||||
productVariantService: ProductVariantService
|
productVariantService: ProductVariantService
|
||||||
productService: ProductService
|
productService: ProductService
|
||||||
|
pricingService: PricingService
|
||||||
regionService: RegionService
|
regionService: RegionService
|
||||||
lineItemAdjustmentService: LineItemAdjustmentService
|
lineItemAdjustmentService: LineItemAdjustmentService
|
||||||
}
|
}
|
||||||
@@ -41,6 +47,7 @@ class LineItemService extends BaseService {
|
|||||||
lineItemTaxLineRepository,
|
lineItemTaxLineRepository,
|
||||||
productVariantService,
|
productVariantService,
|
||||||
productService,
|
productService,
|
||||||
|
pricingService,
|
||||||
regionService,
|
regionService,
|
||||||
cartRepository,
|
cartRepository,
|
||||||
lineItemAdjustmentService,
|
lineItemAdjustmentService,
|
||||||
@@ -52,6 +59,7 @@ class LineItemService extends BaseService {
|
|||||||
this.itemTaxLineRepo_ = lineItemTaxLineRepository
|
this.itemTaxLineRepo_ = lineItemTaxLineRepository
|
||||||
this.productVariantService_ = productVariantService
|
this.productVariantService_ = productVariantService
|
||||||
this.productService_ = productService
|
this.productService_ = productService
|
||||||
|
this.pricingService_ = pricingService
|
||||||
this.regionService_ = regionService
|
this.regionService_ = regionService
|
||||||
this.cartRepository_ = cartRepository
|
this.cartRepository_ = cartRepository
|
||||||
this.lineItemAdjustmentService_ = lineItemAdjustmentService
|
this.lineItemAdjustmentService_ = lineItemAdjustmentService
|
||||||
@@ -68,6 +76,7 @@ class LineItemService extends BaseService {
|
|||||||
lineItemTaxLineRepository: this.itemTaxLineRepo_,
|
lineItemTaxLineRepository: this.itemTaxLineRepo_,
|
||||||
productVariantService: this.productVariantService_,
|
productVariantService: this.productVariantService_,
|
||||||
productService: this.productService_,
|
productService: this.productService_,
|
||||||
|
pricingService: this.pricingService_,
|
||||||
regionService: this.regionService_,
|
regionService: this.regionService_,
|
||||||
cartRepository: this.cartRepository_,
|
cartRepository: this.cartRepository_,
|
||||||
lineItemAdjustmentService: this.lineItemAdjustmentService_,
|
lineItemAdjustmentService: this.lineItemAdjustmentService_,
|
||||||
@@ -201,7 +210,6 @@ class LineItemService extends BaseService {
|
|||||||
.withTransaction(transactionManager)
|
.withTransaction(transactionManager)
|
||||||
.retrieve(variantId, {
|
.retrieve(variantId, {
|
||||||
relations: ["product"],
|
relations: ["product"],
|
||||||
include_discount_prices: true,
|
|
||||||
}),
|
}),
|
||||||
this.regionService_
|
this.regionService_
|
||||||
.withTransaction(transactionManager)
|
.withTransaction(transactionManager)
|
||||||
@@ -213,18 +221,19 @@ class LineItemService extends BaseService {
|
|||||||
|
|
||||||
if (context.unit_price === undefined || context.unit_price === null) {
|
if (context.unit_price === undefined || context.unit_price === null) {
|
||||||
shouldMerge = true
|
shouldMerge = true
|
||||||
unit_price = await this.productVariantService_
|
const variantPricing = await this.pricingService_
|
||||||
.withTransaction(transactionManager)
|
.withTransaction(transactionManager)
|
||||||
.getRegionPrice(variant.id, {
|
.getProductVariantPricingById(variant.id, {
|
||||||
regionId: region.id,
|
region_id: region.id,
|
||||||
quantity: quantity,
|
quantity: quantity,
|
||||||
customer_id: context?.customer_id,
|
customer_id: context?.customer_id,
|
||||||
include_discount_prices: true,
|
include_discount_prices: true,
|
||||||
})
|
})
|
||||||
|
unit_price = variantPricing.calculated_price
|
||||||
}
|
}
|
||||||
|
|
||||||
const rawLineItem: Partial<LineItem> = {
|
const rawLineItem: Partial<LineItem> = {
|
||||||
unit_price: unit_price as number,
|
unit_price: unit_price,
|
||||||
title: variant.product.title,
|
title: variant.product.title,
|
||||||
description: variant.title,
|
description: variant.title,
|
||||||
thumbnail: variant.product.thumbnail,
|
thumbnail: variant.product.thumbnail,
|
||||||
|
|||||||
@@ -0,0 +1,389 @@
|
|||||||
|
import { EntityManager } from "typeorm"
|
||||||
|
import { ProductVariantService, RegionService, TaxProviderService } from "."
|
||||||
|
import { Product, ProductVariant } from "../models"
|
||||||
|
import { TaxServiceRate } from "../types/tax-service"
|
||||||
|
import {
|
||||||
|
ProductVariantPricing,
|
||||||
|
TaxedPricing,
|
||||||
|
PricingContext,
|
||||||
|
PricedProduct,
|
||||||
|
PricedVariant,
|
||||||
|
} from "../types/pricing"
|
||||||
|
import { TransactionBaseService } from "../interfaces"
|
||||||
|
import {
|
||||||
|
IPriceSelectionStrategy,
|
||||||
|
PriceSelectionContext,
|
||||||
|
} from "../interfaces/price-selection-strategy"
|
||||||
|
|
||||||
|
type InjectedDependencies = {
|
||||||
|
manager: EntityManager
|
||||||
|
productVariantService: ProductVariantService
|
||||||
|
taxProviderService: TaxProviderService
|
||||||
|
regionService: RegionService
|
||||||
|
priceSelectionStrategy: IPriceSelectionStrategy
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows retrieval of prices.
|
||||||
|
* @extends BaseService
|
||||||
|
*/
|
||||||
|
class PricingService extends TransactionBaseService<PricingService> {
|
||||||
|
protected manager_: EntityManager
|
||||||
|
protected transactionManager_: EntityManager | undefined
|
||||||
|
protected readonly regionService: RegionService
|
||||||
|
protected readonly taxProviderService: TaxProviderService
|
||||||
|
protected readonly priceSelectionStrategy: IPriceSelectionStrategy
|
||||||
|
protected readonly productVariantService: ProductVariantService
|
||||||
|
|
||||||
|
constructor({
|
||||||
|
manager,
|
||||||
|
productVariantService,
|
||||||
|
taxProviderService,
|
||||||
|
regionService,
|
||||||
|
priceSelectionStrategy,
|
||||||
|
}: InjectedDependencies) {
|
||||||
|
// eslint-disable-next-line prefer-rest-params
|
||||||
|
super(arguments[0])
|
||||||
|
|
||||||
|
this.manager_ = manager
|
||||||
|
this.regionService = regionService
|
||||||
|
this.taxProviderService = taxProviderService
|
||||||
|
this.priceSelectionStrategy = priceSelectionStrategy
|
||||||
|
this.productVariantService = productVariantService
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Collects additional information neccessary for completing the price
|
||||||
|
* selection.
|
||||||
|
* @param context - the price selection context to use
|
||||||
|
* @return The pricing context
|
||||||
|
*/
|
||||||
|
async collectPricingContext(
|
||||||
|
context: PriceSelectionContext
|
||||||
|
): Promise<PricingContext> {
|
||||||
|
return await this.atomicPhase_(
|
||||||
|
async (transactionManager: EntityManager) => {
|
||||||
|
let automaticTaxes = false
|
||||||
|
let taxRate = null
|
||||||
|
let currencyCode = context.currency_code
|
||||||
|
|
||||||
|
if (context.region_id) {
|
||||||
|
const region = await this.regionService
|
||||||
|
.withTransaction(transactionManager)
|
||||||
|
.retrieve(context.region_id, {
|
||||||
|
select: ["id", "currency_code", "automatic_taxes", "tax_rate"],
|
||||||
|
})
|
||||||
|
|
||||||
|
currencyCode = region.currency_code
|
||||||
|
automaticTaxes = region.automatic_taxes
|
||||||
|
taxRate = region.tax_rate
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
price_selection: {
|
||||||
|
...context,
|
||||||
|
currency_code: currencyCode,
|
||||||
|
},
|
||||||
|
automatic_taxes: automaticTaxes,
|
||||||
|
tax_rate: taxRate,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the prices for a product variant
|
||||||
|
* @param variantPricing - the prices retrieved from a variant
|
||||||
|
* @param productRates - the tax rates that the product has applied
|
||||||
|
* @return The tax related variant prices.
|
||||||
|
*/
|
||||||
|
async calculateTaxes(
|
||||||
|
variantPricing: ProductVariantPricing,
|
||||||
|
productRates: TaxServiceRate[]
|
||||||
|
): Promise<TaxedPricing> {
|
||||||
|
const rate = productRates.reduce(
|
||||||
|
(accRate: number, nextTaxRate: TaxServiceRate) => {
|
||||||
|
return accRate + (nextTaxRate.rate || 0) / 100
|
||||||
|
},
|
||||||
|
0
|
||||||
|
)
|
||||||
|
|
||||||
|
const taxedPricing: TaxedPricing = {
|
||||||
|
original_tax: null,
|
||||||
|
calculated_tax: null,
|
||||||
|
original_price_incl_tax: null,
|
||||||
|
calculated_price_incl_tax: null,
|
||||||
|
tax_rates: productRates,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (variantPricing.calculated_price !== null) {
|
||||||
|
const taxAmount = Math.round(variantPricing.calculated_price * rate)
|
||||||
|
taxedPricing.calculated_tax = taxAmount
|
||||||
|
taxedPricing.calculated_price_incl_tax =
|
||||||
|
variantPricing.calculated_price + taxAmount
|
||||||
|
}
|
||||||
|
|
||||||
|
if (variantPricing.original_price !== null) {
|
||||||
|
const taxAmount = Math.round(variantPricing.original_price * rate)
|
||||||
|
taxedPricing.original_tax = taxAmount
|
||||||
|
taxedPricing.original_price_incl_tax =
|
||||||
|
variantPricing.original_price + taxAmount
|
||||||
|
}
|
||||||
|
|
||||||
|
return taxedPricing
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getProductVariantPricing_(
|
||||||
|
variantId: string,
|
||||||
|
taxRates: TaxServiceRate[],
|
||||||
|
context: PricingContext
|
||||||
|
): Promise<ProductVariantPricing> {
|
||||||
|
const transactionManager = this.transactionManager_ ?? this.manager_
|
||||||
|
const pricing = await this.priceSelectionStrategy
|
||||||
|
.withTransaction(transactionManager)
|
||||||
|
.calculateVariantPrice(variantId, context.price_selection)
|
||||||
|
|
||||||
|
const pricingResult: ProductVariantPricing = {
|
||||||
|
prices: pricing.prices,
|
||||||
|
original_price: pricing.originalPrice,
|
||||||
|
calculated_price: pricing.calculatedPrice,
|
||||||
|
calculated_price_type: pricing.calculatedPriceType,
|
||||||
|
original_price_incl_tax: null,
|
||||||
|
calculated_price_incl_tax: null,
|
||||||
|
original_tax: null,
|
||||||
|
calculated_tax: null,
|
||||||
|
tax_rates: null,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.automatic_taxes && context.price_selection.region_id) {
|
||||||
|
const taxResults = await this.calculateTaxes(pricingResult, taxRates)
|
||||||
|
|
||||||
|
pricingResult.original_price_incl_tax = taxResults.original_price_incl_tax
|
||||||
|
pricingResult.calculated_price_incl_tax =
|
||||||
|
taxResults.calculated_price_incl_tax
|
||||||
|
pricingResult.original_tax = taxResults.original_tax
|
||||||
|
pricingResult.calculated_tax = taxResults.calculated_tax
|
||||||
|
pricingResult.tax_rates = taxResults.tax_rates
|
||||||
|
}
|
||||||
|
|
||||||
|
return pricingResult
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the prices for a product variant.
|
||||||
|
* @param variant - the id of the variant to get prices for
|
||||||
|
* @param context - the price selection context to use
|
||||||
|
* @return The product variant prices
|
||||||
|
*/
|
||||||
|
async getProductVariantPricing(
|
||||||
|
variant: Pick<ProductVariant, "id" | "product_id">,
|
||||||
|
context: PriceSelectionContext | PricingContext
|
||||||
|
): Promise<ProductVariantPricing> {
|
||||||
|
let pricingContext: PricingContext
|
||||||
|
if ("automatic_taxes" in context) {
|
||||||
|
pricingContext = context
|
||||||
|
} else {
|
||||||
|
pricingContext = await this.collectPricingContext(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
let productRates: TaxServiceRate[] = []
|
||||||
|
if (
|
||||||
|
pricingContext.automatic_taxes &&
|
||||||
|
pricingContext.price_selection.region_id
|
||||||
|
) {
|
||||||
|
productRates = await this.taxProviderService.getRegionRatesForProduct(
|
||||||
|
variant.product_id,
|
||||||
|
{
|
||||||
|
id: pricingContext.price_selection.region_id,
|
||||||
|
tax_rate: pricingContext.tax_rate,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return await this.getProductVariantPricing_(
|
||||||
|
variant.id,
|
||||||
|
productRates,
|
||||||
|
pricingContext
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the prices for a product variant by a variant id.
|
||||||
|
* @param variantId - the id of the variant to get prices for
|
||||||
|
* @param context - the price selection context to use
|
||||||
|
* @return The product variant prices
|
||||||
|
*/
|
||||||
|
async getProductVariantPricingById(
|
||||||
|
variantId: string,
|
||||||
|
context: PriceSelectionContext | PricingContext
|
||||||
|
): Promise<ProductVariantPricing> {
|
||||||
|
let pricingContext: PricingContext
|
||||||
|
if ("automatic_taxes" in context) {
|
||||||
|
pricingContext = context
|
||||||
|
} else {
|
||||||
|
pricingContext = await this.collectPricingContext(context)
|
||||||
|
}
|
||||||
|
|
||||||
|
let productRates: TaxServiceRate[] = []
|
||||||
|
if (
|
||||||
|
pricingContext.automatic_taxes &&
|
||||||
|
pricingContext.price_selection.region_id
|
||||||
|
) {
|
||||||
|
const { product_id } = await this.productVariantService.retrieve(
|
||||||
|
variantId,
|
||||||
|
{ select: ["id", "product_id"] }
|
||||||
|
)
|
||||||
|
productRates = await this.taxProviderService.getRegionRatesForProduct(
|
||||||
|
product_id,
|
||||||
|
{
|
||||||
|
id: pricingContext.price_selection.region_id,
|
||||||
|
tax_rate: pricingContext.tax_rate,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return await this.getProductVariantPricing_(
|
||||||
|
variantId,
|
||||||
|
productRates,
|
||||||
|
pricingContext
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getProductPricing_(
|
||||||
|
productId: string,
|
||||||
|
variants: ProductVariant[],
|
||||||
|
context: PricingContext
|
||||||
|
): Promise<Record<string, ProductVariantPricing>> {
|
||||||
|
const transactionManager = this.transactionManager_ ?? this.manager_
|
||||||
|
let taxRates: TaxServiceRate[] = []
|
||||||
|
if (context.automatic_taxes && context.price_selection.region_id) {
|
||||||
|
taxRates = await this.taxProviderService
|
||||||
|
.withTransaction(transactionManager)
|
||||||
|
.getRegionRatesForProduct(productId, {
|
||||||
|
id: context.price_selection.region_id,
|
||||||
|
tax_rate: context.tax_rate,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const pricings = {}
|
||||||
|
await Promise.all(
|
||||||
|
variants.map(async ({ id }) => {
|
||||||
|
const variantPricing = await this.getProductVariantPricing_(
|
||||||
|
id,
|
||||||
|
taxRates,
|
||||||
|
context
|
||||||
|
)
|
||||||
|
pricings[id] = variantPricing
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
return pricings
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all the variant prices for a product. All the product's variants will
|
||||||
|
* be fetched.
|
||||||
|
* @param product - the product to get pricing for.
|
||||||
|
* @param context - the price selection context to use
|
||||||
|
* @return A map of variant ids to their corresponding prices
|
||||||
|
*/
|
||||||
|
async getProductPricing(
|
||||||
|
product: Pick<Product, "id" | "variants">,
|
||||||
|
context: PriceSelectionContext
|
||||||
|
): Promise<Record<string, ProductVariantPricing>> {
|
||||||
|
const pricingContext = await this.collectPricingContext(context)
|
||||||
|
return await this.getProductPricing_(
|
||||||
|
product.id,
|
||||||
|
product.variants,
|
||||||
|
pricingContext
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all the variant prices for a product by the product id
|
||||||
|
* @param productId - the id of the product to get prices for
|
||||||
|
* @param context - the price selection context to use
|
||||||
|
* @return A map of variant ids to their corresponding prices
|
||||||
|
*/
|
||||||
|
async getProductPricingById(
|
||||||
|
productId: string,
|
||||||
|
context: PriceSelectionContext
|
||||||
|
): Promise<Record<string, ProductVariantPricing>> {
|
||||||
|
const pricingContext = await this.collectPricingContext(context)
|
||||||
|
const variants = await this.productVariantService.list(
|
||||||
|
{ product_id: productId },
|
||||||
|
{ select: ["id"] }
|
||||||
|
)
|
||||||
|
return await this.getProductPricing_(productId, variants, pricingContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set additional prices on a list of product variants.
|
||||||
|
* @param variants - list of variants on which to set additional prices
|
||||||
|
* @param context - the price selection context to use
|
||||||
|
* @return A list of products with variants decorated with prices
|
||||||
|
*/
|
||||||
|
async setVariantPrices(
|
||||||
|
variants: ProductVariant[],
|
||||||
|
context: PriceSelectionContext
|
||||||
|
): Promise<PricedVariant[]> {
|
||||||
|
const pricingContext = await this.collectPricingContext(context)
|
||||||
|
return await Promise.all(
|
||||||
|
variants.map(async (variant) => {
|
||||||
|
const variantPricing = await this.getProductVariantPricing(
|
||||||
|
variant,
|
||||||
|
pricingContext
|
||||||
|
)
|
||||||
|
return {
|
||||||
|
...variant,
|
||||||
|
...variantPricing,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set additional prices on a list of products.
|
||||||
|
* @param products - list of products on which to set additional prices
|
||||||
|
* @param context - the price selection context to use
|
||||||
|
* @return A list of products with variants decorated with prices
|
||||||
|
*/
|
||||||
|
async setProductPrices(
|
||||||
|
products: Product[],
|
||||||
|
context: PriceSelectionContext = {}
|
||||||
|
): Promise<(Product | PricedProduct)[]> {
|
||||||
|
const pricingContext = await this.collectPricingContext(context)
|
||||||
|
return await Promise.all(
|
||||||
|
products.map(async (product) => {
|
||||||
|
if (!product?.variants?.length) {
|
||||||
|
return product
|
||||||
|
}
|
||||||
|
|
||||||
|
const variantPricing = await this.getProductPricing_(
|
||||||
|
product.id,
|
||||||
|
product.variants,
|
||||||
|
pricingContext
|
||||||
|
)
|
||||||
|
|
||||||
|
const pricedVariants = product.variants.map(
|
||||||
|
(productVariant): PricedVariant => {
|
||||||
|
const pricing = variantPricing[productVariant.id]
|
||||||
|
return {
|
||||||
|
...productVariant,
|
||||||
|
...pricing,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
const pricedProduct = {
|
||||||
|
...product,
|
||||||
|
variants: pricedVariants,
|
||||||
|
}
|
||||||
|
|
||||||
|
return pricedProduct
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PricingService
|
||||||
@@ -125,12 +125,6 @@ class ProductVariantService extends BaseService {
|
|||||||
)
|
)
|
||||||
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)
|
||||||
|
|
||||||
@@ -141,16 +135,7 @@ class ProductVariantService extends BaseService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return priceIndex >= 0
|
return variant
|
||||||
? ((await this.setAdditionalPrices(
|
|
||||||
variant,
|
|
||||||
config.currency_code,
|
|
||||||
config.region_id,
|
|
||||||
config.cart_id,
|
|
||||||
config.customer_id,
|
|
||||||
config.include_discount_prices
|
|
||||||
)) as ProductVariant)
|
|
||||||
: variant
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -185,16 +170,7 @@ class ProductVariantService extends BaseService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return priceIndex >= 0
|
return variant
|
||||||
? ((await this.setAdditionalPrices(
|
|
||||||
variant,
|
|
||||||
config.currency_code,
|
|
||||||
config.region_id,
|
|
||||||
config.cart_id,
|
|
||||||
config.customer_id,
|
|
||||||
config.include_discount_prices
|
|
||||||
)) as ProductVariant)
|
|
||||||
: variant
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -617,12 +593,6 @@ class ProductVariantService extends BaseService {
|
|||||||
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) {
|
||||||
@@ -634,17 +604,6 @@ 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]
|
||||||
}
|
}
|
||||||
@@ -654,18 +613,6 @@ class ProductVariantService extends BaseService {
|
|||||||
query
|
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]
|
return [variants, count]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -722,18 +669,7 @@ class ProductVariantService extends BaseService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const variants = await productVariantRepo.find(query)
|
return 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -883,72 +819,6 @@ 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
|
||||||
@@ -22,13 +22,10 @@ class ProductService extends BaseService {
|
|||||||
productOptionRepository,
|
productOptionRepository,
|
||||||
eventBusService,
|
eventBusService,
|
||||||
productVariantService,
|
productVariantService,
|
||||||
productCollectionService,
|
|
||||||
productTypeRepository,
|
productTypeRepository,
|
||||||
productTagRepository,
|
productTagRepository,
|
||||||
imageRepository,
|
imageRepository,
|
||||||
searchService,
|
searchService,
|
||||||
cartRepository,
|
|
||||||
priceSelectionStrategy,
|
|
||||||
}) {
|
}) {
|
||||||
super()
|
super()
|
||||||
|
|
||||||
@@ -50,9 +47,6 @@ class ProductService extends BaseService {
|
|||||||
/** @private @const {ProductVariantService} */
|
/** @private @const {ProductVariantService} */
|
||||||
this.productVariantService_ = productVariantService
|
this.productVariantService_ = productVariantService
|
||||||
|
|
||||||
/** @private @const {ProductCollectionService} */
|
|
||||||
this.productCollectionService_ = productCollectionService
|
|
||||||
|
|
||||||
/** @private @const {ProductCollectionService} */
|
/** @private @const {ProductCollectionService} */
|
||||||
this.productTypeRepository_ = productTypeRepository
|
this.productTypeRepository_ = productTypeRepository
|
||||||
|
|
||||||
@@ -64,12 +58,6 @@ 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) {
|
||||||
@@ -84,12 +72,9 @@ class ProductService extends BaseService {
|
|||||||
productOptionRepository: this.productOptionRepository_,
|
productOptionRepository: this.productOptionRepository_,
|
||||||
eventBusService: this.eventBus_,
|
eventBusService: this.eventBus_,
|
||||||
productVariantService: this.productVariantService_,
|
productVariantService: this.productVariantService_,
|
||||||
productCollectionService: this.productCollectionService_,
|
|
||||||
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
|
||||||
@@ -117,11 +102,6 @@ class ProductService extends BaseService {
|
|||||||
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)
|
||||||
|
|
||||||
@@ -135,18 +115,7 @@ class ProductService extends BaseService {
|
|||||||
return products
|
return products
|
||||||
}
|
}
|
||||||
|
|
||||||
const products = productRepo.findWithRelations(relations, query)
|
return await 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -173,43 +142,17 @@ 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 { q, query, relations } = this.prepareListQuery_(selector, config)
|
const { q, query, relations } = this.prepareListQuery_(selector, config)
|
||||||
|
|
||||||
let products
|
|
||||||
let count
|
|
||||||
if (q) {
|
if (q) {
|
||||||
;[products, count] = await productRepo.getFreeTextSearchResultsAndCount(
|
return await productRepo.getFreeTextSearchResultsAndCount(
|
||||||
q,
|
q,
|
||||||
query,
|
query,
|
||||||
relations
|
relations
|
||||||
)
|
)
|
||||||
} else {
|
|
||||||
;[products, count] = await productRepo.findWithRelationsAndCount(
|
|
||||||
relations,
|
|
||||||
query
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priceIndex > -1) {
|
return await productRepo.findWithRelationsAndCount(relations, query)
|
||||||
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]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -239,12 +182,6 @@ class ProductService extends BaseService {
|
|||||||
)
|
)
|
||||||
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) {
|
||||||
@@ -266,16 +203,7 @@ class ProductService extends BaseService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -290,12 +218,6 @@ 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) {
|
||||||
@@ -317,16 +239,7 @@ class ProductService extends BaseService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -341,12 +254,6 @@ 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) {
|
||||||
@@ -368,16 +275,7 @@ class ProductService extends BaseService {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -942,29 +840,12 @@ class ProductService extends BaseService {
|
|||||||
async decorate(productId, fields = [], expandFields = [], config = {}) {
|
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, {
|
return await this.retrieve(productId, {
|
||||||
select: fields,
|
select: fields,
|
||||||
relations: expandFields,
|
relations: expandFields,
|
||||||
})
|
})
|
||||||
|
|
||||||
return priceIndex > -1
|
|
||||||
? await this.setAdditionalPrices(
|
|
||||||
product,
|
|
||||||
config.currency_code,
|
|
||||||
config.region_id,
|
|
||||||
config.cart_id,
|
|
||||||
config.customer_id,
|
|
||||||
config.include_discount_prices
|
|
||||||
)
|
|
||||||
: product
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -1000,80 +881,6 @@ class ProductService extends BaseService {
|
|||||||
q,
|
q,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
||||||
@@ -28,6 +28,11 @@ import TaxRateService from "./tax-rate"
|
|||||||
|
|
||||||
const CACHE_TIME = 30 // seconds
|
const CACHE_TIME = 30 // seconds
|
||||||
|
|
||||||
|
type RegionDetails = {
|
||||||
|
id: string
|
||||||
|
tax_rate: number | null
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds tax providers and assists in tax related operations.
|
* Finds tax providers and assists in tax related operations.
|
||||||
*/
|
*/
|
||||||
@@ -321,14 +326,14 @@ class TaxProviderService extends BaseService {
|
|||||||
* Gets the tax rates configured for a shipping option. The rates are cached
|
* Gets the tax rates configured for a shipping option. The rates are cached
|
||||||
* between calls.
|
* between calls.
|
||||||
* @param optionId - the option id of the shipping method.
|
* @param optionId - the option id of the shipping method.
|
||||||
* @param region - the region to get configured rates for.
|
* @param regionDetails - the region to get configured rates for.
|
||||||
* @return the tax rates configured for the shipping option.
|
* @return the tax rates configured for the shipping option.
|
||||||
*/
|
*/
|
||||||
async getRegionRatesForShipping(
|
async getRegionRatesForShipping(
|
||||||
optionId: string,
|
optionId: string,
|
||||||
region: Region
|
regionDetails: RegionDetails
|
||||||
): Promise<TaxServiceRate[]> {
|
): Promise<TaxServiceRate[]> {
|
||||||
const cacheHit = await this.getCacheEntry(optionId, region.id)
|
const cacheHit = await this.getCacheEntry(optionId, regionDetails.id)
|
||||||
if (cacheHit) {
|
if (cacheHit) {
|
||||||
return cacheHit
|
return cacheHit
|
||||||
}
|
}
|
||||||
@@ -336,7 +341,7 @@ class TaxProviderService extends BaseService {
|
|||||||
let toReturn: TaxServiceRate[] = []
|
let toReturn: TaxServiceRate[] = []
|
||||||
const optionRates = await this.taxRateService_.listByShippingOption(
|
const optionRates = await this.taxRateService_.listByShippingOption(
|
||||||
optionId,
|
optionId,
|
||||||
{ region_id: region.id }
|
{ region_id: regionDetails.id }
|
||||||
)
|
)
|
||||||
|
|
||||||
if (optionRates.length > 0) {
|
if (optionRates.length > 0) {
|
||||||
@@ -352,14 +357,14 @@ class TaxProviderService extends BaseService {
|
|||||||
if (toReturn.length === 0) {
|
if (toReturn.length === 0) {
|
||||||
toReturn = [
|
toReturn = [
|
||||||
{
|
{
|
||||||
rate: region.tax_rate,
|
rate: regionDetails.tax_rate,
|
||||||
name: "default",
|
name: "default",
|
||||||
code: "default",
|
code: "default",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.setCache(optionId, region.id, toReturn)
|
await this.setCache(optionId, regionDetails.id, toReturn)
|
||||||
|
|
||||||
return toReturn
|
return toReturn
|
||||||
}
|
}
|
||||||
@@ -373,7 +378,7 @@ class TaxProviderService extends BaseService {
|
|||||||
*/
|
*/
|
||||||
async getRegionRatesForProduct(
|
async getRegionRatesForProduct(
|
||||||
productId: string,
|
productId: string,
|
||||||
region: Region
|
region: RegionDetails
|
||||||
): Promise<TaxServiceRate[]> {
|
): Promise<TaxServiceRate[]> {
|
||||||
const cacheHit = await this.getCacheEntry(productId, region.id)
|
const cacheHit = await this.getCacheEntry(productId, region.id)
|
||||||
if (cacheHit) {
|
if (cacheHit) {
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { MoneyAmount, ProductVariant, Product } from "../models"
|
||||||
|
import { TaxServiceRate } from "./tax-service"
|
||||||
|
import { PriceSelectionContext } from "../interfaces/price-selection-strategy"
|
||||||
|
|
||||||
|
export type ProductVariantPricing = {
|
||||||
|
prices: MoneyAmount[]
|
||||||
|
original_price: number | null
|
||||||
|
calculated_price: number | null
|
||||||
|
calculated_price_type?: string | null
|
||||||
|
} & TaxedPricing
|
||||||
|
|
||||||
|
export type TaxedPricing = {
|
||||||
|
original_price_incl_tax: number | null
|
||||||
|
calculated_price_incl_tax: number | null
|
||||||
|
original_tax: number | null
|
||||||
|
calculated_tax: number | null
|
||||||
|
tax_rates: TaxServiceRate[] | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PricingContext = {
|
||||||
|
price_selection: PriceSelectionContext
|
||||||
|
automatic_taxes: boolean
|
||||||
|
tax_rate: number | null
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PricedVariant = Partial<ProductVariant> & ProductVariantPricing
|
||||||
|
|
||||||
|
export type PricedProduct = Omit<Partial<Product>, "variants"> & {
|
||||||
|
variants: PricedVariant[]
|
||||||
|
}
|
||||||
@@ -7507,7 +7507,7 @@
|
|||||||
"@types/qs" "*"
|
"@types/qs" "*"
|
||||||
"@types/range-parser" "*"
|
"@types/range-parser" "*"
|
||||||
|
|
||||||
"@types/express@^4.17.13":
|
"@types/express@*", "@types/express@^4.17.13":
|
||||||
version "4.17.13"
|
version "4.17.13"
|
||||||
resolved "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz"
|
resolved "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz"
|
||||||
integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==
|
integrity sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==
|
||||||
@@ -7744,6 +7744,13 @@
|
|||||||
"@types/bson" "*"
|
"@types/bson" "*"
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
|
|
||||||
|
"@types/multer@^1.4.7":
|
||||||
|
version "1.4.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/multer/-/multer-1.4.7.tgz#89cf03547c28c7bbcc726f029e2a76a7232cc79e"
|
||||||
|
integrity sha512-/SNsDidUFCvqqcWDwxv2feww/yqhNeTRL5CVoL3jU4Goc4kKEL10T7Eye65ZqPNi4HRx8sAEX59pV1aEH7drNA==
|
||||||
|
dependencies:
|
||||||
|
"@types/express" "*"
|
||||||
|
|
||||||
"@types/node-fetch@2", "@types/node-fetch@^2.5.7":
|
"@types/node-fetch@2", "@types/node-fetch@^2.5.7":
|
||||||
version "2.5.12"
|
version "2.5.12"
|
||||||
resolved "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.12.tgz"
|
resolved "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.12.tgz"
|
||||||
|
|||||||
Reference in new issue
Block a user