diff --git a/InvenTree/InvenTree/validators.py b/InvenTree/InvenTree/validators.py
index e85dc40810..70322df062 100644
--- a/InvenTree/InvenTree/validators.py
+++ b/InvenTree/InvenTree/validators.py
@@ -6,11 +6,22 @@ from django.conf import settings
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
+from moneyed import CURRENCIES
+
import common.models
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():
""" Return the list of allowable URL schemes.
In addition to the default schemes allowed by Django,
diff --git a/InvenTree/common/settings.py b/InvenTree/common/settings.py
new file mode 100644
index 0000000000..832a07f040
--- /dev/null
+++ b/InvenTree/common/settings.py
@@ -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
diff --git a/InvenTree/company/forms.py b/InvenTree/company/forms.py
index 7a27f08251..27f2dce0dc 100644
--- a/InvenTree/company/forms.py
+++ b/InvenTree/company/forms.py
@@ -9,10 +9,13 @@ from InvenTree.forms import HelperForm
from InvenTree.fields import RoundingDecimalFormField
from django.utils.translation import ugettext as _
+import django.forms
+import djmoney.settings
from djmoney.forms.fields import MoneyField
from common.models import InvenTreeSetting
+import common.settings
from .models import Company
from .models import SupplierPart
@@ -30,6 +33,13 @@ class EditCompanyForm(HelperForm):
'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:
model = Company
fields = [
@@ -37,6 +47,7 @@ class EditCompanyForm(HelperForm):
'description',
'website',
'address',
+ 'currency',
'phone',
'email',
'contact',
diff --git a/InvenTree/company/migrations/0029_company_currency.py b/InvenTree/company/migrations/0029_company_currency.py
new file mode 100644
index 0000000000..fda3c15e96
--- /dev/null
+++ b/InvenTree/company/migrations/0029_company_currency.py
@@ -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'),
+ ),
+ ]
diff --git a/InvenTree/company/models.py b/InvenTree/company/models.py
index 75b765bb2e..711a1966ff 100644
--- a/InvenTree/company/models.py
+++ b/InvenTree/company/models.py
@@ -26,6 +26,8 @@ from InvenTree.helpers import normalize
from InvenTree.fields import InvenTreeURLField
from InvenTree.status_codes import PurchaseOrderStatus
+import InvenTree.validators
+
import common.models
@@ -77,6 +79,7 @@ class Company(models.Model):
is_customer: boolean value, is this company a customer
is_supplier: boolean value, is this company a supplier
is_manufacturer: boolean value, is this company a manufacturer
+ currency_code: Specifies the default currency for the company
"""
class Meta:
@@ -126,6 +129,14 @@ class Company(models.Model):
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):
""" Get string representation of a Company """
return "{n} - {d}".format(n=self.name, d=self.description)
diff --git a/InvenTree/company/templates/company/detail.html b/InvenTree/company/templates/company/detail.html
index a166de9048..7243cf4fbc 100644
--- a/InvenTree/company/templates/company/detail.html
+++ b/InvenTree/company/templates/company/detail.html
@@ -8,25 +8,64 @@
{% trans "Company Details" %}
-
-
-
-
- |
- {% trans "Manufacturer" %} |
- {% include "yesnolabel.html" with value=company.is_manufacturer %} |
-
-
- |
- {% trans "Supplier" %} |
- {% include 'yesnolabel.html' with value=company.is_supplier %} |
-
-
- |
- {% trans "Customer" %} |
- {% include 'yesnolabel.html' with value=company.is_customer %} |
-
-
+
+
+
+
+
+
+ |
+ {% trans "Company Name" %} |
+ {{ company.name }} |
+
+
+ |
+ {% trans "Description" %} |
+ {{ company.description }} |
+
+
+ |
+ {% trans "Website" %} |
+
+ {% if company.website %}{{ company.website }}
+ {% else %}{% trans "No website specified" %}
+ {% endif %}
+ |
+
+
+ |
+ {% trans "Currency" %} |
+
+ {% if company.currency %}{{ company.currency }}
+ {% else %}{% trans "Uses default currency" %}
+ {% endif %}
+ |
+
+
+
+
+
+
+
+
+ |
+ {% trans "Manufacturer" %} |
+ {% include "yesnolabel.html" with value=company.is_manufacturer %} |
+
+
+ |
+ {% trans "Supplier" %} |
+ {% include 'yesnolabel.html' with value=company.is_supplier %} |
+
+
+ |
+ {% trans "Customer" %} |
+ {% include 'yesnolabel.html' with value=company.is_customer %} |
+
+
+
+
+
{% endblock %}
{% block js_ready %}
diff --git a/InvenTree/company/tests.py b/InvenTree/company/tests.py
index 24c7e3a20f..5229fdb045 100644
--- a/InvenTree/company/tests.py
+++ b/InvenTree/company/tests.py
@@ -1,4 +1,5 @@
from django.test import TestCase
+from django.core.exceptions import ValidationError
import os
@@ -119,6 +120,30 @@ class CompanySimpleTest(TestCase):
self.assertIsNone(m3x12.get_price_info(3))
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):