Refactor SupplierPartEdit and SupplierPartDelete forms

This commit is contained in:
Oliver Walters 2021-07-18 22:46:23 +10:00
parent 29d7cb40e1
commit 0c91691ed2
11 changed files with 69 additions and 313 deletions

View File

@ -6,13 +6,12 @@ Django Forms for interacting with Company app
from __future__ import unicode_literals
from InvenTree.forms import HelperForm
from InvenTree.fields import InvenTreeMoneyField, RoundingDecimalFormField
from InvenTree.fields import RoundingDecimalFormField
from django.utils.translation import ugettext_lazy as _
import django.forms
from .models import Company
from .models import SupplierPart
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):
""" Form for creating / editing a supplier price break """

View File

@ -9,9 +9,7 @@ import os
from django.utils.translation import ugettext_lazy as _
from django.core.validators import MinValueValidator
from django.core.exceptions import ValidationError
from django.db import models
from django.db.utils import IntegrityError
from django.db.models import Sum, Q, UniqueConstraint
from django.apps import apps

View File

@ -378,22 +378,27 @@
{% endif %}
$("#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) {
parts.push(item.pk);
showQuestionDialog(
'{% 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' %}"
launchModalForm(url, {
data: {
parts: parts,
},
reload: true,
$.when.apply($, requests).then(function() {
$('#supplier-part-table').bootstrapTable('refresh');
});
}
}
);
});
$("#multi-part-order").click(function() {

View File

@ -194,18 +194,25 @@ $("#supplier-part-delete").click(function() {
var selections = $("#supplier-table").bootstrapTable("getSelections");
var parts = [];
var requests = [];
selections.forEach(function(item) {
parts.push(item.pk);
showQuestionDialog(
'{% 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' %}", {
data: {
parts: parts,
},
reload: true,
$.when.apply($, requests).then(function() {
reloadSupplierPartTable();
});
}
}
);
});
$("#multi-parameter-delete").click(function() {

View File

@ -327,21 +327,21 @@ $('#order-part, #order-part2').click(function() {
});
$('#edit-part').click(function () {
launchModalForm(
"{% url 'supplier-part-edit' part.id %}",
{
reload: true
editSupplierPart({{ part.pk }}, {
onSuccess: function() {
location.reload();
}
);
});
});
$('#delete-part').click(function() {
launchModalForm(
"{% url 'supplier-part-delete' %}?part={{ part.id }}",
{
redirect: "{% url 'company-detail' part.supplier.id %}"
deleteSupplierPart({{ part.pk }}, {
onSuccess: function() {
window.location.href = "{% url 'company-detail' part.supplier.id %}";
}
);
});
});
attachNavCallbacks({

View File

@ -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 %}

View File

@ -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 %}

View File

@ -10,9 +10,6 @@ from django.urls import reverse
from django.contrib.auth import get_user_model
from django.contrib.auth.models import Group
from .models import ManufacturerPart
from .models import SupplierPart
class CompanyViewTestBase(TestCase):

View File

@ -35,14 +35,6 @@ manufacturer_part_urls = [
])),
]
supplier_part_detail_urls = [
url(r'^edit/?', views.SupplierPartEdit.as_view(), name='supplier-part-edit'),
supplier_part_urls = [
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)),
]

View File

@ -10,31 +10,22 @@ from django.utils.translation import ugettext_lazy as _
from django.views.generic import DetailView, ListView
from django.urls import reverse
from django.forms import HiddenInput
from django.core.files.base import ContentFile
from moneyed import CURRENCIES
from PIL import Image
import requests
import io
from InvenTree.views import AjaxCreateView, AjaxUpdateView, AjaxDeleteView
from InvenTree.helpers import str2bool
from InvenTree.views import AjaxUpdateView
from InvenTree.views import InvenTreeRoleMixin
from .models import Company
from .models import ManufacturerPart
from .models import SupplierPart
from part.models import Part
from .forms import EditSupplierPartForm
from .forms import CompanyImageDownloadForm
import common.models
import common.settings
class CompanyIndex(InvenTreeRoleMixin, ListView):
""" View for displaying list of companies
@ -231,134 +222,3 @@ class SupplierPartDetail(DetailView):
ctx = super().get_context_data(**kwargs)
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())

View File

@ -817,18 +817,25 @@
var selections = $("#supplier-part-table").bootstrapTable("getSelections");
var parts = [];
var requests = [];
selections.forEach(function(item) {
parts.push(item.pk);
showQuestionDialog(
'{% 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' %}", {
data: {
parts: parts,
},
reload: true,
$.when.apply($, requests).then(function() {
reloadSupplierPartTable();
});
}
}
);
});
loadSupplierPartTable(