mirror of
https://github.com/inventree/InvenTree
synced 2024-08-30 18:33:04 +00:00
Currency API Updates (#4300)
* Adds an API endpoint for manually updating / refreshing currency data from the server * Update currency rates manually from the settings page * Add 'last updated' information to the currency exchange backend * Load currency exchange data via API (on setings page) * Bump API version * Table cleanup
This commit is contained in:
parent
3869d98b32
commit
ce3dabedb6
@ -2,11 +2,15 @@
|
||||
|
||||
|
||||
# InvenTree API version
|
||||
INVENTREE_API_VERSION = 92
|
||||
INVENTREE_API_VERSION = 93
|
||||
|
||||
"""
|
||||
Increment this API version number whenever there is a significant change to the API that any clients need to know about
|
||||
|
||||
v93 -> 2023-02-03 : https://github.com/inventree/InvenTree/pull/4300
|
||||
- Adds extra information to the currency exchange endpoint
|
||||
- Adds API endpoint for manually updating exchange rates
|
||||
|
||||
v92 -> 2023-02-02 : https://github.com/inventree/InvenTree/pull/4293
|
||||
- Adds API endpoint for currency exchange information
|
||||
|
||||
|
@ -31,8 +31,8 @@ from stock.urls import stock_urls
|
||||
from users.api import user_urls
|
||||
|
||||
from .api import InfoView, NotFoundView
|
||||
from .views import (AboutView, AppearanceSelectView, CurrencyRefreshView,
|
||||
CustomConnectionsView, CustomEmailView, CustomLoginView,
|
||||
from .views import (AboutView, AppearanceSelectView, CustomConnectionsView,
|
||||
CustomEmailView, CustomLoginView,
|
||||
CustomPasswordResetFromKeyView,
|
||||
CustomSessionDeleteOtherView, CustomSessionDeleteView,
|
||||
CustomTwoFactorRemove, DatabaseStatsView, DynamicJsView,
|
||||
@ -73,7 +73,6 @@ settings_urls = [
|
||||
re_path(r'^i18n/?', include('django.conf.urls.i18n')),
|
||||
|
||||
re_path(r'^appearance/?', AppearanceSelectView.as_view(), name='settings-appearance'),
|
||||
re_path(r'^currencies-refresh/', CurrencyRefreshView.as_view(), name='settings-currencies-refresh'),
|
||||
|
||||
# Catch any other urls
|
||||
re_path(r'^.*$', SettingsView.as_view(template_name='InvenTree/settings/settings.html'), name='settings'),
|
||||
|
@ -652,20 +652,6 @@ class CustomLoginView(LoginView):
|
||||
return super().get(request, *args, **kwargs)
|
||||
|
||||
|
||||
class CurrencyRefreshView(RedirectView):
|
||||
"""POST endpoint to refresh / update exchange rates."""
|
||||
|
||||
url = reverse_lazy("settings-currencies")
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
"""On a POST request we will attempt to refresh the exchange rates."""
|
||||
from InvenTree.tasks import offload_task, update_exchange_rates
|
||||
|
||||
offload_task(update_exchange_rates, force_sync=True)
|
||||
|
||||
return redirect(reverse_lazy('settings'))
|
||||
|
||||
|
||||
class AppearanceSelectView(RedirectView):
|
||||
"""View for selecting a color theme."""
|
||||
|
||||
|
@ -9,7 +9,7 @@ from django.views.decorators.csrf import csrf_exempt
|
||||
|
||||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from django_q.tasks import async_task
|
||||
from djmoney.contrib.exchange.models import Rate
|
||||
from djmoney.contrib.exchange.models import ExchangeBackend, Rate
|
||||
from rest_framework import filters, permissions, serializers
|
||||
from rest_framework.exceptions import NotAcceptable, NotFound
|
||||
from rest_framework.permissions import IsAdminUser
|
||||
@ -104,10 +104,7 @@ class WebhookView(CsrfExemptMixin, APIView):
|
||||
|
||||
|
||||
class CurrencyExchangeView(APIView):
|
||||
"""API endpoint for displaying currency information
|
||||
|
||||
TODO: Add a POST hook to refresh / update the currency exchange data
|
||||
"""
|
||||
"""API endpoint for displaying currency information"""
|
||||
|
||||
permission_classes = [
|
||||
permissions.IsAuthenticated,
|
||||
@ -122,9 +119,17 @@ class CurrencyExchangeView(APIView):
|
||||
except Exception:
|
||||
rates = []
|
||||
|
||||
# Information on last update
|
||||
try:
|
||||
backend = ExchangeBackend.objects.get(name='InvenTreeExchange')
|
||||
updated = backend.last_update
|
||||
except Exception:
|
||||
updated = None
|
||||
|
||||
response = {
|
||||
'base_currency': common.models.InvenTreeSetting.get_setting('INVENTREE_DEFAULT_CURRENCY', 'USD'),
|
||||
'exchange_rates': {}
|
||||
'exchange_rates': {},
|
||||
'updated': updated,
|
||||
}
|
||||
|
||||
for rate in rates:
|
||||
@ -133,6 +138,29 @@ class CurrencyExchangeView(APIView):
|
||||
return Response(response)
|
||||
|
||||
|
||||
class CurrencyRefreshView(APIView):
|
||||
"""API endpoint for manually refreshing currency exchange rates.
|
||||
|
||||
User must be a 'staff' user to access this endpoint
|
||||
"""
|
||||
|
||||
permission_classes = [
|
||||
permissions.IsAuthenticated,
|
||||
permissions.IsAdminUser,
|
||||
]
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
"""Performing a POST request will update currency exchange rates"""
|
||||
|
||||
from InvenTree.tasks import update_exchange_rates
|
||||
|
||||
update_exchange_rates
|
||||
|
||||
return Response({
|
||||
'success': 'Exchange rates updated',
|
||||
})
|
||||
|
||||
|
||||
class SettingsList(ListAPI):
|
||||
"""Generic ListView for settings.
|
||||
|
||||
@ -452,6 +480,7 @@ common_api_urls = [
|
||||
# Currencies
|
||||
re_path(r'^currency/', include([
|
||||
re_path(r'^exchange/', CurrencyExchangeView.as_view(), name='api-currency-exchange'),
|
||||
re_path(r'^refresh/', CurrencyRefreshView.as_view(), name='api-currency-refresh'),
|
||||
])),
|
||||
|
||||
# Notifications
|
||||
|
@ -11,6 +11,7 @@
|
||||
<div class='panel-content'>
|
||||
<table class='table table-striped table-condensed'>
|
||||
<tbody>
|
||||
{% include "InvenTree/settings/setting.html" with key="INVENTREE_DEFAULT_CURRENCY" icon="fa-globe" %}
|
||||
{% include "InvenTree/settings/setting.html" with key="PART_INTERNAL_PRICE" %}
|
||||
{% include "InvenTree/settings/setting.html" with key="PART_BOM_USE_INTERNAL_PRICE" %}
|
||||
{% include "InvenTree/settings/setting.html" with key="PRICING_DECIMAL_PLACES" %}
|
||||
@ -29,54 +30,27 @@
|
||||
|
||||
<div class='panel-heading'>
|
||||
<div class='d-flex flex-wrap'>
|
||||
<h4>{% trans "Currency Settings" %}</h4>
|
||||
<h4>{% trans "Exchange Rates" %}</h4>
|
||||
{% include "spacer.html" %}
|
||||
<div class='btn-group' role='group'>
|
||||
<form action='{% url "settings-currencies-refresh" %}' method='post'>
|
||||
<div id='refresh-rates-form'>
|
||||
{% csrf_token %}
|
||||
<button type='submit' id='update-rates' class='btn btn-primary float-right'>{% trans "Update Now" %}</button>
|
||||
</div>
|
||||
</form>
|
||||
<button type='button' id='btn-update-rates' class='btn btn-primary float-right'>
|
||||
<span class='fas fa-sync-alt'></span> {% trans "Update Now" %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class='panel-content'>
|
||||
{% if rates_updated %}
|
||||
<div class='alert alert-block alert-info'>
|
||||
{% trans "Last Update" %} - {{ rates_updated }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class='alert alert-block alert-warning'>
|
||||
{% trans "Last Update" %} - {% trans "Never" %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class='alert alert-block alert-info'>
|
||||
{% trans "Last Update" %} - {{ rates_updated }}
|
||||
</div>
|
||||
{% else %}
|
||||
<div class='alert alert-block alert-warning'>
|
||||
{% trans "Last Update" %} - {% trans "Never" %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<table class='table table-striped table-condensed'>
|
||||
<tbody>
|
||||
{% include "InvenTree/settings/setting.html" with key="INVENTREE_DEFAULT_CURRENCY" icon="fa-globe" %}
|
||||
<table class='table table-striped table-condensed' id='exchange-rate-table'></table>
|
||||
|
||||
<tr>
|
||||
<td></td>
|
||||
<th>{% trans "Base Currency" %}</th>
|
||||
<th>{{ base_currency }}</th>
|
||||
<th colspan='2'></th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<th>{% trans "Exchange Rates" %}</th>
|
||||
<th>{% trans "Currency" %}</th>
|
||||
<th>{% trans "Rate" %}</th>
|
||||
</tr>
|
||||
{% for rate in rates %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td>{{ rate.currency }}</td>
|
||||
<td>{{ rate.value }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endblock panel_content %}
|
||||
|
@ -151,6 +151,52 @@ $("#edit-password").on('click', function() {
|
||||
);
|
||||
});
|
||||
|
||||
$('#btn-update-rates').click(function() {
|
||||
inventreePut(
|
||||
'{% url "api-currency-refresh" %}',
|
||||
{},
|
||||
{
|
||||
method: 'POST',
|
||||
success: function(data) {
|
||||
location.reload();
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
$('#exchange-rate-table').inventreeTable({
|
||||
url: '{% url "api-currency-exchange" %}',
|
||||
search: false,
|
||||
showColumns: false,
|
||||
sortable: true,
|
||||
sidePagination: 'client',
|
||||
onLoadSuccess: function(response) {
|
||||
var data = response.exchange_rates || {};
|
||||
|
||||
var rows = [];
|
||||
|
||||
for (var currency in data) {
|
||||
rows.push({
|
||||
'currency': currency,
|
||||
'rate': data[currency],
|
||||
});
|
||||
}
|
||||
|
||||
$('#exchange-rate-table').bootstrapTable('load', rows);
|
||||
},
|
||||
columns: [
|
||||
{
|
||||
field: 'currency',
|
||||
sortable: true,
|
||||
title: '{% trans "Currency" %}',
|
||||
},
|
||||
{
|
||||
field: 'rate',
|
||||
sortable: true,
|
||||
title: '{% trans "Rate" %}',
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
$('#category-select').select2({
|
||||
placeholder: '',
|
||||
|
Loading…
Reference in New Issue
Block a user