diff --git a/InvenTree/InvenTree/api_version.py b/InvenTree/InvenTree/api_version.py index 627433fe95..8e8855a837 100644 --- a/InvenTree/InvenTree/api_version.py +++ b/InvenTree/InvenTree/api_version.py @@ -2,11 +2,14 @@ # InvenTree API version -INVENTREE_API_VERSION = 113 +INVENTREE_API_VERSION = 115 """ Increment this API version number whenever there is a significant change to the API that any clients need to know about +v115 - > 2023-05-18 : https://github.com/inventree/InvenTree/pull/4846 + - Adds ability to partially scrap a build output + v114 -> 2023-05-16 : https://github.com/inventree/InvenTree/pull/4825 - Adds "delivery_date" to shipments diff --git a/InvenTree/build/models.py b/InvenTree/build/models.py index 5e32ab1f1b..ee9c01fcf3 100644 --- a/InvenTree/build/models.py +++ b/InvenTree/build/models.py @@ -797,7 +797,7 @@ class Build(MPTTModel, InvenTree.models.InvenTreeBarcodeMixin, InvenTree.models. items.all().delete() @transaction.atomic - def scrap_build_output(self, output, location, **kwargs): + def scrap_build_output(self, output, quantity, location, **kwargs): """Mark a particular build output as scrapped / rejected - Mark the output as "complete" @@ -809,10 +809,25 @@ class Build(MPTTModel, InvenTree.models.InvenTreeBarcodeMixin, InvenTree.models. if not output: raise ValidationError(_("No build output specified")) + if quantity <= 0: + raise ValidationError({ + 'quantity': _("Quantity must be greater than zero") + }) + + if quantity > output.quantity: + raise ValidationError({ + 'quantity': _("Quantity cannot be greater than the output quantity") + }) + user = kwargs.get('user', None) notes = kwargs.get('notes', '') discard_allocations = kwargs.get('discard_allocations', False) + if quantity < output.quantity: + # Split output into two items + output = output.splitStock(quantity, location=location, user=user) + output.build = self + # Update build output item output.is_building = False output.status = StockStatus.REJECTED diff --git a/InvenTree/build/serializers.py b/InvenTree/build/serializers.py index bba5f75757..e364a1eba8 100644 --- a/InvenTree/build/serializers.py +++ b/InvenTree/build/serializers.py @@ -17,7 +17,7 @@ import InvenTree.helpers from InvenTree.serializers import InvenTreeDecimalField from InvenTree.status_codes import StockStatus -from stock.models import StockItem, StockLocation +from stock.models import generate_batch_code, StockItem, StockLocation from stock.serializers import StockItemSerializerBrief, LocationSerializer from part.models import BomItem @@ -181,6 +181,45 @@ class BuildOutputSerializer(serializers.Serializer): return output +class BuildOutputQuantitySerializer(BuildOutputSerializer): + """Serializer for a single build output, with additional quantity field""" + + class Meta: + """Serializer metaclass""" + fields = BuildOutputSerializer.Meta.fields + [ + 'quantity', + ] + + quantity = serializers.DecimalField( + max_digits=15, + decimal_places=5, + min_value=0, + required=True, + label=_('Quantity'), + help_text=_('Enter quantity for build output'), + ) + + def validate(self, data): + """Validate the serializer data""" + + data = super().validate(data) + + output = data.get('output') + quantity = data.get('quantity') + + if quantity <= 0: + raise ValidationError({ + 'quantity': _('Quantity must be greater than zero') + }) + + if quantity > output.quantity: + raise ValidationError({ + 'quantity': _("Quantity cannot be greater than the output quantity") + }) + + return data + + class BuildOutputCreateSerializer(serializers.Serializer): """Serializer for creating a new BuildOutput against a BuildOrder. @@ -226,6 +265,7 @@ class BuildOutputCreateSerializer(serializers.Serializer): batch_code = serializers.CharField( required=False, allow_blank=True, + default=generate_batch_code, label=_('Batch Code'), help_text=_('Batch code for this build output'), ) @@ -362,7 +402,7 @@ class BuildOutputScrapSerializer(serializers.Serializer): 'notes', ] - outputs = BuildOutputSerializer( + outputs = BuildOutputQuantitySerializer( many=True, required=True, ) @@ -412,8 +452,10 @@ class BuildOutputScrapSerializer(serializers.Serializer): with transaction.atomic(): for item in outputs: output = item['output'] + quantity = item['quantity'] build.scrap_build_output( output, + quantity, data.get('location', None), user=request.user, notes=data.get('notes', ''), diff --git a/InvenTree/build/templates/build/detail.html b/InvenTree/build/templates/build/detail.html index 162263783a..95ae46c8eb 100644 --- a/InvenTree/build/templates/build/detail.html +++ b/InvenTree/build/templates/build/detail.html @@ -302,7 +302,7 @@
{% trans "Output" %} | +{% trans "Quantity" %} | @@ -701,11 +725,14 @@ function scrapBuildOutputs(build_id, outputs, options={}) { outputs.forEach(function(output) { let pk = output.pk; let row = $(opts.modal).find(`#output_row_${pk}`); + let quantity = getFormFieldValue(`outputs_quantity_${pk}`, {}, opts); if (row.exists()) { data.outputs.push({ output: pk, + quantity: quantity, }); + output_pk_values.push(pk); } }); diff --git a/InvenTree/templates/stock_table.html b/InvenTree/templates/stock_table.html index 26a7a5abea..fdbb284f8d 100644 --- a/InvenTree/templates/stock_table.html +++ b/InvenTree/templates/stock_table.html @@ -45,7 +45,7 @@ {% endif %} {% endif %} - {% include "filter_list.html" with id="stock" %} + {% include "filter_list.html" with prefix=prefix id="stock" %} |
---|