From 2c660e39618e2fc2b975a9a4fcf990b2d74275cf Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 18 Apr 2022 21:29:45 +1000 Subject: [PATCH 1/5] Fix "building" quantity string - remove trailing zero --- lib/widget/part_detail.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index 2a6d43f3..ae7a0fed 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -5,6 +5,7 @@ import "package:font_awesome_flutter/font_awesome_flutter.dart"; import "package:inventree/app_colors.dart"; import "package:inventree/inventree/stock.dart"; import "package:inventree/l10.dart"; +import "package:inventree/helpers.dart"; import "package:inventree/widget/part_attachments_widget.dart"; import "package:inventree/widget/part_notes.dart"; import "package:inventree/widget/progress.dart"; @@ -307,7 +308,7 @@ class _PartDisplayState extends RefreshableState { ListTile( title: Text(L10().building), leading: FaIcon(FontAwesomeIcons.tools), - trailing: Text("${part.building}"), + trailing: Text("${simpleNumberString(part.building)}"), onTap: () { // TODO }, From 046af50146e9f469658c7cf340390ab5cc88c21f Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 18 Apr 2022 21:39:09 +1000 Subject: [PATCH 2/5] Use 'available_stock' when available (new API) --- lib/inventree/part.dart | 29 +++++++++---- lib/widget/part_detail.dart | 85 +++++++++++++++++++------------------ 2 files changed, 65 insertions(+), 49 deletions(-) diff --git a/lib/inventree/part.dart b/lib/inventree/part.dart index 7a625a35..db62ba66 100644 --- a/lib/inventree/part.dart +++ b/lib/inventree/part.dart @@ -1,6 +1,7 @@ import "dart:io"; import "package:inventree/api.dart"; +import "package:inventree/helpers.dart"; import "package:inventree/inventree/stock.dart"; import "package:inventree/inventree/company.dart"; import "package:flutter/material.dart"; @@ -250,11 +251,7 @@ class InvenTreePart extends InvenTreeModel { String get onOrderString { - if (onOrder == onOrder.toInt()) { - return onOrder.toInt().toString(); - } else { - return onOrder.toString(); - } + return simpleNumberString(onOrder); } // Get the stock count for this Part @@ -262,12 +259,28 @@ class InvenTreePart extends InvenTreeModel { String get inStockString { - String q = inStock.toString(); + String q = simpleNumberString(inStock); - if (inStock == inStock.toInt()) { - q = inStock.toInt().toString(); + if (units.isNotEmpty) { + q += " ${units}"; } + return q; + } + + // Get the 'available stock' for this Part + double get availableStock { + // Note that the 'available_stock' was not added until API v35 + if (jsondata.containsKey("available_stock")) { + return double.tryParse(jsondata["available_stock"].toString()) ?? 0; + } else { + return inStock; + } + } + + String get availableStockString { + String q = simpleNumberString(availableStock); + if (units.isNotEmpty) { q += " ${units}"; } diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index ae7a0fed..254761f4 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -218,10 +218,10 @@ class _PartDisplayState extends RefreshableState { // Stock information tiles.add( ListTile( - title: Text(L10().stock), + title: Text(L10().availableStock), subtitle: Text(L10().stockDetails), leading: FaIcon(FontAwesomeIcons.boxes, color: COLOR_CLICK), - trailing: Text("${part.inStockString}"), + trailing: Text(part.availableStockString), onTap: () { setState(() { tabIndex = 1; @@ -230,48 +230,9 @@ class _PartDisplayState extends RefreshableState { ), ); - // Keywords? - if (part.keywords.isNotEmpty) { - tiles.add( - ListTile( - title: Text("${part.keywords}"), - leading: FaIcon(FontAwesomeIcons.key), - ) - ); - } - - // External link? - if (part.link.isNotEmpty) { - tiles.add( - ListTile( - title: Text("${part.link}"), - leading: FaIcon(FontAwesomeIcons.link, color: COLOR_CLICK), - onTap: () { - part.openLink(); - }, - ) - ); - } - // Tiles for "purchaseable" parts if (part.isPurchaseable) { - tiles.add( - ListTile( - title: Text(L10().suppliers), - leading: FaIcon(FontAwesomeIcons.industry), - trailing: Text("${part.supplierCount}"), - /* TODO: - onTap: () { - Navigator.push( - context, - MaterialPageRoute(builder: (context) => PartSupplierWidget(part)) - ); - }, - */ - ) - ); - // On order tiles.add( ListTile( @@ -317,6 +278,29 @@ class _PartDisplayState extends RefreshableState { } } + // Keywords? + if (part.keywords.isNotEmpty) { + tiles.add( + ListTile( + title: Text("${part.keywords}"), + leading: FaIcon(FontAwesomeIcons.key), + ) + ); + } + + // External link? + if (part.link.isNotEmpty) { + tiles.add( + ListTile( + title: Text("${part.link}"), + leading: FaIcon(FontAwesomeIcons.link, color: COLOR_CLICK), + onTap: () { + part.openLink(); + }, + ) + ); + } + // Tiles for "component" part if (part.isComponent && part.usedInCount > 0) { @@ -333,6 +317,25 @@ class _PartDisplayState extends RefreshableState { ); } + if (part.isPurchaseable) { + tiles.add( + ListTile( + title: Text(L10().suppliers), + leading: FaIcon(FontAwesomeIcons.industry), + trailing: Text("${part.supplierCount}"), + /* TODO: + onTap: () { + Navigator.push( + context, + MaterialPageRoute(builder: (context) => PartSupplierWidget(part)) + ); + }, + */ + ) + ); + } + + // TODO - Add request tests? /* if (part.isTrackable) { From 3a127cf4fddb0f3e7b134bf9a962106f866cc2fb Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 18 Apr 2022 21:40:44 +1000 Subject: [PATCH 3/5] Track translations --- lib/l10n | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/l10n b/lib/l10n index 581ce0a8..7cc9177c 160000 --- a/lib/l10n +++ b/lib/l10n @@ -1 +1 @@ -Subproject commit 581ce0a818532157ffa0a1b449bf1a240558a238 +Subproject commit 7cc9177c89a4dbd122892b96bbd25f9e9125dfbf From 8d255885cf1736c83d79e525b0f27d6cd11153a2 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 18 Apr 2022 21:40:56 +1000 Subject: [PATCH 4/5] Use "availableStock" in part list --- lib/widget/part_list.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/widget/part_list.dart b/lib/widget/part_list.dart index 7c1233f6..dd8ea6a0 100644 --- a/lib/widget/part_list.dart +++ b/lib/widget/part_list.dart @@ -86,8 +86,8 @@ class _PaginatedPartListState extends PaginatedSearchState { return ListTile( title: Text(part.fullname), - subtitle: Text("${part.description}"), - trailing: Text("${part.inStockString}"), + subtitle: Text(part.description), + trailing: Text(part.availableStockString), leading: InvenTreeAPI().getImage( part.thumbnail, width: 40, From 84edaef10a801834a1ba6c7dce1f940c19833ffc Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Mon, 18 Apr 2022 21:49:10 +1000 Subject: [PATCH 5/5] Bug fix and refactoring - Display difference between "in stock" and "unallocated stock" - Refactor to use single function in detail and list widgets --- lib/inventree/part.dart | 25 ++++++++++++++++++++----- lib/widget/part_detail.dart | 20 ++++++++++---------- lib/widget/part_list.dart | 2 +- 3 files changed, 31 insertions(+), 16 deletions(-) diff --git a/lib/inventree/part.dart b/lib/inventree/part.dart index db62ba66..a5b7ef39 100644 --- a/lib/inventree/part.dart +++ b/lib/inventree/part.dart @@ -269,17 +269,18 @@ class InvenTreePart extends InvenTreeModel { } // Get the 'available stock' for this Part - double get availableStock { + double get unallocatedStock { + // Note that the 'available_stock' was not added until API v35 - if (jsondata.containsKey("available_stock")) { - return double.tryParse(jsondata["available_stock"].toString()) ?? 0; + if (jsondata.containsKey("unallocated_stock")) { + return double.tryParse(jsondata["unallocated_stock"].toString()) ?? 0; } else { return inStock; } } - String get availableStockString { - String q = simpleNumberString(availableStock); + String get unallocatedStockString { + String q = simpleNumberString(unallocatedStock); if (units.isNotEmpty) { q += " ${units}"; @@ -288,6 +289,20 @@ class InvenTreePart extends InvenTreeModel { return q; } + String stockString({bool includeUnits = true}) { + String q = unallocatedStockString; + + if (unallocatedStock != inStock) { + q += " / ${inStockString}"; + } + + if (includeUnits && units.isNotEmpty) { + q += " ${units}"; + } + + return q; + } + String get units => (jsondata["units"] ?? "") as String; // Get the number of units being build for this Part diff --git a/lib/widget/part_detail.dart b/lib/widget/part_detail.dart index 254761f4..07a37c44 100644 --- a/lib/widget/part_detail.dart +++ b/lib/widget/part_detail.dart @@ -204,24 +204,24 @@ class _PartDisplayState extends RefreshableState { ); } else { tiles.add( - ListTile( - title: Text(L10().partCategory), - subtitle: Text(L10().partCategoryTopLevel), - leading: FaIcon(FontAwesomeIcons.sitemap, color: COLOR_CLICK), - onTap: () { - Navigator.push(context, MaterialPageRoute(builder: (context) => CategoryDisplayWidget(null))); - }, - ) + ListTile( + title: Text(L10().partCategory), + subtitle: Text(L10().partCategoryTopLevel), + leading: FaIcon(FontAwesomeIcons.sitemap, color: COLOR_CLICK), + onTap: () { + Navigator.push(context, MaterialPageRoute( + builder: (context) => CategoryDisplayWidget(null))); + }, + ) ); } - // Stock information tiles.add( ListTile( title: Text(L10().availableStock), subtitle: Text(L10().stockDetails), leading: FaIcon(FontAwesomeIcons.boxes, color: COLOR_CLICK), - trailing: Text(part.availableStockString), + trailing: Text(part.stockString()), onTap: () { setState(() { tabIndex = 1; diff --git a/lib/widget/part_list.dart b/lib/widget/part_list.dart index dd8ea6a0..ca4d158e 100644 --- a/lib/widget/part_list.dart +++ b/lib/widget/part_list.dart @@ -87,7 +87,7 @@ class _PaginatedPartListState extends PaginatedSearchState { return ListTile( title: Text(part.fullname), subtitle: Text(part.description), - trailing: Text(part.availableStockString), + trailing: Text(part.stockString()), leading: InvenTreeAPI().getImage( part.thumbnail, width: 40,