Skip to content

Commit

Permalink
Supplier part support (#253)
Browse files Browse the repository at this point in the history
* Bump version and release noes

* Add barebone list and detail widgets for the SupplierPart model

* Launch into SupplierPartList from CompanyDetail

* Update StockDetail widget

* Fixes for SupplierPart model

* Add images to supplier part list

* Add search functionality to SupplierPart list

* Added details to SupplierPartDetail widget

* Link through to supplier company

* Add some more details

* Adds ability to edit SupplierPart information

* Navigate to supplier part list from part detail page

* Display supplier part information on stock item detail page

* Add barcode scan response for SupplierPart

* Refactor barcode scanning code

* Navigate to supplier part detail from stock item page

* Support custom barcode for SupplierPart via app

* Cleanup comment

* linting

* Fix override

* Enable display of supplier list on home screen

* Code cleanup

* Update release noets
  • Loading branch information
SchrodingersGat authored Feb 3, 2023
1 parent ce37d0e commit 15bf109
Show file tree
Hide file tree
Showing 22 changed files with 786 additions and 283 deletions.
6 changes: 6 additions & 0 deletions assets/release_notes.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
## InvenTree App Release Notes
---

### 0.10.0 - February 2023
---

- Add support for Supplier Parts
- Updated translations

### 0.9.3 - February 2023
---

Expand Down
19 changes: 16 additions & 3 deletions lib/api_form.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,21 @@ import "package:intl/intl.dart";
import "package:font_awesome_flutter/font_awesome_flutter.dart";
import "package:dropdown_search/dropdown_search.dart";
import "package:datetime_picker_formfield/datetime_picker_formfield.dart";
import "package:flutter/material.dart";

import "package:inventree/api.dart";
import "package:inventree/app_colors.dart";
import "package:inventree/barcode.dart";
import "package:inventree/helpers.dart";
import "package:inventree/l10.dart";

import "package:inventree/inventree/company.dart";
import "package:inventree/inventree/part.dart";
import "package:inventree/inventree/sentry.dart";
import "package:inventree/inventree/stock.dart";

import "package:inventree/widget/dialogs.dart";
import "package:inventree/widget/fields.dart";
import "package:inventree/l10.dart";

import "package:flutter/material.dart";
import "package:inventree/widget/progress.dart";
import "package:inventree/widget/snacks.dart";

Expand Down Expand Up @@ -642,6 +644,17 @@ class APIFormField {
title: Text(name),
leading: FaIcon(isGroup ? FontAwesomeIcons.users : FontAwesomeIcons.user),
);
case "company":
var company = InvenTreeCompany.fromJson(data);
return ListTile(
title: Text(company.name),
subtitle: extended ? Text(company.description) : null,
leading: InvenTreeAPI().getImage(
company.thumbnail,
width: 40,
height: 40
)
);
default:
return ListTile(
title: Text(
Expand Down
196 changes: 114 additions & 82 deletions lib/barcode.dart
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import "dart:io";
import "package:flutter/material.dart";
import "package:font_awesome_flutter/font_awesome_flutter.dart";
import "package:inventree/widget/refreshable_state.dart";
import "package:one_context/one_context.dart";
import "package:qr_code_scanner/qr_code_scanner.dart";

Expand All @@ -11,10 +10,13 @@ import "package:inventree/helpers.dart";
import "package:inventree/l10.dart";
import "package:inventree/preferences.dart";

import "package:inventree/inventree/company.dart";
import "package:inventree/inventree/part.dart";
import "package:inventree/inventree/sentry.dart";
import "package:inventree/inventree/stock.dart";
import "package:inventree/inventree/part.dart";

import "package:inventree/widget/refreshable_state.dart";
import "package:inventree/widget/supplier_part_detail.dart";
import "package:inventree/widget/dialogs.dart";
import "package:inventree/widget/snacks.dart";
import "package:inventree/widget/location_display.dart";
Expand Down Expand Up @@ -163,6 +165,7 @@ class BarcodeHandler {
* - StockLocation
* - StockItem
* - Part
* - SupplierPart
*/
class BarcodeScanHandler extends BarcodeHandler {

Expand All @@ -181,104 +184,134 @@ class BarcodeScanHandler extends BarcodeHandler {
);
}

@override
Future<void> onBarcodeMatched(Map<String, dynamic> data) async {

int pk = -1;

// A stocklocation has been passed?
if (data.containsKey("stocklocation")) {

pk = (data["stocklocation"]?["pk"] ?? -1) as int;

if (pk > 0) {

barcodeSuccessTone();
/*
* Response when a "Part" instance is scanned
*/
Future<void> handlePart(int pk) async {
InvenTreePart().get(pk).then((var part) {
showSnackIcon(
L10().part,
success: true,
icon: Icons.qr_code,
);
// Dismiss the barcode scanner
OneContext().pop();

InvenTreeStockLocation().get(pk).then((var loc) {
if (loc is InvenTreeStockLocation) {
showSnackIcon(
L10().stockLocation,
success: true,
icon: Icons.qr_code,
);
OneContext().pop();
OneContext().navigator.push(MaterialPageRoute(builder: (context) => LocationDisplayWidget(loc)));
}
});
} else {
if (part is InvenTreePart) {
OneContext().push(MaterialPageRoute(builder: (context) => PartDetailWidget(part)));
}
});
}

barcodeFailureTone();
/*
* Response when a "StockItem" instance is scanned
*/
Future<void> handleStockItem(int pk) async {
InvenTreeStockItem().get(pk).then((var item) {
showSnackIcon(
L10().stockItem,
success: true,
icon: Icons.qr_code,
);
OneContext().pop();
if (item is InvenTreeStockItem) {
OneContext().push(MaterialPageRoute(
builder: (context) => StockDetailWidget(item)));
}
});
}

/*
* Response when a "StockLocation" instance is scanned
*/
Future<void> handleStockLocation(int pk) async {
InvenTreeStockLocation().get(pk).then((var loc) {
if (loc is InvenTreeStockLocation) {
showSnackIcon(
L10().invalidStockLocation,
success: false
L10().stockLocation,
success: true,
icon: Icons.qr_code,
);
OneContext().pop();
OneContext().navigator.push(MaterialPageRoute(
builder: (context) => LocationDisplayWidget(loc)));
}
});
}

} else if (data.containsKey("stockitem")) {

pk = (data["stockitem"]?["pk"] ?? -1) as int;

if (pk > 0) {

barcodeSuccessTone();

InvenTreeStockItem().get(pk).then((var item) {
showSnackIcon(
L10().stockItem,
success: true,
icon: Icons.qr_code,
);
OneContext().pop();
if (item is InvenTreeStockItem) {
OneContext().push(MaterialPageRoute(builder: (context) => StockDetailWidget(item)));
}
});
} else {
/*
* Response when a "SupplierPart" instance is scanned
*/
Future<void> handleSupplierPart(int pk) async {
InvenTreeSupplierPart().get(pk).then((var supplierpart) {
showSnackIcon(
L10().supplierPart,
success: true,
icon: Icons.qr_code,
);

barcodeFailureTone();
OneContext().pop();

showSnackIcon(
L10().invalidStockItem,
success: false
);
if (supplierpart is InvenTreeSupplierPart) {
OneContext().push(MaterialPageRoute(builder: (context) => SupplierPartDetailWidget(supplierpart)));
}
} else if (data.containsKey("part")) {
});
}

pk = (data["part"]?["pk"] ?? -1) as int;
@override
Future<void> onBarcodeMatched(Map<String, dynamic> data) async {
int pk = -1;

if (pk > 0) {
String model = "";

barcodeSuccessTone();
// The following model types can be matched with barcodes
final List<String> validModels = [
"part",
"stockitem",
"stocklocation",
"supplierpart"
];

InvenTreePart().get(pk).then((var part) {
showSnackIcon(
L10().part,
success: true,
icon: Icons.qr_code,
);
// Dismiss the barcode scanner
OneContext().pop();
for (var key in validModels) {
if (data.containsKey(key)) {
pk = (data[key]?["pk"] ?? -1) as int;

if (part is InvenTreePart) {
OneContext().push(MaterialPageRoute(builder: (context) => PartDetailWidget(part)));
}
});
} else {
// Break on the first valid match found
if (pk > 0) {
model = key;
break;
}
}
}

barcodeFailureTone();
// A valid result has been found
if (pk > 0 && model.isNotEmpty) {

showSnackIcon(
L10().invalidPart,
success: false
);
barcodeSuccessTone();

switch (model) {
case "part":
handlePart(pk);
return;
case "stockitem":
handleStockItem(pk);
return;
case "stocklocation":
handleStockLocation(pk);
return;
case "supplierpart":
handleSupplierPart(pk);
return;
default:
// Fall through to failure state
break;
}
} else {
}

barcodeFailureTone();
// If we get here, we have not found a valid barcode result!
barcodeFailureTone();

showSnackIcon(
showSnackIcon(
L10().barcodeUnknown,
success: false,
onAction: () {
Expand All @@ -295,8 +328,7 @@ class BarcodeScanHandler extends BarcodeHandler {
)
);
}
);
}
);
}
}

Expand Down
34 changes: 24 additions & 10 deletions lib/inventree/company.dart
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,23 @@ class InvenTreeSupplierPart extends InvenTreeModel {
@override
String get URL => "company/part/";

@override
Map<String, dynamic> formFields() {
return {
"supplier": {},
"SKU": {},
"link": {},
"note": {},
"packaging": {},
"pack_size": {},
};
}

Map<String, String> _filters() {
return {
"manufacturer_detail": "true",
"supplier_detail": "true",
"manufacturer_part_detail": "true",
"part_detail": "true",
};
}

Expand All @@ -116,29 +128,31 @@ class InvenTreeSupplierPart extends InvenTreeModel {
return _filters();
}

int get manufacturerId => (jsondata["manufacturer"] ?? -1) as int;
String get manufacturerName => (jsondata["manufacturer_detail"]?["name"] ?? "") as String;

String get manufacturerName => (jsondata["manufacturer_detail"]["name"] ?? "") as String;
String get MPN => (jsondata["manufacturer_part_detail"]?["MPN"] ?? "") as String;

String get manufacturerImage => (jsondata["manufacturer_detail"]["image"] ?? jsondata["manufacturer_detail"]["thumbnail"] ?? InvenTreeAPI.staticThumb) as String;
String get manufacturerImage => (jsondata["manufacturer_detail"]?["image"] ?? jsondata["manufacturer_detail"]["thumbnail"] ?? InvenTreeAPI.staticThumb) as String;

int get manufacturerPartId => (jsondata["manufacturer_part"] ?? -1) as int;

int get supplierId => (jsondata["supplier"] ?? -1) as int;

String get supplierName => (jsondata["supplier_detail"]["name"] ?? "") as String;
String get supplierName => (jsondata["supplier_detail"]?["name"] ?? "") as String;

String get supplierImage => (jsondata["supplier_detail"]["image"] ?? jsondata["supplier_detail"]["thumbnail"] ?? InvenTreeAPI.staticThumb) as String;
String get supplierImage => (jsondata["supplier_detail"]?["image"] ?? jsondata["supplier_detail"]["thumbnail"] ?? InvenTreeAPI.staticThumb) as String;

String get SKU => (jsondata["SKU"] ?? "") as String;

String get MPN => (jsondata["MPN"] ?? "") as String;

int get partId => (jsondata["part"] ?? -1) as int;

String get partImage => (jsondata["part_detail"]["thumbnail"] ?? InvenTreeAPI.staticThumb) as String;
String get partImage => (jsondata["part_detail"]?["thumbnail"] ?? InvenTreeAPI.staticThumb) as String;

String get partName => (jsondata["part_detail"]?["full_name"] ?? "") as String;

String get partDescription => (jsondata["part_detail"]?["description"] ?? "") as String;

String get partName => (jsondata["part_detail"]["full_name"] ?? "") as String;
String get note => (jsondata["note"] ?? "") as String;

@override
InvenTreeModel createFromJson(Map<String, dynamic> json) {
Expand Down
10 changes: 6 additions & 4 deletions lib/inventree/stock.dart
Original file line number Diff line number Diff line change
Expand Up @@ -416,8 +416,10 @@ class InvenTreeStockItem extends InvenTreeModel {
String get supplierImage {
String thumb = "";

if (jsondata.containsKey("supplier_detail")) {
thumb = (jsondata["supplier_detail"]["supplier_logo"] ?? "") as String;
if (jsondata.containsKey("supplier_part_detail")) {
thumb = (jsondata["supplier_part_detail"]?["supplier_detail"]?["image"] ?? "") as String;
} else if (jsondata.containsKey("supplier_detail")) {
thumb = (jsondata["supplier_detail"]["image"] ?? "") as String;
}

return thumb;
Expand All @@ -440,8 +442,8 @@ class InvenTreeStockItem extends InvenTreeModel {
String get supplierSKU {
String sku = "";

if (jsondata.containsKey("supplier_detail")) {
sku = (jsondata["supplier_detail"]["SKU"] ?? "") as String;
if (jsondata.containsKey("supplier_part_detail")) {
sku = (jsondata["supplier_part_detail"]["SKU"] ?? "") as String;
}

return sku;
Expand Down
Loading

0 comments on commit 15bf109

Please sign in to comment.