From bed6a7e49c11f2cbb8ad4eb12ef1e6a16f16e616 Mon Sep 17 00:00:00 2001 From: eeintech Date: Thu, 20 May 2021 09:49:56 -0400 Subject: [PATCH] Added exchange rates form --- InvenTree/InvenTree/exchange.py | 61 +++++++++++++------ InvenTree/InvenTree/forms.py | 36 ++++++++++- InvenTree/InvenTree/tasks.py | 10 +-- InvenTree/InvenTree/urls.py | 5 +- InvenTree/InvenTree/views.py | 37 ++++++++++- .../InvenTree/settings/currencies.html | 19 +++--- 6 files changed, 125 insertions(+), 43 deletions(-) diff --git a/InvenTree/InvenTree/exchange.py b/InvenTree/InvenTree/exchange.py index 59d2883e2a..03891828a0 100644 --- a/InvenTree/InvenTree/exchange.py +++ b/InvenTree/InvenTree/exchange.py @@ -1,12 +1,21 @@ +from django.core.exceptions import ImproperlyConfigured from django.conf import settings as inventree_settings from djmoney import settings as djmoney_settings from djmoney.contrib.exchange.backends.base import BaseExchangeBackend -from djmoney.contrib.exchange.backends import FixerBackend from common.models import InvenTreeSetting +def get_exchange_rate_backend(): + """ Return the exchange rate backend set by user """ + + if 'InvenTreeManualExchangeBackend' in inventree_settings.EXCHANGE_BACKEND: + return InvenTreeManualExchangeBackend() + else: + return InvenTreeFixerExchangeBackend() + + class InvenTreeManualExchangeBackend(BaseExchangeBackend): """ Backend for manually updating currency exchange rates @@ -16,22 +25,39 @@ class InvenTreeManualExchangeBackend(BaseExchangeBackend): Specifically: https://github.com/django-money/django-money/tree/master/djmoney/contrib/exchange/backends """ - name = "inventree" + name = 'inventree' url = None + default_currency = None + currencies = [] + + def update_default_currency(self): + + self.default_currency = InvenTreeSetting.get_setting('INVENTREE_DEFAULT_CURRENCY', inventree_settings.BASE_CURRENCY) + + def __init__(self, url=None): + + self.url = url + + self.update_default_currency() + + self.currencies = inventree_settings.CURRENCIES + + super().__init__() def get_rates(self, **kwargs): - """ - Do not get any rates... - """ + """ Returns a mapping : """ return {} -class InvenTreeFixerExchangeBackend(FixerBackend): +class InvenTreeFixerExchangeBackend(InvenTreeManualExchangeBackend): """ Backend for updating currency exchange rates using Fixer.IO API """ + name = 'fixer.io' + access_key = None + def get_api_key(self): """ Get API key from global settings """ @@ -48,18 +74,17 @@ class InvenTreeFixerExchangeBackend(FixerBackend): fixer_api_key = self.get_api_key() - super().__init__(url=djmoney_settings.FIXER_URL, access_key=fixer_api_key) + if fixer_api_key is None: + raise ImproperlyConfigured("fixer.io API key is needed to use InvenTreeFixerExchangeBackend") + + self.access_key = fixer_api_key + + super().__init__(url=djmoney_settings.FIXER_URL) def update_rates(self): - """ Override update_rates method using currencies found in the settings """ + """ Override update_rates method using currencies found in the settings + """ + + symbols = ','.join(self.currencies) - currencies = ','.join(inventree_settings.CURRENCIES) - - base = inventree_settings.BASE_CURRENCY - - super().update_rates(base_currency=base, symbols=currencies) - - def get_rates(self, **kwargs): - """ Returns a mapping : """ - - return {} + super().update_rates(base_currency=self.base_currency, symbols=symbols) diff --git a/InvenTree/InvenTree/forms.py b/InvenTree/InvenTree/forms.py index 52d1c8758f..a744671afb 100644 --- a/InvenTree/InvenTree/forms.py +++ b/InvenTree/InvenTree/forms.py @@ -7,12 +7,15 @@ from __future__ import unicode_literals from django.utils.translation import ugettext_lazy as _ from django import forms +from django.contrib.auth.models import User + from crispy_forms.helper import FormHelper from crispy_forms.layout import Layout, Field from crispy_forms.bootstrap import PrependedText, AppendedText, PrependedAppendedText, StrictButton, Div -from django.contrib.auth.models import User + from common.models import ColorTheme from part.models import PartCategory +from .exchange import InvenTreeManualExchangeBackend class HelperForm(forms.ModelForm): @@ -236,3 +239,34 @@ class SettingCategorySelectForm(forms.ModelForm): css_class='row', ), ) + + +class SettingExchangeRatesForm(forms.Form): + """ Form for displaying and setting currency exchange rates manually """ + + def __init__(self, *args, **kwargs): + + super().__init__(*args, **kwargs) + + exchange_rate_backend = InvenTreeManualExchangeBackend() + + # Update default currency (in case it has changed) + exchange_rate_backend.update_default_currency() + + for currency in exchange_rate_backend.currencies: + if currency != exchange_rate_backend.default_currency: + # Set field name + field_name = currency + # Set field input box + self.fields[field_name] = forms.CharField( + label=field_name, + required=False, + widget=forms.NumberInput(attrs={ + 'name': field_name, + 'class': 'numberinput', + 'type': 'number', + 'min': '0', + 'step': 'any', + 'value': '', + }) + ) diff --git a/InvenTree/InvenTree/tasks.py b/InvenTree/InvenTree/tasks.py index fb6a45f368..0468365dae 100644 --- a/InvenTree/InvenTree/tasks.py +++ b/InvenTree/InvenTree/tasks.py @@ -167,17 +167,13 @@ def update_exchange_rates(): """ try: - from .exchange import InvenTreeManualExchangeBackend, InvenTreeFixerExchangeBackend - from django.conf import settings + from .exchange import get_exchange_rate_backend except AppRegistryNotReady: # Apps not yet loaded! return - # Get backend - if 'InvenTreeManualExchangeBackend' in settings.EXCHANGE_BACKEND: - backend = InvenTreeManualExchangeBackend() - else: - backend = InvenTreeFixerExchangeBackend() + # Get exchange rate backend + backend = get_exchange_rate_backend() # Update rates backend.update_rates() diff --git a/InvenTree/InvenTree/urls.py b/InvenTree/InvenTree/urls.py index d3132ca2a8..d297dc18ad 100644 --- a/InvenTree/InvenTree/urls.py +++ b/InvenTree/InvenTree/urls.py @@ -41,7 +41,7 @@ from .views import IndexView, SearchView, DatabaseStatsView from .views import SettingsView, EditUserView, SetPasswordView from .views import AppearanceSelectView, SettingCategorySelectView from .views import DynamicJsView -from .views import ExchangeRatesView +from .views import CurrencySettingsView from common.views import SettingEdit @@ -91,8 +91,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/?', SettingsView.as_view(template_name='InvenTree/settings/currencies.html'), name='settings-currencies'), - url(r'^echange-rates/?', ExchangeRatesView.as_view(), name='refresh-exchange-rates'), + url(r'^currencies/?', CurrencySettingsView.as_view(), name='settings-currencies'), url(r'^(?P\d+)/edit/', SettingEdit.as_view(), name='setting-edit'), diff --git a/InvenTree/InvenTree/views.py b/InvenTree/InvenTree/views.py index bd03a18dda..50f4a095e8 100644 --- a/InvenTree/InvenTree/views.py +++ b/InvenTree/InvenTree/views.py @@ -26,8 +26,9 @@ from users.models import check_user_role, RuleSet from .forms import DeleteForm, EditUserForm, SetPasswordForm from .forms import ColorThemeSelectForm, SettingCategorySelectForm +from .forms import SettingExchangeRatesForm from .helpers import str2bool -from .tasks import update_exchange_rates +from .exchange import get_exchange_rate_backend from rest_framework import views @@ -911,14 +912,44 @@ class DatabaseStatsView(AjaxView): return ctx -class ExchangeRatesView(SettingsView): +class CurrencySettingsView(FormView): + form_class = SettingExchangeRatesForm + template_name = 'InvenTree/settings/currencies.html' success_url = reverse_lazy('settings-currencies') + def get_context_data(self, **kwargs): + + context = super().get_context_data(**kwargs) + + # Get exchange rate backend + exchange_rate_backend = get_exchange_rate_backend() + + context['exchange_backend'] = exchange_rate_backend.name + + return context + + def get_form(self): + + form = super().get_form() + + # Get exchange rate backend + exchange_rate_backend = get_exchange_rate_backend() + + if exchange_rate_backend.name == 'fixer.io': + # Disable all the fields + for field in form.fields: + form.fields[field].disabled = True + + return form + def post(self, request, *args, **kwargs): + # Get exchange rate backend + exchange_rate_backend = get_exchange_rate_backend() + # Process exchange rates - update_exchange_rates() + exchange_rate_backend.update_rates() # TODO: Update context diff --git a/InvenTree/templates/InvenTree/settings/currencies.html b/InvenTree/templates/InvenTree/settings/currencies.html index 9ec5b518fb..52d6558bad 100644 --- a/InvenTree/templates/InvenTree/settings/currencies.html +++ b/InvenTree/templates/InvenTree/settings/currencies.html @@ -26,18 +26,15 @@ - -
- -
+ {% csrf_token %} - + {% load crispy_forms_tags %} + {% crispy form %} + {% if exchange_backend == 'fixer.io' %} + + {% else %} + + {% endif %}
{% endblock %} - -{% block js_ready %} -{{ block.super }} -{% comment %} TODO: Update exchange-rates table! {% endcomment %} -{% comment %} Or do it using context instead of JS? {% endcomment %} -{% endblock %} \ No newline at end of file