grocy/controllers/StockReportsController.php
google-labs-jules[bot] f41cb227fc feat: Adapt Grocy for the Chinese market
This commit introduces a range of features and improvements to make Grocy more suitable for the Chinese market, based on the high-level goal of creating a better item management system for Chinese households.

The key changes include:

1.  **New 'Last Used' Report:** A new stock report has been added to show products that have not been used for a long time. This feature is inspired by the 'Danshari' (断舍离) philosophy of decluttering and helps you identify and reduce waste. This includes a new controller method, a route, a Blade view, and the necessary JavaScript for the interactive data table.

2.  **Chinese Units of Measurement:** A database migration has been added to include common Chinese units of measurement, such as 克 (gram), 斤 (jin), 公斤 (kilogram), and others. This makes inventory and recipe management more intuitive for you. Conversion factors between related units are also included.

3.  **Improved Chinese Localization:** The Chinese (zh_CN) localization file has been significantly updated by filling in a large number of previously missing translations. This provides a more complete and professional experience for you. New translations for the 'Last Used' report have also been added.

4.  **Future Work Planning:** A `TODO.md` file has been created to track the next steps for this project, specifically noting the need to research and integrate a barcode lookup API that is more suitable for Chinese products.
2025-08-13 13:55:17 +00:00

126 lines
3.6 KiB
PHP

<?php
namespace Grocy\Controllers;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
class StockReportsController extends BaseController
{
public function Spendings(Request $request, Response $response, array $args)
{
$where = "pph.transaction_type != 'self-production'";
if (isset($request->getQueryParams()['start_date']) && isset($request->getQueryParams()['end_date']) && IsIsoDate($request->getQueryParams()['start_date']) && IsIsoDate($request->getQueryParams()['end_date']))
{
$startDate = $request->getQueryParams()['start_date'];
$endDate = $request->getQueryParams()['end_date'];
$where .= " AND pph.purchased_date BETWEEN '$startDate' AND '$endDate'";
}
else
{
// Default to this month
$where .= " AND pph.purchased_date >= DATE(DATE('now', 'localtime'), 'start of month')";
}
$groupBy = 'product';
if (isset($request->getQueryParams()['group-by']) && in_array($request->getQueryParams()['group-by'], ['product', 'productgroup', 'store']))
{
$groupBy = $request->getQueryParams()['group-by'];
}
if ($groupBy == 'product')
{
if (isset($request->getQueryParams()['product-group']))
{
if ($request->getQueryParams()['product-group'] == 'ungrouped')
{
$where .= ' AND pg.id IS NULL';
}
elseif ($request->getQueryParams()['product-group'] != 'all')
{
$where .= ' AND pg.id = ' . $request->getQueryParams()['product-group'];
}
}
$sql = "
SELECT
p.id AS id,
p.name AS name,
pg.id AS group_id,
pg.name AS group_name,
SUM(pph.amount * pph.price) AS total
FROM products_price_history pph
JOIN products p
ON pph.product_id = p.id
LEFT JOIN product_groups pg
ON p.product_group_id = pg.id
WHERE $where
GROUP BY p.id, p.name, pg.id, pg.name
ORDER BY p.name COLLATE NOCASE
";
}
elseif ($groupBy == 'productgroup')
{
$sql = "
SELECT
pg.id AS id,
pg.name AS name,
SUM(pph.amount * pph.price) AS total
FROM products_price_history pph
JOIN products p
ON pph.product_id = p.id
LEFT JOIN product_groups pg
ON p.product_group_id = pg.id
WHERE $where
GROUP BY pg.id, pg.name
ORDER BY pg.name COLLATE NOCASE
";
}
elseif ($groupBy == 'store')
{
$sql = "
SELECT
sl.id AS id,
sl.name AS name,
SUM(pph.amount * pph.price) AS total
FROM products_price_history pph
JOIN products p
ON pph.product_id = p.id
LEFT JOIN shopping_locations sl
ON pph.shopping_location_id = sl.id
WHERE $where
GROUP BY sl.id, sl.name
ORDER BY sl.NAME COLLATE NOCASE
";
}
return $this->renderPage($response, 'stockreportspendings', [
'metrics' => $this->getDatabaseService()->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ),
'productGroups' => $this->getDatabase()->product_groups()->where('active = 1')->orderBy('name', 'COLLATE NOCASE'),
'selectedGroup' => isset($request->getQueryParams()['product-group']) ? $request->getQueryParams()['product-group'] : null,
'groupBy' => $groupBy
]);
}
public function LastUsed(Request $request, Response $response, array $args)
{
$sql = "
SELECT
p.id,
p.name,
sc.amount,
MAX(sl.used_date) as last_used
FROM products p
JOIN stock_current sc ON p.id = sc.product_id
LEFT JOIN stock_log sl ON p.id = sl.product_id AND sl.transaction_type = 'consume'
GROUP BY p.id, p.name, sc.amount
ORDER BY last_used IS NULL DESC, last_used ASC
";
return $this->renderPage($response, 'stockreportlastused', [
'products' => $this->getDatabaseService()->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ)
]);
}
}