diff --git a/lib/barcode.dart b/lib/barcode.dart index 805c7b7d..f88f5cba 100644 --- a/lib/barcode.dart +++ b/lib/barcode.dart @@ -267,6 +267,116 @@ class StockItemBarcodeAssignmentHandler extends BarcodeHandler { } + + + +class StockItemScanIntoLocationHandler extends BarcodeHandler { + /** + * Barcode handler for scanning a provided StockItem into a scanned StockLocation + */ + + final InvenTreeStockItem item; + + StockItemScanIntoLocationHandler(this.item); + + @override + String getOverlayText(BuildContext context) => I18N.of(context).barcodeScanLocation; + + @override + Future onBarcodeMatched(Map data) async { + // If the barcode points to a 'stocklocation', great! + if (data.containsKey('stocklocation')) { + // Extract location information + int location = data['stocklocation']['pk'] as int; + + // Transfer stock to specified location + final result = await item.transferStock(location); + + if (result) { + // Close the scanner + _controller.dispose(); + Navigator.of(_context).pop(); + + showSnackIcon( + I18N.of(OneContext().context).barcodeScanIntoLocationSuccess, + success: true, + ); + } else { + showSnackIcon( + I18N.of(OneContext().context).barcodeScanIntoLocationFailure, + success: false + ); + } + } else { + showSnackIcon( + I18N.of(OneContext().context).invalidStockLocation, + success: false, + ); + } + } +} + + +class StockLocationScanInItemsHandler extends BarcodeHandler { + /** + * Barcode handler for scanning stock item(s) into the specified StockLocation + */ + + final InvenTreeStockLocation location; + + StockLocationScanInItemsHandler(this.location); + + @override + String getOverlayText(BuildContext context) => I18N.of(context).barcodeScanItem; + + @override + Future onBarcodeMatched(Map data) async { + + // Returned barcode must match a stock item + if (data.containsKey('stockitem')) { + + int item_id = data['stockitem']['pk'] as int; + + final InvenTreeStockItem item = await InvenTreeStockItem().get(_context, item_id); + + if (item == null) { + showSnackIcon( + I18N.of(OneContext().context).invalidStockItem, + success: false, + ); + } else if (item.locationId == location.pk) { + showSnackIcon( + I18N.of(OneContext().context).itemInLocation, + success: true + ); + } + + else { + final result = await item.transferStock(location.pk); + + if (result) { + showSnackIcon( + I18N.of(OneContext().context).barcodeScanIntoLocationSuccess, + success: true + ); + } else { + showSnackIcon( + I18N.of(OneContext().context).barcodeScanIntoLocationFailure, + success: false + ); + } + } + } else { + // Does not match a valid stock item! + showSnackIcon( + I18N.of(OneContext().context).invalidStockItem, + success: false, + ); + } + } +} + + class InvenTreeQRView extends StatefulWidget { final BarcodeHandler _handler; @@ -311,107 +421,43 @@ class _QRViewState extends State { this.context = context; return Scaffold( - body: Stack( - children: [ - Expanded( - flex: 4, - child: QRView( - key: qrKey, - onQRViewCreated: _onViewCreated, - overlay: QrScannerOverlayShape( - borderColor: Colors.red, - borderRadius: 10, - borderLength: 30, - borderWidth: 10, - cutOutSize: 300, - ), - ) - ), - Center( - child: Column( - children: [ - Spacer(), - Padding( - child: Text(_handler.getOverlayText(context), - style: TextStyle( - fontWeight: FontWeight.bold, - color: Colors.white), + body: Stack( + children: [ + Expanded( + flex: 4, + child: QRView( + key: qrKey, + onQRViewCreated: _onViewCreated, + overlay: QrScannerOverlayShape( + borderColor: Colors.red, + borderRadius: 10, + borderLength: 30, + borderWidth: 10, + cutOutSize: 300, ), - padding: EdgeInsets.all(20), - ), - ] + ) + ), + Center( + child: Column( + children: [ + Spacer(), + Padding( + child: Text(_handler.getOverlayText(context), + style: TextStyle( + fontWeight: FontWeight.bold, + color: Colors.white), + ), + padding: EdgeInsets.all(20), + ), + ] + ) ) - ) - ], - ) + ], + ) ); } } - -class StockItemScanIntoLocationHandler extends BarcodeHandler { - /** - * Barcode handler for scanning a provided StockItem into a scanned StockLocation - */ - - final InvenTreeStockItem item; - - StockItemScanIntoLocationHandler(this.item); - - @override - String getOverlayText(BuildContext context) => I18N.of(context).barcodeScanLocation; - - @override - Future onBarcodeMatched(Map data) { - // If the barcode points to a 'stocklocation', great! - if (data.containsKey('stocklocation')) { - // Extract location information - int location = data['stocklocation']['pk'] as int; - - // Transfer stock to specified location - item.transferStock(location).then((response) { - print("Response: ${response.statusCode}"); - - // Close the scanner - _controller.dispose(); - Navigator.of(_context).pop(); - - showSnackIcon( - I18N.of(OneContext().context).barcodeScanIntoLocationSuccess, - success: true, - ); - - }); - } else { - showSnackIcon( - I18N.of(OneContext().context).invalidStockLocation, - success: false, - ); - - } - } -} - - -class StockLocationScanInItemsHandler extends BarcodeHandler { - /** - * Barcode handler for scanning stock item(s) into the specified StockLocation - */ - - final InvenTreeStockLocation location; - - StockLocationScanInItemsHandler(this.location); - - @override - String getOverlayText(BuildContext context) => I18N.of(context).barcodeScanItem; - - @override - Future onBarcodeMatched(Map data) { - print("TODO, YO!"); - } -} - - Future scanQrCode(BuildContext context) async { Navigator.push(context, MaterialPageRoute(builder: (context) => InvenTreeQRView(BarcodeScanHandler()))); diff --git a/lib/inventree/stock.dart b/lib/inventree/stock.dart index b39e6a04..738dda6f 100644 --- a/lib/inventree/stock.dart +++ b/lib/inventree/stock.dart @@ -486,7 +486,7 @@ class InvenTreeStockItem extends InvenTreeModel { return result; } - Future transferStock(int location, {double quantity, String notes}) async { + Future transferStock(int location, {double quantity, String notes}) async { if (quantity == null) {} else if ((quantity < 0) || (quantity > this.quantity)) { quantity = this.quantity; @@ -504,7 +504,9 @@ class InvenTreeStockItem extends InvenTreeModel { data["item"]["quantity"] = "${quantity}"; } - return api.post("/stock/transfer/", body: data); + final response = await api.post("/stock/transfer/", body: data); + + return (response.statusCode == 200); } } diff --git a/lib/l10n b/lib/l10n index 0e412995..bc85d5b1 160000 --- a/lib/l10n +++ b/lib/l10n @@ -1 +1 @@ -Subproject commit 0e412995061a5b01530d0929f80e06c29ff639f8 +Subproject commit bc85d5b16cd74623ce42bd82b3ac30b9be1da6c6 diff --git a/lib/widget/location_display.dart b/lib/widget/location_display.dart index 50f13dd7..a3c82e1f 100644 --- a/lib/widget/location_display.dart +++ b/lib/widget/location_display.dart @@ -1,4 +1,5 @@ import 'package:InvenTree/api.dart'; +import 'package:InvenTree/barcode.dart'; import 'package:InvenTree/inventree/stock.dart'; import 'package:InvenTree/preferences.dart'; import 'package:InvenTree/widget/progress.dart'; @@ -224,12 +225,10 @@ class _LocationDisplayState extends RefreshableState { label: I18N.of(context).stock, ), // TODO - Add in actions when they are written... - /* BottomNavigationBarItem( icon: FaIcon(FontAwesomeIcons.wrench), label: I18N.of(context).actions, ) - */ ] ); } @@ -324,14 +323,23 @@ List detailTiles() { // Scan items into location tiles.add( ListTile( - title: Text("Scan in Stock Item"), + title: Text(I18N.of(context).barcodeScanInItems), leading: FaIcon(FontAwesomeIcons.exchangeAlt), trailing: FaIcon(FontAwesomeIcons.qrcode), - onTap: null, + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => InvenTreeQRView(StockLocationScanInItemsHandler(location))) + ).then((context) { + refresh(); + }); + }, ) ); // Move location into another location + // TODO: Implement this! + /* tiles.add( ListTile( title: Text("Move Stock Location"), @@ -339,6 +347,7 @@ List detailTiles() { trailing: FaIcon(FontAwesomeIcons.qrcode), ) ); + */ return tiles; }