diff --git a/controllers/StockApiController.php b/controllers/StockApiController.php index ae793e14..1830f943 100644 --- a/controllers/StockApiController.php +++ b/controllers/StockApiController.php @@ -715,6 +715,16 @@ class StockApiController extends BaseApiController } } + public function Journal(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) + { + return $this->FilteredApiResponse($response, $this->getDatabase()->uihelper_stock_journal(), $request->getQueryParams()); + } + + public function JournalSummary(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) + { + return $this->FilteredApiResponse($response, $this->getDatabase()->uihelper_stock_journal_summary(), $request->getQueryParams()); + } + public function __construct(\DI\Container $container) { parent::__construct($container); diff --git a/controllers/StockController.php b/controllers/StockController.php index e7d56684..1de5e420 100644 --- a/controllers/StockController.php +++ b/controllers/StockController.php @@ -33,10 +33,8 @@ class StockController extends BaseController public function Journal(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) { return $this->renderPage($response, 'stockjournal', [ - 'stockLog' => $this->getDatabase()->stock_log()->orderBy('row_created_timestamp', 'DESC'), - 'locations' => $this->getDatabase()->locations()->orderBy('name'), + 'stockLog' => $this->getDatabase()->uihelper_stock_journal()->orderBy('row_created_timestamp', 'DESC'), 'products' => $this->getDatabase()->products()->where('active = 1')->orderBy('name'), - 'quantityunits' => $this->getDatabase()->quantity_units()->orderBy('name') ]); } @@ -442,4 +440,24 @@ class StockController extends BaseController { parent::__construct($container); } + + public function JournalSummary(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args) + { + $entries = $this->getDatabase()->uihelper_stock_journal_summary(); + if (isset($request->getQueryParams()['product_id'])) + { + $entries = $entries->where('product_id', $request->getQueryParams()['product_id']); + } + if (isset($request->getQueryParams()['user_id'])) + { + $entries = $entries->where('user_id', $request->getQueryParams()['user_id']); + } + if (isset($request->getQueryParams()['transaction_type'])) + { + $entries = $entries->where('transaction_type', $request->getQueryParams()['transaction_type']); + } + return $this->renderPage($response, 'stockjournalsummary', [ + 'entries' => $entries + ]); + } } diff --git a/localization/strings.pot b/localization/strings.pot index e76abe32..ed3ccb92 100644 --- a/localization/strings.pot +++ b/localization/strings.pot @@ -1900,3 +1900,12 @@ msgstr "" msgid "Default" msgstr "" + +msgid "Stock journal summary" +msgstr "" + +msgid "Journal summary" +msgstr "" + +msgid "Journal summary for this product" +msgstr "" diff --git a/migrations/0115.sql b/migrations/0115.sql new file mode 100644 index 00000000..9a5d50ec --- /dev/null +++ b/migrations/0115.sql @@ -0,0 +1,41 @@ +ALTER TABLE stock_log ADD COLUMN + user_id INTEGER NOT NULL DEFAULT 1; + +CREATE VIEW uihelper_stock_journal +AS +SELECT stock_log.id, + stock_log.row_created_timestamp, + stock_log.correlation_id, + stock_log.undone, + stock_log.undone_timestamp, + stock_log.row_created_timestamp, + stock_log.transaction_type, + stock_log.spoiled, + stock_log.amount, + stock_log.location_id, + l.name AS location_name, + p.name AS product_name, + qu.name AS qu_name, + qu.name_plural AS qu_name_plural, + u.display_name AS user_display_name + +FROM stock_log + JOIN users_dto u on stock_log.user_id = u.id + JOIN products p on stock_log.product_id = p.id + JOIN locations l on p.location_id = l.id + JOIN quantity_units qu ON p.qu_id_stock = qu.id; + + +CREATE VIEW uihelper_stock_journal_summary +AS +SELECT user_id AS id, -- dummy, LessQL needs an id column + user_id, u.display_name AS user_display_name, p.name AS product_name, product_id, transaction_type, + qu.name AS qu_name, + qu.name_plural AS qu_name_plural, + SUM(amount) AS amount +FROM stock_log + JOIN users_dto u on stock_log.user_id = u.id + JOIN products p on stock_log.product_id = p.id + JOIN quantity_units qu ON p.qu_id_stock = qu.id +WHERE undone = 0 + GROUP BY user_id, product_id,transaction_type; diff --git a/public/viewjs/stockjournalsummary.js b/public/viewjs/stockjournalsummary.js new file mode 100644 index 00000000..1fae9a18 --- /dev/null +++ b/public/viewjs/stockjournalsummary.js @@ -0,0 +1,6 @@ +var journalSummaryTable = $('#journal-summary-table').DataTable({ + 'paginate': true, + 'order': [[0, 'desc']] +}); +$('#journal-summary-table tbody').removeClass("d-none"); +journalSummaryTable.columns.adjust().draw(); diff --git a/routes.php b/routes.php index 05829647..ab1377af 100644 --- a/routes.php +++ b/routes.php @@ -57,6 +57,7 @@ $app->group('', function (RouteCollectorProxy $group) { $group->get('/stockjournal', '\Grocy\Controllers\StockController:Journal'); $group->get('/locationcontentsheet', '\Grocy\Controllers\StockController:LocationContentSheet'); $group->get('/quantityunitpluraltesting', '\Grocy\Controllers\StockController:QuantityUnitPluralFormTesting'); + $group->get('/stockjournal/summary', '\Grocy\Controllers\StockController:JournalSummary'); } // Stock price tracking @@ -203,6 +204,8 @@ $app->group('/api', function (RouteCollectorProxy $group) { $group->post('/stock/transactions/{transactionId}/undo', '\Grocy\Controllers\StockApiController:UndoTransaction'); $group->get('/stock/barcodes/external-lookup/{barcode}', '\Grocy\Controllers\StockApiController:ExternalBarcodeLookup'); $group->get('/productbarcodedetails/{barcode}', '\Grocy\Controllers\StockApiController:ProductBarcodeDetails'); + $group->get('/stock/journal', '\Grocy\Controllers\StockApiController:Journal'); + $group->get('/stock/journal/summary', '\Grocy\Controllers\StockApiController:JournalSummary'); } // Shopping list diff --git a/services/StockService.php b/services/StockService.php index 3a6ca876..768c3e92 100644 --- a/services/StockService.php +++ b/services/StockService.php @@ -112,7 +112,8 @@ class StockService extends BaseService 'location_id' => $locationId, 'transaction_id' => $transactionId, 'shopping_location_id' => $shoppingLocationId, - 'qu_factor_purchase_to_stock' => $quFactorPurchaseToStock + 'qu_factor_purchase_to_stock' => $quFactorPurchaseToStock, + 'user_id' => GROCY_USER_ID ]); $logRow->save(); @@ -259,7 +260,8 @@ class StockService extends BaseService 'price' => $stockEntry->price, 'opened_date' => $stockEntry->opened_date, 'recipe_id' => $recipeId, - 'transaction_id' => $transactionId + 'transaction_id' => $transactionId, + 'user_id' => GROCY_USER_ID ]); $logRow->save(); @@ -283,7 +285,8 @@ class StockService extends BaseService 'price' => $stockEntry->price, 'opened_date' => $stockEntry->opened_date, 'recipe_id' => $recipeId, - 'transaction_id' => $transactionId + 'transaction_id' => $transactionId, + 'user_id' => GROCY_USER_ID ]); $logRow->save(); @@ -328,7 +331,8 @@ class StockService extends BaseService 'qu_factor_purchase_to_stock' => $stockRow->qu_factor_purchase_to_stock, 'correlation_id' => $correlationId, 'transaction_id' => $transactionId, - 'stock_row_id' => $stockRow->id + 'stock_row_id' => $stockRow->id, + 'user_id' => GROCY_USER_ID ]); $logOldRowForStockUpdate->save(); @@ -369,7 +373,8 @@ class StockService extends BaseService 'qu_factor_purchase_to_stock' => $stockRow->qu_factor_purchase_to_stock, 'correlation_id' => $correlationId, 'transaction_id' => $transactionId, - 'stock_row_id' => $stockRow->id + 'stock_row_id' => $stockRow->id, + 'user_id' => GROCY_USER_ID ]); $logNewRowForStockUpdate->save(); @@ -738,7 +743,8 @@ class StockService extends BaseService 'transaction_type' => self::TRANSACTION_TYPE_PRODUCT_OPENED, 'price' => $stockEntry->price, 'opened_date' => date('Y-m-d'), - 'transaction_id' => $transactionId + 'transaction_id' => $transactionId, + 'user_id' => GROCY_USER_ID ]); $logRow->save(); @@ -777,7 +783,8 @@ class StockService extends BaseService 'transaction_type' => self::TRANSACTION_TYPE_PRODUCT_OPENED, 'price' => $stockEntry->price, 'opened_date' => date('Y-m-d'), - 'transaction_id' => $transactionId + 'transaction_id' => $transactionId, + 'user_id' => GROCY_USER_ID ]); $logRow->save(); @@ -914,7 +921,8 @@ class StockService extends BaseService 'opened_date' => $stockEntry->opened_date, 'location_id' => $stockEntry->location_id, 'correlation_id' => $correlationId, - 'transaction_Id' => $transactionId + 'transaction_Id' => $transactionId, + 'user_id' => GROCY_USER_ID ]); $logRowForLocationFrom->save(); @@ -930,7 +938,8 @@ class StockService extends BaseService 'opened_date' => $stockEntry->opened_date, 'location_id' => $locationIdTo, 'correlation_id' => $correlationId, - 'transaction_Id' => $transactionId + 'transaction_Id' => $transactionId, + 'user_id' => GROCY_USER_ID ]); $logRowForLocationTo->save(); @@ -957,7 +966,8 @@ class StockService extends BaseService 'opened_date' => $stockEntry->opened_date, 'location_id' => $stockEntry->location_id, 'correlation_id' => $correlationId, - 'transaction_Id' => $transactionId + 'transaction_Id' => $transactionId, + 'user_id' => GROCY_USER_ID ]); $logRowForLocationFrom->save(); @@ -973,7 +983,8 @@ class StockService extends BaseService 'opened_date' => $stockEntry->opened_date, 'location_id' => $locationIdTo, 'correlation_id' => $correlationId, - 'transaction_Id' => $transactionId + 'transaction_Id' => $transactionId, + 'user_id' => GROCY_USER_ID ]); $logRowForLocationTo->save(); diff --git a/views/stockjournal.blade.php b/views/stockjournal.blade.php index bb6fd994..a98622dd 100644 --- a/views/stockjournal.blade.php +++ b/views/stockjournal.blade.php @@ -5,12 +5,15 @@ @section('viewJsName', 'stockjournal') @section('content') -
-
-

@yield('title')

+ -
@@ -52,6 +55,7 @@ {{ $__t('Booking time') }} {{ $__t('Booking type') }} {{ $__t('Location') }} + {{ $__t('Done by') }} @@ -70,7 +74,7 @@ - {{ FindObjectInArrayByPropertyValue($products, 'id', $stockLogEntry->product_id)->name }} + {{ $stockLogEntry->product_name }} @if($stockLogEntry->undone == 1)
{{ $__t('Undone on') . ' ' . $stockLogEntry->undone_timestamp }} @@ -79,7 +83,7 @@ @endif - {{ $stockLogEntry->amount }} {{ $__n($stockLogEntry->amount, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $stockLogEntry->product_id)->qu_id_stock)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', FindObjectInArrayByPropertyValue($products, 'id', $stockLogEntry->product_id)->qu_id_stock)->name_plural) }} + {{ $stockLogEntry->amount }} {{ $__n($stockLogEntry->amount, $stockLogEntry->qu_name, $stockLogEntry->qu_name_plural) }} {{ $stockLogEntry->row_created_timestamp }} @@ -93,7 +97,10 @@ @endif - {{ FindObjectInArrayByPropertyValue($locations, 'id', $stockLogEntry->location_id)->name }} + {{ $stockLogEntry->location_name }} + + + {{ $stockLogEntry->user_display_name }} @endforeach diff --git a/views/stockjournalsummary.blade.php b/views/stockjournalsummary.blade.php new file mode 100644 index 00000000..ba3e2b5f --- /dev/null +++ b/views/stockjournalsummary.blade.php @@ -0,0 +1,47 @@ +@extends('layout.default') + +@section('title', $__t('Stock journal summary')) +@section('activeNav', '') +@section('viewJsName', 'stockjournalsummary') + +@section('content') +
+
+

@yield('title')

+
+
+
+
+
+ + + + + + + + + + + @foreach($entries as $journalEntry) + + + + + + + @endforeach + +
{{ $__t('Product') }}{{ $__t('Booking type') }}{{ $__t('User') }}{{ $__t('Amount') }}
+ {{ $journalEntry->product_name }} + + {{ $__t($journalEntry->transaction_type) }} + + {{ $journalEntry->user_display_name }} + + {{ $journalEntry->amount }} {{ $__n($journalEntry->amount, $journalEntry->qu_name, $journalEntry->qu_name_plural) }} +
+
+
+@stop diff --git a/views/stockoverview.blade.php b/views/stockoverview.blade.php index 78c579a4..a9bebf48 100644 --- a/views/stockoverview.blade.php +++ b/views/stockoverview.blade.php @@ -142,7 +142,9 @@ @foreach($currentStock as $currentStockEntry) amount > 0) table-warning @elseif ($currentStockEntry->product_missing) table-info @endif"> @@ -246,6 +248,11 @@ href="{{ $U('/stockjournal?product=') }}{{ $currentStockEntry->product_id }}"> {{ $__t('Stock journal for this product') }} + + {{ $__t('Journal summary for this product') }} + @@ -322,7 +329,8 @@ && $currentStockEntry->amount > 0) expired @elseif($currentStockEntry->best_before_date < date('Y-m-d 23:59:59', - strtotime("+$nextXDays days")) + strtotime("+$nextXDays + days")) && $currentStockEntry->amount > 0) expiring @endif @if($currentStockEntry->product_missing) belowminstockamount @endif