diff --git a/src/backend/InvenTree/common/currency.py b/src/backend/InvenTree/common/currency.py index adb3b55cff..ca936c6e2d 100644 --- a/src/backend/InvenTree/common/currency.py +++ b/src/backend/InvenTree/common/currency.py @@ -162,13 +162,21 @@ def currency_exchange_plugins() -> Optional[list]: def get_price( instance, quantity, - moq=True, - multiples=True, - currency=None, + moq: bool = True, + multiples: bool = True, + currency: Optional[str] = None, break_name: str = 'price_breaks', ): """Calculate the price based on quantity price breaks. + Arguments: + instance: The model instance which contains the price break information + quantity: The quantity to calculate the price for + moq: If True, then minimum order quantity will be observed (CURRENTLY NOT IMPLEMENTED) + multiples: If True, then order multiples will be observed + currency: The currency code to use for the calculation (default is None) + break_name: The name of the price break field on the instance (default is 'price_breaks') + - Don't forget to add in flat-fee cost (base_cost field) - If MOQ (minimum order quantity) is required, bump quantity - If order multiples are to be observed, then we need to calculate based on that, too @@ -185,7 +193,7 @@ def get_price( return None # Check if quantity is fraction and disable multiples - multiples = quantity % 1 == 0 + multiples = multiples and (quantity % 1 == 0) # Order multiples if multiples: diff --git a/src/backend/InvenTree/common/models.py b/src/backend/InvenTree/common/models.py index bb89a0622b..9f198f0e92 100644 --- a/src/backend/InvenTree/common/models.py +++ b/src/backend/InvenTree/common/models.py @@ -1388,21 +1388,27 @@ class PriceBreak(MetaMixin): help_text=_('Unit price at specified quantity'), ) - def convert_to(self, currency_code): + def convert_to(self, currency_code: str, raise_error: bool = False): """Convert the unit-price at this price break to the specified currency code. - Args: + Arguments: currency_code: The currency code to convert to (e.g "USD" or "AUD") + raise_error: If True, raise an error if the conversion fails. If False, return None. """ try: converted = convert_money(self.price, currency_code) - except MissingRate: + except MissingRate: # pragma: no cover + InvenTree.exceptions.log_error('PriceBreak.convert_to') logger.warning( 'No currency conversion rate available for %s -> %s', self.price_currency, currency_code, ) - return self.price.amount + + if raise_error: + raise + + return None return converted.amount diff --git a/src/backend/InvenTree/part/models.py b/src/backend/InvenTree/part/models.py index 33d1d683ab..03e0b5f138 100644 --- a/src/backend/InvenTree/part/models.py +++ b/src/backend/InvenTree/part/models.py @@ -53,7 +53,7 @@ from common.settings import get_global_setting from InvenTree import helpers, validators from InvenTree.exceptions import log_error from InvenTree.fields import InvenTreeURLField -from InvenTree.helpers import decimal2money, decimal2string, normalize +from InvenTree.helpers import decimal2string, normalize from order import models as OrderModels from order.status_codes import ( PurchaseOrderStatus, @@ -3001,15 +3001,12 @@ class PartPricing(common.models.MetaMixin): try: self.update_overall_cost() - except Exception: - # If something has happened to the Part model, might throw an error - pass - - try: super().save(*args, **kwargs) except Exception: - # This error may be thrown if there is already duplicate pricing data - pass + log_error('PartPricing.save') + logger.error( + "Could not save PartPricing for part '%s' to the database", self.part + ) def update_bom_cost(self, save=True): """Recalculate BOM cost for the referenced Part instance. @@ -4426,29 +4423,6 @@ class BomItem(InvenTree.models.MetadataMixin, InvenTree.models.InvenTreeModel): return required - @property - def price_range(self, internal=False): - """Return the price-range for this BOM item.""" - # get internal price setting - use_internal = get_global_setting('PART_BOM_USE_INTERNAL_PRICE', False) - p_range = self.sub_part.get_price_range( - self.quantity, internal=use_internal and internal - ) - - if p_range is None: - return p_range - - p_min, p_max = p_range - - if p_min == p_max: - return decimal2money(p_min) - - # Convert to better string representation - p_min = decimal2money(p_min) - p_max = decimal2money(p_max) - - return f'{p_min} to {p_max}' - @receiver(post_save, sender=BomItem, dispatch_uid='update_bom_build_lines') def update_bom_build_lines(sender, instance, created, **kwargs):