Refresh stock statistics on consume on stock overview page (references #26)

This commit is contained in:
Bernd Bestel 2018-08-04 14:25:32 +02:00
parent 6081b8ee67
commit ca3f28b615
No known key found for this signature in database
GPG Key ID: 71BD34C0D4891300
7 changed files with 125 additions and 13 deletions

View File

@ -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();

View File

@ -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
]);
}

View File

@ -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": {

View File

@ -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();

View File

@ -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');

View File

@ -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))

View File

@ -11,10 +11,10 @@
@section('content')
<div class="row">
<div class="col">
<h1>@yield('title') <small class="text-muted">{{ count($currentStock) . ' ' . Pluralize(count($currentStock), $L('Product'), $L('Products')) }}, {{ SumArrayValue($currentStock, 'amount') . ' ' . Pluralize(SumArrayValue($currentStock, 'amount'), $L('Unit'), $L('Units')) }}</small></h1>
<p class="btn btn-lg btn-warning no-real-button responsive-button mr-2">{{ Pluralize($countExpiringNextXDays, $L('#1 product expires within the next #2 days', $countExpiringNextXDays, $nextXDays), $L('#1 products expiring within the next #2 days', $countExpiringNextXDays, $nextXDays)) }}</p>
<p class="btn btn-lg btn-danger no-real-button responsive-button mr-2">{{ Pluralize($countAlreadyExpired, $L('#1 product is already expired', $countAlreadyExpired), $L('#1 products are already expired', $countAlreadyExpired)) }}</p>
<p class="btn btn-lg btn-info no-real-button responsive-button">{{ 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))) }}</p>
<h1>@yield('title') <small id="info-current-stock" class="text-muted"></small></h1>
<p id="info-expiring-products" data-next-x-days="{{ $nextXDays }}" class="btn btn-lg btn-warning no-real-button responsive-button mr-2"></p>
<p id="info-expired-products" class="btn btn-lg btn-danger no-real-button responsive-button mr-2"></p>
<p id="info-missing-products" class="btn btn-lg btn-info no-real-button responsive-button"></p>
</div>
</div>
@ -48,7 +48,7 @@
</thead>
<tbody>
@foreach($currentStock as $currentStockEntry)
<tr id="product-{{ $currentStockEntry->product_id }}-row" class="@if($currentStockEntry->best_before_date < date('Y-m-d', strtotime('-1 days'))) table-danger @elseif($currentStockEntry->best_before_date < date('Y-m-d', strtotime('+5 days'))) table-warning @elseif (FindObjectInArrayByPropertyValue($missingProducts, 'id', $currentStockEntry->product_id) !== null) table-info @endif">
<tr id="product-{{ $currentStockEntry->product_id }}-row" class="@if($currentStockEntry->best_before_date < date('Y-m-d', strtotime('-1 days'))) table-danger @elseif($currentStockEntry->best_before_date < date('Y-m-d', strtotime("+$nextXDays days"))) table-warning @elseif (FindObjectInArrayByPropertyValue($missingProducts, 'id', $currentStockEntry->product_id) !== null) table-info @endif">
<td class="fit-content">
<a class="btn btn-success btn-sm product-consume-button" href="#" title="{{ $L('Consume #3 #1 of #2', FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->qu_id_stock)->name, FindObjectInArrayByPropertyValue($products, 'id', $currentStockEntry->product_id)->name, 1) }}"
data-product-id="{{ $currentStockEntry->product_id }}"