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
02ec1d4fa2
@ -8,6 +8,8 @@ from .validators import allowable_url_schemes
|
|||||||
from django.forms.fields import URLField as FormURLField
|
from django.forms.fields import URLField as FormURLField
|
||||||
from django.db import models as models
|
from django.db import models as models
|
||||||
from django.core import validators
|
from django.core import validators
|
||||||
|
from django import forms
|
||||||
|
from decimal import Decimal
|
||||||
|
|
||||||
|
|
||||||
class InvenTreeURLFormField(FormURLField):
|
class InvenTreeURLFormField(FormURLField):
|
||||||
@ -25,3 +27,33 @@ class InvenTreeURLField(models.URLField):
|
|||||||
return super().formfield(**{
|
return super().formfield(**{
|
||||||
'form_class': InvenTreeURLFormField
|
'form_class': InvenTreeURLFormField
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
def round_decimal(value, places):
|
||||||
|
"""
|
||||||
|
Round value to the specified number of places.
|
||||||
|
"""
|
||||||
|
|
||||||
|
if value is not None:
|
||||||
|
# see https://docs.python.org/2/library/decimal.html#decimal.Decimal.quantize for options
|
||||||
|
return value.quantize(Decimal(10) ** -places)
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
class RoundingDecimalFormField(forms.DecimalField):
|
||||||
|
def to_python(self, value):
|
||||||
|
value = super(RoundingDecimalFormField, self).to_python(value)
|
||||||
|
return round_decimal(value, self.decimal_places)
|
||||||
|
|
||||||
|
|
||||||
|
class RoundingDecimalField(models.DecimalField):
|
||||||
|
def to_python(self, value):
|
||||||
|
value = super(RoundingDecimalField, self).to_python(value)
|
||||||
|
return round_decimal(value, self.decimal_places)
|
||||||
|
|
||||||
|
def formfield(self, **kwargs):
|
||||||
|
defaults = {
|
||||||
|
'form_class': RoundingDecimalFormField
|
||||||
|
}
|
||||||
|
defaults.update(kwargs)
|
||||||
|
return super(RoundingDecimalField, self).formfield(**kwargs)
|
||||||
|
@ -71,7 +71,7 @@ function loadAllocationTable(table, part_id, part, url, required, button) {
|
|||||||
var count = 0;
|
var count = 0;
|
||||||
|
|
||||||
for (var i = 0; i < results.length; i++) {
|
for (var i = 0; i < results.length; i++) {
|
||||||
count += results[i].quantity;
|
count += parseFloat(results[i].quantity);
|
||||||
}
|
}
|
||||||
|
|
||||||
updateAllocationTotal(part_id, count, required);
|
updateAllocationTotal(part_id, count, required);
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
<b>{% decimal item.sub_part.total_stock %}</b>
|
<b>{% decimal item.sub_part.total_stock %}</b>
|
||||||
</div>
|
</div>
|
||||||
<div class='col-sm-2'>
|
<div class='col-sm-2'>
|
||||||
<b>{% multiply build.quantity item.quantity %}</b>
|
<b>{% multiply build.quantity item.quantity %}{% if item.overage %} (+ {{ item.overage }}){% endif %}</b>
|
||||||
</div>
|
</div>
|
||||||
<div class='col-sm-2'>
|
<div class='col-sm-2'>
|
||||||
<b><span id='allocation-total-{{ item.sub_part.id }}'>{% part_allocation_count build item.sub_part %}</span></b>
|
<b><span id='allocation-total-{{ item.sub_part.id }}'>{% part_allocation_count build item.sub_part %}</span></b>
|
||||||
|
@ -6,6 +6,7 @@ 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 RoundingDecimalFormField
|
||||||
|
|
||||||
from .models import Company
|
from .models import Company
|
||||||
from .models import SupplierPart
|
from .models import SupplierPart
|
||||||
@ -64,6 +65,10 @@ class EditSupplierPartForm(HelperForm):
|
|||||||
class EditPriceBreakForm(HelperForm):
|
class EditPriceBreakForm(HelperForm):
|
||||||
""" Form for creating / editing a supplier price break """
|
""" Form for creating / editing a supplier price break """
|
||||||
|
|
||||||
|
quantity = RoundingDecimalFormField(max_digits=10, decimal_places=5)
|
||||||
|
|
||||||
|
cost = RoundingDecimalFormField(max_digits=10, decimal_places=5)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = SupplierPriceBreak
|
model = SupplierPriceBreak
|
||||||
fields = [
|
fields = [
|
||||||
|
20
InvenTree/company/migrations/0011_auto_20200318_1114.py
Normal file
20
InvenTree/company/migrations/0011_auto_20200318_1114.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Generated by Django 2.2.9 on 2020-03-18 11:14
|
||||||
|
|
||||||
|
import InvenTree.fields
|
||||||
|
import django.core.validators
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('company', '0010_auto_20200201_1231'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='supplierpricebreak',
|
||||||
|
name='cost',
|
||||||
|
field=InvenTree.fields.RoundingDecimalField(decimal_places=5, max_digits=10, validators=[django.core.validators.MinValueValidator(0)]),
|
||||||
|
),
|
||||||
|
]
|
20
InvenTree/company/migrations/0012_auto_20200318_1114.py
Normal file
20
InvenTree/company/migrations/0012_auto_20200318_1114.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
# Generated by Django 2.2.9 on 2020-03-18 11:14
|
||||||
|
|
||||||
|
import InvenTree.fields
|
||||||
|
import django.core.validators
|
||||||
|
from django.db import migrations
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('company', '0011_auto_20200318_1114'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='supplierpricebreak',
|
||||||
|
name='quantity',
|
||||||
|
field=InvenTree.fields.RoundingDecimalField(decimal_places=5, default=1, max_digits=15, validators=[django.core.validators.MinValueValidator(1)]),
|
||||||
|
),
|
||||||
|
]
|
@ -21,7 +21,7 @@ from django.conf import settings
|
|||||||
|
|
||||||
from markdownx.models import MarkdownxField
|
from markdownx.models import MarkdownxField
|
||||||
|
|
||||||
from InvenTree.fields import InvenTreeURLField
|
from InvenTree.fields import InvenTreeURLField, RoundingDecimalField
|
||||||
from InvenTree.status_codes import OrderStatus
|
from InvenTree.status_codes import OrderStatus
|
||||||
from common.models import Currency
|
from common.models import Currency
|
||||||
|
|
||||||
@ -381,9 +381,9 @@ class SupplierPriceBreak(models.Model):
|
|||||||
|
|
||||||
part = models.ForeignKey(SupplierPart, on_delete=models.CASCADE, related_name='pricebreaks')
|
part = models.ForeignKey(SupplierPart, on_delete=models.CASCADE, related_name='pricebreaks')
|
||||||
|
|
||||||
quantity = models.DecimalField(max_digits=15, decimal_places=5, default=1, validators=[MinValueValidator(1)])
|
quantity = RoundingDecimalField(max_digits=15, decimal_places=5, default=1, validators=[MinValueValidator(1)])
|
||||||
|
|
||||||
cost = models.DecimalField(max_digits=10, decimal_places=5, validators=[MinValueValidator(0)])
|
cost = RoundingDecimalField(max_digits=10, decimal_places=5, validators=[MinValueValidator(0)])
|
||||||
|
|
||||||
currency = models.ForeignKey(Currency, blank=True, null=True, on_delete=models.SET_NULL)
|
currency = models.ForeignKey(Currency, blank=True, null=True, on_delete=models.SET_NULL)
|
||||||
|
|
||||||
|
@ -21,19 +21,49 @@ InvenTree | {% trans "Supplier Part" %}
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class='col-sm-6'>
|
|
||||||
<div class='media-left'>
|
<div class='media-left'>
|
||||||
<img class='part-thumb'
|
<img class='part-thumb'
|
||||||
{% if part.part.image %}
|
{% if part.part.image %}
|
||||||
src='{{ part.part.image.url }}'
|
src='{{ part.part.image.url }}'
|
||||||
{% else %}
|
{% else %}
|
||||||
src="{% static 'img/blank_image.png' %}"
|
src="{% static 'img/blank_image.png' %}"
|
||||||
{% endif %}/>
|
{% endif %}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class='col-sm-6'>
|
||||||
|
<h4>{% trans "Supplier Part Details" %}</h4>
|
||||||
|
<table class="table table-striped table-condensed">
|
||||||
|
<tr>
|
||||||
|
<td>{% trans "Internal Part" %}</td>
|
||||||
|
<td>
|
||||||
|
{% if part.part %}
|
||||||
|
<a href="{% url 'part-suppliers' part.part.id %}">{{ part.part.full_name }}</a>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr><td>{% trans "Supplier" %}</td><td><a href="{% url 'company-detail-parts' part.supplier.id %}">{{ part.supplier.name }}</a></td></tr>
|
||||||
|
<tr><td>{% trans "SKU" %}</td><td>{{ part.SKU }}</tr></tr>
|
||||||
|
{% if part.URL %}
|
||||||
|
<tr><td>{% trans "URL" %}</td><td><a href="{{ part.URL }}">{{ part.URL }}</a></td></tr>
|
||||||
|
{% endif %}
|
||||||
|
{% if part.description %}
|
||||||
|
<tr><td>{% trans "Description" %}</td><td>{{ part.description }}</td></tr>
|
||||||
|
{% endif %}
|
||||||
|
{% if part.manufacturer %}
|
||||||
|
<tr><td>{% trans "Manufacturer" %}</td><td>{{ part.manufacturer }}</td></tr>
|
||||||
|
<tr><td>{% trans "MPN" %}</td><td>{{ part.MPN }}</td></tr>
|
||||||
|
{% endif %}
|
||||||
|
{% if part.note %}
|
||||||
|
<tr><td>{% trans "Note" %}</td><td>{{ part.note }}</td></tr>
|
||||||
|
{% endif %}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
<div class='container-fluid'>
|
<div class='container-fluid'>
|
||||||
|
@ -1,9 +1,6 @@
|
|||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
|
|
||||||
<ul class='nav nav-tabs'>
|
<ul class='nav nav-tabs'>
|
||||||
<li{% if tab == 'details' %} class='active'{% endif %}>
|
|
||||||
<a href="{% url 'supplier-part-detail' part.id %}">{% trans "Details" %}</a>
|
|
||||||
</li>
|
|
||||||
<li{% if tab == 'pricing' %} class='active'{% endif %}>
|
<li{% if tab == 'pricing' %} class='active'{% endif %}>
|
||||||
<a href="{% url 'supplier-part-pricing' part.id %}">{% trans "Pricing" %}</a>
|
<a href="{% url 'supplier-part-pricing' part.id %}">{% trans "Pricing" %}</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -53,7 +53,7 @@ supplier_part_detail_urls = [
|
|||||||
url(r'^orders/', views.SupplierPartDetail.as_view(template_name='company/supplier_part_orders.html'), name='supplier-part-orders'),
|
url(r'^orders/', views.SupplierPartDetail.as_view(template_name='company/supplier_part_orders.html'), name='supplier-part-orders'),
|
||||||
url(r'^stock/', views.SupplierPartDetail.as_view(template_name='company/supplier_part_stock.html'), name='supplier-part-stock'),
|
url(r'^stock/', views.SupplierPartDetail.as_view(template_name='company/supplier_part_stock.html'), name='supplier-part-stock'),
|
||||||
|
|
||||||
url('^.*$', views.SupplierPartDetail.as_view(), name='supplier-part-detail'),
|
url('^.*$', views.SupplierPartDetail.as_view(template_name='company/supplier_part_pricing.html'), name='supplier-part-detail'),
|
||||||
]
|
]
|
||||||
|
|
||||||
supplier_part_urls = [
|
supplier_part_urls = [
|
||||||
|
@ -1198,9 +1198,9 @@ class BomItem(models.Model):
|
|||||||
|
|
||||||
overage = str(self.overage).strip()
|
overage = str(self.overage).strip()
|
||||||
|
|
||||||
# Is the overage an integer value?
|
# Is the overage a numerical value?
|
||||||
try:
|
try:
|
||||||
ovg = int(overage)
|
ovg = float(overage)
|
||||||
|
|
||||||
if ovg < 0:
|
if ovg < 0:
|
||||||
ovg = 0
|
ovg = 0
|
||||||
@ -1223,7 +1223,7 @@ class BomItem(models.Model):
|
|||||||
# Must be represented as a decimal
|
# Must be represented as a decimal
|
||||||
percent = Decimal(percent)
|
percent = Decimal(percent)
|
||||||
|
|
||||||
return int(percent * quantity)
|
return float(percent * quantity)
|
||||||
|
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
@ -1245,7 +1245,12 @@ class BomItem(models.Model):
|
|||||||
# Base quantity requirement
|
# Base quantity requirement
|
||||||
base_quantity = self.quantity * build_quantity
|
base_quantity = self.quantity * build_quantity
|
||||||
|
|
||||||
return base_quantity + self.get_overage_quantity(base_quantity)
|
# Overage requiremet
|
||||||
|
ovrg_quantity = self.get_overage_quantity(base_quantity)
|
||||||
|
|
||||||
|
required = float(base_quantity) + float(ovrg_quantity)
|
||||||
|
|
||||||
|
return required
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def price_range(self):
|
def price_range(self):
|
||||||
|
@ -38,7 +38,7 @@ from InvenTree.views import AjaxView, AjaxCreateView, AjaxUpdateView, AjaxDelete
|
|||||||
from InvenTree.views import QRCodeView
|
from InvenTree.views import QRCodeView
|
||||||
|
|
||||||
from InvenTree.helpers import DownloadFile, str2bool
|
from InvenTree.helpers import DownloadFile, str2bool
|
||||||
from InvenTree.status_codes import OrderStatus
|
from InvenTree.status_codes import OrderStatus, BuildStatus
|
||||||
|
|
||||||
|
|
||||||
class PartIndex(ListView):
|
class PartIndex(ListView):
|
||||||
@ -593,6 +593,7 @@ class PartDetail(DetailView):
|
|||||||
context['disabled'] = not part.active
|
context['disabled'] = not part.active
|
||||||
|
|
||||||
context['OrderStatus'] = OrderStatus
|
context['OrderStatus'] = OrderStatus
|
||||||
|
context['BuildStatus'] = BuildStatus
|
||||||
|
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user