2
0
mirror of https://github.com/inventree/inventree-app.git synced 2025-04-28 13:36:50 +00:00

Merge pull request #92 from inventree/stock-history

Stock history
This commit is contained in:
Oliver 2022-03-28 21:51:32 +11:00 committed by GitHub
commit 884a6850f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 172 additions and 10 deletions

View File

@ -18,6 +18,7 @@ const String INV_SOUNDS_SERVER = "serverSounds";
const String INV_PART_SUBCATEGORY = "partSubcategory"; const String INV_PART_SUBCATEGORY = "partSubcategory";
const String INV_STOCK_SUBLOCATION = "stockSublocation"; const String INV_STOCK_SUBLOCATION = "stockSublocation";
const String INV_STOCK_SHOW_HISTORY = "stockShowHistory";
const String INV_REPORT_ERRORS = "reportErrors"; const String INV_REPORT_ERRORS = "reportErrors";

View File

@ -56,6 +56,67 @@ class InvenTreeStockItemTestResult extends InvenTreeModel {
} }
class InvenTreeStockItemHistory extends InvenTreeModel {
InvenTreeStockItemHistory() : super();
InvenTreeStockItemHistory.fromJson(Map<String, dynamic> json) : super.fromJson(json);
@override
InvenTreeModel createFromJson(Map<String, dynamic> json) {
return InvenTreeStockItemHistory.fromJson(json);
}
@override
String get URL => "stock/track/";
@override
Map<String, String> 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<String, dynamic> deltas = (jsondata["deltas"] ?? {}) as Map<String, dynamic>;
// Serial number takes priority here
if (deltas.containsKey("serial")) {
var serial = (deltas["serial"] ?? "") as String;
return "# ${serial}";
} else if (deltas.containsKey("quantity")) {
double q = (deltas["quantity"] ?? 0) as double;
return simpleNumberString(q);
} else {
return "";
}
}
}
class InvenTreeStockItem extends InvenTreeModel { class InvenTreeStockItem extends InvenTreeModel {
InvenTreeStockItem() : super(); InvenTreeStockItem() : super();

@ -1 +1 @@
Subproject commit a66dab998bc92b3cceed70aaffc92ffa8b5da836 Subproject commit 10ae8c64e0754206e21b06531186375e247c796d

View File

@ -28,6 +28,7 @@ class _InvenTreeAppSettingsState extends State<InvenTreeAppSettingsWidget> {
// Stock settings // Stock settings
bool stockSublocation = false; bool stockSublocation = false;
bool stockShowHistory = false;
bool reportErrors = true; bool reportErrors = true;
@ -48,6 +49,7 @@ class _InvenTreeAppSettingsState extends State<InvenTreeAppSettingsWidget> {
partSubcategory = await InvenTreeSettingsManager().getValue(INV_PART_SUBCATEGORY, true) as bool; partSubcategory = await InvenTreeSettingsManager().getValue(INV_PART_SUBCATEGORY, true) as bool;
stockSublocation = await InvenTreeSettingsManager().getValue(INV_STOCK_SUBLOCATION, 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; reportErrors = await InvenTreeSettingsManager().getValue(INV_REPORT_ERRORS, true) as bool;
@ -109,6 +111,20 @@ class _InvenTreeAppSettingsState extends State<InvenTreeAppSettingsWidget> {
}, },
), ),
), ),
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 */ /* Sound Settings */
Divider(height: 3), Divider(height: 3),
ListTile( ListTile(

View File

@ -16,12 +16,14 @@ import "package:inventree/widget/part_detail.dart";
import "package:inventree/widget/progress.dart"; import "package:inventree/widget/progress.dart";
import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/refreshable_state.dart";
import "package:inventree/widget/snacks.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_item_test_results.dart";
import "package:inventree/widget/stock_notes.dart"; import "package:inventree/widget/stock_notes.dart";
import "package:inventree/l10.dart"; import "package:inventree/l10.dart";
import "package:inventree/helpers.dart"; import "package:inventree/helpers.dart";
import "package:inventree/api.dart"; import "package:inventree/api.dart";
import "package:inventree/api_form.dart"; import "package:inventree/api_form.dart";
import "package:inventree/app_settings.dart";
class StockDetailWidget extends StatefulWidget { class StockDetailWidget extends StatefulWidget {
@ -50,6 +52,8 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
final _countStockKey = GlobalKey<FormState>(); final _countStockKey = GlobalKey<FormState>();
final _moveStockKey = GlobalKey<FormState>(); final _moveStockKey = GlobalKey<FormState>();
bool stockShowHistory = false;
@override @override
List<Widget> getAppBarActions(BuildContext context) { List<Widget> getAppBarActions(BuildContext context) {
@ -105,6 +109,8 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
final bool result = await item.reload(); 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 // Could not load this stock item for some reason
// Perhaps it has been depleted? // Perhaps it has been depleted?
if (!result || item.pk == -1) { if (!result || item.pk == -1) {
@ -861,24 +867,24 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
// TODO - Is this stock item linked to a PurchaseOrder? // TODO - Is this stock item linked to a PurchaseOrder?
// TODO - Re-enable stock item history display if (stockShowHistory && item.trackingItemCount > 0) {
/*
if (item.trackingItemCount > 0) {
tiles.add( tiles.add(
ListTile( ListTile(
title: Text(L10().history), title: Text(L10().history),
leading: FaIcon(FontAwesomeIcons.history), leading: FaIcon(FontAwesomeIcons.history, color: COLOR_CLICK),
trailing: Text("${item.trackingItemCount}"), trailing: Text("${item.trackingItemCount}"),
onTap: () { onTap: () {
// TODO: Load tracking history Navigator.push(
context,
// TODO: Push tracking history page to the route MaterialPageRoute(
builder: (context) => StockItemHistoryWidget(item))
).then((ctx) {
refresh(context);
});
}, },
) )
); );
} }
*/
// Notes field // Notes field
tiles.add( tiles.add(

View File

@ -0,0 +1,78 @@
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";
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<StockItemHistoryWidget> {
_StockItemHistoryDisplayState(this.item);
final InvenTreeStockItem item;
@override
String getAppBarTitle(BuildContext context) => L10().stockItemHistory;
List<InvenTreeStockItemHistory> history = [];
@override
Future<void> request(BuildContext refresh) async {
history.clear();
InvenTreeStockItemHistory().list(filters: {"item": "${item.pk}"}).then((List<InvenTreeModel> results) {
for (var result in results) {
if (result is InvenTreeStockItemHistory) {
history.add(result);
}
}
// Refresh
setState(() {
});
});
}
@override
Widget getBody(BuildContext context) {
return ListView(
children: ListTile.divideTiles(
context: context,
tiles: historyList(),
).toList()
);
}
List<Widget> historyList() {
List<Widget> 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;
}
}