mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-31 05:05:42 +00:00 
			
		
		
		
	StockItem Serialization Improvements (#9968)
* Add "serialize" form to build output table * Fix dependencies for useGenerator hook * Improve serializing of stock - Copy test results - Ensure fields get copied across * Fix rendering for StockItemTestResultTable * Enhanced playwright test * Fix code * Fix for unit test
This commit is contained in:
		| @@ -26,12 +26,14 @@ from mptt.managers import TreeManager | ||||
| from mptt.models import MPTTModel, TreeForeignKey | ||||
| from taggit.managers import TaggableManager | ||||
|  | ||||
| import build.models | ||||
| import common.models | ||||
| import InvenTree.exceptions | ||||
| import InvenTree.helpers | ||||
| import InvenTree.models | ||||
| import InvenTree.ready | ||||
| import InvenTree.tasks | ||||
| import order.models | ||||
| import report.mixins | ||||
| import stock.tasks | ||||
| from common.icons import validate_icon | ||||
| @@ -556,24 +558,51 @@ class StockItem( | ||||
|         kwargs.pop('id', None) | ||||
|         kwargs.pop('pk', None) | ||||
|  | ||||
|         part = kwargs.get('part') | ||||
|  | ||||
|         if not part: | ||||
|             raise ValidationError({'part': _('Part must be specified')}) | ||||
|  | ||||
|         # Create a list of StockItem objects | ||||
|         items = [] | ||||
|  | ||||
|         # Provide some default field values | ||||
|         data = {**kwargs} | ||||
|  | ||||
|         # Remove some extraneous keys which cause issues | ||||
|         for key in ['parent_id', 'part_id', 'build_id']: | ||||
|             data.pop(key, None) | ||||
|         # Extract foreign-key fields from the provided data | ||||
|         fk_relations = { | ||||
|             'parent': StockItem, | ||||
|             'part': PartModels.Part, | ||||
|             'build': build.models.Build, | ||||
|             'purchase_order': order.models.PurchaseOrder, | ||||
|             'supplier_part': CompanyModels.SupplierPart, | ||||
|             'location': StockLocation, | ||||
|             'belongs_to': StockItem, | ||||
|             'customer': CompanyModels.Company, | ||||
|             'consumed_by': build.models.Build, | ||||
|             'sales_order': order.models.SalesOrder, | ||||
|         } | ||||
|  | ||||
|         for field, model in fk_relations.items(): | ||||
|             if instance_id := data.pop(f'{field}_id', None): | ||||
|                 try: | ||||
|                     instance = model.objects.get(pk=instance_id) | ||||
|                     data[field] = instance | ||||
|                 except (ValueError, model.DoesNotExist): | ||||
|                     raise ValidationError({field: _(f'{field} does not exist')}) | ||||
|  | ||||
|         # Remove some fields which we do not want copied across | ||||
|         for field in [ | ||||
|             'barcode_data', | ||||
|             'barcode_hash', | ||||
|             'stocktake_date', | ||||
|             'stocktake_user', | ||||
|             'stocktake_user_id', | ||||
|         ]: | ||||
|             data.pop(field, None) | ||||
|  | ||||
|         if 'part' not in data: | ||||
|             raise ValidationError({'part': _('Part must be specified')}) | ||||
|  | ||||
|         part = data['part'] | ||||
|         tree_id = kwargs.pop('tree_id', 0) | ||||
|  | ||||
|         data['parent'] = kwargs.pop('parent', None) | ||||
|         data['parent'] = kwargs.pop('parent', None) or data.get('parent') | ||||
|         data['tree_id'] = tree_id | ||||
|         data['level'] = kwargs.pop('level', 0) | ||||
|         data['rght'] = kwargs.pop('rght', 0) | ||||
| @@ -586,6 +615,7 @@ class StockItem( | ||||
|             data['serial'] = serial | ||||
|             data['serial_int'] = StockItem.convert_serial_to_int(serial) | ||||
|  | ||||
|             # Construct a new StockItem from the provided dict | ||||
|             items.append(StockItem(**data)) | ||||
|  | ||||
|         # Create the StockItem objects in bulk | ||||
| @@ -1786,7 +1816,7 @@ class StockItem( | ||||
|         if location: | ||||
|             data['location'] = location | ||||
|  | ||||
|         data['part'] = self.part | ||||
|         # Set the parent ID correctly | ||||
|         data['parent'] = self | ||||
|         data['tree_id'] = self.tree_id | ||||
|  | ||||
| @@ -1797,6 +1827,7 @@ class StockItem( | ||||
|         history_items = [] | ||||
|  | ||||
|         for item in items: | ||||
|             # Construct a tracking entry for the new StockItem | ||||
|             if entry := item.add_tracking_entry( | ||||
|                 StockHistoryCode.ASSIGNED_SERIAL, | ||||
|                 user, | ||||
| @@ -1807,20 +1838,11 @@ class StockItem( | ||||
|             ): | ||||
|                 history_items.append(entry) | ||||
|  | ||||
|             # Copy any test results from this item to the new one | ||||
|             item.copyTestResultsFrom(self) | ||||
|  | ||||
|         StockItemTracking.objects.bulk_create(history_items) | ||||
|  | ||||
|         # Duplicate test results | ||||
|         test_results = [] | ||||
|  | ||||
|         for test_result in self.test_results.all(): | ||||
|             for item in items: | ||||
|                 test_result.pk = None | ||||
|                 test_result.stock_item = item | ||||
|  | ||||
|                 test_results.append(test_result) | ||||
|  | ||||
|         StockItemTestResult.objects.bulk_create(test_results) | ||||
|  | ||||
|         # Remove the equivalent number of items | ||||
|         self.take_stock(quantity, user, notes=notes) | ||||
|  | ||||
| @@ -1835,17 +1857,24 @@ class StockItem( | ||||
|             item.save() | ||||
|  | ||||
|     @transaction.atomic | ||||
|     def copyTestResultsFrom(self, other, filters=None): | ||||
|     def copyTestResultsFrom(self, other: StockItem, filters: Optional[dict] = None): | ||||
|         """Copy all test results from another StockItem.""" | ||||
|         # Set default - see B006 | ||||
|         if filters is None: | ||||
|             filters = {} | ||||
|  | ||||
|         for result in other.test_results.all().filter(**filters): | ||||
|         results = other.test_results.all() | ||||
|  | ||||
|         if filters: | ||||
|             results = results.filter(**filters) | ||||
|  | ||||
|         results_to_create = [] | ||||
|  | ||||
|         for result in list(results): | ||||
|             # Create a copy of the test result by nulling-out the pk | ||||
|             result.pk = None | ||||
|             result.stock_item = self | ||||
|             result.save() | ||||
|             results_to_create.append(result) | ||||
|  | ||||
|         StockItemTestResult.objects.bulk_create(results_to_create) | ||||
|  | ||||
|     def add_test_result(self, create_template=True, **kwargs): | ||||
|         """Helper function to add a new StockItemTestResult. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user