mirror of
				https://github.com/inventree/inventree-app.git
				synced 2025-10-30 04:45:39 +00:00 
			
		
		
		
	Show used in assembly list (#209)
* Update default list filters for BomItem * Display "usedIn" count for part detail view * Improve BillOfMaterials widget to display "used in" parts * Update release notes
This commit is contained in:
		| @@ -24,6 +24,8 @@ class InvenTreeBomItem extends InvenTreeModel { | ||||
|   Map<String, String> defaultListFilters() { | ||||
|     return { | ||||
|       "sub_part_detail": "true", | ||||
|       "part_detail": "true", | ||||
|       "show_pricing": "false", | ||||
|     }; | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -21,23 +21,29 @@ import "package:inventree/widget/refreshable_state.dart"; | ||||
|  */ | ||||
| class BillOfMaterialsWidget extends StatefulWidget { | ||||
|  | ||||
|   const BillOfMaterialsWidget(this.part, {Key? key}) : super(key: key); | ||||
|   const BillOfMaterialsWidget(this.part, {this.isParentComponent = true, Key? key}) : super(key: key); | ||||
|  | ||||
|   final InvenTreePart part; | ||||
|  | ||||
|   final bool isParentComponent; | ||||
|  | ||||
|   @override | ||||
|   _BillOfMaterialsState createState() => _BillOfMaterialsState(part); | ||||
|   _BillOfMaterialsState createState() => _BillOfMaterialsState(); | ||||
| } | ||||
|  | ||||
| class _BillOfMaterialsState extends RefreshableState<BillOfMaterialsWidget> { | ||||
|   _BillOfMaterialsState(this.part); | ||||
|  | ||||
|   final InvenTreePart part; | ||||
|   _BillOfMaterialsState(); | ||||
|  | ||||
|   bool showFilterOptions = false; | ||||
|  | ||||
|   @override | ||||
|   String getAppBarTitle(BuildContext context) => L10().billOfMaterials; | ||||
|   String getAppBarTitle(BuildContext context) { | ||||
|     if (widget.isParentComponent) { | ||||
|       return L10().billOfMaterials; | ||||
|     } else { | ||||
|       return L10().usedIn; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   @override | ||||
|   List<Widget> getAppBarActions(BuildContext context) => [ | ||||
| @@ -53,11 +59,36 @@ class _BillOfMaterialsState extends RefreshableState<BillOfMaterialsWidget> { | ||||
|  | ||||
|   @override | ||||
|   Widget getBody(BuildContext context) { | ||||
|     return PaginatedBomList( | ||||
|       { | ||||
|         "part": part.pk.toString(), | ||||
|       }, | ||||
|       showFilterOptions, | ||||
|  | ||||
|     Map<String, String> filters = {}; | ||||
|  | ||||
|     if (widget.isParentComponent) { | ||||
|       filters["part"] = widget.part.pk.toString(); | ||||
|     } else { | ||||
|       filters["uses"] = widget.part.pk.toString(); | ||||
|     } | ||||
|  | ||||
|     return Column( | ||||
|       children: [ | ||||
|         ListTile( | ||||
|           leading: InvenTreeAPI().getImage( | ||||
|             widget.part.thumbnail, | ||||
|             width: 32, | ||||
|             height: 32, | ||||
|           ), | ||||
|           title: Text(widget.part.fullname), | ||||
|           subtitle: Text(widget.isParentComponent ? L10().billOfMaterials : L10().usedInDetails), | ||||
|           trailing: Text(L10().quantity), | ||||
|         ), | ||||
|         Divider(thickness: 1.25), | ||||
|         Expanded( | ||||
|           child: PaginatedBomList( | ||||
|             filters, | ||||
|             showSearch: showFilterOptions, | ||||
|             isParentPart: widget.isParentComponent, | ||||
|           ), | ||||
|         ), | ||||
|       ], | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @@ -68,7 +99,9 @@ class _BillOfMaterialsState extends RefreshableState<BillOfMaterialsWidget> { | ||||
|  */ | ||||
| class PaginatedBomList extends PaginatedSearchWidget { | ||||
|  | ||||
|   const PaginatedBomList(Map<String, String> filters, bool showSearch) : super(filters: filters, showSearch: showSearch); | ||||
|   const PaginatedBomList(Map<String, String> filters, {bool showSearch = false, this.isParentPart = true}) : super(filters: filters, showSearch: showSearch); | ||||
|  | ||||
|   final bool isParentPart; | ||||
|  | ||||
|   @override | ||||
|   _PaginatedBomListState createState() => _PaginatedBomListState(); | ||||
| @@ -109,7 +142,7 @@ class _PaginatedBomListState extends PaginatedSearchState<PaginatedBomList> { | ||||
|  | ||||
|     InvenTreeBomItem bomItem = model as InvenTreeBomItem; | ||||
|  | ||||
|     InvenTreePart? subPart = bomItem.subPart; | ||||
|     InvenTreePart? subPart = widget.isParentPart ? bomItem.subPart : bomItem.part; | ||||
|  | ||||
|     String title = subPart?.fullname ?? "error - no name"; | ||||
|  | ||||
| @@ -128,7 +161,7 @@ class _PaginatedBomListState extends PaginatedSearchState<PaginatedBomList> { | ||||
|       onTap: subPart == null ? null : () async { | ||||
|  | ||||
|         showLoadingOverlay(context); | ||||
|         var part = await InvenTreePart().get(bomItem.subPartId); | ||||
|         var part = await InvenTreePart().get(subPart.pk); | ||||
|         hideLoadingOverlay(); | ||||
|  | ||||
|         if (part is InvenTreePart) { | ||||
|   | ||||
| @@ -4,10 +4,12 @@ import "package:font_awesome_flutter/font_awesome_flutter.dart"; | ||||
|  | ||||
| import "package:inventree/api.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/inventree/bom.dart"; | ||||
| import "package:inventree/inventree/part.dart"; | ||||
| import "package:inventree/inventree/stock.dart"; | ||||
|  | ||||
| import "package:inventree/widget/attachment_widget.dart"; | ||||
| import "package:inventree/widget/bom_list.dart"; | ||||
| @@ -49,6 +51,8 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> { | ||||
|  | ||||
|   int bomCount = 0; | ||||
|  | ||||
|   int usedInCount = 0; | ||||
|  | ||||
|   int variantCount = 0; | ||||
|  | ||||
|   @override | ||||
| @@ -154,6 +158,19 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> { | ||||
|       } | ||||
|     }); | ||||
|  | ||||
|     // Request number of "used in" parts | ||||
|     InvenTreeBomItem().count( | ||||
|       filters: { | ||||
|         "uses": part.pk.toString(), | ||||
|       } | ||||
|     ).then((int value) { | ||||
|       if (mounted) { | ||||
|         setState(() { | ||||
|           usedInCount = value; | ||||
|         }); | ||||
|       } | ||||
|     }); | ||||
|  | ||||
|     // Request the number of variant items | ||||
|     InvenTreePart().count( | ||||
|       filters: { | ||||
| @@ -415,6 +432,27 @@ class _PartDisplayState extends RefreshableState<PartDetailWidget> { | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     if (part.isComponent) { | ||||
|       if (usedInCount > 0) { | ||||
|         tiles.add( | ||||
|           ListTile( | ||||
|             title: Text(L10().usedIn), | ||||
|             subtitle: Text(L10().usedInDetails), | ||||
|             leading: FaIcon(FontAwesomeIcons.layerGroup, color: COLOR_CLICK), | ||||
|             trailing: Text(usedInCount.toString()), | ||||
|               onTap: () { | ||||
|                 Navigator.push( | ||||
|                     context, | ||||
|                     MaterialPageRoute( | ||||
|                         builder: (context) => BillOfMaterialsWidget(part, isParentComponent: false) | ||||
|                     ) | ||||
|                 ); | ||||
|               } | ||||
|           ) | ||||
|         ); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     // Keywords? | ||||
|     if (part.keywords.isNotEmpty) { | ||||
|       tiles.add( | ||||
|   | ||||
		Reference in New Issue
	
	Block a user