diff --git a/InvenTree/InvenTree/views.py b/InvenTree/InvenTree/views.py index b837b3da59..ed07318e28 100644 --- a/InvenTree/InvenTree/views.py +++ b/InvenTree/InvenTree/views.py @@ -116,7 +116,7 @@ class AjaxMixin(object): """ return {} - def renderJsonResponse(self, request, form=None, data={}, context={}): + def renderJsonResponse(self, request, form=None, data={}, context=None): """ Render a JSON response based on specific class context. Args: @@ -129,6 +129,12 @@ class AjaxMixin(object): JSON response object """ + if context is None: + try: + context = self.get_context_data() + except AttributeError: + context = {} + if form: context['form'] = form diff --git a/InvenTree/part/forms.py b/InvenTree/part/forms.py index 2256f28210..580ed737a4 100644 --- a/InvenTree/part/forms.py +++ b/InvenTree/part/forms.py @@ -75,11 +75,20 @@ class EditPartAttachmentForm(HelperForm): class EditPartForm(HelperForm): """ Form for editing a Part object """ - confirm_creation = forms.BooleanField(required=False, initial=False, help_text='Confirm part creation', widget=forms.HiddenInput()) + deep_copy = forms.BooleanField(required=False, + initial=True, + help_text="Perform 'deep copy' which will duplicate all BOM data for this part", + widget=forms.HiddenInput()) + + confirm_creation = forms.BooleanField(required=False, + initial=False, + help_text='Confirm part creation', + widget=forms.HiddenInput()) class Meta: model = Part fields = [ + 'deep_copy', 'confirm_creation', 'category', 'name', diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index d119c3094e..5a609c0e59 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -16,6 +16,7 @@ from django.core.exceptions import ValidationError from django.urls import reverse from django.conf import settings +from django.core.files.base import ContentFile from django.db import models, transaction from django.core.validators import MinValueValidator @@ -533,6 +534,33 @@ class Part(models.Model): """ Return the number of supplier parts available for this part """ return self.supplier_parts.count() + def deepCopy(self, other, **kwargs): + """ Duplicates non-field data from another part. + Does not alter the normal fields of this part, + but can be used to copy other data linked by ForeignKey refernce. + + Keyword Args: + image: If True, copies Part image (default = True) + bom: If True, copies BOM data (default = False) + """ + + # Copy the part image + if kwargs.get('image', True): + image_file = ContentFile(other.image.read()) + image_file.name = rename_part_image(self, 'test.png') + + self.image = image_file + + # Copy the BOM data + if kwargs.get('bom', False): + for item in other.bom_items.all(): + # Point the item to THIS part + item.part = self + item.pk = None + item.save() + + self.save() + def export_bom(self, **kwargs): data = tablib.Dataset(headers=[ diff --git a/InvenTree/part/templates/part/copy_part.html b/InvenTree/part/templates/part/copy_part.html new file mode 100644 index 0000000000..3abf0c5d54 --- /dev/null +++ b/InvenTree/part/templates/part/copy_part.html @@ -0,0 +1,24 @@ +{% extends "modal_form.html" %} + +{% block pre_form_content %} + +{{ block.super }} + +
+ Duplicate Part
+ Make a copy of part '{{ part.full_name }}'. +
+ +{% if matches %} +Possible Matching Parts +

The new part may be a duplicate of these existing parts:

+ +{% endif %} + +{% endblock %} \ No newline at end of file diff --git a/InvenTree/part/templates/part/detail.html b/InvenTree/part/templates/part/detail.html index ddb0523a83..c352bfa7ee 100644 --- a/InvenTree/part/templates/part/detail.html +++ b/InvenTree/part/templates/part/detail.html @@ -14,8 +14,8 @@