mirror of
https://github.com/inventree/inventree-app.git
synced 2025-04-28 21:46:46 +00:00
commit
884a6850f6
@ -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";
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
2
lib/l10n
2
lib/l10n
@ -1 +1 @@
|
|||||||
Subproject commit a66dab998bc92b3cceed70aaffc92ffa8b5da836
|
Subproject commit 10ae8c64e0754206e21b06531186375e247c796d
|
@ -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(
|
||||||
|
@ -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(
|
||||||
|
78
lib/widget/stock_item_history.dart
Normal file
78
lib/widget/stock_item_history.dart
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user