mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Functional checkpoint: add/delete related parts from template
This commit is contained in:
parent
8579abb9c2
commit
34e4409e7f
@ -1254,25 +1254,32 @@ class Part(MPTTModel):
|
|||||||
|
|
||||||
return self.get_descendants(include_self=False)
|
return self.get_descendants(include_self=False)
|
||||||
|
|
||||||
def fetch_related_parts(self):
|
def get_related_parts(self):
|
||||||
""" Return all related parts """
|
""" Return list of tuples for all related parts:
|
||||||
|
- first value is PartRelated object
|
||||||
|
- second value is matching Part object
|
||||||
|
"""
|
||||||
|
|
||||||
related_parts = []
|
related_parts = []
|
||||||
|
|
||||||
parts_1 = self.related_parts_1.filter(part_1__id=self.pk)
|
related_parts_1 = self.related_parts_1.filter(part_1__id=self.pk)
|
||||||
|
|
||||||
parts_2 = self.related_parts_2.filter(part_2__id=self.pk)
|
related_parts_2 = self.related_parts_2.filter(part_2__id=self.pk)
|
||||||
|
|
||||||
for part in parts_1:
|
for related_part in related_parts_1:
|
||||||
# Append
|
# Add to related parts list
|
||||||
related_parts.append(part.part_2)
|
related_parts.append((related_part, related_part.part_2))
|
||||||
|
|
||||||
for part in parts_2:
|
for related_part in related_parts_2:
|
||||||
# Append
|
# Add to related parts list
|
||||||
related_parts.append(part.part_1)
|
related_parts.append((related_part, related_part.part_1))
|
||||||
|
|
||||||
return related_parts
|
return related_parts
|
||||||
|
|
||||||
|
@property
|
||||||
|
def related_count(self):
|
||||||
|
return len(self.get_related_parts())
|
||||||
|
|
||||||
|
|
||||||
def attach_file(instance, filename):
|
def attach_file(instance, filename):
|
||||||
""" Function for storing a file for a PartAttachment
|
""" Function for storing a file for a PartAttachment
|
||||||
@ -1783,7 +1790,8 @@ class PartRelated(models.Model):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls, part_1, part_2):
|
def create(cls, part_1, part_2):
|
||||||
''' Create PartRelated object '''
|
''' Create PartRelated object and relationship between two parts '''
|
||||||
|
|
||||||
related_part = cls()
|
related_part = cls()
|
||||||
related_part.create_relationship(part_1, part_2)
|
related_part.create_relationship(part_1, part_2)
|
||||||
return related_part
|
return related_part
|
||||||
|
@ -18,7 +18,32 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table class='table table-striped table-condensed related-table' id='table-related-part' data-toolbar='#button-bar'>
|
<table id='table-related-part' class='table table-condensed table-striped' data-toolbar='#button-toolbar'>
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th data-field='part' data-serachable='true'>{% trans "Part" %}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for item in part.get_related_parts %}
|
||||||
|
{% with part_related=item.0 part=item.1 %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<a class='hover-icon'>
|
||||||
|
<img class='hover-img-thumb' src='{{ part.get_thumbnail_url }}'>
|
||||||
|
<img class='hover-img-large' src='{{ part.get_thumbnail_url }}'>
|
||||||
|
</a>
|
||||||
|
<a href='/part/{{ part.id }}/'>{{ part }}</a>
|
||||||
|
<div class='btn-group' style='float: right;'>
|
||||||
|
{% if roles.part.change %}
|
||||||
|
<button title='{% trans "Delete" %}' class='btn btn-default btn-glyph delete-related-part' url="{% url 'part-related-delete' part_related.id %}" type='button'><span class='fas fa-trash-alt icon-red'/></button>
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endwith %}
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
|
||||||
@ -27,20 +52,24 @@
|
|||||||
{% block js_ready %}
|
{% block js_ready %}
|
||||||
{{ block.super }}
|
{{ block.super }}
|
||||||
|
|
||||||
loadPartRelatedTable($("#table-related-part"), {
|
$('#table-related-part').inventreeTable({
|
||||||
url: "{% url 'api-part-list' %}",
|
});
|
||||||
params: {
|
|
||||||
part: {{ part.id }},
|
$("#add-related-part").click(function() {
|
||||||
},
|
launchModalForm("{% url 'part-related-create' %}", {
|
||||||
});
|
data: {
|
||||||
|
part: {{ part.id }},
|
||||||
$("#add-related-part").click(function() {
|
},
|
||||||
launchModalForm("{% url 'part-related-create' %}", {
|
reload: true,
|
||||||
data: {
|
});
|
||||||
part: {{ part.id }},
|
});
|
||||||
},
|
|
||||||
reload: true,
|
$('.delete-related-part').click(function() {
|
||||||
|
var button = $(this);
|
||||||
|
|
||||||
|
launchModalForm(button.attr('url'), {
|
||||||
|
reload: true,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
@ -64,7 +64,7 @@
|
|||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<li{% ifequal tab 'related-parts' %} class="active"{% endifequal %}>
|
<li{% ifequal tab 'related-parts' %} class="active"{% endifequal %}>
|
||||||
<a href="{% url 'part-related' part.id %}">{% trans "Related Parts" %} {% if part.related_count > 0 %}<span class="badge">{{ part.related_count }}</span>{% endif %}</a>
|
<a href="{% url 'part-related' part.id %}">{% trans "Related" %} {% if part.related_count > 0 %}<span class="badge">{{ part.related_count }}</span>{% endif %}</a>
|
||||||
</li>
|
</li>
|
||||||
<li{% ifequal tab 'attachments' %} class="active"{% endifequal %}>
|
<li{% ifequal tab 'attachments' %} class="active"{% endifequal %}>
|
||||||
<a href="{% url 'part-attachments' part.id %}">{% trans "Attachments" %} {% if part.attachment_count > 0 %}<span class="badge">{{ part.attachment_count }}</span>{% endif %}</a>
|
<a href="{% url 'part-attachments' part.id %}">{% trans "Attachments" %} {% if part.attachment_count > 0 %}<span class="badge">{{ part.attachment_count }}</span>{% endif %}</a>
|
||||||
|
@ -81,10 +81,8 @@ class PartRelatedCreate(AjaxCreateView):
|
|||||||
ajax_template_name = "modal_form.html"
|
ajax_template_name = "modal_form.html"
|
||||||
role_required = 'part.change'
|
role_required = 'part.change'
|
||||||
|
|
||||||
# TODO: QuerySet should not show parts already related to object
|
|
||||||
|
|
||||||
def get_initial(self):
|
def get_initial(self):
|
||||||
""" Point part_1 to parent part """
|
""" Set parent part as part_1 field """
|
||||||
|
|
||||||
initials = {}
|
initials = {}
|
||||||
|
|
||||||
@ -102,12 +100,30 @@ class PartRelatedCreate(AjaxCreateView):
|
|||||||
""" Create a form to upload a new PartRelated
|
""" Create a form to upload a new PartRelated
|
||||||
|
|
||||||
- Hide the 'part_1' field (parent part)
|
- Hide the 'part_1' field (parent part)
|
||||||
|
- Display parts which are not yet related
|
||||||
"""
|
"""
|
||||||
|
|
||||||
form = super(AjaxCreateView, self).get_form()
|
form = super(AjaxCreateView, self).get_form()
|
||||||
|
|
||||||
form.fields['part_1'].widget = HiddenInput()
|
form.fields['part_1'].widget = HiddenInput()
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Get parent part
|
||||||
|
parent_part = self.get_initial()['part_1']
|
||||||
|
# Get existing related parts
|
||||||
|
related_parts = [related_part[1].pk for related_part in parent_part.get_related_parts()]
|
||||||
|
|
||||||
|
# Build updated choice list excluding parts already related to parent part
|
||||||
|
updated_choices = []
|
||||||
|
for choice in form.fields["part_2"].choices:
|
||||||
|
if choice[0] not in related_parts:
|
||||||
|
updated_choices.append(choice)
|
||||||
|
|
||||||
|
# Update choices for related part
|
||||||
|
form.fields['part_2'].choices = updated_choices
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
return form
|
return form
|
||||||
|
|
||||||
def post_save(self):
|
def post_save(self):
|
||||||
@ -116,14 +132,9 @@ class PartRelatedCreate(AjaxCreateView):
|
|||||||
form = self.get_form()
|
form = self.get_form()
|
||||||
|
|
||||||
if form.is_valid():
|
if form.is_valid():
|
||||||
print('form is valid!')
|
|
||||||
|
|
||||||
part_1 = form.cleaned_data['part_1']
|
part_1 = form.cleaned_data['part_1']
|
||||||
part_2 = form.cleaned_data['part_2']
|
part_2 = form.cleaned_data['part_2']
|
||||||
|
|
||||||
print(f'{part_1=}')
|
|
||||||
print(f'{part_2=}')
|
|
||||||
|
|
||||||
PartRelated.create(part_1, part_2)
|
PartRelated.create(part_1, part_2)
|
||||||
|
|
||||||
|
|
||||||
@ -132,7 +143,6 @@ class PartRelatedDelete(AjaxDeleteView):
|
|||||||
|
|
||||||
model = PartRelated
|
model = PartRelated
|
||||||
ajax_form_title = _("Delete Related Part")
|
ajax_form_title = _("Delete Related Part")
|
||||||
ajax_template_name = "related_delete.html"
|
|
||||||
context_object_name = "related"
|
context_object_name = "related"
|
||||||
role_required = 'part.change'
|
role_required = 'part.change'
|
||||||
|
|
||||||
|
@ -163,41 +163,6 @@ function loadSimplePartTable(table, url, options={}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function loadPartRelatedTable(table, options={}) {
|
|
||||||
/* Load related parts table */
|
|
||||||
|
|
||||||
var columns = [
|
|
||||||
{
|
|
||||||
field: options.params['part'],
|
|
||||||
title: '{% trans 'Part' %}',
|
|
||||||
sortable: true,
|
|
||||||
sortName: 'name',
|
|
||||||
formatter: function(value, row, index, field) {
|
|
||||||
|
|
||||||
var name = '';
|
|
||||||
|
|
||||||
if (row.IPN) {
|
|
||||||
name += row.IPN + ' | ' + row.name;
|
|
||||||
} else {
|
|
||||||
name += row.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
return renderLink(name, '/part/' + row.pk + '/');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
$(table).inventreeTable({
|
|
||||||
sortName: 'part',
|
|
||||||
groupBy: false,
|
|
||||||
name: options.name || 'related_parts',
|
|
||||||
formatNoMatches: function() { return "{% trans "No parts found" %}"; },
|
|
||||||
columns: columns,
|
|
||||||
showColumns: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function loadParametricPartTable(table, options={}) {
|
function loadParametricPartTable(table, options={}) {
|
||||||
/* Load parametric table for part parameters
|
/* Load parametric table for part parameters
|
||||||
*
|
*
|
||||||
|
Loading…
Reference in New Issue
Block a user