From af1904b6e4762e08e87b74c0bdc1ed90d8822cf9 Mon Sep 17 00:00:00 2001 From: Oliver Walters Date: Thu, 27 May 2021 15:45:38 +1000 Subject: [PATCH] Simplify exhange rate backend --- InvenTree/InvenTree/exchange.py | 113 ++---------------- InvenTree/InvenTree/settings.py | 17 ++- InvenTree/InvenTree/tasks.py | 8 +- InvenTree/InvenTree/urls.py | 3 +- InvenTree/common/forms.py | 4 +- InvenTree/common/models.py | 18 +-- InvenTree/common/settings.py | 7 +- InvenTree/config_template.yaml | 3 + InvenTree/part/views.py | 2 +- .../templates/InvenTree/settings/tabs.html | 6 +- 10 files changed, 47 insertions(+), 134 deletions(-) diff --git a/InvenTree/InvenTree/exchange.py b/InvenTree/InvenTree/exchange.py index 0a75436b1e..dfbfff872c 100644 --- a/InvenTree/InvenTree/exchange.py +++ b/InvenTree/InvenTree/exchange.py @@ -1,120 +1,29 @@ from django.conf import settings as inventree_settings -from djmoney.contrib.exchange.backends.base import BaseExchangeBackend -from djmoney.contrib.exchange.models import Rate - -from common.models import InvenTreeSetting +from djmoney.contrib.exchange.backends.base import SimpleExchangeBackend -def get_exchange_rate_backend(): - """ Return the exchange rate backend set by user """ - - custom = InvenTreeSetting.get_setting('CUSTOM_EXCHANGE_RATES', False) - - if custom: - return InvenTreeManualExchangeBackend() - else: - return ExchangeRateHostBackend() - - -class InvenTreeManualExchangeBackend(BaseExchangeBackend): +class InvenTreeExchange(SimpleExchangeBackend): """ - Backend for manually updating currency exchange rates + Backend for automatically updating currency exchange rates. - See the documentation for django-money: https://github.com/django-money/django-money - - Specifically: https://github.com/django-money/django-money/tree/master/djmoney/contrib/exchange/backends + Uses the exchangerate.host service API """ - name = 'inventree' - url = None - custom_rates = True - base_currency = None - currencies = [] - - def update_default_currency(self): - """ Update to base currency """ - - self.base_currency = InvenTreeSetting.get_setting('INVENTREE_DEFAULT_CURRENCY', 'USD') - - def __init__(self, url=None): - """ Overrides init to update url, base currency and currencies """ - - self.url = url - - self.update_default_currency() - - # Update name - self.name = self.name + '-' + self.base_currency.lower() - - self.currencies = inventree_settings.CURRENCIES - - super().__init__() - - def get_rates(self, **kwargs): - """ Returns a mapping : """ - - return kwargs.get('rates', {}) - - def get_stored_rates(self): - """ Returns stored rate for specified backend and base currency """ - - stored_rates = {} - - stored_rates_obj = Rate.objects.all().prefetch_related('backend') - - for rate in stored_rates_obj: - # Find match for backend and base currency - if rate.backend.name == self.name and rate.backend.base_currency == self.base_currency: - # print(f'{rate.currency} | {rate.value} | {rate.backend} | {rate.backend.base_currency}') - stored_rates[rate.currency] = rate.value - - return stored_rates - - -class ExchangeRateHostBackend(InvenTreeManualExchangeBackend): - """ - Backend for https://exchangerate.host/ - """ - - name = "exchangerate.host" + name = "InvenTreeExchange" def __init__(self): self.url = "https://api.exchangerate.host/latest" - self.custom_rates = False - - super().__init__(url=self.url) + super().__init__() def get_params(self): # No API key is required - return {} + return { + } - def update_rates(self, base_currency=None): - """ Override update_rates method using currencies found in the settings - """ + def update_rates(self, base_currency=inventree_settings.BASE_CURRENCY): - if base_currency: - self.base_currency = base_currency - else: - self.update_default_currency() - - symbols = ','.join(self.currencies) + symbols = ','.join(inventree_settings.CURRENCIES) - super().update_rates(base_currency=self.base_currency, symbols=symbols) - - def get_rates(self, **params): - """ Returns a mapping : """ - - # Set base currency - params.update(base=self.base_currency) - - response = self.get_response(**params) - - try: - return self.parse_json(response)['rates'] - except KeyError: - # API response did not contain any rate - pass - - return {} + super().update_rates(base=base_currency, symbols=symbols) diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index 718a10b5e5..618c9f730f 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -19,6 +19,8 @@ import shutil import sys from datetime import datetime +import moneyed + import yaml from django.utils.translation import gettext_lazy as _ @@ -513,11 +515,20 @@ CURRENCIES = CONFIG.get( ], ) -DEFAULT_CURRENCY = get_setting( - 'INVENTREE_DEFAULT_CURRENCY', - CONFIG.get('default_currency', 'USD') +# Check that each provided currency is supported +for currency in CURRENCIES: + if currency not in moneyed.CURRENCIES: + print(f"Currency code '{currency}' is not supported") + sys.exit(1) + +BASE_CURRENCY = get_setting( + 'INVENTREE_BASE_CURRENCY', + CONFIG.get('base_currency', 'USD') ) +# Custom currency exchange backend +EXCHANGE_BACKEND = 'InvenTree.exchange.InvenTreeExchange' + # Extract email settings from the config file email_config = CONFIG.get('email', {}) diff --git a/InvenTree/InvenTree/tasks.py b/InvenTree/InvenTree/tasks.py index 365a94fd07..9a71d5d84c 100644 --- a/InvenTree/InvenTree/tasks.py +++ b/InvenTree/InvenTree/tasks.py @@ -167,16 +167,16 @@ def update_exchange_rates(): """ try: - import common.models - from InvenTree.exchange import ExchangeRateHostBackend + from InvenTree.exchange import InvenTreeExchange + from django.conf import settings except AppRegistryNotReady: # Apps not yet loaded! return - backend = ExchangeRateHostBackend() + backend = InvenTreeExchange() print(f"Updating exchange rates from {backend.url}") - base = common.models.InvenTreeSetting.get_setting('INVENTREE_DEFAULT_CURRENCY') + base = settings.BASE_CURRENCY print(f"Using base currency '{base}'") diff --git a/InvenTree/InvenTree/urls.py b/InvenTree/InvenTree/urls.py index d297dc18ad..88ee554203 100644 --- a/InvenTree/InvenTree/urls.py +++ b/InvenTree/InvenTree/urls.py @@ -41,7 +41,6 @@ from .views import IndexView, SearchView, DatabaseStatsView from .views import SettingsView, EditUserView, SetPasswordView from .views import AppearanceSelectView, SettingCategorySelectView from .views import DynamicJsView -from .views import CurrencySettingsView from common.views import SettingEdit @@ -91,7 +90,7 @@ settings_urls = [ url(r'^build/?', SettingsView.as_view(template_name='InvenTree/settings/build.html'), name='settings-build'), url(r'^purchase-order/?', SettingsView.as_view(template_name='InvenTree/settings/po.html'), name='settings-po'), url(r'^sales-order/?', SettingsView.as_view(template_name='InvenTree/settings/so.html'), name='settings-so'), - url(r'^currencies/?', CurrencySettingsView.as_view(), name='settings-currencies'), + url(r'^currencies/?', SettingsView.as_view(template_name='InvenTree/settings/currencies.html'), name='settings-currencies'), url(r'^(?P\d+)/edit/', SettingEdit.as_view(), name='setting-edit'), diff --git a/InvenTree/common/forms.py b/InvenTree/common/forms.py index bab7ede74c..f161c8cc01 100644 --- a/InvenTree/common/forms.py +++ b/InvenTree/common/forms.py @@ -13,6 +13,8 @@ from djmoney.forms.fields import MoneyField from InvenTree.forms import HelperForm from InvenTree.helpers import clean_decimal +from common.settings import currency_code_default + from .files import FileManager from .models import InvenTreeSetting @@ -182,7 +184,7 @@ class MatchItem(forms.Form): if 'price' in col_guess.lower(): self.fields[field_name] = MoneyField( label=_(col_guess), - default_currency=InvenTreeSetting.get_setting('INVENTREE_DEFAULT_CURRENCY'), + default_currency=currency_code_default(), decimal_places=5, max_digits=19, required=False, diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index 74c6c82b41..6cfe5915e0 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -19,6 +19,8 @@ from djmoney.models.fields import MoneyField from djmoney.contrib.exchange.models import convert_money from djmoney.contrib.exchange.exceptions import MissingRate +from common.settings import currency_code_default + from django.utils.translation import ugettext_lazy as _ from django.core.validators import MinValueValidator, URLValidator from django.core.exceptions import ValidationError @@ -80,20 +82,6 @@ class InvenTreeSetting(models.Model): 'default': '', }, - 'INVENTREE_DEFAULT_CURRENCY': { - 'name': _('Default Currency'), - 'description': _('Default currency'), - 'default': 'USD', - 'choices': djmoney.settings.CURRENCY_CHOICES, - }, - - 'CUSTOM_EXCHANGE_RATES': { - 'name': _('Custom Exchange Rates'), - 'description': _('Enable custom exchange rates'), - 'validator': bool, - 'default': False, - }, - 'INVENTREE_DOWNLOAD_FROM_URL': { 'name': _('Download from URL'), 'description': _('Allow download of remote images and files from external URL'), @@ -766,7 +754,7 @@ def get_price(instance, quantity, moq=True, multiples=True, currency=None): if currency is None: # Default currency selection - currency = InvenTreeSetting.get_setting('INVENTREE_DEFAULT_CURRENCY') + currency = currency_code_default() pb_min = None for pb in instance.price_breaks.all(): diff --git a/InvenTree/common/settings.py b/InvenTree/common/settings.py index 4d98bc495b..60265f4cb9 100644 --- a/InvenTree/common/settings.py +++ b/InvenTree/common/settings.py @@ -7,7 +7,8 @@ from __future__ import unicode_literals from moneyed import CURRENCIES -from common.models import InvenTreeSetting +import common.models +from django.conf import settings def currency_code_default(): @@ -15,7 +16,7 @@ def currency_code_default(): Returns the default currency code (or USD if not specified) """ - code = InvenTreeSetting.get_setting('INVENTREE_DEFAULT_CURRENCY') + code = settings.BASE_CURRENCY if code not in CURRENCIES: code = 'USD' @@ -28,4 +29,4 @@ def stock_expiry_enabled(): Returns True if the stock expiry feature is enabled """ - return InvenTreeSetting.get_setting('STOCK_ENABLE_EXPIRY') + return common.models.InvenTreeSetting.get_setting('STOCK_ENABLE_EXPIRY') diff --git a/InvenTree/config_template.yaml b/InvenTree/config_template.yaml index 87dfb6b545..1333b876b8 100644 --- a/InvenTree/config_template.yaml +++ b/InvenTree/config_template.yaml @@ -52,6 +52,9 @@ language: en-us # Use the environment variable INVENTREE_TIMEZONE timezone: UTC +# Base currency code +base_currency: USD + # List of currencies supported by default. # Add other currencies here to allow use in InvenTree currencies: diff --git a/InvenTree/part/views.py b/InvenTree/part/views.py index 2fabdb9fc8..af817f1cf3 100644 --- a/InvenTree/part/views.py +++ b/InvenTree/part/views.py @@ -2675,7 +2675,7 @@ class PartSalePriceBreakCreate(AjaxCreateView): initials['part'] = self.get_part() - default_currency = InvenTreeSetting.get_setting('INVENTREE_DEFAULT_CURRENCY') + default_currency = settings.BASE_CURRENCY currency = CURRENCIES.get(default_currency, None) if currency is not None: diff --git a/InvenTree/templates/InvenTree/settings/tabs.html b/InvenTree/templates/InvenTree/settings/tabs.html index 360618fc34..86a88b68f0 100644 --- a/InvenTree/templates/InvenTree/settings/tabs.html +++ b/InvenTree/templates/InvenTree/settings/tabs.html @@ -15,6 +15,9 @@
  • {% trans "Global" %}
  • +
  • + {% trans "Currencies" %} +
  • {% trans "Report" %}
  • @@ -36,8 +39,5 @@
  • {% trans "Sales Orders" %}
  • -
  • - {% trans "Currencies" %} -
  • {% endif %}