From ba41ebde737229f14607eda4eab6262f3a89053c Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 5 Oct 2021 22:45:47 +1100 Subject: [PATCH 1/5] Add support for "modern" stock actions via the API - In the future, will have to deprecate support for the old ways - Probably v0.6.x? --- lib/api.dart | 10 ++- lib/inventree/stock.dart | 18 ++++- lib/widget/stock_detail.dart | 148 +++++++++++++++++++++++++++++++++-- 3 files changed, 165 insertions(+), 11 deletions(-) diff --git a/lib/api.dart b/lib/api.dart index 64a74682..7e751653 100644 --- a/lib/api.dart +++ b/lib/api.dart @@ -225,6 +225,8 @@ class InvenTreeAPI { // API version of the connected server int _apiVersion = 1; + int get apiVersion => _apiVersion; + // Getter for server version information String get version => _version; @@ -244,10 +246,14 @@ class InvenTreeAPI { // Ensure we only ever create a single instance of the API class static final InvenTreeAPI _api = InvenTreeAPI._internal(); + // API endpoint for receiving purchase order line items was introduced in v12 bool supportPoReceive() { + return apiVersion >= 12; + } - // API endpoint for receiving purchase order line items was introduced in v12 - return _apiVersion >= 12; + // "Modern" API transactions were implemented in API v14 + bool supportModernStockTransactions() { + return apiVersion >= 14; } /* diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index 29391b26..8ce457f5 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -115,6 +115,16 @@ class InvenTreeStockItem extends InvenTreeModel { @override String get URL => "stock/"; + // URLs for performing stock actions + + static String transferStockUrl() => "stock/transfer/"; + + static String countStockUrl() => "stock/count/"; + + static String addStockUrl() => "stock/add/"; + + static String removeStockUrl() => "stock/remove/"; + @override String get WEB_URL => "stock/item/"; @@ -474,7 +484,7 @@ class InvenTreeStockItem extends InvenTreeModel { return response.isValid(); } - // TODO: Refactor this once the server supports API metadata for this action + // TODO: Remove this function when we deprecate support for the old API Future countStock(BuildContext context, double q, {String? notes}) async { final bool result = await adjustStock(context, "/stock/count/", q, notes: notes); @@ -482,7 +492,7 @@ class InvenTreeStockItem extends InvenTreeModel { return result; } - // TODO: Refactor this once the server supports API metadata for this action + // TODO: Remove this function when we deprecate support for the old API Future addStock(BuildContext context, double q, {String? notes}) async { final bool result = await adjustStock(context, "/stock/add/", q, notes: notes); @@ -490,7 +500,7 @@ class InvenTreeStockItem extends InvenTreeModel { return result; } - // TODO: Refactor this once the server supports API metadata for this action + // TODO: Remove this function when we deprecate support for the old API Future removeStock(BuildContext context, double q, {String? notes}) async { final bool result = await adjustStock(context, "/stock/remove/", q, notes: notes); @@ -498,7 +508,7 @@ class InvenTreeStockItem extends InvenTreeModel { return result; } - // TODO: Refactor this once the server supports API metadata for this action + // TODO: Remove this function when we deprecate support for the old API Future transferStock(int location, {double? quantity, String? notes}) async { if ((quantity == null) || (quantity < 0) || (quantity > this.quantity)) { quantity = this.quantity; diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index 46e49cfb..bca258be 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -1,3 +1,9 @@ +import "package:flutter/cupertino.dart"; +import "package:flutter/material.dart"; + +import "package:dropdown_search/dropdown_search.dart"; +import "package:font_awesome_flutter/font_awesome_flutter.dart"; + import "package:inventree/app_colors.dart"; import "package:inventree/barcode.dart"; import "package:inventree/inventree/model.dart"; @@ -12,15 +18,11 @@ import "package:inventree/widget/refreshable_state.dart"; import "package:inventree/widget/snacks.dart"; import "package:inventree/widget/stock_item_test_results.dart"; import "package:inventree/widget/stock_notes.dart"; -import "package:flutter/cupertino.dart"; -import "package:flutter/material.dart"; - import "package:inventree/l10.dart"; import "package:inventree/helpers.dart"; import "package:inventree/api.dart"; +import "package:inventree/api_form.dart"; -import "package:dropdown_search/dropdown_search.dart"; -import "package:font_awesome_flutter/font_awesome_flutter.dart"; class StockDetailWidget extends StatefulWidget { @@ -140,6 +142,39 @@ class _StockItemDisplayState extends RefreshableState { Future _addStockDialog() async { + // TODO: In future, deprecate support for older API + if (InvenTreeAPI().supportModernStockTransactions()) { + + Map fields = { + "pk": { + "parent": "items", + "nested": true, + "hidden": true, + "value": item.pk, + }, + "quantity": { + "parent": "items", + "nested": true, + "value": 0, + }, + "notes": {}, + }; + + launchApiForm( + context, + L10().addStock, + InvenTreeStockItem.addStockUrl(), + fields, + method: "POST", + icon: FontAwesomeIcons.plusCircle, + onSuccess: (data) async { + refresh(); + } + ); + + return; + } + _quantityController.clear(); _notesController.clear(); @@ -186,6 +221,38 @@ class _StockItemDisplayState extends RefreshableState { void _removeStockDialog() { + // TODO: In future, deprecate support for the older API + if (InvenTreeAPI().supportModernStockTransactions()) { + Map fields = { + "pk": { + "parent": "items", + "nested": true, + "hidden": true, + "value": item.pk, + }, + "quantity": { + "parent": "items", + "nested": true, + "value": 0, + }, + "notes": {}, + }; + + launchApiForm( + context, + L10().addStock, + InvenTreeStockItem.removeStockUrl(), + fields, + method: "POST", + icon: FontAwesomeIcons.minusCircle, + onSuccess: (data) async { + refresh(); + } + ); + + return; + } + _quantityController.clear(); _notesController.clear(); @@ -225,6 +292,39 @@ class _StockItemDisplayState extends RefreshableState { Future _countStockDialog() async { + // TODO: In future, deprecate support for older API + if (InvenTreeAPI().supportModernStockTransactions()) { + + Map fields = { + "pk": { + "parent": "items", + "nested": true, + "hidden": true, + "value": item.pk, + }, + "quantity": { + "parent": "items", + "nested": true, + "value": item.quantity, + }, + "notes": {}, + }; + + launchApiForm( + context, + L10().addStock, + InvenTreeStockItem.countStockUrl(), + fields, + method: "POST", + icon: FontAwesomeIcons.plusCircle, + onSuccess: (data) async { + refresh(); + } + ); + + return; + } + _quantityController.text = item.quantity.toString(); _notesController.clear(); @@ -271,6 +371,7 @@ class _StockItemDisplayState extends RefreshableState { } + // TODO: Delete this function once support for old API is deprecated Future _transferStock(int locationId) async { double quantity = double.tryParse(_quantityController.text) ?? item.quantity; @@ -288,8 +389,45 @@ class _StockItemDisplayState extends RefreshableState { } } + /* + * Launches an API Form to transfer this stock item to a new location + */ Future _transferStockDialog(BuildContext context) async { + // TODO: In future, deprecate support for older API + if (InvenTreeAPI().supportModernStockTransactions()) { + + Map fields = { + "pk": { + "parent": "items", + "nested": true, + "hidden": true, + "value": item.pk, + }, + "quantity": { + "parent": "items", + "nested": true, + "value": item.quantity, + }, + "location": {}, + "notes": {}, + }; + + launchApiForm( + context, + L10().transferStock, + InvenTreeStockItem.transferStockUrl(), + fields, + method: "POST", + icon: FontAwesomeIcons.dolly, + onSuccess: (data) async { + refresh(); + } + ); + + return; + } + int? location_pk; _quantityController.text = "${item.quantity}"; From 4d5af825b112e6436345f0afbd174b94e7733bb3 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 5 Oct 2021 22:48:45 +1100 Subject: [PATCH 2/5] Add some friendly update messages --- lib/widget/stock_detail.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index bca258be..7909fcd7 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -168,6 +168,7 @@ class _StockItemDisplayState extends RefreshableState { method: "POST", icon: FontAwesomeIcons.plusCircle, onSuccess: (data) async { + _stockUpdateMessage(); refresh(); } ); @@ -199,7 +200,7 @@ class _StockItemDisplayState extends RefreshableState { ); } - void _stockUpdateMessage(bool result) { + void _stockUpdateMessage({bool result = true}) { if (result) { showSnackIcon(L10().stockItemUpdated, success: true); @@ -246,6 +247,7 @@ class _StockItemDisplayState extends RefreshableState { method: "POST", icon: FontAwesomeIcons.minusCircle, onSuccess: (data) async { + _stockUpdateMessage(); refresh(); } ); @@ -318,6 +320,7 @@ class _StockItemDisplayState extends RefreshableState { method: "POST", icon: FontAwesomeIcons.plusCircle, onSuccess: (data) async { + _stockUpdateMessage(); refresh(); } ); @@ -421,6 +424,7 @@ class _StockItemDisplayState extends RefreshableState { method: "POST", icon: FontAwesomeIcons.dolly, onSuccess: (data) async { + _stockUpdateMessage(); refresh(); } ); From b7bb81c0eae591dacb4fac94937ef7e9e1d01c3c Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 5 Oct 2021 22:52:23 +1100 Subject: [PATCH 3/5] Fixes --- lib/widget/stock_detail.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index 7909fcd7..4bddef8d 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -135,7 +135,7 @@ class _StockItemDisplayState extends RefreshableState { final bool result = await item.addStock(context, quantity, notes: _notesController.text); _notesController.clear(); - _stockUpdateMessage(result); + _stockUpdateMessage(); refresh(); } @@ -214,7 +214,7 @@ class _StockItemDisplayState extends RefreshableState { final bool result = await item.removeStock(context, quantity, notes: _notesController.text); - _stockUpdateMessage(result); + _stockUpdateMessage(); refresh(); @@ -287,7 +287,7 @@ class _StockItemDisplayState extends RefreshableState { final bool result = await item.countStock(context, quantity, notes: _notesController.text); - _stockUpdateMessage(result); + _stockUpdateMessage(); refresh(); } From 3daae47a25fbecc8e02a3f922f0310865c35f774 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 5 Oct 2021 22:54:17 +1100 Subject: [PATCH 4/5] Fix strings and icons --- lib/widget/stock_detail.dart | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index 4bddef8d..a1986427 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -241,7 +241,7 @@ class _StockItemDisplayState extends RefreshableState { launchApiForm( context, - L10().addStock, + L10().removeStock, InvenTreeStockItem.removeStockUrl(), fields, method: "POST", @@ -314,11 +314,11 @@ class _StockItemDisplayState extends RefreshableState { launchApiForm( context, - L10().addStock, + L10().countStock, InvenTreeStockItem.countStockUrl(), fields, method: "POST", - icon: FontAwesomeIcons.plusCircle, + icon: FontAwesomeIcons.clipboardCheck, onSuccess: (data) async { _stockUpdateMessage(); refresh(); From 3e16ab80f780c6c5f6f803b570a7a2f39fd1e9f8 Mon Sep 17 00:00:00 2001 From: Oliver Date: Tue, 5 Oct 2021 23:01:37 +1100 Subject: [PATCH 5/5] bug fixes --- lib/widget/stock_detail.dart | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/widget/stock_detail.dart b/lib/widget/stock_detail.dart index a1986427..9c746ad2 100644 --- a/lib/widget/stock_detail.dart +++ b/lib/widget/stock_detail.dart @@ -135,7 +135,7 @@ class _StockItemDisplayState extends RefreshableState { final bool result = await item.addStock(context, quantity, notes: _notesController.text); _notesController.clear(); - _stockUpdateMessage(); + _stockUpdateMessage(result); refresh(); } @@ -168,7 +168,7 @@ class _StockItemDisplayState extends RefreshableState { method: "POST", icon: FontAwesomeIcons.plusCircle, onSuccess: (data) async { - _stockUpdateMessage(); + _stockUpdateMessage(true); refresh(); } ); @@ -200,7 +200,7 @@ class _StockItemDisplayState extends RefreshableState { ); } - void _stockUpdateMessage({bool result = true}) { + void _stockUpdateMessage(bool result) { if (result) { showSnackIcon(L10().stockItemUpdated, success: true); @@ -214,7 +214,7 @@ class _StockItemDisplayState extends RefreshableState { final bool result = await item.removeStock(context, quantity, notes: _notesController.text); - _stockUpdateMessage(); + _stockUpdateMessage(result); refresh(); @@ -247,7 +247,7 @@ class _StockItemDisplayState extends RefreshableState { method: "POST", icon: FontAwesomeIcons.minusCircle, onSuccess: (data) async { - _stockUpdateMessage(); + _stockUpdateMessage(true); refresh(); } ); @@ -287,7 +287,7 @@ class _StockItemDisplayState extends RefreshableState { final bool result = await item.countStock(context, quantity, notes: _notesController.text); - _stockUpdateMessage(); + _stockUpdateMessage(result); refresh(); } @@ -320,7 +320,7 @@ class _StockItemDisplayState extends RefreshableState { method: "POST", icon: FontAwesomeIcons.clipboardCheck, onSuccess: (data) async { - _stockUpdateMessage(); + _stockUpdateMessage(true); refresh(); } ); @@ -424,7 +424,7 @@ class _StockItemDisplayState extends RefreshableState { method: "POST", icon: FontAwesomeIcons.dolly, onSuccess: (data) async { - _stockUpdateMessage(); + _stockUpdateMessage(true); refresh(); } );