mirror of
				https://github.com/inventree/inventree-app.git
				synced 2025-11-04 07:15:46 +00:00 
			
		
		
		
	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?
This commit is contained in:
		
							
								
								
									
										10
									
								
								lib/api.dart
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								lib/api.dart
									
									
									
									
									
								
							@@ -225,6 +225,8 @@ class InvenTreeAPI {
 | 
				
			|||||||
  // API version of the connected server
 | 
					  // API version of the connected server
 | 
				
			||||||
  int _apiVersion = 1;
 | 
					  int _apiVersion = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  int get apiVersion => _apiVersion;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  // Getter for server version information
 | 
					  // Getter for server version information
 | 
				
			||||||
  String get version => _version;
 | 
					  String get version => _version;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -244,10 +246,14 @@ class InvenTreeAPI {
 | 
				
			|||||||
  // Ensure we only ever create a single instance of the API class
 | 
					  // Ensure we only ever create a single instance of the API class
 | 
				
			||||||
  static final InvenTreeAPI _api = InvenTreeAPI._internal();
 | 
					  static final InvenTreeAPI _api = InvenTreeAPI._internal();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // API endpoint for receiving purchase order line items was introduced in v12
 | 
				
			||||||
  bool supportPoReceive() {
 | 
					  bool supportPoReceive() {
 | 
				
			||||||
 | 
					    return apiVersion >= 12;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // API endpoint for receiving purchase order line items was introduced in v12
 | 
					  // "Modern" API transactions were implemented in API v14
 | 
				
			||||||
    return _apiVersion >= 12;
 | 
					  bool supportModernStockTransactions() {
 | 
				
			||||||
 | 
					    return apiVersion >= 14;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /*
 | 
					  /*
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -115,6 +115,16 @@ class InvenTreeStockItem extends InvenTreeModel {
 | 
				
			|||||||
  @override
 | 
					  @override
 | 
				
			||||||
  String get URL => "stock/";
 | 
					  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
 | 
					  @override
 | 
				
			||||||
  String get WEB_URL => "stock/item/";
 | 
					  String get WEB_URL => "stock/item/";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -474,7 +484,7 @@ class InvenTreeStockItem extends InvenTreeModel {
 | 
				
			|||||||
    return response.isValid();
 | 
					    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<bool> countStock(BuildContext context, double q, {String? notes}) async {
 | 
					  Future<bool> countStock(BuildContext context, double q, {String? notes}) async {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    final bool result = await adjustStock(context, "/stock/count/", q, notes: notes);
 | 
					    final bool result = await adjustStock(context, "/stock/count/", q, notes: notes);
 | 
				
			||||||
@@ -482,7 +492,7 @@ class InvenTreeStockItem extends InvenTreeModel {
 | 
				
			|||||||
    return result;
 | 
					    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<bool> addStock(BuildContext context, double q, {String? notes}) async {
 | 
					  Future<bool> addStock(BuildContext context, double q, {String? notes}) async {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    final bool result = await adjustStock(context,  "/stock/add/", q, notes: notes);
 | 
					    final bool result = await adjustStock(context,  "/stock/add/", q, notes: notes);
 | 
				
			||||||
@@ -490,7 +500,7 @@ class InvenTreeStockItem extends InvenTreeModel {
 | 
				
			|||||||
    return result;
 | 
					    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<bool> removeStock(BuildContext context, double q, {String? notes}) async {
 | 
					  Future<bool> removeStock(BuildContext context, double q, {String? notes}) async {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    final bool result = await adjustStock(context, "/stock/remove/", q, notes: notes);
 | 
					    final bool result = await adjustStock(context, "/stock/remove/", q, notes: notes);
 | 
				
			||||||
@@ -498,7 +508,7 @@ class InvenTreeStockItem extends InvenTreeModel {
 | 
				
			|||||||
    return result;
 | 
					    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<bool> transferStock(int location, {double? quantity, String? notes}) async {
 | 
					  Future<bool> transferStock(int location, {double? quantity, String? notes}) async {
 | 
				
			||||||
    if ((quantity == null) || (quantity < 0) || (quantity > this.quantity)) {
 | 
					    if ((quantity == null) || (quantity < 0) || (quantity > this.quantity)) {
 | 
				
			||||||
      quantity = this.quantity;
 | 
					      quantity = this.quantity;
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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/app_colors.dart";
 | 
				
			||||||
import "package:inventree/barcode.dart";
 | 
					import "package:inventree/barcode.dart";
 | 
				
			||||||
import "package:inventree/inventree/model.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/snacks.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:flutter/cupertino.dart";
 | 
					 | 
				
			||||||
import "package:flutter/material.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:dropdown_search/dropdown_search.dart";
 | 
					 | 
				
			||||||
import "package:font_awesome_flutter/font_awesome_flutter.dart";
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
class StockDetailWidget extends StatefulWidget {
 | 
					class StockDetailWidget extends StatefulWidget {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -140,6 +142,39 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  Future <void> _addStockDialog() async {
 | 
					  Future <void> _addStockDialog() async {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO: In future, deprecate support for older API
 | 
				
			||||||
 | 
					    if (InvenTreeAPI().supportModernStockTransactions()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Map<String, dynamic> 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();
 | 
					    _quantityController.clear();
 | 
				
			||||||
    _notesController.clear();
 | 
					    _notesController.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -186,6 +221,38 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  void _removeStockDialog() {
 | 
					  void _removeStockDialog() {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO: In future, deprecate support for the older API
 | 
				
			||||||
 | 
					    if (InvenTreeAPI().supportModernStockTransactions()) {
 | 
				
			||||||
 | 
					      Map<String, dynamic> 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();
 | 
					    _quantityController.clear();
 | 
				
			||||||
    _notesController.clear();
 | 
					    _notesController.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -225,6 +292,39 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  Future <void> _countStockDialog() async {
 | 
					  Future <void> _countStockDialog() async {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO: In future, deprecate support for older API
 | 
				
			||||||
 | 
					    if (InvenTreeAPI().supportModernStockTransactions()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Map<String, dynamic> 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();
 | 
					    _quantityController.text = item.quantity.toString();
 | 
				
			||||||
    _notesController.clear();
 | 
					    _notesController.clear();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -271,6 +371,7 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  // TODO: Delete this function once support for old API is deprecated
 | 
				
			||||||
  Future <void> _transferStock(int locationId) async {
 | 
					  Future <void> _transferStock(int locationId) async {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    double quantity = double.tryParse(_quantityController.text) ?? item.quantity;
 | 
					    double quantity = double.tryParse(_quantityController.text) ?? item.quantity;
 | 
				
			||||||
@@ -288,8 +389,45 @@ class _StockItemDisplayState extends RefreshableState<StockDetailWidget> {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /*
 | 
				
			||||||
 | 
					   * Launches an API Form to transfer this stock item to a new location
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
  Future <void> _transferStockDialog(BuildContext context) async {
 | 
					  Future <void> _transferStockDialog(BuildContext context) async {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO: In future, deprecate support for older API
 | 
				
			||||||
 | 
					    if (InvenTreeAPI().supportModernStockTransactions()) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Map<String, dynamic> 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;
 | 
					    int? location_pk;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    _quantityController.text = "${item.quantity}";
 | 
					    _quantityController.text = "${item.quantity}";
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user