Merge pull request #1535 from eeintech/get_price

Added support for fractional price and lower price break
This commit is contained in:
Oliver 2021-05-01 09:52:21 +10:00 committed by GitHub
commit 5d214fc869
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 54 additions and 19 deletions

View File

@ -6,7 +6,7 @@ Company database model definitions
from __future__ import unicode_literals
import os
import decimal
import math
from django.utils.translation import ugettext_lazy as _
@ -566,12 +566,15 @@ class SupplierPart(models.Model):
- If order multiples are to be observed, then we need to calculate based on that, too
"""
price_breaks = self.price_breaks.filter(quantity__lte=quantity)
price_breaks = self.price_breaks.all()
# No price break information available?
if len(price_breaks) == 0:
return None
# Check if quantity is fraction and disable multiples
multiples = (quantity % 1 == 0)
# Order multiples
if multiples:
quantity = int(math.ceil(quantity / self.multiple) * self.multiple)
@ -584,7 +587,12 @@ class SupplierPart(models.Model):
# Default currency selection
currency = common.models.InvenTreeSetting.get_setting('INVENTREE_DEFAULT_CURRENCY')
pb_min = None
for pb in self.price_breaks.all():
# Store smallest price break
if not pb_min:
pb_min = pb
# Ignore this pricebreak (quantity is too high)
if pb.quantity > quantity:
continue
@ -598,6 +606,17 @@ class SupplierPart(models.Model):
# Convert everything to the selected currency
pb_cost = pb.convert_to(currency)
# Use smallest price break
if not pb_found and pb_min:
# Update price break information
pb_quantity = pb_min.quantity
pb_cost = pb_min.convert_to(currency)
# Trigger cost calculation using smallest price break
pb_found = True
# Convert quantity to decimal.Decimal format
quantity = decimal.Decimal(f'{quantity}')
if pb_found:
cost = pb_cost * quantity
return normalize(cost + self.base_cost)

View File

@ -5,6 +5,7 @@ from django.test import TestCase
from django.core.exceptions import ValidationError
import os
from decimal import Decimal
from .models import Company, Contact, ManufacturerPart, SupplierPart
from .models import rename_company_image
@ -103,8 +104,9 @@ class CompanySimpleTest(TestCase):
self.assertEqual(p(100), 350)
p = self.acme0002.get_price
self.assertEqual(p(1), None)
self.assertEqual(p(2), None)
self.assertEqual(p(0.5), 3.5)
self.assertEqual(p(1), 7)
self.assertEqual(p(2), 14)
self.assertEqual(p(5), 35)
self.assertEqual(p(45), 315)
self.assertEqual(p(55), 68.75)
@ -112,6 +114,7 @@ class CompanySimpleTest(TestCase):
def test_part_pricing(self):
m2x4 = Part.objects.get(name='M2x4 LPHS')
self.assertEqual(m2x4.get_price_info(5.5), "38.5 - 41.25")
self.assertEqual(m2x4.get_price_info(10), "70 - 75")
self.assertEqual(m2x4.get_price_info(100), "125 - 350")
@ -121,7 +124,8 @@ class CompanySimpleTest(TestCase):
m3x12 = Part.objects.get(name='M3x12 SHCS')
self.assertIsNone(m3x12.get_price_info(3))
self.assertEqual(m3x12.get_price_info(0.3), Decimal('2.4'))
self.assertEqual(m3x12.get_price_info(3), Decimal('24'))
self.assertIsNotNone(m3x12.get_price_info(50))
def test_currency_validation(self):

View File

@ -1957,6 +1957,11 @@ class PartPricing(AjaxView):
role_required = ['sales_order.view', 'part.view']
def get_quantity(self):
""" Return set quantity in decimal format """
return Decimal(self.request.POST.get('quantity', 1))
def get_part(self):
try:
return Part.objects.get(id=self.kwargs['pk'])
@ -1965,12 +1970,12 @@ class PartPricing(AjaxView):
def get_pricing(self, quantity=1, currency=None):
try:
quantity = int(quantity)
except ValueError:
quantity = 1
# try:
# quantity = int(quantity)
# except ValueError:
# quantity = 1
if quantity < 1:
if quantity <= 0:
quantity = 1
# TODO - Capacity for price comparison in different currencies
@ -2000,16 +2005,19 @@ class PartPricing(AjaxView):
min_buy_price /= scaler
max_buy_price /= scaler
min_unit_buy_price = round(min_buy_price / quantity, 3)
max_unit_buy_price = round(max_buy_price / quantity, 3)
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
ctx['min_unit_buy_price'] = min_unit_buy_price
if max_buy_price:
ctx['max_total_buy_price'] = max_buy_price
ctx['max_unit_buy_price'] = max_buy_price / quantity
ctx['max_unit_buy_price'] = max_unit_buy_price
# BOM pricing information
if part.bom_count > 0:
@ -2022,16 +2030,19 @@ class PartPricing(AjaxView):
min_bom_price /= scaler
max_bom_price /= scaler
min_unit_bom_price = round(min_bom_price / quantity, 3)
max_unit_bom_price = round(max_bom_price / quantity, 3)
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
ctx['min_unit_bom_price'] = min_unit_bom_price
if max_bom_price:
ctx['max_total_bom_price'] = max_bom_price
ctx['max_unit_bom_price'] = max_bom_price / quantity
ctx['max_unit_bom_price'] = max_unit_bom_price
return ctx
@ -2043,10 +2054,11 @@ class PartPricing(AjaxView):
currency = None
try:
quantity = int(self.request.POST.get('quantity', 1))
except ValueError:
quantity = 1
quantity = self.get_quantity()
# Retain quantity value set by user
form = self.form_class()
form.fields['quantity'].initial = quantity
# TODO - How to handle pricing in different currencies?
currency = None
@ -2056,7 +2068,7 @@ class PartPricing(AjaxView):
'form_valid': False,
}
return self.renderJsonResponse(request, self.form_class(), data=data, context=self.get_pricing(quantity, currency))
return self.renderJsonResponse(request, form, data=data, context=self.get_pricing(quantity, currency))
class PartParameterTemplateCreate(AjaxCreateView):