Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Supplier part support #253

Merged
merged 23 commits into from
Feb 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
33a225b
Bump version and release noes
SchrodingersGat Feb 3, 2023
c33e1d1
Add barebone list and detail widgets for the SupplierPart model
SchrodingersGat Feb 3, 2023
d5c022b
Launch into SupplierPartList from CompanyDetail
SchrodingersGat Feb 3, 2023
a8e45a9
Update StockDetail widget
SchrodingersGat Feb 3, 2023
2398f53
Fixes for SupplierPart model
SchrodingersGat Feb 3, 2023
3491c88
Add images to supplier part list
SchrodingersGat Feb 3, 2023
a2cf67b
Add search functionality to SupplierPart list
SchrodingersGat Feb 3, 2023
cb2bbf9
Added details to SupplierPartDetail widget
SchrodingersGat Feb 3, 2023
f36b320
Link through to supplier company
SchrodingersGat Feb 3, 2023
11a463e
Add some more details
SchrodingersGat Feb 3, 2023
7396395
Adds ability to edit SupplierPart information
SchrodingersGat Feb 3, 2023
81ddae6
Navigate to supplier part list from part detail page
SchrodingersGat Feb 3, 2023
b203d87
Display supplier part information on stock item detail page
SchrodingersGat Feb 3, 2023
ad4db20
Add barcode scan response for SupplierPart
SchrodingersGat Feb 3, 2023
b26f262
Refactor barcode scanning code
SchrodingersGat Feb 3, 2023
c22e995
Navigate to supplier part detail from stock item page
SchrodingersGat Feb 3, 2023
9d03b8a
Support custom barcode for SupplierPart via app
SchrodingersGat Feb 3, 2023
d8f14cf
Cleanup comment
SchrodingersGat Feb 3, 2023
abfd114
linting
SchrodingersGat Feb 3, 2023
c10867a
Fix override
SchrodingersGat Feb 3, 2023
31f4b80
Enable display of supplier list on home screen
SchrodingersGat Feb 3, 2023
394246d
Code cleanup
SchrodingersGat Feb 3, 2023
6a1e875
Update release noets
SchrodingersGat Feb 3, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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