diff --git a/controllers/StockApiController.php b/controllers/StockApiController.php index 8892eeef..350a580f 100644 --- a/controllers/StockApiController.php +++ b/controllers/StockApiController.php @@ -118,6 +118,24 @@ class StockApiController extends BaseApiController return $this->ApiResponse($this->StockService->GetCurrentStock()); } + public function CurrentVolatilStock(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args) + { + $nextXDays = 5; + if (isset($request->getQueryParams()['expiring_days']) && !empty($request->getQueryParams()['expiring_days']) && is_numeric($request->getQueryParams()['expiring_days'])) + { + $nextXDays = $request->getQueryParams()['expiring_days']; + } + + $expiringProducts = $this->StockService->GetExpiringProducts($nextXDays); + $expiredProducts = $this->StockService->GetExpiringProducts(-1); + $missingProducts = $this->StockService->GetMissingProducts(); + return $this->ApiResponse(array( + 'expiring_products' => $expiringProducts, + 'expired_products' => $expiredProducts, + 'missing_products' => $missingProducts + )); + } + public function AddMissingProductsToShoppingList(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args) { $this->StockService->AddMissingProductsToShoppingList(); diff --git a/controllers/StockController.php b/controllers/StockController.php index 504eb7a7..18bba451 100644 --- a/controllers/StockController.php +++ b/controllers/StockController.php @@ -17,19 +17,13 @@ class StockController extends BaseController public function Overview(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args) { - $currentStock = $this->StockService->GetCurrentStock(); - $nextXDays = 5; - $countExpiringNextXDays = count(FindAllObjectsInArrayByPropertyValue($currentStock, 'best_before_date', date('Y-m-d', strtotime('+5 days')), '<')); - $countAlreadyExpired = count(FindAllObjectsInArrayByPropertyValue($currentStock, 'best_before_date', date('Y-m-d', strtotime('-1 days')), '<')); return $this->AppContainer->view->render($response, 'stockoverview', [ 'products' => $this->Database->products()->orderBy('name'), 'quantityunits' => $this->Database->quantity_units()->orderBy('name'), 'locations' => $this->Database->locations()->orderBy('name'), - 'currentStock' => $currentStock, + 'currentStock' => $this->StockService->GetCurrentStock(), 'missingProducts' => $this->StockService->GetMissingProducts(), - 'nextXDays' => $nextXDays, - 'countExpiringNextXDays' => $countExpiringNextXDays, - 'countAlreadyExpired' => $countAlreadyExpired + 'nextXDays' => 5 ]); } diff --git a/grocy.openapi.json b/grocy.openapi.json index f72b4a09..d30a3e4b 100644 --- a/grocy.openapi.json +++ b/grocy.openapi.json @@ -851,6 +851,41 @@ } } }, + "/stock/get-current-volatil-stock": { + "get": { + "description": "Returns all products which are expiring soon, are already expired or currently missing", + "tags": [ + "Stock" + ], + "parameters": [ + { + "in": "path", + "name": "expiring_days", + "required": false, + "description": "The number of days in which products are considered expiring soon", + "schema": { + "type": "integer", + "default": 5 + } + } + ], + "responses": { + "200": { + "description": "A CurrentVolatilStockResponse object", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CurrentVolatilStockResponse" + } + } + } + } + } + } + } + }, "/stock/add-missing-products-to-shoppinglist": { "get": { "description": "Adds currently missing products (below defined min. stock amount) to the shopping list", @@ -1709,6 +1744,29 @@ "description": "The next best before date for this product" } } + }, + "CurrentVolatilStockResponse": { + "type": "object", + "properties": { + "expiring_products": { + "type": "array", + "items":{ + "$ref": "#/components/schemas/Product" + } + }, + "expired_products": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + }, + "missing_products": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Product" + } + } + } } }, "examples": { diff --git a/public/viewjs/stockoverview.js b/public/viewjs/stockoverview.js index 3b2c358c..48a23fb2 100644 --- a/public/viewjs/stockoverview.js +++ b/public/viewjs/stockoverview.js @@ -63,6 +63,7 @@ $(document).on('click', '.product-consume-button', function(e) } toastr.success(L('Removed #1 #2 of #3 from stock', consumeAmount, productQuName, productName)); + RefreshStatistics(); }, function(xhr) { @@ -70,3 +71,37 @@ $(document).on('click', '.product-consume-button', function(e) } ); }); + +function RefreshStatistics() +{ + Grocy.Api.Get('stock/get-current-stock', + function(result) + { + var amountSum = 0; + result.forEach(element => { + amountSum += parseInt(element.amount); + }); + $("#info-current-stock").text(result.length + " " + Pluralize(result.length, L('Product'), L('Products')) + ", " + amountSum.toString() + " " + Pluralize(amountSum, L('Unit'), L('Units'))); + }, + function(xhr) + { + console.error(xhr); + } + ); + + var nextXDays = $("#info-expiring-products").data("next-x-days"); + Grocy.Api.Get('stock/get-current-volatil-stock?expiring_days=' + nextXDays, + function(result) + { + $("#info-expiring-products").text(Pluralize(result.expiring_products.length, L('#1 product expires within the next #2 days', result.expiring_products.length, nextXDays), L('#1 products expiring within the next #2 days', result.expiring_products.length, nextXDays))); + $("#info-expired-products").text(Pluralize(result.expired_products.length, L('#1 product is already expired', result.expired_products.length), L('#1 products are already expired', result.expired_products.length))); + $("#info-missing-products").text(Pluralize(result.missing_products.length, L('#1 product is below defined min. stock amount', result.missing_products.length), L('#1 products are below defined min. stock amount', result.missing_products.length))); + }, + function(xhr) + { + console.error(xhr); + } + ); +} + +RefreshStatistics(); diff --git a/routes.php b/routes.php index d7d6f046..d451314e 100644 --- a/routes.php +++ b/routes.php @@ -84,6 +84,7 @@ $app->group('/api', function() $this->get('/stock/get-product-details/{productId}', '\Grocy\Controllers\StockApiController:ProductDetails'); $this->get('/stock/get-product-price-history/{productId}', '\Grocy\Controllers\StockApiController:ProductPriceHistory'); $this->get('/stock/get-current-stock', '\Grocy\Controllers\StockApiController:CurrentStock'); + $this->get('/stock/get-current-volatil-stock', '\Grocy\Controllers\StockApiController:CurrentVolatilStock'); $this->get('/stock/add-missing-products-to-shoppinglist', '\Grocy\Controllers\StockApiController:AddMissingProductsToShoppingList'); $this->get('/stock/clear-shopping-list', '\Grocy\Controllers\StockApiController:ClearShoppingList'); $this->get('/stock/external-barcode-lookup/{barcode}', '\Grocy\Controllers\StockApiController:ExternalBarcodeLookup'); diff --git a/services/StockService.php b/services/StockService.php index 1c5bf024..d79b7a34 100644 --- a/services/StockService.php +++ b/services/StockService.php @@ -20,6 +20,12 @@ class StockService extends BaseService return $this->DatabaseService->ExecuteDbQuery($sql)->fetchAll(\PDO::FETCH_OBJ); } + public function GetExpiringProducts(int $days = 5) + { + $currentStock = $this->GetCurrentStock(); + return FindAllObjectsInArrayByPropertyValue($currentStock, 'best_before_date', date('Y-m-d', strtotime("+$days days")), '<'); + } + public function GetProductDetails(int $productId) { if (!$this->ProductExists($productId)) diff --git a/views/stockoverview.blade.php b/views/stockoverview.blade.php index a563209e..2996cbcf 100644 --- a/views/stockoverview.blade.php +++ b/views/stockoverview.blade.php @@ -11,10 +11,10 @@ @section('content')
-

@yield('title') {{ count($currentStock) . ' ' . Pluralize(count($currentStock), $L('Product'), $L('Products')) }}, {{ SumArrayValue($currentStock, 'amount') . ' ' . Pluralize(SumArrayValue($currentStock, 'amount'), $L('Unit'), $L('Units')) }}

-

{{ Pluralize($countExpiringNextXDays, $L('#1 product expires within the next #2 days', $countExpiringNextXDays, $nextXDays), $L('#1 products expiring within the next #2 days', $countExpiringNextXDays, $nextXDays)) }}

-

{{ Pluralize($countAlreadyExpired, $L('#1 product is already expired', $countAlreadyExpired), $L('#1 products are already expired', $countAlreadyExpired)) }}

-

{{ Pluralize(count($missingProducts), $L('#1 product is below defined min. stock amount', count($missingProducts)), $L('#1 products are below defined min. stock amount', count($missingProducts))) }}

+

@yield('title')

+

+

+

@@ -48,7 +48,7 @@ @foreach($currentStock as $currentStockEntry) - + product_id) !== null) table-info @endif">