diff --git a/assets/release_notes.md b/assets/release_notes.md index 2e6b291a..b1c2f958 100644 --- a/assets/release_notes.md +++ b/assets/release_notes.md @@ -1,3 +1,8 @@ +### 0.21.0 - November 2025 +--- + +- Display default stock location in part detail page + ### 0.20.2 - November 2025 --- diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 83fef3af..b57df1f1 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -719,7 +719,6 @@ "languageSelect": "Select Language", "@languageSelect": {}, - "lastStocktake": "Last Stocktake", "@lastStocktake": {}, @@ -753,6 +752,9 @@ "locationCreateDetail": "Create new stock location", "@locationCreateDetail": {}, + "locationDefault": "Default Location", + "@locationDefault": {}, + "locationNotSet": "No location specified", "@locationNotSet": {}, diff --git a/lib/widget/part/part_detail.dart b/lib/widget/part/part_detail.dart index 4cbfa494..e54bb753 100644 --- a/lib/widget/part/part_detail.dart +++ b/lib/widget/part/part_detail.dart @@ -47,6 +47,8 @@ class _PartDisplayState extends RefreshableState { InvenTreePart? parentPart; + InvenTreeStockLocation? defaultLocation; + int parameterCount = 0; bool allowLabelPrinting = false; @@ -177,16 +179,35 @@ class _PartDisplayState extends RefreshableState { // If the part points to a parent "template" part, request that too int? templatePartId = part.variantOf; - if (templatePartId == null) { - parentPart = null; - } else { - final result = await InvenTreePart().get(templatePartId); - - if (result != null && result is InvenTreePart) { - parentPart = result; - } else { + if (templatePartId != null) { + InvenTreePart().get(templatePartId).then((value) { + if (mounted) { + setState(() { + parentPart = value as InvenTreePart?; + }); + } + }); + } else if (mounted) { + setState(() { parentPart = null; - } + }); + } + + // Is there a default location specified for this part? + int? defaultLocationId = part.defaultLocation; + + if (defaultLocationId != null) { + InvenTreeStockLocation().get(defaultLocationId).then((value) { + if (mounted) { + setState(() { + defaultLocation = value as InvenTreeStockLocation?; + }); + } + }); + } else if (mounted) { + setState(() { + defaultLocation = null; + }); } // Request part test templates @@ -414,6 +435,20 @@ class _PartDisplayState extends RefreshableState { ), ); + if (defaultLocation != null) { + tiles.add( + ListTile( + title: Text(L10().locationDefault), + subtitle: Text(defaultLocation!.pathstring), + leading: Icon(TablerIcons.map_pin), + trailing: LinkIcon(), + onTap: () { + defaultLocation?.goToDetailPage(context); + }, + ), + ); + } + if (showPricing && partPricing != null) { String pricing = formatPriceRange( partPricing?.overallMin, diff --git a/lib/widget/stock/stock_detail.dart b/lib/widget/stock/stock_detail.dart index 19f1592e..648610c0 100644 --- a/lib/widget/stock/stock_detail.dart +++ b/lib/widget/stock/stock_detail.dart @@ -49,6 +49,7 @@ class _StockItemDisplayState extends RefreshableState { // Linked data fields InvenTreePart? part; + InvenTreeStockLocation? defaultLocation; InvenTreeSalesOrder? salesOrder; InvenTreeCompany? customer; @@ -234,6 +235,23 @@ class _StockItemDisplayState extends RefreshableState { stockShowTests &= part?.isTrackable ?? false; + // Request default location + int? defaultLocationId = part?.defaultLocation; + + if (defaultLocationId != null) { + InvenTreeStockLocation().get(defaultLocationId).then((value) { + if (mounted) { + setState(() { + defaultLocation = value as InvenTreeStockLocation?; + }); + } + }); + } else if (mounted) { + setState(() { + defaultLocation = null; + }); + } + // Request test results (async) if (stockShowTests) { widget.item.getTestResults().then((value) { @@ -569,6 +587,21 @@ class _StockItemDisplayState extends RefreshableState { ); } + if (defaultLocation != null && + defaultLocation?.pk != widget.item.locationId) { + tiles.add( + ListTile( + title: Text(L10().locationDefault), + subtitle: Text(defaultLocation!.pathstring), + leading: Icon(TablerIcons.map_pin), + trailing: LinkIcon(), + onTap: () { + defaultLocation?.goToDetailPage(context); + }, + ), + ); + } + // Quantity information if (widget.item.isSerialized()) { tiles.add( @@ -744,7 +777,7 @@ class _StockItemDisplayState extends RefreshableState { tiles.add( ListTile( title: Text(L10().lastStocktake), - subtitle: Text(widget.item.stocktakeDateString), + trailing: LargeText(widget.item.stocktakeDateString), leading: Icon(TablerIcons.calendar), ), ); diff --git a/pubspec.yaml b/pubspec.yaml index a6c479e1..a4450354 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: inventree description: InvenTree stock management -version: 0.20.2+105 +version: 0.21.0+106 environment: sdk: ^3.8.1