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)
|
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):
|
class PartDetail(generics.RetrieveUpdateDestroyAPIView):
|
||||||
""" API endpoint for detail view of a single Part object """
|
""" API endpoint for detail view of a single Part object """
|
||||||
|
|
||||||
@ -1585,6 +1605,9 @@ part_api_urls = [
|
|||||||
# Endpoint for extra serial number information
|
# Endpoint for extra serial number information
|
||||||
url(r'^serial-numbers/', PartSerialNumberDetail.as_view(), name='api-part-serial-number-detail'),
|
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
|
# Part detail endpoint
|
||||||
url(r'^.*$', PartDetail.as_view(), name='api-part-detail'),
|
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):
|
class BomValidateForm(HelperForm):
|
||||||
""" Simple confirmation form for BOM validation.
|
""" Simple confirmation form for BOM validation.
|
||||||
User is presented with a single checkbox input,
|
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 import models
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.db.models.functions import Coalesce
|
from django.db.models.functions import Coalesce
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from sql_util.utils import SubqueryCount, SubquerySum
|
from sql_util.utils import SubqueryCount, SubquerySum
|
||||||
@ -636,3 +637,53 @@ class CategoryParameterTemplateSerializer(InvenTreeModelSerializer):
|
|||||||
'parameter_template',
|
'parameter_template',
|
||||||
'default_value',
|
'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() {
|
$('#bom-duplicate').click(function() {
|
||||||
launchModalForm(
|
|
||||||
"{% url 'duplicate-bom' part.id %}",
|
duplicateBom({{ part.pk }}, {
|
||||||
{
|
|
||||||
success: function() {
|
});
|
||||||
$('#bom-table').bootstrapTable('refresh');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#bom-item-new").click(function () {
|
$("#bom-item-new").click(function () {
|
||||||
|
@ -40,7 +40,6 @@ part_detail_urls = [
|
|||||||
url(r'^pricing/', views.PartPricing.as_view(), name='part-pricing'),
|
url(r'^pricing/', views.PartPricing.as_view(), name='part-pricing'),
|
||||||
|
|
||||||
url(r'^bom-upload/?', views.BomUpload.as_view(), name='upload-bom'),
|
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'),
|
url(r'^qr_code/?', views.PartQRCode.as_view(), name='part-qr'),
|
||||||
|
|
||||||
|
@ -694,58 +694,6 @@ class PartImageSelect(AjaxUpdateView):
|
|||||||
return self.renderJsonResponse(request, form, data)
|
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):
|
class BomValidate(AjaxUpdateView):
|
||||||
"""
|
"""
|
||||||
Modal form view for validating a part BOM
|
Modal form view for validating a part BOM
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* exported
|
/* exported
|
||||||
|
duplicateBom,
|
||||||
duplicatePart,
|
duplicatePart,
|
||||||
editCategory,
|
editCategory,
|
||||||
editPart,
|
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={}) {
|
function partStockLabel(part, options={}) {
|
||||||
|
|
||||||
if (part.in_stock) {
|
if (part.in_stock) {
|
||||||
|
Loading…
Reference in New Issue
Block a user