Merge remote-tracking branch 'inventree/master'

This commit is contained in:
Oliver Walters 2019-09-04 08:57:24 +10:00
commit 8f3a022b3c
5 changed files with 84 additions and 20 deletions

View File

@ -8,11 +8,14 @@ from __future__ import unicode_literals
from InvenTree.forms import HelperForm from InvenTree.forms import HelperForm
from django import forms from django import forms
from django.utils.translation import ugettext as _
from .models import Part, PartCategory, PartAttachment from .models import Part, PartCategory, PartAttachment
from .models import BomItem from .models import BomItem
from .models import PartParameterTemplate, PartParameter from .models import PartParameterTemplate, PartParameter
from common.models import Currency
class PartImageForm(HelperForm): class PartImageForm(HelperForm):
""" Form for uploading a Part image """ """ Form for uploading a Part image """
@ -30,7 +33,7 @@ class BomValidateForm(HelperForm):
to confirm that the BOM for this part is valid to confirm that the BOM for this part is valid
""" """
validate = forms.BooleanField(required=False, initial=False, help_text='Confirm that the BOM is correct') validate = forms.BooleanField(required=False, initial=False, help_text=_('Confirm that the BOM is correct'))
class Meta: class Meta:
model = Part model = Part
@ -42,7 +45,7 @@ class BomValidateForm(HelperForm):
class BomUploadSelectFile(HelperForm): class BomUploadSelectFile(HelperForm):
""" Form for importing a BOM. Provides a file input box for upload """ """ Form for importing a BOM. Provides a file input box for upload """
bom_file = forms.FileField(label='BOM file', required=True, help_text="Select BOM file to upload") bom_file = forms.FileField(label='BOM file', required=True, help_text=_("Select BOM file to upload"))
class Meta: class Meta:
model = Part model = Part
@ -68,12 +71,12 @@ class EditPartForm(HelperForm):
deep_copy = forms.BooleanField(required=False, deep_copy = forms.BooleanField(required=False,
initial=True, initial=True,
help_text="Perform 'deep copy' which will duplicate all BOM data for this part", help_text=_("Perform 'deep copy' which will duplicate all BOM data for this part"),
widget=forms.HiddenInput()) widget=forms.HiddenInput())
confirm_creation = forms.BooleanField(required=False, confirm_creation = forms.BooleanField(required=False,
initial=False, initial=False,
help_text='Confirm part creation', help_text=_('Confirm part creation'),
widget=forms.HiddenInput()) widget=forms.HiddenInput())
class Meta: class Meta:
@ -160,11 +163,30 @@ class PartPriceForm(forms.Form):
quantity = forms.IntegerField( quantity = forms.IntegerField(
required=True, required=True,
initial=1, initial=1,
help_text='Input quantity for price calculation' help_text=_('Input quantity for price calculation')
) )
currency = forms.ChoiceField(label='Currency', help_text=_('Select currency for price calculation'))
def get_currency_choices(self):
""" Create options for Currency """
currencies = Currency.objects.all()
choices = [(None, '---------')]
for c in currencies:
choices.append((c.pk, str(c)))
return choices
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['currency'].choices = self.get_currency_choices()
class Meta: class Meta:
model = Part model = Part
fields = [ fields = [
'quantity' 'quantity',
'currency',
] ]

View File

@ -24,14 +24,14 @@ Pricing information for:<br>
{% if min_total_buy_price %} {% if min_total_buy_price %}
<tr> <tr>
<td><b>Unit Cost</b></td> <td><b>Unit Cost</b></td>
<td>Min: {{ min_unit_buy_price }}</td> <td>Min: {% include "price.html" with price=min_unit_buy_price %}</td>
<td>Max: {{ max_unit_buy_price }}</td> <td>Max: {% include "price.html" with price=max_unit_buy_price %}</td>
</tr> </tr>
{% if quantity > 1 %} {% if quantity > 1 %}
<tr> <tr>
<td><b>Total Cost</b></td> <td><b>Total Cost</b></td>
<td>Min: {{ min_total_buy_price }}</td> <td>Min: {% include "price.html" with price=min_total_buy_price %}</td>
<td>Max: {{ max_total_buy_price }}</td> <td>Max: {% include "price.html" with price=max_total_buy_price %}</td>
</tr> </tr>
{% endif %} {% endif %}
{% else %} {% else %}
@ -50,14 +50,14 @@ Pricing information for:<br>
{% if min_total_bom_price %} {% if min_total_bom_price %}
<tr> <tr>
<td><b>Unit Cost</b></td> <td><b>Unit Cost</b></td>
<td>Min: {{ min_unit_bom_price }}</td> <td>Min: {% include "price.html" with price=min_unit_bom_price %}</td>
<td>Max: {{ max_unit_bom_price }}</td> <td>Max: {% include "price.html" with price=max_unit_bom_price %}</td>
</tr> </tr>
{% if quantity > 1 %} {% if quantity > 1 %}
<tr> <tr>
<td><b>Total Cost</b></td> <td><b>Total Cost</b></td>
<td>Min: {{ min_total_bom_price }}</td> <td>Min: {% include "price.html" with price=min_total_bom_price %}</td>
<td>Max: {{ max_total_bom_price }}</td> <td>Max: {% include "price.html" with price=max_total_bom_price %}</td>
</tr> </tr>
{% endif %} {% endif %}
{% if part.has_complete_bom_pricing == False %} {% if part.has_complete_bom_pricing == False %}

