mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Adds simply endpoint for BOM duplication
This commit is contained in:
parent
09777c5764
commit
0c8a047bc2
@ -454,6 +454,26 @@ class PartSerialNumberDetail(generics.RetrieveAPIView):
|
||||
return Response(data)
|
||||
|
||||
|
||||
class PartCopyBOM(generics.CreateAPIView):
|
||||
"""
|
||||
API endpoint for duplicating a BOM
|
||||
"""
|
||||
|
||||
queryset = Part.objects.all()
|
||||
serializer_class = part_serializers.PartCopyBOMSerializer
|
||||
|
||||
def get_serializer_context(self):
|
||||
|
||||
ctx = super().get_serializer_context()
|
||||
|
||||
try:
|
||||
ctx['part'] = Part.objects.get(pk=self.kwargs.get('pk', None))
|
||||
except:
|
||||
pass
|
||||
|
||||
return ctx
|
||||
|
||||
|
||||
class PartDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||
""" API endpoint for detail view of a single Part object """
|
||||
|
||||
@ -1585,6 +1605,9 @@ part_api_urls = [
|
||||
# Endpoint for extra serial number information
|
||||
url(r'^serial-numbers/', PartSerialNumberDetail.as_view(), name='api-part-serial-number-detail'),
|
||||
|
||||
# Endpoint for duplicating a BOM
|
||||
url(r'^copy-bom/', PartCopyBOM.as_view(), name='api-part-copy-bom'),
|
||||
|
||||
# Part detail endpoint
|
||||
url(r'^.*$', PartDetail.as_view(), name='api-part-detail'),
|
||||
])),
|
||||
|
@ -55,39 +55,6 @@ class PartImageDownloadForm(HelperForm):
|
||||
]
|
||||
|
||||
|
||||
class BomDuplicateForm(HelperForm):
|
||||
"""
|
||||
Simple confirmation form for BOM duplication.
|
||||
|
||||
Select which parent to select from.
|
||||
"""
|
||||
|
||||
parent = PartModelChoiceField(
|
||||
label=_('Parent Part'),
|
||||
help_text=_('Select parent part to copy BOM from'),
|
||||
queryset=Part.objects.filter(is_template=True),
|
||||
)
|
||||
|
||||
clear = forms.BooleanField(
|
||||
required=False, initial=True,
|
||||
help_text=_('Clear existing BOM items')
|
||||
)
|
||||
|
||||
confirm = forms.BooleanField(
|
||||
required=False, initial=False,
|
||||
label=_('Confirm'),
|
||||
help_text=_('Confirm BOM duplication')
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Part
|
||||
fields = [
|
||||
'parent',
|
||||
'clear',
|
||||
'confirm',
|
||||
]
|
||||
|
||||
|
||||
class BomValidateForm(HelperForm):
|
||||
""" Simple confirmation form for BOM validation.
|
||||
User is presented with a single checkbox input,
|
||||
|
@ -9,6 +9,7 @@ from django.urls import reverse_lazy
|
||||
from django.db import models
|
||||
from django.db.models import Q
|
||||
from django.db.models.functions import Coalesce
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from rest_framework import serializers
|
||||
from sql_util.utils import SubqueryCount, SubquerySum
|
||||
@ -636,3 +637,53 @@ class CategoryParameterTemplateSerializer(InvenTreeModelSerializer):
|
||||
'parameter_template',
|
||||
'default_value',
|
||||
]
|
||||
|
||||
|
||||
class PartCopyBOMSerializer(serializers.Serializer):
|
||||
"""
|
||||
Serializer for copying a BOM from another part
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
fields = [
|
||||
'part',
|
||||
'remove_existing',
|
||||
]
|
||||
|
||||
part = serializers.PrimaryKeyRelatedField(
|
||||
queryset=Part.objects.all(),
|
||||
many=False,
|
||||
required=True,
|
||||
allow_null=False,
|
||||
label=_('Part'),
|
||||
help_text=_('Select part to copy BOM from'),
|
||||
)
|
||||
|
||||
def validate_part(self, part):
|
||||
"""
|
||||
Check that a 'valid' part was selected
|
||||
"""
|
||||
|
||||
# Check if the BOM can be copied from the provided part
|
||||
base_part = self.context['part']
|
||||
|
||||
return part
|
||||
|
||||
remove_existing = serializers.BooleanField(
|
||||
label=_('Remove Existing Data'),
|
||||
help_text=_('Remove existing BOM items before copying')
|
||||
)
|
||||
|
||||
def save(self):
|
||||
"""
|
||||
Actually duplicate the BOM
|
||||
"""
|
||||
|
||||
base_part = self.context['part']
|
||||
|
||||
data = self.validated_data
|
||||
|
||||
part = data['part']
|
||||
clear = data.get('remove_existing', True)
|
||||
|
||||
base_part.copy_bom_from(part, clear=clear)
|
||||
|
@ -1,17 +0,0 @@
|
||||
{% extends "modal_form.html" %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block pre_form_content %}
|
||||
|
||||
<p>
|
||||
{% trans "Select parent part to copy BOM from" %}
|
||||
</p>
|
||||
|
||||
{% if part.has_bom %}
|
||||
<div class='alert alert-block alert-danger'>
|
||||
<strong>{% trans "Warning" %}</strong><br>
|
||||
{% trans "This part already has a Bill of Materials" %}<br>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% endblock %}
|
@ -580,14 +580,10 @@
|
||||
});
|
||||
|
||||
$('#bom-duplicate').click(function() {
|
||||
launchModalForm(
|
||||
"{% url 'duplicate-bom' part.id %}",
|
||||
{
|
||||
success: function() {
|
||||
$('#bom-table').bootstrapTable('refresh');
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
duplicateBom({{ part.pk }}, {
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
$("#bom-item-new").click(function () {
|
||||
|
@ -40,7 +40,6 @@ part_detail_urls = [
|
||||
url(r'^pricing/', views.PartPricing.as_view(), name='part-pricing'),
|
||||
|
||||
url(r'^bom-upload/?', views.BomUpload.as_view(), name='upload-bom'),
|
||||
url(r'^bom-duplicate/?', views.BomDuplicate.as_view(), name='duplicate-bom'),
|
||||
|
||||
url(r'^qr_code/?', views.PartQRCode.as_view(), name='part-qr'),
|
||||
|
||||
|
@ -694,58 +694,6 @@ class PartImageSelect(AjaxUpdateView):
|
||||
return self.renderJsonResponse(request, form, data)
|
||||
|
||||
|
||||
class BomDuplicate(AjaxUpdateView):
|
||||
"""
|
||||
View for duplicating BOM from a parent item.
|
||||
"""
|
||||
|
||||
model = Part
|
||||
context_object_name = 'part'
|
||||
ajax_form_title = _('Duplicate BOM')
|
||||
ajax_template_name = 'part/bom_duplicate.html'
|
||||
form_class = part_forms.BomDuplicateForm
|
||||
|
||||
def get_form(self):
|
||||
|
||||
form = super().get_form()
|
||||
|
||||
# Limit choices to parents of the current part
|
||||
parents = self.get_object().get_ancestors()
|
||||
|
||||
form.fields['parent'].queryset = parents
|
||||
|
||||
return form
|
||||
|
||||
def get_initial(self):
|
||||
initials = super().get_initial()
|
||||
|
||||
parents = self.get_object().get_ancestors()
|
||||
|
||||
if parents.count() == 1:
|
||||
initials['parent'] = parents[0]
|
||||
|
||||
return initials
|
||||
|
||||
def validate(self, part, form):
|
||||
|
||||
confirm = str2bool(form.cleaned_data.get('confirm', False))
|
||||
|
||||
if not confirm:
|
||||
form.add_error('confirm', _('Confirm duplication of BOM from parent'))
|
||||
|
||||
def save(self, part, form):
|
||||
"""
|
||||
Duplicate BOM from the specified parent
|
||||
"""
|
||||
|
||||
parent = form.cleaned_data.get('parent', None)
|
||||
|
||||
clear = str2bool(form.cleaned_data.get('clear', True))
|
||||
|
||||
if parent:
|
||||
part.copy_bom_from(parent, clear=clear)
|
||||
|
||||
|
||||
class BomValidate(AjaxUpdateView):
|
||||
"""
|
||||
Modal form view for validating a part BOM
|
||||
|
@ -21,6 +21,7 @@
|
||||
*/
|
||||
|
||||
/* exported
|
||||
duplicateBom,
|
||||
duplicatePart,
|
||||
editCategory,
|
||||
editPart,
|
||||
@ -428,6 +429,29 @@ function toggleStar(options) {
|
||||
}
|
||||
|
||||
|
||||
/* Duplicate a BOM */
|
||||
function duplicateBom(part_id, options={}) {
|
||||
constructForm(`/api/part/${part_id}/copy-bom/`, {
|
||||
method: 'POST',
|
||||
fields: {
|
||||
part: {
|
||||
icon: 'fa-shapes',
|
||||
filters: {
|
||||
assembly: true,
|
||||
ancestor: part_id,
|
||||
}
|
||||
},
|
||||
remove_existing: {
|
||||
value: true,
|
||||
},
|
||||
},
|
||||
confirm: true,
|
||||
title: '{% trans "Copy Bill of Materials" %}',
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
function partStockLabel(part, options={}) {
|
||||
|
||||
if (part.in_stock) {
|
||||
|
Loading…
Reference in New Issue
Block a user