mirror of
https://github.com/grocy/grocy.git
synced 2025-08-17 11:06:36 +00:00
Optimized performance of GetProductDetails
This commit is contained in:
64
migrations/0234.sql
Normal file
64
migrations/0234.sql
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
CREATE VIEW uihelper_product_details
|
||||||
|
AS
|
||||||
|
SELECT
|
||||||
|
p.id,
|
||||||
|
plp.purchased_date AS last_purchased_date,
|
||||||
|
plp.price AS last_purchased_price,
|
||||||
|
plp.shopping_location_id AS last_purchased_shopping_location_id,
|
||||||
|
pap.price AS average_price,
|
||||||
|
sl.average_shelf_life_days,
|
||||||
|
pcp.price AS current_price,
|
||||||
|
last_used.used_date AS last_used_date,
|
||||||
|
next_due.best_before_date AS next_due_date,
|
||||||
|
IFNULL((spoil_count.amount * 100.0) / consume_count.amount, 0) AS spoil_rate,
|
||||||
|
CAST(IFNULL(quc_purchase2stock.factor, 1.0) AS REAL) AS qu_factor_purchase_to_stock,
|
||||||
|
CAST(IFNULL(quc_price2stock.factor, 1.0) AS REAL) AS qu_factor_price_to_stock,
|
||||||
|
CASE WHEN EXISTS(SELECT 1 FROM products px WHERE px.parent_product_id = p.id) THEN 1 ELSE 0 END AS has_childs
|
||||||
|
FROM products p
|
||||||
|
LEFT JOIN cache__products_last_purchased plp
|
||||||
|
ON p.id = plp.product_id
|
||||||
|
LEFT JOIN cache__products_average_price pap
|
||||||
|
ON p.id = pap.product_id
|
||||||
|
LEFT JOIN stock_average_product_shelf_life sl
|
||||||
|
ON p.id = sl.id
|
||||||
|
LEFT JOIN products_current_price pcp
|
||||||
|
ON p.id = pcp.product_id
|
||||||
|
LEFT JOIN cache__quantity_unit_conversions_resolved quc_purchase2stock
|
||||||
|
ON p.id = quc_purchase2stock.product_id
|
||||||
|
AND p.qu_id_purchase = quc_purchase2stock.from_qu_id
|
||||||
|
AND p.qu_id_stock = quc_purchase2stock.to_qu_id
|
||||||
|
LEFT JOIN cache__quantity_unit_conversions_resolved quc_price2stock
|
||||||
|
ON p.id = quc_price2stock.product_id
|
||||||
|
AND p.qu_id_price = quc_price2stock.from_qu_id
|
||||||
|
AND p.qu_id_stock = quc_price2stock.to_qu_id
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT product_id, MAX(used_date) AS used_date
|
||||||
|
FROM stock_log
|
||||||
|
WHERE transaction_type = 'consume'
|
||||||
|
AND undone = 0
|
||||||
|
GROUP BY product_id
|
||||||
|
) last_used
|
||||||
|
ON p.id = last_used.product_id
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT product_id,MIN(best_before_date) AS best_before_date
|
||||||
|
FROM stock
|
||||||
|
GROUP BY product_id
|
||||||
|
) next_due
|
||||||
|
ON p.id = next_due.product_id
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT product_id, SUM(amount) AS amount
|
||||||
|
FROM stock_log
|
||||||
|
WHERE transaction_type = 'consume'
|
||||||
|
AND undone = 0
|
||||||
|
GROUP BY product_id
|
||||||
|
) consume_count
|
||||||
|
ON p.id = consume_count.product_id
|
||||||
|
LEFT JOIN (
|
||||||
|
SELECT product_id, SUM(amount) AS amount
|
||||||
|
FROM stock_log
|
||||||
|
WHERE transaction_type = 'consume'
|
||||||
|
AND undone = 0
|
||||||
|
AND spoiled = 1
|
||||||
|
GROUP BY product_id
|
||||||
|
) spoil_count
|
||||||
|
ON p.id = spoil_count.product_id;
|
@@ -204,7 +204,7 @@ class LocalizationService
|
|||||||
$quantityUnits = null;
|
$quantityUnits = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
$quantityUnits = $this->getDatabase()->quantity_units()->fetchAll();
|
$quantityUnits = $this->getDatabase()->quantity_units()->where('active = 1')->fetchAll();
|
||||||
}
|
}
|
||||||
catch (\Exception $ex)
|
catch (\Exception $ex)
|
||||||
{
|
{
|
||||||
|
@@ -711,42 +711,14 @@ class StockService extends BaseService
|
|||||||
$stockCurrentRow->is_aggregated_amount = 0;
|
$stockCurrentRow->is_aggregated_amount = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
$productLastPurchased = $this->getDatabase()->cache__products_last_purchased()->where('product_id', $productId)->fetch();
|
$detailsRow = $this->getDatabase()->uihelper_product_details()->where('id', $productId)->fetch();
|
||||||
$lastPurchasedDate = null;
|
|
||||||
$lastPrice = null;
|
|
||||||
$lastShoppingLocation = null;
|
|
||||||
$avgPrice = null;
|
|
||||||
if ($productLastPurchased)
|
|
||||||
{
|
|
||||||
$lastPurchasedDate = $productLastPurchased->purchased_date;
|
|
||||||
$lastPrice = $productLastPurchased->price;
|
|
||||||
$lastShoppingLocation = $productLastPurchased->shopping_location_id;
|
|
||||||
$avgPriceRow = $this->getDatabase()->cache__products_average_price()->where('product_id', $productId)->fetch();
|
|
||||||
if ($avgPriceRow)
|
|
||||||
{
|
|
||||||
$avgPrice = $avgPriceRow->price;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$product = $this->getDatabase()->products($productId);
|
$product = $this->getDatabase()->products($productId);
|
||||||
$productBarcodes = $this->getDatabase()->product_barcodes()->where('product_id', $productId)->fetchAll();
|
$productBarcodes = $this->getDatabase()->product_barcodes()->where('product_id', $productId)->fetchAll();
|
||||||
$productLastUsed = $this->getDatabase()->stock_log()->where('product_id', $productId)->where('transaction_type', self::TRANSACTION_TYPE_CONSUME)->where('undone', 0)->max('used_date');
|
|
||||||
$nextDueDate = $this->getDatabase()->stock()->where('product_id', $productId)->min('best_before_date');
|
|
||||||
$quPurchase = $this->getDatabase()->quantity_units($product->qu_id_purchase);
|
$quPurchase = $this->getDatabase()->quantity_units($product->qu_id_purchase);
|
||||||
$quStock = $this->getDatabase()->quantity_units($product->qu_id_stock);
|
$quStock = $this->getDatabase()->quantity_units($product->qu_id_stock);
|
||||||
$quConsume = $this->getDatabase()->quantity_units($product->qu_id_consume);
|
$quConsume = $this->getDatabase()->quantity_units($product->qu_id_consume);
|
||||||
$quPrice = $this->getDatabase()->quantity_units($product->qu_id_price);
|
$quPrice = $this->getDatabase()->quantity_units($product->qu_id_price);
|
||||||
$location = $this->getDatabase()->locations($product->location_id);
|
$location = $this->getDatabase()->locations($product->location_id);
|
||||||
$averageShelfLifeDays = $this->getDatabase()->stock_average_product_shelf_life()->where('id', $productId)->fetch()->average_shelf_life_days;
|
|
||||||
$currentPrice = $this->getDatabase()->products_current_price()->where('product_id', $productId)->fetch()->price;
|
|
||||||
|
|
||||||
$consumeCount = $this->getDatabase()->stock_log()->where('product_id', $productId)->where('transaction_type', self::TRANSACTION_TYPE_CONSUME)->where('undone = 0')->sum('amount') * -1;
|
|
||||||
$consumeCountSpoiled = $this->getDatabase()->stock_log()->where('product_id', $productId)->where('transaction_type', self::TRANSACTION_TYPE_CONSUME)->where('undone = 0 AND spoiled = 1')->sum('amount') * -1;
|
|
||||||
if ($consumeCount == 0 || $consumeCount == null)
|
|
||||||
{
|
|
||||||
$consumeCount = 1;
|
|
||||||
}
|
|
||||||
$spoilRate = ($consumeCountSpoiled * 100.0) / $consumeCount;
|
|
||||||
|
|
||||||
$defaultConsumeLocation = null;
|
$defaultConsumeLocation = null;
|
||||||
if (!empty($product->default_consume_location_id))
|
if (!empty($product->default_consume_location_id))
|
||||||
@@ -754,31 +726,11 @@ class StockService extends BaseService
|
|||||||
$defaultConsumeLocation = $this->getDatabase()->locations($product->default_consume_location_id);
|
$defaultConsumeLocation = $this->getDatabase()->locations($product->default_consume_location_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
$quConversionFactorPurchaseToStock = 1.0;
|
|
||||||
if ($product->qu_id_stock != $product->qu_id_purchase)
|
|
||||||
{
|
|
||||||
$conversion = $this->getDatabase()->cache__quantity_unit_conversions_resolved()->where('product_id = :1 AND from_qu_id = :2 AND to_qu_id = :3', $product->id, $product->qu_id_purchase, $product->qu_id_stock)->fetch();
|
|
||||||
if ($conversion != null)
|
|
||||||
{
|
|
||||||
$quConversionFactorPurchaseToStock = $conversion->factor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$quConversionFactorPriceToStock = 1.0;
|
|
||||||
if ($product->qu_id_stock != $product->qu_id_price)
|
|
||||||
{
|
|
||||||
$conversion = $this->getDatabase()->cache__quantity_unit_conversions_resolved()->where('product_id = :1 AND from_qu_id = :2 AND to_qu_id = :3', $product->id, $product->qu_id_price, $product->qu_id_stock)->fetch();
|
|
||||||
if ($conversion != null)
|
|
||||||
{
|
|
||||||
$quConversionFactorPriceToStock = $conversion->factor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
'product' => $product,
|
'product' => $product,
|
||||||
'product_barcodes' => $productBarcodes,
|
'product_barcodes' => $productBarcodes,
|
||||||
'last_purchased' => $lastPurchasedDate,
|
'last_purchased' => $detailsRow->last_purchased_date,
|
||||||
'last_used' => $productLastUsed,
|
'last_used' => $detailsRow->last_used_date,
|
||||||
'stock_amount' => $stockCurrentRow->amount,
|
'stock_amount' => $stockCurrentRow->amount,
|
||||||
'stock_value' => $stockCurrentRow->value,
|
'stock_value' => $stockCurrentRow->value,
|
||||||
'stock_amount_opened' => $stockCurrentRow->amount_opened,
|
'stock_amount_opened' => $stockCurrentRow->amount_opened,
|
||||||
@@ -788,21 +740,21 @@ class StockService extends BaseService
|
|||||||
'default_quantity_unit_purchase' => $quPurchase,
|
'default_quantity_unit_purchase' => $quPurchase,
|
||||||
'default_quantity_unit_consume' => $quConsume,
|
'default_quantity_unit_consume' => $quConsume,
|
||||||
'quantity_unit_price' => $quPrice,
|
'quantity_unit_price' => $quPrice,
|
||||||
'last_price' => $lastPrice,
|
'last_price' => $detailsRow->last_purchased_price,
|
||||||
'avg_price' => $avgPrice,
|
'avg_price' => $detailsRow->average_price,
|
||||||
'oldest_price' => $currentPrice, // Deprecated
|
'oldest_price' => $detailsRow->current_price, // Deprecated
|
||||||
'current_price' => $currentPrice,
|
'current_price' => $detailsRow->current_price,
|
||||||
'last_shopping_location_id' => $lastShoppingLocation,
|
'last_shopping_location_id' => $detailsRow->last_purchased_shopping_location_id,
|
||||||
'default_shopping_location_id' => $product->shopping_location_id,
|
'default_shopping_location_id' => $product->shopping_location_id,
|
||||||
'next_due_date' => $nextDueDate,
|
'next_due_date' => $detailsRow->next_due_date,
|
||||||
'location' => $location,
|
'location' => $location,
|
||||||
'average_shelf_life_days' => $averageShelfLifeDays,
|
'average_shelf_life_days' => $detailsRow->average_shelf_life_days,
|
||||||
'spoil_rate_percent' => $spoilRate,
|
'spoil_rate_percent' => $detailsRow->spoil_rate,
|
||||||
'is_aggregated_amount' => $stockCurrentRow->is_aggregated_amount,
|
'is_aggregated_amount' => $stockCurrentRow->is_aggregated_amount,
|
||||||
'has_childs' => $this->getDatabase()->products()->where('parent_product_id = :1', $product->id)->count() !== 0,
|
'has_childs' => boolval($detailsRow->has_childs),
|
||||||
'default_consume_location' => $defaultConsumeLocation,
|
'default_consume_location' => $defaultConsumeLocation,
|
||||||
'qu_conversion_factor_purchase_to_stock' => $quConversionFactorPurchaseToStock,
|
'qu_conversion_factor_purchase_to_stock' => $detailsRow->qu_factor_purchase_to_stock,
|
||||||
'qu_conversion_factor_price_to_stock' => $quConversionFactorPriceToStock
|
'qu_conversion_factor_price_to_stock' => $detailsRow->qu_factor_price_to_stock
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user