diff --git a/lib/api.dart b/lib/api.dart index aa9b73b6..fc900c1d 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -453,6 +453,10 @@ class InvenTreeAPI { _connecting = false; _token = ""; profile = null; + + // Clear received settings + _globalSettings.clear(); + _userSettings.clear(); } /* @@ -492,7 +496,9 @@ class InvenTreeAPI { return _connected; } - + /* + * Request the user roles (permissions) from the InvenTree server + */ Future getUserRoles() async { roles.clear(); @@ -1147,4 +1153,51 @@ class InvenTreeAPI { cacheManager: manager, ); } + + bool get supportsSettings => isConnected() && apiVersion >= 46; + + // Keep a record of which settings we have received from the server + Map _globalSettings = {}; + Map _userSettings = {}; + + Future getGlobalSetting(String key) async { + if (!supportsSettings) return ""; + + InvenTreeGlobalSetting? setting = _globalSettings[key]; + + if ((setting != null) && setting.reloadedWithin(Duration(minutes: 5))) { + return setting.value; + } + + final response = await InvenTreeGlobalSetting().getModel(key); + + if (response is InvenTreeGlobalSetting) { + response.lastReload = DateTime.now(); + _globalSettings[key] = response; + return response.value; + } else { + return ""; + } + } + + Future getUserSetting(String key) async { + if (!supportsSettings) return ""; + + InvenTreeUserSetting? setting = _userSettings[key]; + + if ((setting != null) && setting.reloadedWithin(Duration(minutes: 5))) { + return setting.value; + } + + final response = await InvenTreeGlobalSetting().getModel(key); + + if (response is InvenTreeUserSetting) { + response.lastReload = DateTime.now(); + _userSettings[key] = response; + return response.value; + } else { + return ""; + } + } + } diff --git a/lib/inventree/model.dart b/lib/inventree/model.dart index c39da8fe..1d13d175 100644 --- a/lib/inventree/model.dart +++ b/lib/inventree/model.dart @@ -44,6 +44,17 @@ class InvenTreeModel { // Construct an InvenTreeModel from a JSON data object InvenTreeModel.fromJson(this.jsondata); + // Update whenever the model is loaded from the server + DateTime? lastReload; + + bool reloadedWithin(Duration d) { + if (lastReload == null) { + return false; + } else { + return lastReload!.add(d).isAfter(DateTime.now()); + } + } + // Override the endpoint URL for each subclass String get URL => ""; @@ -287,6 +298,8 @@ class InvenTreeModel { } + lastReload = DateTime.now(); + jsondata = response.asMap(); return true; @@ -315,7 +328,7 @@ class InvenTreeModel { } // Return the detail view for the associated pk - Future get(int pk, {Map filters = const {}}) async { + Future getModel(String pk, {Map filters = const {}}) async { var url = path.join(URL, pk.toString()); @@ -357,9 +370,15 @@ class InvenTreeModel { } + lastReload = DateTime.now(); + return createFromJson(response.asMap()); } + Future get(int pk, {Map filters = const {}}) async { + return getModel(pk.toString(), filters: filters); + } + Future create(Map data) async { if (data.containsKey("pk")) { @@ -565,6 +584,50 @@ class InvenTreePlugin extends InvenTreeModel { } +/* + * Class representing a 'setting' object on the InvenTree server. + * There are two sorts of settings available from the server, via the API: + * - GlobalSetting (applicable to all users) + * - UserSetting (applicable only to the current user) + */ +class InvenTreeGlobalSetting extends InvenTreeModel { + + InvenTreeGlobalSetting() : super(); + + InvenTreeGlobalSetting.fromJson(Map json) : super.fromJson(json); + + @override + InvenTreeGlobalSetting createFromJson(Map json) { + return InvenTreeGlobalSetting.fromJson(json); + } + + @override + String get URL => "settings/global/"; + + String get key => (jsondata["key"] ?? "") as String; + + String get value => (jsondata["value"] ?? "") as String; + + String get type => (jsondata["type"] ?? "") as String; + +} + +class InvenTreeUserSetting extends InvenTreeGlobalSetting { + + InvenTreeUserSetting() : super(); + + InvenTreeUserSetting.fromJson(Map json) : super.fromJson(json); + + @override + InvenTreeGlobalSetting createFromJson(Map json) { + return InvenTreeGlobalSetting.fromJson(json); + } + + @override + String get URL => "settings/user/"; +} + + class InvenTreeAttachment extends InvenTreeModel { // Class representing an "attachment" file InvenTreeAttachment() : super(); diff --git a/lib/widget/paginator.dart b/lib/widget/paginator.dart index c3343a77..f1bfbc85 100644 --- a/lib/widget/paginator.dart +++ b/lib/widget/paginator.dart @@ -44,7 +44,6 @@ class PaginatedSearchState extends State { Future requestPage(int limit, int offset, Map params) async { - print("Blank request page"); // Default implementation returns null - must be overridden return null; } diff --git a/lib/widget/purchase_order_detail.dart b/lib/widget/purchase_order_detail.dart index 2a657ec0..27486969 100644 --- a/lib/widget/purchase_order_detail.dart +++ b/lib/widget/purchase_order_detail.dart @@ -37,6 +37,8 @@ class _PurchaseOrderDetailState extends RefreshableState L10().purchaseOrder; @@ -61,6 +63,9 @@ class _PurchaseOrderDetailState extends RefreshableState request(BuildContext context) async { + + _poPrefix = await InvenTreeAPI().getGlobalSetting("PURCHASEORDER_REFERENCE_PREFIX"); + await order.reload(); lines = await order.getLineItems(); @@ -72,7 +77,6 @@ class _PurchaseOrderDetailState extends RefreshableState editOrder(BuildContext context) async { @@ -93,7 +97,7 @@ class _PurchaseOrderDetailState extends RefreshableState filters) : super(filters); + // Purchase order prefix + String _poPrefix = ""; + @override Future requestPage(int limit, int offset, Map params) async { + _poPrefix = await InvenTreeAPI().getGlobalSetting("PURCHASEORDER_REFERENCE_PREFIX"); + params["outstanding"] = "true"; final page = await InvenTreePurchaseOrder().listPaginated(limit, offset, filters: params); @@ -72,9 +77,9 @@ class _PaginatedPurchaseOrderListState extends PaginatedSearchState