mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Refactor SupplierPartEdit and SupplierPartDelete forms
This commit is contained in:
parent
29d7cb40e1
commit
0c91691ed2
@ -6,13 +6,12 @@ Django Forms for interacting with Company app
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from InvenTree.forms import HelperForm
|
from InvenTree.forms import HelperForm
|
||||||
from InvenTree.fields import InvenTreeMoneyField, RoundingDecimalFormField
|
from InvenTree.fields import RoundingDecimalFormField
|
||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
import django.forms
|
import django.forms
|
||||||
|
|
||||||
from .models import Company
|
from .models import Company
|
||||||
from .models import SupplierPart
|
|
||||||
from .models import SupplierPriceBreak
|
from .models import SupplierPriceBreak
|
||||||
|
|
||||||
|
|
||||||
@ -34,67 +33,6 @@ class CompanyImageDownloadForm(HelperForm):
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
class EditSupplierPartForm(HelperForm):
|
|
||||||
""" Form for editing a SupplierPart object """
|
|
||||||
|
|
||||||
field_prefix = {
|
|
||||||
'link': 'fa-link',
|
|
||||||
'SKU': 'fa-hashtag',
|
|
||||||
'note': 'fa-pencil-alt',
|
|
||||||
}
|
|
||||||
|
|
||||||
single_pricing = InvenTreeMoneyField(
|
|
||||||
label=_('Single Price'),
|
|
||||||
help_text=_('Single quantity price'),
|
|
||||||
decimal_places=4,
|
|
||||||
max_digits=19,
|
|
||||||
required=False,
|
|
||||||
)
|
|
||||||
|
|
||||||
manufacturer = django.forms.ChoiceField(
|
|
||||||
required=False,
|
|
||||||
help_text=_('Select manufacturer'),
|
|
||||||
choices=[],
|
|
||||||
)
|
|
||||||
|
|
||||||
MPN = django.forms.CharField(
|
|
||||||
required=False,
|
|
||||||
help_text=_('Manufacturer Part Number'),
|
|
||||||
max_length=100,
|
|
||||||
label=_('MPN'),
|
|
||||||
)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = SupplierPart
|
|
||||||
fields = [
|
|
||||||
'part',
|
|
||||||
'supplier',
|
|
||||||
'SKU',
|
|
||||||
'manufacturer',
|
|
||||||
'MPN',
|
|
||||||
'description',
|
|
||||||
'link',
|
|
||||||
'note',
|
|
||||||
'single_pricing',
|
|
||||||
# 'base_cost',
|
|
||||||
# 'multiple',
|
|
||||||
'packaging',
|
|
||||||
]
|
|
||||||
|
|
||||||
def get_manufacturer_choices(self):
|
|
||||||
""" Returns tuples for all manufacturers """
|
|
||||||
empty_choice = [('', '----------')]
|
|
||||||
|
|
||||||
manufacturers = [(manufacturer.id, manufacturer.name) for manufacturer in Company.objects.filter(is_manufacturer=True)]
|
|
||||||
|
|
||||||
return empty_choice + manufacturers
|
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
self.fields['manufacturer'].choices = self.get_manufacturer_choices()
|
|
||||||
|
|
||||||
|
|
||||||
class EditPriceBreakForm(HelperForm):
|
class EditPriceBreakForm(HelperForm):
|
||||||
""" Form for creating / editing a supplier price break """
|
""" Form for creating / editing a supplier price break """
|
||||||
|
|
||||||
|
@ -9,9 +9,7 @@ import os
|
|||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from django.core.validators import MinValueValidator
|
from django.core.validators import MinValueValidator
|
||||||
from django.core.exceptions import ValidationError
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.utils import IntegrityError
|
|
||||||
from django.db.models import Sum, Q, UniqueConstraint
|
from django.db.models import Sum, Q, UniqueConstraint
|
||||||
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
|
@ -378,22 +378,27 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
$("#multi-part-delete").click(function() {
|
$("#multi-part-delete").click(function() {
|
||||||
var selections = $("#part-table").bootstrapTable("getSelections");
|
var selections = $("#supplier-part-table").bootstrapTable("getSelections");
|
||||||
|
|
||||||
var parts = [];
|
var requests = [];
|
||||||
|
|
||||||
selections.forEach(function(item) {
|
showQuestionDialog(
|
||||||
parts.push(item.pk);
|
'{% trans "Delete Supplier Parts?" %}',
|
||||||
|
'{% trans "All selected supplier parts will be deleted" %}',
|
||||||
|
{
|
||||||
|
accept: function() {
|
||||||
|
selections.forEach(function(part) {
|
||||||
|
var url = `/api/company/part/${part.pk}/`;
|
||||||
|
|
||||||
|
requests.push(inventreeDelete(url));
|
||||||
});
|
});
|
||||||
|
|
||||||
var url = "{% url 'supplier-part-delete' %}"
|
$.when.apply($, requests).then(function() {
|
||||||
|
$('#supplier-part-table').bootstrapTable('refresh');
|
||||||
launchModalForm(url, {
|
|
||||||
data: {
|
|
||||||
parts: parts,
|
|
||||||
},
|
|
||||||
reload: true,
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#multi-part-order").click(function() {
|
$("#multi-part-order").click(function() {
|
||||||
|
@ -194,18 +194,25 @@ $("#supplier-part-delete").click(function() {
|
|||||||
|
|
||||||
var selections = $("#supplier-table").bootstrapTable("getSelections");
|
var selections = $("#supplier-table").bootstrapTable("getSelections");
|
||||||
|
|
||||||
var parts = [];
|
var requests = [];
|
||||||
|
|
||||||
selections.forEach(function(item) {
|
showQuestionDialog(
|
||||||
parts.push(item.pk);
|
'{% trans "Delete Supplier Parts?" %}',
|
||||||
|
'{% trans "All selected supplier parts will be deleted" %}',
|
||||||
|
{
|
||||||
|
accept: function() {
|
||||||
|
selections.forEach(function(part) {
|
||||||
|
var url = `/api/company/part/${part.pk}/`;
|
||||||
|
|
||||||
|
requests.push(inventreeDelete(url));
|
||||||
});
|
});
|
||||||
|
|
||||||
launchModalForm("{% url 'supplier-part-delete' %}", {
|
$.when.apply($, requests).then(function() {
|
||||||
data: {
|
reloadSupplierPartTable();
|
||||||
parts: parts,
|
|
||||||
},
|
|
||||||
reload: true,
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
$("#multi-parameter-delete").click(function() {
|
$("#multi-parameter-delete").click(function() {
|
||||||
|
@ -327,21 +327,21 @@ $('#order-part, #order-part2').click(function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$('#edit-part').click(function () {
|
$('#edit-part').click(function () {
|
||||||
launchModalForm(
|
|
||||||
"{% url 'supplier-part-edit' part.id %}",
|
editSupplierPart({{ part.pk }}, {
|
||||||
{
|
onSuccess: function() {
|
||||||
reload: true
|
location.reload();
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#delete-part').click(function() {
|
$('#delete-part').click(function() {
|
||||||
launchModalForm(
|
|
||||||
"{% url 'supplier-part-delete' %}?part={{ part.id }}",
|
deleteSupplierPart({{ part.pk }}, {
|
||||||
{
|
onSuccess: function() {
|
||||||
redirect: "{% url 'company-detail' part.supplier.id %}"
|
window.location.href = "{% url 'company-detail' part.supplier.id %}";
|
||||||
}
|
}
|
||||||
);
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
attachNavCallbacks({
|
attachNavCallbacks({
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
{% extends "modal_form.html" %}
|
|
||||||
|
|
||||||
{% load i18n %}
|
|
||||||
|
|
||||||
{% block pre_form_content %}
|
|
||||||
{{ block.super }}
|
|
||||||
|
|
||||||
{% if part %}
|
|
||||||
<div class='alert alert-block alert-info'>
|
|
||||||
{% include "hover_image.html" with image=part.image %}
|
|
||||||
{{ part.full_name}}
|
|
||||||
<br>
|
|
||||||
<i>{{ part.description }}</i>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% endblock %}
|
|
@ -1,31 +0,0 @@
|
|||||||
{% extends "modal_delete_form.html" %}
|
|
||||||
{% load i18n %}
|
|
||||||
|
|
||||||
{% block pre_form_content %}
|
|
||||||
{% trans "Are you sure you want to delete the following Supplier Parts?" %}
|
|
||||||
|
|
||||||
<hr>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block form_data %}
|
|
||||||
<table class='table table-striped table-condensed'>
|
|
||||||
{% for part in parts %}
|
|
||||||
<tr>
|
|
||||||
<input type='hidden' name='supplier-part-{{ part.id}}' value='supplier-part-{{ part.id }}'/>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
{% include "hover_image.html" with image=part.part.image %}
|
|
||||||
{{ part.part.full_name }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{% include "hover_image.html" with image=part.supplier.image %}
|
|
||||||
{{ part.supplier.name }}
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
{{ part.SKU }}
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
</table>
|
|
||||||
|
|
||||||
{% endblock %}
|
|
@ -10,9 +10,6 @@ from django.urls import reverse
|
|||||||
from django.contrib.auth import get_user_model
|
from django.contrib.auth import get_user_model
|
||||||
from django.contrib.auth.models import Group
|
from django.contrib.auth.models import Group
|
||||||
|
|
||||||
from .models import ManufacturerPart
|
|
||||||
from .models import SupplierPart
|
|
||||||
|
|
||||||
|
|
||||||
class CompanyViewTestBase(TestCase):
|
class CompanyViewTestBase(TestCase):
|
||||||
|
|
||||||
|
@ -35,14 +35,6 @@ manufacturer_part_urls = [
|
|||||||
])),
|
])),
|
||||||
]
|
]
|
||||||
|
|
||||||
supplier_part_detail_urls = [
|
supplier_part_urls = [
|
||||||
url(r'^edit/?', views.SupplierPartEdit.as_view(), name='supplier-part-edit'),
|
|
||||||
|
|
||||||
url('^.*$', views.SupplierPartDetail.as_view(template_name='company/supplier_part.html'), name='supplier-part-detail'),
|
url('^.*$', views.SupplierPartDetail.as_view(template_name='company/supplier_part.html'), name='supplier-part-detail'),
|
||||||
]
|
]
|
||||||
|
|
||||||
supplier_part_urls = [
|
|
||||||
url(r'delete/', views.SupplierPartDelete.as_view(), name='supplier-part-delete'),
|
|
||||||
|
|
||||||
url(r'^(?P<pk>\d+)/', include(supplier_part_detail_urls)),
|
|
||||||
]
|
|
||||||
|
@ -10,31 +10,22 @@ from django.utils.translation import ugettext_lazy as _
|
|||||||
from django.views.generic import DetailView, ListView
|
from django.views.generic import DetailView, ListView
|
||||||
|
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.forms import HiddenInput
|
|
||||||
from django.core.files.base import ContentFile
|
from django.core.files.base import ContentFile
|
||||||
|
|
||||||
from moneyed import CURRENCIES
|
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
import requests
|
import requests
|
||||||
import io
|
import io
|
||||||
|
|
||||||
from InvenTree.views import AjaxCreateView, AjaxUpdateView, AjaxDeleteView
|
from InvenTree.views import AjaxUpdateView
|
||||||
from InvenTree.helpers import str2bool
|
|
||||||
from InvenTree.views import InvenTreeRoleMixin
|
from InvenTree.views import InvenTreeRoleMixin
|
||||||
|
|
||||||
from .models import Company
|
from .models import Company
|
||||||
from .models import ManufacturerPart
|
from .models import ManufacturerPart
|
||||||
from .models import SupplierPart
|
from .models import SupplierPart
|
||||||
|
|
||||||
from part.models import Part
|
|
||||||
|
|
||||||
from .forms import EditSupplierPartForm
|
|
||||||
from .forms import CompanyImageDownloadForm
|
from .forms import CompanyImageDownloadForm
|
||||||
|
|
||||||
import common.models
|
|
||||||
import common.settings
|
|
||||||
|
|
||||||
|
|
||||||
class CompanyIndex(InvenTreeRoleMixin, ListView):
|
class CompanyIndex(InvenTreeRoleMixin, ListView):
|
||||||
""" View for displaying list of companies
|
""" View for displaying list of companies
|
||||||
@ -231,134 +222,3 @@ class SupplierPartDetail(DetailView):
|
|||||||
ctx = super().get_context_data(**kwargs)
|
ctx = super().get_context_data(**kwargs)
|
||||||
|
|
||||||
return ctx
|
return ctx
|
||||||
|
|
||||||
|
|
||||||
class SupplierPartEdit(AjaxUpdateView):
|
|
||||||
""" Update view for editing SupplierPart """
|
|
||||||
|
|
||||||
model = SupplierPart
|
|
||||||
context_object_name = 'part'
|
|
||||||
form_class = EditSupplierPartForm
|
|
||||||
ajax_template_name = 'modal_form.html'
|
|
||||||
ajax_form_title = _('Edit Supplier Part')
|
|
||||||
|
|
||||||
def save(self, supplier_part, form, **kwargs):
|
|
||||||
""" Process ManufacturerPart data """
|
|
||||||
|
|
||||||
manufacturer = form.cleaned_data.get('manufacturer', None)
|
|
||||||
MPN = form.cleaned_data.get('MPN', None)
|
|
||||||
kwargs = {'manufacturer': manufacturer,
|
|
||||||
'MPN': MPN,
|
|
||||||
}
|
|
||||||
supplier_part.save(**kwargs)
|
|
||||||
|
|
||||||
def get_form(self):
|
|
||||||
form = super().get_form()
|
|
||||||
|
|
||||||
supplier_part = self.get_object()
|
|
||||||
|
|
||||||
# Hide Manufacturer fields
|
|
||||||
form.fields['manufacturer'].widget = HiddenInput()
|
|
||||||
form.fields['MPN'].widget = HiddenInput()
|
|
||||||
|
|
||||||
# It appears that hiding a MoneyField fails validation
|
|
||||||
# Therefore the idea to set the value before hiding
|
|
||||||
if form.is_valid():
|
|
||||||
form.cleaned_data['single_pricing'] = supplier_part.unit_pricing
|
|
||||||
# Hide the single-pricing field (only for creating a new SupplierPart!)
|
|
||||||
form.fields['single_pricing'].widget = HiddenInput()
|
|
||||||
|
|
||||||
return form
|
|
||||||
|
|
||||||
def get_initial(self):
|
|
||||||
""" Fetch data from ManufacturerPart """
|
|
||||||
|
|
||||||
initials = super(SupplierPartEdit, self).get_initial().copy()
|
|
||||||
|
|
||||||
supplier_part = self.get_object()
|
|
||||||
|
|
||||||
if supplier_part.manufacturer_part:
|
|
||||||
if supplier_part.manufacturer_part.manufacturer:
|
|
||||||
initials['manufacturer'] = supplier_part.manufacturer_part.manufacturer.id
|
|
||||||
initials['MPN'] = supplier_part.manufacturer_part.MPN
|
|
||||||
|
|
||||||
return initials
|
|
||||||
|
|
||||||
|
|
||||||
class SupplierPartDelete(AjaxDeleteView):
|
|
||||||
""" Delete view for removing a SupplierPart.
|
|
||||||
|
|
||||||
SupplierParts can be deleted using a variety of 'selectors'.
|
|
||||||
|
|
||||||
- ?part=<pk> -> Delete a single SupplierPart object
|
|
||||||
- ?parts=[] -> Delete a list of SupplierPart objects
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
success_url = '/supplier/'
|
|
||||||
ajax_template_name = 'company/supplier_part_delete.html'
|
|
||||||
ajax_form_title = _('Delete Supplier Part')
|
|
||||||
|
|
||||||
role_required = 'purchase_order.delete'
|
|
||||||
|
|
||||||
parts = []
|
|
||||||
|
|
||||||
def get_context_data(self):
|
|
||||||
ctx = {}
|
|
||||||
|
|
||||||
ctx['parts'] = self.parts
|
|
||||||
|
|
||||||
return ctx
|
|
||||||
|
|
||||||
def get_parts(self):
|
|
||||||
""" Determine which SupplierPart object(s) the user wishes to delete.
|
|
||||||
"""
|
|
||||||
|
|
||||||
self.parts = []
|
|
||||||
|
|
||||||
# User passes a single SupplierPart ID
|
|
||||||
if 'part' in self.request.GET:
|
|
||||||
try:
|
|
||||||
self.parts.append(SupplierPart.objects.get(pk=self.request.GET.get('part')))
|
|
||||||
except (ValueError, SupplierPart.DoesNotExist):
|
|
||||||
pass
|
|
||||||
|
|
||||||
elif 'parts[]' in self.request.GET:
|
|
||||||
|
|
||||||
part_id_list = self.request.GET.getlist('parts[]')
|
|
||||||
|
|
||||||
self.parts = SupplierPart.objects.filter(id__in=part_id_list)
|
|
||||||
|
|
||||||
def get(self, request, *args, **kwargs):
|
|
||||||
self.request = request
|
|
||||||
self.get_parts()
|
|
||||||
|
|
||||||
return self.renderJsonResponse(request, form=self.get_form())
|
|
||||||
|
|
||||||
def post(self, request, *args, **kwargs):
|
|
||||||
""" Handle the POST action for deleting supplier parts.
|
|
||||||
"""
|
|
||||||
|
|
||||||
self.request = request
|
|
||||||
self.parts = []
|
|
||||||
|
|
||||||
for item in self.request.POST:
|
|
||||||
if item.startswith('supplier-part-'):
|
|
||||||
pk = item.replace('supplier-part-', '')
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.parts.append(SupplierPart.objects.get(pk=pk))
|
|
||||||
except (ValueError, SupplierPart.DoesNotExist):
|
|
||||||
pass
|
|
||||||
|
|
||||||
confirm = str2bool(self.request.POST.get('confirm_delete', False))
|
|
||||||
|
|
||||||
data = {
|
|
||||||
'form_valid': confirm,
|
|
||||||
}
|
|
||||||
|
|
||||||
if confirm:
|
|
||||||
for part in self.parts:
|
|
||||||
part.delete()
|
|
||||||
|
|
||||||
return self.renderJsonResponse(self.request, data=data, form=self.get_form())
|
|
||||||
|
@ -817,18 +817,25 @@
|
|||||||
|
|
||||||
var selections = $("#supplier-part-table").bootstrapTable("getSelections");
|
var selections = $("#supplier-part-table").bootstrapTable("getSelections");
|
||||||
|
|
||||||
var parts = [];
|
var requests = [];
|
||||||
|
|
||||||
selections.forEach(function(item) {
|
showQuestionDialog(
|
||||||
parts.push(item.pk);
|
'{% trans "Delete Supplier Parts?" %}',
|
||||||
|
'{% trans "All selected supplier parts will be deleted" %}',
|
||||||
|
{
|
||||||
|
accept: function() {
|
||||||
|
selections.forEach(function(part) {
|
||||||
|
var url = `/api/company/part/${part.pk}/`;
|
||||||
|
|
||||||
|
requests.push(inventreeDelete(url));
|
||||||
});
|
});
|
||||||
|
|
||||||
launchModalForm("{% url 'supplier-part-delete' %}", {
|
$.when.apply($, requests).then(function() {
|
||||||
data: {
|
reloadSupplierPartTable();
|
||||||
parts: parts,
|
|
||||||
},
|
|
||||||
reload: true,
|
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
loadSupplierPartTable(
|
loadSupplierPartTable(
|
||||||
|
Loading…
Reference in New Issue
Block a user