mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
607cc90ce0
(cherry picked from commit 5f8f0232a9
)
567 lines
16 KiB
Python
567 lines
16 KiB
Python
"""
|
|
Django views for interacting with Company app
|
|
"""
|
|
|
|
|
|
# -*- coding: utf-8 -*-
|
|
from __future__ import unicode_literals
|
|
|
|
from django.utils.translation import ugettext as _
|
|
from django.views.generic import DetailView, ListView, UpdateView
|
|
|
|
from django.urls import reverse
|
|
from django.forms import HiddenInput
|
|
|
|
from moneyed import CURRENCIES
|
|
|
|
from InvenTree.views import AjaxCreateView, AjaxUpdateView, AjaxDeleteView
|
|
from InvenTree.helpers import str2bool
|
|
from InvenTree.views import InvenTreeRoleMixin
|
|
|
|
from .models import Company
|
|
from .models import SupplierPart
|
|
from .models import SupplierPriceBreak
|
|
|
|
from part.models import Part
|
|
|
|
from .forms import EditCompanyForm
|
|
from .forms import CompanyImageForm
|
|
from .forms import EditSupplierPartForm
|
|
from .forms import EditPriceBreakForm
|
|
|
|
import common.models
|
|
import common.settings
|
|
|
|
|
|
class CompanyIndex(InvenTreeRoleMixin, ListView):
|
|
""" View for displaying list of companies
|
|
"""
|
|
|
|
model = Company
|
|
template_name = 'company/index.html'
|
|
context_object_name = 'companies'
|
|
paginate_by = 50
|
|
permission_required = 'company.view_company'
|
|
|
|
def get_context_data(self, **kwargs):
|
|
|
|
ctx = super().get_context_data(**kwargs)
|
|
|
|
# Provide custom context data to the template,
|
|
# based on the URL we use to access this page
|
|
|
|
lookup = {
|
|
reverse('supplier-index'): {
|
|
'title': _('Suppliers'),
|
|
'button_text': _('New Supplier'),
|
|
'filters': {'is_supplier': 'true'},
|
|
'create_url': reverse('supplier-create'),
|
|
'pagetype': 'suppliers',
|
|
},
|
|
reverse('manufacturer-index'): {
|
|
'title': _('Manufacturers'),
|
|
'button_text': _('New Manufacturer'),
|
|
'filters': {'is_manufacturer': 'true'},
|
|
'create_url': reverse('manufacturer-create'),
|
|
'pagetype': 'manufacturers',
|
|
},
|
|
reverse('customer-index'): {
|
|
'title': _('Customers'),
|
|
'button_text': _('New Customer'),
|
|
'filters': {'is_customer': 'true'},
|
|
'create_url': reverse('customer-create'),
|
|
'pagetype': 'customers',
|
|
}
|
|
}
|
|
|
|
default = {
|
|
'title': _('Companies'),
|
|
'button_text': _('New Company'),
|
|
'filters': {},
|
|
'create_url': reverse('company-create'),
|
|
'pagetype': 'companies'
|
|
}
|
|
|
|
context = None
|
|
|
|
for item in lookup:
|
|
if self.request.path == item:
|
|
context = lookup[item]
|
|
break
|
|
|
|
if context is None:
|
|
context = default
|
|
|
|
for key, value in context.items():
|
|
ctx[key] = value
|
|
|
|
return ctx
|
|
|
|
def get_queryset(self):
|
|
""" Retrieve the Company queryset based on HTTP request parameters.
|
|
|
|
- supplier: Filter by supplier
|
|
- customer: Filter by customer
|
|
"""
|
|
queryset = Company.objects.all().order_by('name')
|
|
|
|
if self.request.GET.get('supplier', None):
|
|
queryset = queryset.filter(is_supplier=True)
|
|
|
|
if self.request.GET.get('customer', None):
|
|
queryset = queryset.filter(is_customer=True)
|
|
|
|
return queryset
|
|
|
|
|
|
class CompanyNotes(UpdateView):
|
|
""" View for editing the 'notes' field of a Company object.
|
|
"""
|
|
|
|
context_object_name = 'company'
|
|
template_name = 'company/notes.html'
|
|
model = Company
|
|
fields = ['notes']
|
|
permission_required = 'company.view_company'
|
|
|
|
def get_success_url(self):
|
|
return reverse('company-notes', kwargs={'pk': self.get_object().id})
|
|
|
|
def get_context_data(self, **kwargs):
|
|
|
|
ctx = super().get_context_data(**kwargs)
|
|
|
|
ctx['editing'] = str2bool(self.request.GET.get('edit', ''))
|
|
|
|
return ctx
|
|
|
|
|
|
class CompanyDetail(DetailView):
|
|
""" Detail view for Company object """
|
|
context_obect_name = 'company'
|
|
template_name = 'company/detail.html'
|
|
queryset = Company.objects.all()
|
|
model = Company
|
|
permission_required = 'company.view_company'
|
|
|
|
def get_context_data(self, **kwargs):
|
|
ctx = super().get_context_data(**kwargs)
|
|
|
|
return ctx
|
|
|
|
|
|
class CompanyImage(AjaxUpdateView):
|
|
""" View for uploading an image for the Company """
|
|
model = Company
|
|
ajax_template_name = 'modal_form.html'
|
|
ajax_form_title = _('Update Company Image')
|
|
form_class = CompanyImageForm
|
|
permission_required = 'company.change_company'
|
|
|
|
def get_data(self):
|
|
return {
|
|
'success': _('Updated company image'),
|
|
}
|
|
|
|
|
|
class CompanyEdit(AjaxUpdateView):
|
|
""" View for editing a Company object """
|
|
model = Company
|
|
form_class = EditCompanyForm
|
|
context_object_name = 'company'
|
|
ajax_template_name = 'modal_form.html'
|
|
ajax_form_title = _('Edit Company')
|
|
permission_required = 'company.change_company'
|
|
|
|
def get_data(self):
|
|
return {
|
|
'info': _('Edited company information'),
|
|
}
|
|
|
|
|
|
class CompanyCreate(AjaxCreateView):
|
|
""" View for creating a new Company object """
|
|
model = Company
|
|
context_object_name = 'company'
|
|
form_class = EditCompanyForm
|
|
ajax_template_name = 'modal_form.html'
|
|
permission_required = 'company.add_company'
|
|
|
|
def get_form_title(self):
|
|
|
|
url = self.request.path
|
|
|
|
if url == reverse('supplier-create'):
|
|
return _("Create new Supplier")
|
|
|
|
if url == reverse('manufacturer-create'):
|
|
return _('Create new Manufacturer')
|
|
|
|
if url == reverse('customer-create'):
|
|
return _('Create new Customer')
|
|
|
|
return _('Create new Company')
|
|
|
|
def get_initial(self):
|
|
""" Initial values for the form data """
|
|
initials = super().get_initial().copy()
|
|
|
|
url = self.request.path
|
|
|
|
if url == reverse('supplier-create'):
|
|
initials['is_supplier'] = True
|
|
initials['is_customer'] = False
|
|
initials['is_manufacturer'] = False
|
|
|
|
elif url == reverse('manufacturer-create'):
|
|
initials['is_manufacturer'] = True
|
|
initials['is_supplier'] = True
|
|
initials['is_customer'] = False
|
|
|
|
elif url == reverse('customer-create'):
|
|
initials['is_customer'] = True
|
|
initials['is_manufacturer'] = False
|
|
initials['is_supplier'] = False
|
|
|
|
return initials
|
|
|
|
def get_data(self):
|
|
return {
|
|
'success': _("Created new company"),
|
|
}
|
|
|
|
|
|
class CompanyDelete(AjaxDeleteView):
|
|
""" View for deleting a Company object """
|
|
|
|
model = Company
|
|
success_url = '/company/'
|
|
ajax_template_name = 'company/delete.html'
|
|
ajax_form_title = _('Delete Company')
|
|
context_object_name = 'company'
|
|
permission_required = 'company.delete_company'
|
|
|
|
def get_data(self):
|
|
return {
|
|
'danger': _('Company was deleted'),
|
|
}
|
|
|
|
|
|
class SupplierPartDetail(DetailView):
|
|
""" Detail view for SupplierPart """
|
|
model = SupplierPart
|
|
template_name = 'company/supplier_part_detail.html'
|
|
context_object_name = 'part'
|
|
queryset = SupplierPart.objects.all()
|
|
permission_required = 'purchase_order.view'
|
|
|
|
def get_context_data(self, **kwargs):
|
|
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')
|
|
role_required = 'purchase_order.change'
|
|
|
|
def get_form(self):
|
|
form = super().get_form()
|
|
|
|
supplier_part = self.get_object()
|
|
|
|
# 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
|
|
|
|
|
|
class SupplierPartCreate(AjaxCreateView):
|
|
""" Create view for making new SupplierPart """
|
|
|
|
model = SupplierPart
|
|
form_class = EditSupplierPartForm
|
|
ajax_template_name = 'company/supplier_part_create.html'
|
|
ajax_form_title = _('Create new Supplier Part')
|
|
context_object_name = 'part'
|
|
role_required = 'purchase_order.add'
|
|
|
|
def validate(self, part, form):
|
|
|
|
single_pricing = form.cleaned_data.get('single_pricing', None)
|
|
|
|
if single_pricing:
|
|
# TODO - What validation steps can be performed on the single_pricing field?
|
|
pass
|
|
|
|
def get_context_data(self):
|
|
"""
|
|
Supply context data to the form
|
|
"""
|
|
|
|
ctx = super().get_context_data()
|
|
|
|
# Add 'part' object
|
|
form = self.get_form()
|
|
|
|
part = form['part'].value()
|
|
|
|
try:
|
|
part = Part.objects.get(pk=part)
|
|
except (ValueError, Part.DoesNotExist):
|
|
part = None
|
|
|
|
ctx['part'] = part
|
|
|
|
return ctx
|
|
|
|
def save(self, form):
|
|
"""
|
|
If single_pricing is defined, add a price break for quantity=1
|
|
"""
|
|
|
|
# Save the supplier part object
|
|
supplier_part = super().save(form)
|
|
|
|
single_pricing = form.cleaned_data.get('single_pricing', None)
|
|
|
|
if single_pricing:
|
|
|
|
supplier_part.add_price_break(1, single_pricing)
|
|
|
|
return supplier_part
|
|
|
|
def get_form(self):
|
|
""" Create Form instance to create a new SupplierPart object.
|
|
Hide some fields if they are not appropriate in context
|
|
"""
|
|
form = super(AjaxCreateView, self).get_form()
|
|
|
|
if form.initial.get('part', None):
|
|
# Hide the part field
|
|
form.fields['part'].widget = HiddenInput()
|
|
|
|
return form
|
|
|
|
def get_initial(self):
|
|
""" Provide initial data for new SupplierPart:
|
|
|
|
- If 'supplier_id' provided, pre-fill supplier field
|
|
- If 'part_id' provided, pre-fill part field
|
|
"""
|
|
initials = super(SupplierPartCreate, self).get_initial().copy()
|
|
|
|
manufacturer_id = self.get_param('manufacturer')
|
|
supplier_id = self.get_param('supplier')
|
|
part_id = self.get_param('part')
|
|
|
|
supplier = None
|
|
|
|
if supplier_id:
|
|
try:
|
|
supplier = Company.objects.get(pk=supplier_id)
|
|
initials['supplier'] = supplier
|
|
except (ValueError, Company.DoesNotExist):
|
|
supplier = None
|
|
|
|
if manufacturer_id:
|
|
try:
|
|
initials['manufacturer'] = Company.objects.get(pk=manufacturer_id)
|
|
except (ValueError, Company.DoesNotExist):
|
|
pass
|
|
|
|
if part_id:
|
|
try:
|
|
initials['part'] = Part.objects.get(pk=part_id)
|
|
except (ValueError, Part.DoesNotExist):
|
|
pass
|
|
|
|
# Initial value for single pricing
|
|
if supplier:
|
|
currency_code = supplier.currency_code
|
|
else:
|
|
currency_code = common.settings.currency_code_default()
|
|
|
|
currency = CURRENCIES.get(currency_code, None)
|
|
|
|
if currency_code:
|
|
initials['single_pricing'] = ('', currency)
|
|
|
|
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/partdelete.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())
|
|
|
|
|
|
class PriceBreakCreate(AjaxCreateView):
|
|
""" View for creating a supplier price break """
|
|
|
|
model = SupplierPriceBreak
|
|
form_class = EditPriceBreakForm
|
|
ajax_form_title = _('Add Price Break')
|
|
ajax_template_name = 'modal_form.html'
|
|
role_required = 'purchase_order.add'
|
|
|
|
def get_data(self):
|
|
return {
|
|
'success': _('Added new price break')
|
|
}
|
|
|
|
def get_part(self):
|
|
"""
|
|
Attempt to extract SupplierPart object from the supplied data.
|
|
"""
|
|
|
|
try:
|
|
supplier_part = SupplierPart.objects.get(pk=self.request.GET.get('part'))
|
|
return supplier_part
|
|
except (ValueError, SupplierPart.DoesNotExist):
|
|
pass
|
|
|
|
try:
|
|
supplier_part = SupplierPart.objects.get(pk=self.request.POST.get('part'))
|
|
return supplier_part
|
|
except (ValueError, SupplierPart.DoesNotExist):
|
|
pass
|
|
|
|
return None
|
|
|
|
def get_form(self):
|
|
|
|
form = super(AjaxCreateView, self).get_form()
|
|
form.fields['part'].widget = HiddenInput()
|
|
|
|
return form
|
|
|
|
def get_initial(self):
|
|
|
|
initials = super(AjaxCreateView, self).get_initial()
|
|
|
|
supplier_part = self.get_part()
|
|
|
|
initials['part'] = self.get_part()
|
|
|
|
if supplier_part is not None:
|
|
currency_code = supplier_part.supplier.currency_code
|
|
else:
|
|
currency_code = common.settings.currency_code_default()
|
|
|
|
# Extract the currency object associated with the code
|
|
currency = CURRENCIES.get(currency_code, None)
|
|
|
|
if currency:
|
|
initials['price'] = [1.0, currency]
|
|
|
|
return initials
|
|
|
|
|
|
class PriceBreakEdit(AjaxUpdateView):
|
|
""" View for editing a supplier price break """
|
|
|
|
model = SupplierPriceBreak
|
|
form_class = EditPriceBreakForm
|
|
ajax_form_title = _('Edit Price Break')
|
|
ajax_template_name = 'modal_form.html'
|
|
role_required = 'purchase_order.change'
|
|
|
|
def get_form(self):
|
|
|
|
form = super(AjaxUpdateView, self).get_form()
|
|
form.fields['part'].widget = HiddenInput()
|
|
|
|
return form
|
|
|
|
|
|
class PriceBreakDelete(AjaxDeleteView):
|
|
""" View for deleting a supplier price break """
|
|
|
|
model = SupplierPriceBreak
|
|
ajax_form_title = _("Delete Price Break")
|
|
ajax_template_name = 'modal_delete_form.html'
|
|
role_required = 'purchase_order.delete'
|