mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Merge remote-tracking branch 'inventree/master'
This commit is contained in:
commit
8f3a022b3c
@ -8,11 +8,14 @@ from __future__ import unicode_literals
|
||||
from InvenTree.forms import HelperForm
|
||||
|
||||
from django import forms
|
||||
from django.utils.translation import ugettext as _
|
||||
|
||||
from .models import Part, PartCategory, PartAttachment
|
||||
from .models import BomItem
|
||||
from .models import PartParameterTemplate, PartParameter
|
||||
|
||||
from common.models import Currency
|
||||
|
||||
|
||||
class PartImageForm(HelperForm):
|
||||
""" Form for uploading a Part image """
|
||||
@ -30,7 +33,7 @@ class BomValidateForm(HelperForm):
|
||||
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:
|
||||
model = Part
|
||||
@ -42,7 +45,7 @@ class BomValidateForm(HelperForm):
|
||||
class BomUploadSelectFile(HelperForm):
|
||||
""" 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:
|
||||
model = Part
|
||||
@ -68,12 +71,12 @@ class EditPartForm(HelperForm):
|
||||
|
||||
deep_copy = forms.BooleanField(required=False,
|
||||
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())
|
||||
|
||||
confirm_creation = forms.BooleanField(required=False,
|
||||
initial=False,
|
||||
help_text='Confirm part creation',
|
||||
help_text=_('Confirm part creation'),
|
||||
widget=forms.HiddenInput())
|
||||
|
||||
class Meta:
|
||||
@ -160,11 +163,30 @@ class PartPriceForm(forms.Form):
|
||||
quantity = forms.IntegerField(
|
||||
required=True,
|
||||
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:
|
||||
model = Part
|
||||
fields = [
|
||||
'quantity'
|
||||
'quantity',
|
||||
'currency',
|
||||
]
|
||||
|
@ -24,14 +24,14 @@ Pricing information for:<br>
|
||||
{% if min_total_buy_price %}
|
||||
<tr>
|
||||
<td><b>Unit Cost</b></td>
|
||||
<td>Min: {{ min_unit_buy_price }}</td>
|
||||
<td>Max: {{ max_unit_buy_price }}</td>
|
||||
<td>Min: {% include "price.html" with price=min_unit_buy_price %}</td>
|
||||
<td>Max: {% include "price.html" with price=max_unit_buy_price %}</td>
|
||||
</tr>
|
||||
{% if quantity > 1 %}
|
||||
<tr>
|
||||
<td><b>Total Cost</b></td>
|
||||
<td>Min: {{ min_total_buy_price }}</td>
|
||||
<td>Max: {{ max_total_buy_price }}</td>
|
||||
<td>Min: {% include "price.html" with price=min_total_buy_price %}</td>
|
||||
<td>Max: {% include "price.html" with price=max_total_buy_price %}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
@ -50,14 +50,14 @@ Pricing information for:<br>
|
||||
{% if min_total_bom_price %}
|
||||
<tr>
|
||||
<td><b>Unit Cost</b></td>
|
||||
<td>Min: {{ min_unit_bom_price }}</td>
|
||||
<td>Max: {{ max_unit_bom_price }}</td>
|
||||
<td>Min: {% include "price.html" with price=min_unit_bom_price %}</td>
|
||||
<td>Max: {% include "price.html" with price=max_unit_bom_price %}</td>
|
||||
</tr>
|
||||
{% if quantity > 1 %}
|
||||
<tr>
|
||||
<td><b>Total Cost</b></td>
|
||||
<td>Min: {{ min_total_bom_price }}</td>
|
||||
<td>Max: {{ max_total_bom_price }}</td>
|
||||
<td>Min: {% include "price.html" with price=min_total_bom_price %}</td>
|
||||
<td>Max: {% include "price.html" with price=max_total_bom_price %}</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% if part.has_complete_bom_pricing == False %}
|
||||
|
@ -142,8 +142,8 @@ class PartAttachmentTests(PartViewTestCase):
|
||||
def test_invalid_create(self):
|
||||
""" test creation of an attachment for an invalid part """
|
||||
|
||||
with self.assertRaises(Part.DoesNotExist):
|
||||
self.client.get(reverse('part-attachment-create'), {'part': 999}, HTTP_X_REQUESTED_WITH='XMLHttpRequest')
|
||||
# TODO
|
||||
pass
|
||||
|
||||
def test_edit(self):
|
||||
""" test editing an attachment """
|
||||
|
@ -17,12 +17,14 @@ from django.forms import HiddenInput, CheckboxInput
|
||||
import tablib
|
||||
|
||||
from fuzzywuzzy import fuzz
|
||||
from decimal import Decimal
|
||||
|
||||
from .models import PartCategory, Part, PartAttachment
|
||||
from .models import PartParameterTemplate, PartParameter
|
||||
from .models import BomItem
|
||||
from .models import match_part_names
|
||||
|
||||
from common.models import Currency
|
||||
from company.models import SupplierPart
|
||||
|
||||
from . import forms as part_forms
|
||||
@ -82,7 +84,10 @@ class PartAttachmentCreate(AjaxCreateView):
|
||||
initials = super(AjaxCreateView, self).get_initial()
|
||||
|
||||
# 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
|
||||
|
||||
@ -1325,7 +1330,7 @@ class PartPricing(AjaxView):
|
||||
except Part.DoesNotExist:
|
||||
return None
|
||||
|
||||
def get_pricing(self, quantity=1):
|
||||
def get_pricing(self, quantity=1, currency=None):
|
||||
|
||||
try:
|
||||
quantity = int(quantity)
|
||||
@ -1335,11 +1340,25 @@ class PartPricing(AjaxView):
|
||||
if 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()
|
||||
|
||||
ctx = {
|
||||
'part': part,
|
||||
'quantity': quantity
|
||||
'quantity': quantity,
|
||||
'currency': currency,
|
||||
}
|
||||
|
||||
if part is None:
|
||||
@ -1352,6 +1371,12 @@ class PartPricing(AjaxView):
|
||||
if buy_price is not None:
|
||||
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:
|
||||
ctx['min_total_buy_price'] = min_buy_price
|
||||
ctx['min_unit_buy_price'] = min_buy_price / quantity
|
||||
@ -1368,6 +1393,12 @@ class PartPricing(AjaxView):
|
||||
if bom_price is not None:
|
||||
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:
|
||||
ctx['min_total_bom_price'] = min_bom_price
|
||||
ctx['min_unit_bom_price'] = min_bom_price / quantity
|
||||
@ -1384,17 +1415,27 @@ class PartPricing(AjaxView):
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
|
||||
currency = None
|
||||
|
||||
try:
|
||||
quantity = int(self.request.POST.get('quantity', 1))
|
||||
except ValueError:
|
||||
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)
|
||||
data = {
|
||||
'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):
|
||||
|
1
InvenTree/templates/price.html
Normal file
1
InvenTree/templates/price.html
Normal file
@ -0,0 +1 @@
|
||||
{% if currency %}{{ currency.symbol }}{% endif %}{{ price }}{% if currency %} {{ currency.suffix }}{% endif %}
|
Loading…
Reference in New Issue
Block a user