mirror of
				https://github.com/inventree/inventree-app.git
				synced 2025-10-31 13:25:40 +00:00 
			
		
		
		
	Po barcode scan (#458)
* Refactor existing barcode scan endpoint - Break out into new file just for purchase orders * Handle scanning of salesorder * Add new handler for adding items to PO via barcode * Allocate with barcode * Add new string
This commit is contained in:
		| @@ -330,8 +330,12 @@ class InvenTreeAPI { | |||||||
|   // Does the server support extra fields on stock adjustment actions? |   // Does the server support extra fields on stock adjustment actions? | ||||||
|   bool get supportsStockAdjustExtraFields => isConnected() && apiVersion >= 133; |   bool get supportsStockAdjustExtraFields => isConnected() && apiVersion >= 133; | ||||||
|  |  | ||||||
|  |   // Does the server support receiving items against a PO using barcodes? | ||||||
|   bool get supportsBarcodePOReceiveEndpoint => isConnected() && apiVersion >= 139; |   bool get supportsBarcodePOReceiveEndpoint => isConnected() && apiVersion >= 139; | ||||||
|  |  | ||||||
|  |   // Does the server support adding line items to a PO using barcodes? | ||||||
|  |   bool get supportsBarcodePOAddLineEndpoint => isConnected() && apiVersion >= 153; | ||||||
|  |  | ||||||
|   // Cached list of plugins (refreshed when we connect to the server) |   // Cached list of plugins (refreshed when we connect to the server) | ||||||
|   List<InvenTreePlugin> _plugins = []; |   List<InvenTreePlugin> _plugins = []; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,12 +2,13 @@ import "package:flutter/material.dart"; | |||||||
|  |  | ||||||
| import "package:flutter_speed_dial/flutter_speed_dial.dart"; | import "package:flutter_speed_dial/flutter_speed_dial.dart"; | ||||||
| import "package:font_awesome_flutter/font_awesome_flutter.dart"; | import "package:font_awesome_flutter/font_awesome_flutter.dart"; | ||||||
|  | import "package:inventree/inventree/sales_order.dart"; | ||||||
| import "package:inventree/preferences.dart"; | import "package:inventree/preferences.dart"; | ||||||
|  | import "package:inventree/widget/order/sales_order_detail.dart"; | ||||||
| import "package:one_context/one_context.dart"; | import "package:one_context/one_context.dart"; | ||||||
|  |  | ||||||
|  |  | ||||||
| import "package:inventree/api.dart"; | import "package:inventree/api.dart"; | ||||||
| import "package:inventree/api_form.dart"; |  | ||||||
| import "package:inventree/helpers.dart"; | import "package:inventree/helpers.dart"; | ||||||
| import "package:inventree/l10.dart"; | import "package:inventree/l10.dart"; | ||||||
|  |  | ||||||
| @@ -166,6 +167,16 @@ class BarcodeScanHandler extends BarcodeHandler { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   // Response when a SalesOrder instance is scanned | ||||||
|  |   Future<void> handleSalesOrder(int pk) async { | ||||||
|  |     var order = await InvenTreeSalesOrder().get(pk); | ||||||
|  |  | ||||||
|  |     if (order is InvenTreeSalesOrder) { | ||||||
|  |       OneContext().pop(); | ||||||
|  |       OneContext().push(MaterialPageRoute( | ||||||
|  |         builder: (context) => SalesOrderDetailWidget(order))); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Future<void> onBarcodeMatched(Map<String, dynamic> data) async { |   Future<void> onBarcodeMatched(Map<String, dynamic> data) async { | ||||||
| @@ -184,6 +195,7 @@ class BarcodeScanHandler extends BarcodeHandler { | |||||||
|  |  | ||||||
|     if (InvenTreeAPI().supportsOrderBarcodes) { |     if (InvenTreeAPI().supportsOrderBarcodes) { | ||||||
|       validModels.add("purchaseorder"); |       validModels.add("purchaseorder"); | ||||||
|  |       validModels.add("salesorder"); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     for (var key in validModels) { |     for (var key in validModels) { | ||||||
| @@ -219,6 +231,10 @@ class BarcodeScanHandler extends BarcodeHandler { | |||||||
|         case "purchaseorder": |         case "purchaseorder": | ||||||
|           await handlePurchaseOrder(pk); |           await handlePurchaseOrder(pk); | ||||||
|           return; |           return; | ||||||
|  |         case "salesorder": | ||||||
|  |           await handleSalesOrder(pk); | ||||||
|  |           return; | ||||||
|  |           // TODO: Handle manufacturer part | ||||||
|         default: |         default: | ||||||
|           // Fall through to failure state |           // Fall through to failure state | ||||||
|           break; |           break; | ||||||
| @@ -478,116 +494,6 @@ class ScanParentLocationHandler extends BarcodeScanStockLocationHandler { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * Barcode handler class for scanning a supplier barcode to receive a part |  | ||||||
|  * |  | ||||||
|  * - The class can be initialized by optionally passing a valid, placed PurchaseOrder object |  | ||||||
|  * - Expects to scan supplier barcode, possibly containing order_number and quantity |  | ||||||
|  * - If location or quantity information wasn't provided, show a form to fill it in |  | ||||||
|  */ |  | ||||||
| class POReceiveBarcodeHandler extends BarcodeHandler { |  | ||||||
|  |  | ||||||
|   POReceiveBarcodeHandler({this.purchaseOrder, this.location}); |  | ||||||
|  |  | ||||||
|   InvenTreePurchaseOrder? purchaseOrder; |  | ||||||
|   InvenTreeStockLocation? location; |  | ||||||
|  |  | ||||||
|   @override |  | ||||||
|   String getOverlayText(BuildContext context) => L10().barcodeReceivePart; |  | ||||||
|  |  | ||||||
|   @override |  | ||||||
|   Future<void> processBarcode(String barcode, |  | ||||||
|       {String url = "barcode/po-receive/", |  | ||||||
|       Map<String, dynamic> extra_data = const {}}) { |  | ||||||
|  |  | ||||||
|     final po_extra_data = { |  | ||||||
|       "purchase_order": purchaseOrder?.pk, |  | ||||||
|       "location": location?.pk, |  | ||||||
|       ...extra_data, |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     return super.processBarcode(barcode, url: url, extra_data: po_extra_data); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   @override |  | ||||||
|   Future<void> onBarcodeMatched(Map<String, dynamic> data) async { |  | ||||||
|       if (!data.containsKey("lineitem")) { |  | ||||||
|         return onBarcodeUnknown(data); |  | ||||||
|       } |  | ||||||
|  |  | ||||||
|       barcodeSuccessTone(); |  | ||||||
|       showSnackIcon(L10().receivedItem, success: true); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   @override |  | ||||||
|   Future<void> onBarcodeUnhandled(Map<String, dynamic> data) async { |  | ||||||
|     if (!data.containsKey("action_required") || !data.containsKey("lineitem")) { |  | ||||||
|       return super.onBarcodeUnhandled(data); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     final lineItemData = data["lineitem"] as Map<String, dynamic>; |  | ||||||
|     if (!lineItemData.containsKey("pk") || !lineItemData.containsKey("purchase_order")) { |  | ||||||
|       barcodeFailureTone(); |  | ||||||
|       showSnackIcon(L10().missingData, success: false); |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // Construct fields to receive |  | ||||||
|     Map<String, dynamic> fields = { |  | ||||||
|       "line_item": { |  | ||||||
|         "parent": "items", |  | ||||||
|         "nested": true, |  | ||||||
|         "hidden": true, |  | ||||||
|         "value": lineItemData["pk"] as int, |  | ||||||
|       }, |  | ||||||
|       "quantity": { |  | ||||||
|         "parent": "items", |  | ||||||
|         "nested": true, |  | ||||||
|         "value": lineItemData["quantity"] as double?, |  | ||||||
|       }, |  | ||||||
|       "status": { |  | ||||||
|         "parent": "items", |  | ||||||
|         "nested": true, |  | ||||||
|       }, |  | ||||||
|       "location": { |  | ||||||
|         "value": lineItemData["location"] as int?, |  | ||||||
|       }, |  | ||||||
|       "barcode": { |  | ||||||
|         "parent": "items", |  | ||||||
|         "nested": true, |  | ||||||
|         "hidden": true, |  | ||||||
|         "type": "barcode", |  | ||||||
|         "value": data["barcode_data"] as String, |  | ||||||
|       } |  | ||||||
|     }; |  | ||||||
|  |  | ||||||
|     final context = OneContext().context!; |  | ||||||
|     final purchase_order_pk = lineItemData["purchase_order"]; |  | ||||||
|     final receive_url = "${InvenTreePurchaseOrder().URL}${purchase_order_pk}/receive/"; |  | ||||||
|  |  | ||||||
|     launchApiForm( |  | ||||||
|       context, |  | ||||||
|       L10().receiveItem, |  | ||||||
|       receive_url, |  | ||||||
|       fields, |  | ||||||
|       method: "POST", |  | ||||||
|       icon: FontAwesomeIcons.rightToBracket, |  | ||||||
|       onSuccess: (data) async { |  | ||||||
|         showSnackIcon(L10().receivedItem, success: true); |  | ||||||
|       } |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   @override |  | ||||||
|   Future<void> onBarcodeUnknown(Map<String, dynamic> data) async { |  | ||||||
|     barcodeFailureTone(); |  | ||||||
|     showSnackIcon( |  | ||||||
|       data["error"] as String? ?? L10().barcodeError, |  | ||||||
|       success: false |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * Barcode handler for finding a "unique" barcode (one that does not match an item in the database) |  * Barcode handler for finding a "unique" barcode (one that does not match an item in the database) | ||||||
|  */ |  */ | ||||||
|   | |||||||
| @@ -41,7 +41,7 @@ class BarcodeHandler { | |||||||
|     barcodeFailureTone(); |     barcodeFailureTone(); | ||||||
|  |  | ||||||
|     showSnackIcon( |     showSnackIcon( | ||||||
|       L10().barcodeNoMatch, |       (data["error"] ?? L10().barcodeNoMatch) as String, | ||||||
|       success: false, |       success: false, | ||||||
|       icon: Icons.qr_code, |       icon: Icons.qr_code, | ||||||
|     ); |     ); | ||||||
|   | |||||||
							
								
								
									
										203
									
								
								lib/barcode/purchase_order.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								lib/barcode/purchase_order.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,203 @@ | |||||||
|  | import "package:flutter/material.dart"; | ||||||
|  |  | ||||||
|  | import "package:font_awesome_flutter/font_awesome_flutter.dart"; | ||||||
|  | import "package:one_context/one_context.dart"; | ||||||
|  |  | ||||||
|  | import "package:inventree/l10.dart"; | ||||||
|  | import "package:inventree/api_form.dart"; | ||||||
|  |  | ||||||
|  | import "package:inventree/barcode/handler.dart"; | ||||||
|  | import "package:inventree/barcode/tones.dart"; | ||||||
|  |  | ||||||
|  | import "package:inventree/inventree/purchase_order.dart"; | ||||||
|  | import "package:inventree/inventree/stock.dart"; | ||||||
|  |  | ||||||
|  | import "package:inventree/widget/snacks.dart"; | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Barcode handler class for scanning a supplier barcode to receive a part | ||||||
|  |  * | ||||||
|  |  * - The class can be initialized by optionally passing a valid, placed PurchaseOrder object | ||||||
|  |  * - Expects to scan supplier barcode, possibly containing order_number and quantity | ||||||
|  |  * - If location or quantity information wasn't provided, show a form to fill it in | ||||||
|  |  */ | ||||||
|  | class POReceiveBarcodeHandler extends BarcodeHandler { | ||||||
|  |  | ||||||
|  |   POReceiveBarcodeHandler({this.purchaseOrder, this.location}); | ||||||
|  |  | ||||||
|  |   InvenTreePurchaseOrder? purchaseOrder; | ||||||
|  |   InvenTreeStockLocation? location; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   String getOverlayText(BuildContext context) => L10().barcodeReceivePart; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Future<void> processBarcode(String barcode, | ||||||
|  |       {String url = "barcode/po-receive/", | ||||||
|  |         Map<String, dynamic> extra_data = const {}}) { | ||||||
|  |  | ||||||
|  |     final po_extra_data = { | ||||||
|  |       "purchase_order": purchaseOrder?.pk, | ||||||
|  |       "location": location?.pk, | ||||||
|  |       ...extra_data, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     return super.processBarcode(barcode, url: url, extra_data: po_extra_data); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Future<void> onBarcodeMatched(Map<String, dynamic> data) async { | ||||||
|  |     if (!data.containsKey("lineitem")) { | ||||||
|  |       return onBarcodeUnknown(data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     barcodeSuccessTone(); | ||||||
|  |     showSnackIcon(L10().receivedItem, success: true); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Future<void> onBarcodeUnhandled(Map<String, dynamic> data) async { | ||||||
|  |     if (!data.containsKey("action_required") || !data.containsKey("lineitem")) { | ||||||
|  |       return super.onBarcodeUnhandled(data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     final lineItemData = data["lineitem"] as Map<String, dynamic>; | ||||||
|  |     if (!lineItemData.containsKey("pk") || !lineItemData.containsKey("purchase_order")) { | ||||||
|  |       barcodeFailureTone(); | ||||||
|  |       showSnackIcon(L10().missingData, success: false); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Construct fields to receive | ||||||
|  |     Map<String, dynamic> fields = { | ||||||
|  |       "line_item": { | ||||||
|  |         "parent": "items", | ||||||
|  |         "nested": true, | ||||||
|  |         "hidden": true, | ||||||
|  |         "value": lineItemData["pk"] as int, | ||||||
|  |       }, | ||||||
|  |       "quantity": { | ||||||
|  |         "parent": "items", | ||||||
|  |         "nested": true, | ||||||
|  |         "value": lineItemData["quantity"] as double?, | ||||||
|  |       }, | ||||||
|  |       "status": { | ||||||
|  |         "parent": "items", | ||||||
|  |         "nested": true, | ||||||
|  |       }, | ||||||
|  |       "location": { | ||||||
|  |         "value": lineItemData["location"] as int?, | ||||||
|  |       }, | ||||||
|  |       "barcode": { | ||||||
|  |         "parent": "items", | ||||||
|  |         "nested": true, | ||||||
|  |         "hidden": true, | ||||||
|  |         "type": "barcode", | ||||||
|  |         "value": data["barcode_data"] as String, | ||||||
|  |       } | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     final context = OneContext().context!; | ||||||
|  |     final purchase_order_pk = lineItemData["purchase_order"]; | ||||||
|  |     final receive_url = "${InvenTreePurchaseOrder().URL}${purchase_order_pk}/receive/"; | ||||||
|  |  | ||||||
|  |     launchApiForm( | ||||||
|  |         context, | ||||||
|  |         L10().receiveItem, | ||||||
|  |         receive_url, | ||||||
|  |         fields, | ||||||
|  |         method: "POST", | ||||||
|  |         icon: FontAwesomeIcons.rightToBracket, | ||||||
|  |         onSuccess: (data) async { | ||||||
|  |           showSnackIcon(L10().receivedItem, success: true); | ||||||
|  |         } | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Future<void> onBarcodeUnknown(Map<String, dynamic> data) async { | ||||||
|  |     barcodeFailureTone(); | ||||||
|  |     showSnackIcon( | ||||||
|  |         data["error"] as String? ?? L10().barcodeError, | ||||||
|  |         success: false | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Barcode handler to add a line item to a purchase order | ||||||
|  |  */ | ||||||
|  | class POAllocateBarcodeHandler extends BarcodeHandler { | ||||||
|  |  | ||||||
|  |   POAllocateBarcodeHandler({this.purchaseOrder}); | ||||||
|  |  | ||||||
|  |   InvenTreePurchaseOrder? purchaseOrder; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   String getOverlayText(BuildContext context) => L10().scanSupplierPart; | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Future<void> processBarcode(String barcode, { | ||||||
|  |     String url = "barcode/po-allocate/", | ||||||
|  |     Map<String, dynamic> extra_data = const {}} | ||||||
|  |   ) { | ||||||
|  |  | ||||||
|  |     final po_extra_data = { | ||||||
|  |       "purchase_order": purchaseOrder?.pk, | ||||||
|  |       ...extra_data, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     return super.processBarcode( | ||||||
|  |       barcode, | ||||||
|  |       url: url, | ||||||
|  |       extra_data: po_extra_data, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Future<void> onBarcodeMatched(Map<String, dynamic> data) async { | ||||||
|  |     // Server must respond with a suppliertpart instance | ||||||
|  |     if (!data.containsKey("supplierpart")) { | ||||||
|  |       return onBarcodeUnknown(data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     dynamic supplier_part = data["supplierpart"]; | ||||||
|  |  | ||||||
|  |     int supplier_part_pk = -1; | ||||||
|  |  | ||||||
|  |     if (supplier_part is Map<String, dynamic>) { | ||||||
|  |       supplier_part_pk = (supplier_part["pk"] ?? -1) as int; | ||||||
|  |     } else { | ||||||
|  |       return onBarcodeUnknown(data); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // Dispose of the barcode scanner | ||||||
|  |     if (OneContext.hasContext) { | ||||||
|  |       OneContext().pop(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     final context = OneContext().context!; | ||||||
|  |  | ||||||
|  |     var fields = InvenTreePOLineItem().formFields(); | ||||||
|  |  | ||||||
|  |     fields["order"]?["value"] = purchaseOrder!.pk; | ||||||
|  |     fields["part"]?["hidden"] = false; | ||||||
|  |     fields["part"]?["value"] = supplier_part_pk; | ||||||
|  |  | ||||||
|  |     InvenTreePOLineItem().createForm( | ||||||
|  |       context, | ||||||
|  |       L10().lineItemAdd, | ||||||
|  |       fields: fields, | ||||||
|  |       onSuccess: (data) async {}, | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   Future<void> onBarcodeUnhandled(Map<String, dynamic> data) async { | ||||||
|  |  | ||||||
|  |     print("onBarcodeUnhandled:"); | ||||||
|  |     print(data.toString()); | ||||||
|  |  | ||||||
|  |     super.onBarcodeUnhandled(data); | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -1057,6 +1057,9 @@ | |||||||
|   "@scanBarcode": { |   "@scanBarcode": { | ||||||
|   }, |   }, | ||||||
|  |  | ||||||
|  |   "scanSupplierPart": "Scan supplier part barcode", | ||||||
|  |   "@scanSupplierPart": {}, | ||||||
|  |  | ||||||
|   "scanIntoLocation": "Scan Into Location", |   "scanIntoLocation": "Scan Into Location", | ||||||
|   "@scanIntoLocation": {}, |   "@scanIntoLocation": {}, | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ import "package:inventree/widget/order/po_line_list.dart"; | |||||||
|  |  | ||||||
| import "package:inventree/app_colors.dart"; | import "package:inventree/app_colors.dart"; | ||||||
| import "package:inventree/barcode/barcode.dart"; | import "package:inventree/barcode/barcode.dart"; | ||||||
|  | import "package:inventree/barcode/purchase_order.dart"; | ||||||
| import "package:inventree/helpers.dart"; | import "package:inventree/helpers.dart"; | ||||||
| import "package:inventree/l10.dart"; | import "package:inventree/l10.dart"; | ||||||
|  |  | ||||||
| @@ -173,7 +174,7 @@ class _PurchaseOrderDetailState extends RefreshableState<PurchaseOrderDetailWidg | |||||||
|   List<SpeedDialChild> barcodeButtons(BuildContext context) { |   List<SpeedDialChild> barcodeButtons(BuildContext context) { | ||||||
|     List<SpeedDialChild> actions = []; |     List<SpeedDialChild> actions = []; | ||||||
|  |  | ||||||
|     if (api.supportsBarcodePOReceiveEndpoint) { |     if (api.supportsBarcodePOReceiveEndpoint && widget.order.isPlaced) { | ||||||
|       actions.add( |       actions.add( | ||||||
|         SpeedDialChild( |         SpeedDialChild( | ||||||
|           child: Icon(Icons.barcode_reader), |           child: Icon(Icons.barcode_reader), | ||||||
| @@ -182,12 +183,29 @@ class _PurchaseOrderDetailState extends RefreshableState<PurchaseOrderDetailWidg | |||||||
|             scanBarcode( |             scanBarcode( | ||||||
|               context, |               context, | ||||||
|               handler: POReceiveBarcodeHandler(purchaseOrder: widget.order), |               handler: POReceiveBarcodeHandler(purchaseOrder: widget.order), | ||||||
|             ); |             ).then((value) { | ||||||
|  |               refresh(context); | ||||||
|  |             }); | ||||||
|           }, |           }, | ||||||
|         ) |         ) | ||||||
|       ); |       ); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     if (widget.order.isPending && api.supportsBarcodePOAddLineEndpoint) { | ||||||
|  |       actions.add( | ||||||
|  |         SpeedDialChild( | ||||||
|  |           child: FaIcon(FontAwesomeIcons.circlePlus, color: COLOR_SUCCESS), | ||||||
|  |           label: L10().lineItemAdd, | ||||||
|  |           onTap: () async { | ||||||
|  |             scanBarcode( | ||||||
|  |               context, | ||||||
|  |               handler: POAllocateBarcodeHandler(purchaseOrder: widget.order), | ||||||
|  |             ); | ||||||
|  |           } | ||||||
|  |         ) | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     return actions; |     return actions; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ import "package:inventree/widget/refreshable_state.dart"; | |||||||
| import "package:inventree/l10.dart"; | import "package:inventree/l10.dart"; | ||||||
| import "package:inventree/api.dart"; | import "package:inventree/api.dart"; | ||||||
| import "package:inventree/barcode/barcode.dart"; | import "package:inventree/barcode/barcode.dart"; | ||||||
|  | import "package:inventree/barcode/purchase_order.dart"; | ||||||
| import "package:inventree/inventree/purchase_order.dart"; | import "package:inventree/inventree/purchase_order.dart"; | ||||||
|  |  | ||||||
| /* | /* | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ 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/barcode.dart"; | import "package:inventree/barcode/barcode.dart"; | ||||||
|  | import "package:inventree/barcode/purchase_order.dart"; | ||||||
| import "package:inventree/l10.dart"; | import "package:inventree/l10.dart"; | ||||||
|  |  | ||||||
| import "package:inventree/inventree/stock.dart"; | import "package:inventree/inventree/stock.dart"; | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user