From 4a7884f7fdb4fa324e85458eab3d371f27193a1f Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 28 Mar 2022 21:00:20 +1100 Subject: [PATCH 1/4] Add skeleton for "Stock History" widget --- lib/widget/stock_detail.dart | 15 +++++----- lib/widget/stock_item_history.dart | 44 ++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 7 deletions(-) create mode 100644 lib/widget/stock_item_history.dart diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index 4733674f..330d55e1 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -16,6 +16,7 @@ import "package:inventree/widget/part_detail.dart"; import "package:inventree/widget/progress.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; +import 'package:inventree/widget/stock_item_history.dart'; import "package:inventree/widget/stock_item_test_results.dart"; import "package:inventree/widget/stock_notes.dart"; import "package:inventree/l10.dart"; @@ -861,8 +862,6 @@ class _StockItemDisplayState extends RefreshableState { // TODO - Is this stock item linked to a PurchaseOrder? - // TODO - Re-enable stock item history display - /* if (item.trackingItemCount > 0) { tiles.add( ListTile( @@ -870,15 +869,17 @@ class _StockItemDisplayState extends RefreshableState { leading: FaIcon(FontAwesomeIcons.history), trailing: Text("${item.trackingItemCount}"), onTap: () { - // TODO: Load tracking history - - // TODO: Push tracking history page to the route - + Navigator.push( + context, + MaterialPageRoute( + builder: (context) => StockItemHistoryWidget(item)) + ).then((ctx) { + refresh(context); + }); }, ) ); } - */ // Notes field tiles.add( diff --git a/lib/widget/stock_item_history.dart b/lib/widget/stock_item_history.dart new file mode 100644 index 00000000..ffc6a8cd --- /dev/null +++ b/lib/widget/stock_item_history.dart @@ -0,0 +1,44 @@ + + +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import 'package:inventree/widget/refreshable_state.dart'; +import 'package:inventree/l10.dart'; +import 'package:inventree/inventree/stock.dart'; + +class StockItemHistoryWidget extends StatefulWidget { + + const StockItemHistoryWidget(this.item, {Key? key}) : super(key: key); + + final InvenTreeStockItem item; + + @override + _StockItemHistoryDisplayState createState() => _StockItemHistoryDisplayState(item); +} + + +class _StockItemHistoryDisplayState extends RefreshableState { + + _StockItemHistoryDisplayState(this.item); + + final InvenTreeStockItem item; + + @override + String getAppBarTitle(BuildContext context) => L10().stockItemHistory; + + @override + Future request(BuildContext refresh) async { + // TODO + } + + @override + Widget getBody(BuildContext context) { + return ListView( + children: ListTile.divideTiles( + context: context, + tiles: [], + ).toList() + ); + } +} \ No newline at end of file From 43faec8b210b2e17d087a9763af1428c5b19e7f4 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 28 Mar 2022 21:23:56 +1100 Subject: [PATCH 2/4] Display history --- lib/inventree/stock.dart | 61 ++++++++++++++++++++++++++++++ lib/widget/stock_item_history.dart | 38 ++++++++++++++++++- 2 files changed, 97 insertions(+), 2 deletions(-) diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index 2e85a201..0de430ae 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -56,6 +56,67 @@ class InvenTreeStockItemTestResult extends InvenTreeModel { } +class InvenTreeStockItemHistory extends InvenTreeModel { + + InvenTreeStockItemHistory() : super(); + + InvenTreeStockItemHistory.fromJson(Map json) : super.fromJson(json); + + @override + InvenTreeModel createFromJson(Map json) { + return InvenTreeStockItemHistory.fromJson(json); + } + + @override + String get URL => "stock/track/"; + + @override + Map defaultListFilters() { + + // By default, order by decreasing date + return { + "ordering": "-date", + }; + } + + DateTime? get date { + if (jsondata.containsKey("date")) { + return DateTime.tryParse((jsondata["date"] ?? "") as String); + } else { + return null; + } + } + + String get dateString { + var d = date; + + if (d == null) { + return ""; + } + + return DateFormat("yyyy-MM-dd").format(d); + } + + String get label => (jsondata["label"] ?? "") as String; + + String get quantityString { + Map deltas = (jsondata["deltas"] ?? {}) as Map; + + // Serial number takes priority here + if (deltas.containsKey("serial")) { + var serial = (deltas["serial"] ?? "").toString() as String; + return "# ${serial}"; + } else if (deltas.containsKey("quantity")) { + double q = (deltas["quantity"] ?? 0); + + return simpleNumberString(q); + } else { + return ""; + } + } +} + + class InvenTreeStockItem extends InvenTreeModel { InvenTreeStockItem() : super(); diff --git a/lib/widget/stock_item_history.dart b/lib/widget/stock_item_history.dart index ffc6a8cd..7cfb260f 100644 --- a/lib/widget/stock_item_history.dart +++ b/lib/widget/stock_item_history.dart @@ -6,6 +6,8 @@ import 'package:flutter/material.dart'; import 'package:inventree/widget/refreshable_state.dart'; import 'package:inventree/l10.dart'; import 'package:inventree/inventree/stock.dart'; +import 'package:inventree/inventree/model.dart'; + class StockItemHistoryWidget extends StatefulWidget { @@ -27,9 +29,24 @@ class _StockItemHistoryDisplayState extends RefreshableState L10().stockItemHistory; + List history = []; + @override Future request(BuildContext refresh) async { - // TODO + + history.clear(); + + InvenTreeStockItemHistory().list(filters: {"item": "${item.pk}"}).then((List results) { + for (var result in results) { + if (result is InvenTreeStockItemHistory) { + history.add(result); + } + } + + // Refresh + setState(() { + }); + }); } @override @@ -37,8 +54,25 @@ class _StockItemHistoryDisplayState extends RefreshableState historyList() { + List tiles = []; + + for (var entry in history) { + tiles.add( + ListTile( + leading: Text(entry.dateString), + trailing: entry.quantityString.isNotEmpty ? Text(entry.quantityString) : null, + title: Text(entry.label), + subtitle: entry.notes.isNotEmpty ? Text(entry.notes) : null, + ) + ); + } + + return tiles; + } } \ No newline at end of file From 8233fb39d61765044ddffc36c9fb32c99bab5f6a Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 28 Mar 2022 21:41:21 +1100 Subject: [PATCH 3/4] Adds user setting to show or hide stock history --- lib/app_settings.dart | 1 + lib/l10n | 2 +- lib/settings/app_settings.dart | 16 ++++++++++++++++ lib/widget/stock_detail.dart | 11 ++++++++--- 4 files changed, 26 insertions(+), 4 deletions(-) diff --git a/lib/app_settings.dart b/lib/app_settings.dart index 88145bd2..7d97b9c4 100644 --- a/lib/app_settings.dart +++ b/lib/app_settings.dart @@ -18,6 +18,7 @@ const String INV_SOUNDS_SERVER = "serverSounds"; const String INV_PART_SUBCATEGORY = "partSubcategory"; const String INV_STOCK_SUBLOCATION = "stockSublocation"; +const String INV_STOCK_SHOW_HISTORY = "stockShowHistory"; const String INV_REPORT_ERRORS = "reportErrors"; diff --git a/lib/l10n b/lib/l10n index a66dab99..10ae8c64 160000 --- a/lib/l10n +++ b/lib/l10n @@ -1 +1 @@ -Subproject commit a66dab998bc92b3cceed70aaffc92ffa8b5da836 +Subproject commit 10ae8c64e0754206e21b06531186375e247c796d diff --git a/lib/settings/app_settings.dart b/lib/settings/app_settings.dart index 2431b630..46306bbe 100644 --- a/lib/settings/app_settings.dart +++ b/lib/settings/app_settings.dart @@ -28,6 +28,7 @@ class _InvenTreeAppSettingsState extends State { // Stock settings bool stockSublocation = false; + bool stockShowHistory = false; bool reportErrors = true; @@ -48,6 +49,7 @@ class _InvenTreeAppSettingsState extends State { partSubcategory = await InvenTreeSettingsManager().getValue(INV_PART_SUBCATEGORY, true) as bool; stockSublocation = await InvenTreeSettingsManager().getValue(INV_STOCK_SUBLOCATION, true) as bool; + stockShowHistory = await InvenTreeSettingsManager().getValue(INV_STOCK_SHOW_HISTORY, false) as bool; reportErrors = await InvenTreeSettingsManager().getValue(INV_REPORT_ERRORS, true) as bool; @@ -109,6 +111,20 @@ class _InvenTreeAppSettingsState extends State { }, ), ), + ListTile( + title: Text(L10().stockItemHistory), + subtitle: Text(L10().stockItemHistoryDetail), + leading: FaIcon(FontAwesomeIcons.history), + trailing: Switch( + value: stockShowHistory, + onChanged: (bool value) { + InvenTreeSettingsManager().setValue(INV_STOCK_SHOW_HISTORY, value); + setState(() { + stockShowHistory = value; + }); + }, + ), + ), /* Sound Settings */ Divider(height: 3), ListTile( diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index 330d55e1..389abfe5 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -16,13 +16,14 @@ import "package:inventree/widget/part_detail.dart"; import "package:inventree/widget/progress.dart"; import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; -import 'package:inventree/widget/stock_item_history.dart'; +import "package:inventree/widget/stock_item_history.dart"; import "package:inventree/widget/stock_item_test_results.dart"; import "package:inventree/widget/stock_notes.dart"; import "package:inventree/l10.dart"; import "package:inventree/helpers.dart"; import "package:inventree/api.dart"; import "package:inventree/api_form.dart"; +import "package:inventree/app_settings.dart"; class StockDetailWidget extends StatefulWidget { @@ -51,6 +52,8 @@ class _StockItemDisplayState extends RefreshableState { final _countStockKey = GlobalKey(); final _moveStockKey = GlobalKey(); + bool stockShowHistory = false; + @override List getAppBarActions(BuildContext context) { @@ -106,6 +109,8 @@ class _StockItemDisplayState extends RefreshableState { final bool result = await item.reload(); + stockShowHistory = await InvenTreeSettingsManager().getValue(INV_STOCK_SHOW_HISTORY, false) as bool; + // Could not load this stock item for some reason // Perhaps it has been depleted? if (!result || item.pk == -1) { @@ -862,11 +867,11 @@ class _StockItemDisplayState extends RefreshableState { // TODO - Is this stock item linked to a PurchaseOrder? - if (item.trackingItemCount > 0) { + if (stockShowHistory && item.trackingItemCount > 0) { tiles.add( ListTile( title: Text(L10().history), - leading: FaIcon(FontAwesomeIcons.history), + leading: FaIcon(FontAwesomeIcons.history, color: COLOR_CLICK), trailing: Text("${item.trackingItemCount}"), onTap: () { Navigator.push( From 5c0ffe795caf6d35fbe89a3c0baf901c3c3904db Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 28 Mar 2022 21:48:23 +1100 Subject: [PATCH 4/4] Fixes --- lib/inventree/stock.dart | 4 ++-- lib/widget/stock_item_history.dart | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index 0de430ae..8b2f1ec7 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -104,10 +104,10 @@ class InvenTreeStockItemHistory extends InvenTreeModel { // Serial number takes priority here if (deltas.containsKey("serial")) { - var serial = (deltas["serial"] ?? "").toString() as String; + var serial = (deltas["serial"] ?? "") as String; return "# ${serial}"; } else if (deltas.containsKey("quantity")) { - double q = (deltas["quantity"] ?? 0); + double q = (deltas["quantity"] ?? 0) as double; return simpleNumberString(q); } else { diff --git a/lib/widget/stock_item_history.dart b/lib/widget/stock_item_history.dart index 7cfb260f..f4c5afe3 100644 --- a/lib/widget/stock_item_history.dart +++ b/lib/widget/stock_item_history.dart @@ -1,12 +1,12 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; +import "package:flutter/cupertino.dart"; +import "package:flutter/material.dart"; -import 'package:inventree/widget/refreshable_state.dart'; -import 'package:inventree/l10.dart'; -import 'package:inventree/inventree/stock.dart'; -import 'package:inventree/inventree/model.dart'; +import "package:inventree/widget/refreshable_state.dart"; +import "package:inventree/l10.dart"; +import "package:inventree/inventree/stock.dart"; +import "package:inventree/inventree/model.dart"; class StockItemHistoryWidget extends StatefulWidget {