2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-04-30 04:26:44 +00:00

Add 'currency' option for company

- e.g. an external supplier might have a default currency
- Adds a form input which only allows selection of allowed currency codes
- Add unit testing for currency validation
This commit is contained in:
Oliver Walters 2020-11-12 11:02:10 +11:00
parent ebac06ebee
commit 1532be9c1e
7 changed files with 158 additions and 19 deletions

View File

@ -6,11 +6,22 @@ from django.conf import settings
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from moneyed import CURRENCIES
import common.models import common.models
import re import re
def validate_currency_code(code):
"""
Check that a given code is a valid currency code.
"""
if code not in CURRENCIES:
raise ValidationError(_('Not a valid currency code'))
def allowable_url_schemes(): def allowable_url_schemes():
""" Return the list of allowable URL schemes. """ Return the list of allowable URL schemes.
In addition to the default schemes allowed by Django, In addition to the default schemes allowed by Django,

View File

@ -0,0 +1,23 @@
"""
User-configurable settings for the common app
"""
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from moneyed import CURRENCIES
from common.models import InvenTreeSetting
def currency_code_default():
"""
Returns the default currency code (or USD if not specified)
"""
code = InvenTreeSetting.get_setting('INVENTREE_DEFAULT_CURRENCY')
if code not in CURRENCIES:
code = 'USD'
return code

View File

@ -9,10 +9,13 @@ from InvenTree.forms import HelperForm
from InvenTree.fields import RoundingDecimalFormField from InvenTree.fields import RoundingDecimalFormField
from django.utils.translation import ugettext as _ from django.utils.translation import ugettext as _
import django.forms
import djmoney.settings
from djmoney.forms.fields import MoneyField from djmoney.forms.fields import MoneyField
from common.models import InvenTreeSetting from common.models import InvenTreeSetting
import common.settings
from .models import Company from .models import Company
from .models import SupplierPart from .models import SupplierPart
@ -30,6 +33,13 @@ class EditCompanyForm(HelperForm):
'phone': 'fa-phone', 'phone': 'fa-phone',
} }
currency = django.forms.ChoiceField(
required=False,
help_text=_('Default currency used for this company'),
choices=[('', '----------')] + djmoney.settings.CURRENCY_CHOICES,
initial=common.settings.currency_code_default,
)
class Meta: class Meta:
model = Company model = Company
fields = [ fields = [
@ -37,6 +47,7 @@ class EditCompanyForm(HelperForm):
'description', 'description',
'website', 'website',
'address', 'address',
'currency',
'phone', 'phone',
'email', 'email',
'contact', 'contact',

View File

@ -0,0 +1,19 @@
# Generated by Django 3.0.7 on 2020-11-11 23:22
import InvenTree.validators
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('company', '0028_remove_supplierpricebreak_cost'),
]
operations = [
migrations.AddField(
model_name='company',
name='currency',
field=models.CharField(blank=True, help_text='Default currency used for this company', max_length=3, validators=[InvenTree.validators.validate_currency_code], verbose_name='Currency'),
),
]

View File

@ -26,6 +26,8 @@ from InvenTree.helpers import normalize
from InvenTree.fields import InvenTreeURLField from InvenTree.fields import InvenTreeURLField
from InvenTree.status_codes import PurchaseOrderStatus from InvenTree.status_codes import PurchaseOrderStatus
import InvenTree.validators
import common.models import common.models
@ -77,6 +79,7 @@ class Company(models.Model):
is_customer: boolean value, is this company a customer is_customer: boolean value, is this company a customer
is_supplier: boolean value, is this company a supplier is_supplier: boolean value, is this company a supplier
is_manufacturer: boolean value, is this company a manufacturer is_manufacturer: boolean value, is this company a manufacturer
currency_code: Specifies the default currency for the company
""" """
class Meta: class Meta:
@ -126,6 +129,14 @@ class Company(models.Model):
is_manufacturer = models.BooleanField(default=False, help_text=_('Does this company manufacture parts?')) is_manufacturer = models.BooleanField(default=False, help_text=_('Does this company manufacture parts?'))
currency = models.CharField(
max_length=3,
verbose_name=_('Currency'),
blank=True,
help_text=_('Default currency used for this company'),
validators=[InvenTree.validators.validate_currency_code],
)
def __str__(self): def __str__(self):
""" Get string representation of a Company """ """ Get string representation of a Company """
return "{n} - {d}".format(n=self.name, d=self.description) return "{n} - {d}".format(n=self.name, d=self.description)

View File

@ -8,7 +8,43 @@
<h4>{% trans "Company Details" %}</h4> <h4>{% trans "Company Details" %}</h4>
<hr> <hr>
<table class='table table-striped'> <div class='row'>
<div class='col-sm-6'>
<table class='table table-striped'>
<col width='25'>
<col>
<tr>
<td><span class='fas fa-font'></span></td>
<td>{% trans "Company Name" %}</td>
<td>{{ company.name }}</td>
</tr>
<tr>
<td><span class='fas fa-info'></span></td>
<td>{% trans "Description" %}</td>
<td>{{ company.description }}</td>
</tr>
<tr>
<td><span class='fas fa-globe'></span></td>
<td>{% trans "Website" %}</td>
<td>
{% if company.website %}<a href='{{ company.website }}'>{{ company.website }}</a>
{% else %}<i>{% trans "No website specified" %}</i>
{% endif %}
</td>
</tr>
<tr>
<td><span class='fas fa-dollar-sign'></span></td>
<td>{% trans "Currency" %}</td>
<td>
{% if company.currency %}{{ company.currency }}
{% else %}<i>{% trans "Uses default currency" %}</i>
{% endif %}
</td>
</tr>
</table>
</div>
<div class='col-sm-6'>
<table class='table table-striped'>
<col width='25'> <col width='25'>
<col> <col>
<tr> <tr>
@ -26,7 +62,10 @@
<td>{% trans "Customer" %}</td> <td>{% trans "Customer" %}</td>
<td>{% include 'yesnolabel.html' with value=company.is_customer %}</td> <td>{% include 'yesnolabel.html' with value=company.is_customer %}</td>
</tr> </tr>
</table> </table>
</div>
</div>
{% endblock %} {% endblock %}
{% block js_ready %} {% block js_ready %}

View File

@ -1,4 +1,5 @@
from django.test import TestCase from django.test import TestCase
from django.core.exceptions import ValidationError
import os import os
@ -119,6 +120,30 @@ class CompanySimpleTest(TestCase):
self.assertIsNone(m3x12.get_price_info(3)) self.assertIsNone(m3x12.get_price_info(3))
self.assertIsNotNone(m3x12.get_price_info(50)) self.assertIsNotNone(m3x12.get_price_info(50))
def test_currency_validation(self):
"""
Test validation for currency selection
"""
# Create a company with a valid currency code (should pass)
company = Company.objects.create(
name='Test',
description='Toast',
currency='AUD',
)
company.full_clean()
# Create a company with an invalid currency code (should fail)
company = Company.objects.create(
name='test',
description='Toasty',
currency='XZY',
)
with self.assertRaises(ValidationError):
company.full_clean()
class ContactSimpleTest(TestCase): class ContactSimpleTest(TestCase):