diff --git a/InvenTree/InvenTree/settings.py b/InvenTree/InvenTree/settings.py index 1e993e5068..6c9d4a9b55 100644 --- a/InvenTree/InvenTree/settings.py +++ b/InvenTree/InvenTree/settings.py @@ -83,6 +83,7 @@ INSTALLED_APPS = [ 'django.contrib.staticfiles', # InvenTree apps + 'common.apps.CommonConfig', 'part.apps.PartConfig', 'stock.apps.StockConfig', 'company.apps.CompanyConfig', diff --git a/InvenTree/common/admin.py b/InvenTree/common/admin.py index 8c38f3f3da..faf6dd578e 100644 --- a/InvenTree/common/admin.py +++ b/InvenTree/common/admin.py @@ -1,3 +1,10 @@ from django.contrib import admin -# Register your models here. +from .models import Currency + + +class CurrencyAdmin(admin.ModelAdmin): + list_display = ('symbol', 'suffix', 'description', 'value', 'base') + + +admin.site.register(Currency, CurrencyAdmin) \ No newline at end of file diff --git a/InvenTree/common/migrations/0001_initial.py b/InvenTree/common/migrations/0001_initial.py new file mode 100644 index 0000000000..a3a357b86f --- /dev/null +++ b/InvenTree/common/migrations/0001_initial.py @@ -0,0 +1,26 @@ +# Generated by Django 2.2.4 on 2019-09-02 23:02 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='Currency', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('symbol', models.CharField(help_text='Currency Symbol e.g. $', max_length=10)), + ('suffix', models.CharField(help_text='Currency Suffix e.g. AUD', max_length=10, unique=True)), + ('description', models.CharField(help_text='Currency Description', max_length=100)), + ('value', models.DecimalField(decimal_places=5, help_text='Currency Value', max_digits=10, validators=[django.core.validators.MinValueValidator(1e-05), django.core.validators.MaxValueValidator(100000)])), + ('base', models.BooleanField(default=False, help_text='Use this currency as the base currency')), + ], + ), + ] diff --git a/InvenTree/common/migrations/0002_auto_20190902_2304.py b/InvenTree/common/migrations/0002_auto_20190902_2304.py new file mode 100644 index 0000000000..a8daf16139 --- /dev/null +++ b/InvenTree/common/migrations/0002_auto_20190902_2304.py @@ -0,0 +1,17 @@ +# Generated by Django 2.2.4 on 2019-09-02 23:04 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('common', '0001_initial'), + ] + + operations = [ + migrations.AlterModelOptions( + name='currency', + options={'verbose_name_plural': 'Currencies'}, + ), + ] diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index 71a8362390..43bc41db34 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -1,3 +1,79 @@ -from django.db import models +""" +Common database model definitions. +These models are 'generic' and do not fit a particular business logic object. +""" -# Create your models here. +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models +from django.utils.translation import ugettext as _ +from django.core.validators import MinValueValidator, MaxValueValidator + + +class Currency(models.Model): + """ + A Currency object represents a particular unit of currency. + Each Currency has a scaling factor which relates it to the base currency. + There must be one (and only one) currency which is selected as the base currency, + and each other currency is calculated relative to it. + + Attributes: + symbol: Currency symbol e.g. $ + suffix: Currency suffix e.g. AUD + description: Long-form description e.g. "Australian Dollars" + value: The value of this currency compared to the base currency. + base: True if this currency is the base currency + + """ + + symbol = models.CharField(max_length=10, blank=False, unique=False, help_text=_('Currency Symbol e.g. $')) + + suffix = models.CharField(max_length=10, blank=False, unique=True, help_text=_('Currency Suffix e.g. AUD')) + + description = models.CharField(max_length=100, blank=False, help_text=_('Currency Description')) + + value = models.DecimalField(max_digits=10, decimal_places=5, validators=[MinValueValidator(0.00001), MaxValueValidator(100000)], help_text=_('Currency Value')) + + base = models.BooleanField(default=False, help_text=_('Use this currency as the base currency')) + + class Meta: + verbose_name_plural = 'Currencies' + + def __str__(self): + """ Format string for currency representation """ + s = "{sym} {suf} - {desc}".format( + sym=self.symbol, + suf=self.suffix, + desc=self.description + ) + + if self.base: + s += " (Base)" + + else: + s += " = {v}".format(v=self.value) + + return s + + def save(self, *args, **kwargs): + """ Validate the model before saving + + - Ensure that there is only one base currency! + """ + + # If this currency is set as the base currency, ensure no others are + if self.base: + for cur in Currency.objects.filter(base=True).exclude(pk=self.pk): + cur.base = False + cur.save() + + # If there are no currencies set as the base currency, set this as base + if not Currency.objects.filter(base=True).exists(): + self.base = True + + # If this is the base currency, ensure value is set to unity + if self.base: + self.value = 1.0 + + super().save(*args, **kwargs) diff --git a/Makefile b/Makefile index c898af195d..0b3379a724 100644 --- a/Makefile +++ b/Makefile @@ -9,6 +9,7 @@ clean: # Perform database migrations (after schema changes are made) migrate: + python3 InvenTree/manage.py makemigrations common python3 InvenTree/manage.py makemigrations company python3 InvenTree/manage.py makemigrations part python3 InvenTree/manage.py makemigrations stock @@ -40,12 +41,12 @@ style: # Run unit tests test: python3 InvenTree/manage.py check - python3 InvenTree/manage.py test build company part stock order + python3 InvenTree/manage.py test build common company order part stock # Run code coverage coverage: python3 InvenTree/manage.py check - coverage run InvenTree/manage.py test build company part stock order InvenTree + coverage run InvenTree/manage.py test build common company order part stock InvenTree coverage html # Install packages required to generate code docs