diff --git a/InvenTree/build/api.py b/InvenTree/build/api.py index 600f738982..733799f890 100644 --- a/InvenTree/build/api.py +++ b/InvenTree/build/api.py @@ -275,6 +275,7 @@ class BuildFinish(generics.CreateAPIView): return ctx + class BuildAllocate(generics.CreateAPIView): """ API endpoint to allocate stock items to a build order diff --git a/InvenTree/build/models.py b/InvenTree/build/models.py index 392c773e6b..f03cb30c74 100644 --- a/InvenTree/build/models.py +++ b/InvenTree/build/models.py @@ -555,7 +555,7 @@ class Build(MPTTModel, ReferenceIndexingMixin): if self.incomplete_count > 0: return False - if self.completed < self.quantity: + if self.remaining > 0: return False if not self.areUntrackedPartsFullyAllocated(): diff --git a/InvenTree/build/serializers.py b/InvenTree/build/serializers.py index 41b4f84009..55f89c1844 100644 --- a/InvenTree/build/serializers.py +++ b/InvenTree/build/serializers.py @@ -250,13 +250,35 @@ class BuildCompleteSerializer(serializers.Serializer): help_text=_('Accept that stock items have not been fully allocated to this build order'), ) + def validate_accept_unallocated(self, value): + + build = self.context['build'] + + if not build.areUntrackedPartsFullyAllocated() and not value: + raise ValidationError(_('Required stock has not been fully allocated')) + + return value + accept_incomplete = serializers.BooleanField( label=_('Accept Incomplete'), help_text=_('Accept that the required number of build outputs have not been completed'), ) + def validate_accept_incomplete(self, value): + + build = self.context['build'] + + if build.remaining > 0 and not value: + raise ValidationError(_('Required build quantity has not been completed')) + + return value + def save(self): - pass + + request = self.context['request'] + build = self.context['build'] + + build.complete_build(request.user) class BuildUnallocationSerializer(serializers.Serializer): diff --git a/InvenTree/build/templates/build/build_base.html b/InvenTree/build/templates/build/build_base.html index 48ef98b2b1..74cd1a9d96 100644 --- a/InvenTree/build/templates/build/build_base.html +++ b/InvenTree/build/templates/build/build_base.html @@ -224,6 +224,13 @@ src="{% static 'img/blank_image.png' %}" '{% trans "Build Order cannot be completed as incomplete build outputs remain" %}' ); {% else %} + + completeBuildOrder({{ build.pk }}, { + allocated: {% if build.areUntrackedPartsFullyAllocated %}true{% else %}false{% endif %}, + completed: {% if build.remaining == 0 %}true{% else %}false{% endif %}, + }); + + return; launchModalForm( "{% url 'build-complete' build.id %}", { diff --git a/InvenTree/templates/js/translated/build.js b/InvenTree/templates/js/translated/build.js index 0deec4f859..ebb37fa61c 100644 --- a/InvenTree/templates/js/translated/build.js +++ b/InvenTree/templates/js/translated/build.js @@ -20,6 +20,7 @@ /* exported allocateStockToBuild, + completeBuildOrder, editBuildOrder, loadAllocationTable, loadBuildOrderAllocationTable, @@ -120,6 +121,57 @@ function newBuildOrder(options={}) { } +/* Construct a form to "complete" (finish) a build order */ +function completeBuildOrder(build_id, options={}) { + + var url = `/api/build/${build_id}/finish/`; + + var fields = { + accept_unallocated: {}, + accept_incomplete: {}, + }; + + var html = ''; + + if (options.can_complete) { + + } else { + html += ` +