mirror of
				https://github.com/inventree/InvenTree.git
				synced 2025-10-30 20:55:42 +00:00 
			
		
		
		
	Delete a build output entirely
TODO: Needs to describe in the confirmation dialog what is going to happen!
This commit is contained in:
		| @@ -78,7 +78,7 @@ function getImageUrlFromTransfer(transfer) { | ||||
|     return url; | ||||
| } | ||||
|  | ||||
| function makeIconButton(icon, cls, pk, title) { | ||||
| function makeIconButton(icon, cls, pk, title, options={}) { | ||||
|     // Construct an 'icon button' using the fontawesome set | ||||
|  | ||||
|     var classes = `btn btn-default btn-glyph ${cls}`; | ||||
| @@ -86,8 +86,14 @@ function makeIconButton(icon, cls, pk, title) { | ||||
|     var id = `${cls}-${pk}`; | ||||
|  | ||||
|     var html = ''; | ||||
|  | ||||
|     var extraProps = ''; | ||||
|  | ||||
|     if (options.disabled) { | ||||
|         extraProps += "disabled='true' "; | ||||
|     } | ||||
|      | ||||
|     html += `<button pk='${pk}' id='${id}' class='${classes}' title='${title}'>`; | ||||
|     html += `<button pk='${pk}' id='${id}' class='${classes}' title='${title}' ${extraProps}>`; | ||||
|     html += `<span class='fas ${icon}'></span>`; | ||||
|     html += `</button>`; | ||||
|  | ||||
|   | ||||
| @@ -46,6 +46,29 @@ class EditBuildForm(HelperForm): | ||||
|         ] | ||||
|  | ||||
|  | ||||
| class BuildOutputDeleteForm(HelperForm): | ||||
|     """ | ||||
|     Form for deleting a build output. | ||||
|     """ | ||||
|  | ||||
|     confirm = forms.BooleanField( | ||||
|         required=False, | ||||
|         help_text=_('Confirm deletion of build output') | ||||
|     ) | ||||
|  | ||||
|     output_id = forms.IntegerField( | ||||
|         required=True, | ||||
|         widget=forms.HiddenInput() | ||||
|     ) | ||||
|  | ||||
|     class Meta: | ||||
|         model = Build | ||||
|         fields = [ | ||||
|             'confirm', | ||||
|             'output_id', | ||||
|         ] | ||||
|  | ||||
|  | ||||
| class UnallocateBuildForm(HelperForm): | ||||
|     """ | ||||
|     Form for auto-de-allocation of stock from a build | ||||
|   | ||||
| @@ -380,6 +380,29 @@ class Build(MPTTModel): | ||||
|         # Remove all the allocations | ||||
|         allocations.delete() | ||||
|  | ||||
|     def deleteBuildOutput(self, output): | ||||
|         """ | ||||
|         Remove a build output from the database: | ||||
|  | ||||
|         - Unallocate any build items against the output | ||||
|         - Delete the output StockItem | ||||
|         """ | ||||
|  | ||||
|         if not output: | ||||
|             raise ValidationError(_("No build output specified")) | ||||
|  | ||||
|         if not output.is_building: | ||||
|             raise ValidationError(_("Build output is already completed")) | ||||
|  | ||||
|         if not output.build == self: | ||||
|             raise ValidationError(_("Build output does not match Build Order")) | ||||
|  | ||||
|         # Unallocate all build items against the output | ||||
|         self.unallocateStock(output) | ||||
|  | ||||
|         # Remove the build output from the database | ||||
|         output.delete() | ||||
|  | ||||
|     @transaction.atomic | ||||
|     def autoAllocate(self): | ||||
|         """ Run auto-allocation routine to allocate StockItems to this Build. | ||||
|   | ||||
| @@ -11,6 +11,7 @@ build_detail_urls = [ | ||||
|     url(r'^allocate/', views.BuildAllocate.as_view(), name='build-allocate'), | ||||
|     url(r'^cancel/', views.BuildCancel.as_view(), name='build-cancel'), | ||||
|     url(r'^delete/', views.BuildDelete.as_view(), name='build-delete'), | ||||
|     url(r'^delete-output/', views.BuildOutputDelete.as_view(), name='build-output-delete'), | ||||
|     url(r'^complete/?', views.BuildComplete.as_view(), name='build-complete'), | ||||
|     url(r'^auto-allocate/?', views.BuildAutoAllocate.as_view(), name='build-auto-allocate'), | ||||
|     url(r'^unallocate/', views.BuildUnallocate.as_view(), name='build-unallocate'), | ||||
|   | ||||
| @@ -141,6 +141,56 @@ class BuildAutoAllocate(AjaxUpdateView): | ||||
|         return self.renderJsonResponse(request, form, data, context=self.get_context_data()) | ||||
|  | ||||
|  | ||||
| class BuildOutputDelete(AjaxUpdateView): | ||||
|     """ | ||||
|     Delete a build output (StockItem) for a given build. | ||||
|  | ||||
|     Form is a simple confirmation dialog | ||||
|     """ | ||||
|  | ||||
|     model = Build | ||||
|     form_class = forms.BuildOutputDeleteForm | ||||
|     ajax_form_title = _('Delete build output') | ||||
|     role_required = 'build.delete' | ||||
|  | ||||
|     def get_initial(self): | ||||
|  | ||||
|         initials = super().get_initial() | ||||
|  | ||||
|         output = self.get_param('output') | ||||
|  | ||||
|         initials['output_id'] = output | ||||
|  | ||||
|         return initials | ||||
|  | ||||
|     def post(self, request, *args, **kwargs): | ||||
|  | ||||
|         build = self.get_object() | ||||
|         form = self.get_form() | ||||
|  | ||||
|         confirm = request.POST.get('confirm', False) | ||||
|  | ||||
|         output_id = request.POST.get('output_id', None) | ||||
|  | ||||
|         try: | ||||
|             output = StockItem.objects.get(pk=output_id) | ||||
|         except (ValueError, StockItem.DoesNotExist): | ||||
|             output = None | ||||
|  | ||||
|         valid = False | ||||
|  | ||||
|         if output: | ||||
|             build.deleteBuildOutput(output) | ||||
|             valid = True | ||||
|         else: | ||||
|             form.non_field_errors = [_('Build or output not specified')] | ||||
|  | ||||
|         data = { | ||||
|             'form_valid': valid, | ||||
|         } | ||||
|  | ||||
|         return self.renderJsonResponse(request, form, data) | ||||
|  | ||||
| class BuildUnallocate(AjaxUpdateView): | ||||
|     """ View to un-allocate all parts from a build. | ||||
|  | ||||
| @@ -151,7 +201,7 @@ class BuildUnallocate(AjaxUpdateView): | ||||
|     form_class = forms.UnallocateBuildForm | ||||
|     ajax_form_title = _("Unallocate Stock") | ||||
|     ajax_template_name = "build/unallocate.html" | ||||
|     form_required = 'build.change' | ||||
|     role_required = 'build.change' | ||||
|  | ||||
|     def get_initial(self): | ||||
|  | ||||
| @@ -161,13 +211,7 @@ class BuildUnallocate(AjaxUpdateView): | ||||
|         output = self.get_param('output') | ||||
|  | ||||
|         if output: | ||||
|             try: | ||||
|                 output = StockItem.objects.get(pk=output) | ||||
|             except (ValueError, StockItem.DoesNotExist): | ||||
|                 output = None | ||||
|  | ||||
|         if output: | ||||
|             initials['output_id'] = output.pk | ||||
|             initials['output_id'] = output | ||||
|  | ||||
|         return initials | ||||
|  | ||||
|   | ||||
| @@ -954,7 +954,8 @@ class Part(MPTTModel): | ||||
|         return parts | ||||
|  | ||||
|     def get_allowed_bom_items(self): | ||||
|         """ Return a list of parts which can be added to a BOM for this part. | ||||
|         """ | ||||
|         Return a list of parts which can be added to a BOM for this part. | ||||
|  | ||||
|         - Exclude parts which are not 'component' parts | ||||
|         - Exclude parts which this part is in the BOM for | ||||
|   | ||||
| @@ -52,13 +52,19 @@ function makeBuildOutputActionButtons(output, buildId) { | ||||
|     // Add a button to "auto allocate" against the particular build output | ||||
|     html += makeIconButton( | ||||
|         'fa-clipboard-check icon-blue', 'button-output-auto', outputId, | ||||
|         '{% trans "Allocate stock items to this output" %}' | ||||
|         '{% trans "Allocate stock items to this output" %}', | ||||
|         { | ||||
|             disabled: true, | ||||
|         } | ||||
|     ); | ||||
|  | ||||
|     if (output.quantity > 1) { | ||||
|         html += makeIconButton( | ||||
|             'fa-random icon-blue', 'button-output-split', outputId, | ||||
|             '{% trans "Split build output into separate items" %}', | ||||
|             { | ||||
|                 disabled: true | ||||
|             } | ||||
|         ); | ||||
|     } | ||||
|  | ||||
| @@ -66,6 +72,9 @@ function makeBuildOutputActionButtons(output, buildId) { | ||||
|     html += makeIconButton( | ||||
|         'fa-tools icon-green', 'button-output-complete', outputId, | ||||
|         '{% trans "Complete build output" %}', | ||||
|         { | ||||
|             disabled: true | ||||
|         } | ||||
|     ); | ||||
|  | ||||
|     // Add a button to "cancel" the particular build output (unallocate) | ||||
| @@ -116,6 +125,17 @@ function makeBuildOutputActionButtons(output, buildId) { | ||||
|         ); | ||||
|     }); | ||||
|  | ||||
|     $(panel).find(`#button-output-delete-${outputId}`).click(function() { | ||||
|         launchModalForm( | ||||
|             `/build/${buildId}/delete-output/`, | ||||
|             { | ||||
|                 reload: true, | ||||
|                 data: { | ||||
|                     output: outputId | ||||
|                 } | ||||
|             } | ||||
|         ); | ||||
|     }); | ||||
| } | ||||
|  | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user