View File

@ -142,8 +142,8 @@ class PartAttachmentTests(PartViewTestCase):
def test_invalid_create(self): def test_invalid_create(self):
""" test creation of an attachment for an invalid part """ """ test creation of an attachment for an invalid part """
with self.assertRaises(Part.DoesNotExist): # TODO
self.client.get(reverse('part-attachment-create'), {'part': 999}, HTTP_X_REQUESTED_WITH='XMLHttpRequest') pass
def test_edit(self): def test_edit(self):
""" test editing an attachment """ """ test editing an attachment """

View File

@ -17,12 +17,14 @@ from django.forms import HiddenInput, CheckboxInput
import tablib import tablib
from fuzzywuzzy import fuzz from fuzzywuzzy import fuzz
from decimal import Decimal
from .models import PartCategory, Part, PartAttachment from .models import PartCategory, Part, PartAttachment
from .models import PartParameterTemplate, PartParameter from .models import PartParameterTemplate, PartParameter
from .models import BomItem from .models import BomItem
from .models import match_part_names from .models import match_part_names
from common.models import Currency
from company.models import SupplierPart from company.models import SupplierPart
from . import forms as part_forms from . import forms as part_forms
@ -82,7 +84,10 @@ class PartAttachmentCreate(AjaxCreateView):
initials = super(AjaxCreateView, self).get_initial() initials = super(AjaxCreateView, self).get_initial()
# TODO - If the proper part was not sent, return an error message # TODO - If the proper part was not sent, return an error message
initials['part'] = Part.objects.get(id=self.request.GET.get('part')) try:
initials['part'] = Part.objects.get(id=self.request.GET.get('part', None))
except (ValueError, Part.DoesNotExist):
pass
return initials return initials
@ -1325,7 +1330,7 @@ class PartPricing(AjaxView):
except Part.DoesNotExist: except Part.DoesNotExist:
return None return None
def get_pricing(self, quantity=1): def get_pricing(self, quantity=1, currency=None):
try: try:
quantity = int(quantity) quantity = int(quantity)
@ -1335,11 +1340,25 @@ class PartPricing(AjaxView):
if quantity < 1: if quantity < 1:
quantity = 1 quantity = 1
if currency is None:
# No currency selected? Try to select a default one
try:
currency = Currency.objects.get(base=1)
except Currency.DoesNotExist:
currency = None
# Currency scaler
scaler = Decimal(1.0)
if currency is not None:
scaler = Decimal(currency.value)
part = self.get_part() part = self.get_part()
ctx = { ctx = {
'part': part, 'part': part,
'quantity': quantity 'quantity': quantity,
'currency': currency,
} }
if part is None: if part is None:
@ -1352,6 +1371,12 @@ class PartPricing(AjaxView):
if buy_price is not None: if buy_price is not None:
min_buy_price, max_buy_price = buy_price min_buy_price, max_buy_price = buy_price
min_buy_price /= scaler
max_buy_price /= scaler
min_buy_price = round(min_buy_price, 3)
max_buy_price = round(max_buy_price, 3)
if min_buy_price: if min_buy_price:
ctx['min_total_buy_price'] = min_buy_price ctx['min_total_buy_price'] = min_buy_price
ctx['min_unit_buy_price'] = min_buy_price / quantity ctx['min_unit_buy_price'] = min_buy_price / quantity
@ -1368,6 +1393,12 @@ class PartPricing(AjaxView):
if bom_price is not None: if bom_price is not None:
min_bom_price, max_bom_price = bom_price min_bom_price, max_bom_price = bom_price
min_bom_price /= scaler
max_bom_price /= scaler
min_bom_price = round(min_bom_price, 3)
max_bom_price = round(max_bom_price, 3)
if min_bom_price: if min_bom_price:
ctx['min_total_bom_price'] = min_bom_price ctx['min_total_bom_price'] = min_bom_price
ctx['min_unit_bom_price'] = min_bom_price / quantity ctx['min_unit_bom_price'] = min_bom_price / quantity
@ -1384,17 +1415,27 @@ class PartPricing(AjaxView):
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
currency = None
try: try:
quantity = int(self.request.POST.get('quantity', 1)) quantity = int(self.request.POST.get('quantity', 1))
except ValueError: except ValueError:
quantity = 1 quantity = 1
try:
currency_id = int(self.request.POST.get('currency', None))
if currency_id:
currency = Currency.objects.get(pk=currency_id)
except (ValueError, Currency.DoesNotExist):
currency = None
# Always mark the form as 'invalid' (the user may wish to keep getting pricing data) # Always mark the form as 'invalid' (the user may wish to keep getting pricing data)
data = { data = {
'form_valid': False, 'form_valid': False,
} }
return self.renderJsonResponse(request, self.form_class(), data=data, context=self.get_pricing(quantity)) return self.renderJsonResponse(request, self.form_class(), data=data, context=self.get_pricing(quantity, currency))
class PartParameterTemplateCreate(AjaxCreateView): class PartParameterTemplateCreate(AjaxCreateView):

View File

@ -0,0 +1 @@
{% if currency %}{{ currency.symbol }}{% endif %}{{ price }}{% if currency %} {{ currency.suffix }}{% endif %}