2
0
mirror of https://github.com/inventree/InvenTree.git synced 2025-11-13 19:36:46 +00:00

Default stock currency (#10641) (#10644)

* Default stock currency (#10641)

* Fix for useStockFields

- Use default currency

* Ensure default currency is observed

* Specify field default

* Improve import (for ty)

* Update migration files

- Point currency fields to the correct default method

* Unit tests

- Ensure stock item gets correct default currency

* Cleaner generation of default currency value

- Return empty string during migratoins

* Update existing migrations

* Reduce noise

* Ignore "no-matching-overload" rule for ty

* Tweak money_kwargs

* Remove conflicting code

* Fix import

* Tweak currency_code_default
This commit is contained in:
Oliver
2025-10-21 16:29:24 +11:00
committed by GitHub
parent f8bcc3ec17
commit 0dcb706f4c
14 changed files with 52 additions and 27 deletions

View File

@@ -15,6 +15,8 @@ from rest_framework.fields import URLField as RestURLField
from rest_framework.fields import empty
import InvenTree.helpers
import InvenTree.ready
from common.currency import currency_code_default
from common.settings import get_global_setting
from .validators import AllowedURLValidator, allowable_url_schemes
@@ -59,7 +61,7 @@ class InvenTreeURLField(models.URLField):
def money_kwargs(**kwargs):
"""Returns the database settings for MoneyFields."""
from common.currency import currency_code_default, currency_code_mappings
from common.currency import currency_code_mappings
# Default values (if not specified)
if 'max_digits' not in kwargs:
@@ -71,8 +73,14 @@ def money_kwargs(**kwargs):
if 'currency_choices' not in kwargs:
kwargs['currency_choices'] = currency_code_mappings()
if 'default_currency' not in kwargs:
kwargs['default_currency'] = currency_code_default()
if InvenTree.ready.isRunningMigrations():
# During migrations, avoid setting a default currency
# This prevents issues related to early evaluation of the default currency value
kwargs['default_currency'] = ''
else:
# Override default currency with a callable function
# This ensures that the default currency is always up-to-date
kwargs['default_currency'] = currency_code_default
return kwargs

View File

@@ -11,6 +11,7 @@ import structlog
from moneyed import CURRENCIES
import InvenTree.helpers
import InvenTree.ready
logger = structlog.get_logger('inventree')

View File

@@ -3,7 +3,6 @@
from django.db import migrations, connection
import djmoney.models.fields
import common.currency
import common.settings
class Migration(migrations.Migration):
@@ -17,11 +16,11 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='supplierpricebreak',
name='price',
field=djmoney.models.fields.MoneyField(decimal_places=4, default_currency=common.currency.currency_code_default(), help_text='Unit price at specified quantity', max_digits=19, null=True, verbose_name='Price'),
field=djmoney.models.fields.MoneyField(decimal_places=4, default_currency='', help_text='Unit price at specified quantity', max_digits=19, null=True, verbose_name='Price'),
),
migrations.AddField(
model_name='supplierpricebreak',
name='price_currency',
field=djmoney.models.fields.CurrencyField(choices=common.currency.currency_code_mappings(), default=common.currency.currency_code_default(), editable=False, max_length=3),
field=djmoney.models.fields.CurrencyField(choices=common.currency.currency_code_mappings(), default='', editable=False, max_length=3),
),
]

View File

@@ -2,7 +2,6 @@
import InvenTree.validators
import common.currency
import common.settings
from django.db import migrations, models

View File

@@ -3,7 +3,6 @@
from django.db import migrations
import djmoney.models.fields
import common.currency
import common.settings
class Migration(migrations.Migration):
@@ -17,11 +16,11 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='purchaseorderlineitem',
name='purchase_price',
field=djmoney.models.fields.MoneyField(decimal_places=4, default_currency=common.currency.currency_code_default(), help_text='Unit purchase price', max_digits=19, null=True, verbose_name='Purchase Price'),
field=djmoney.models.fields.MoneyField(decimal_places=4, default_currency='', help_text='Unit purchase price', max_digits=19, null=True, verbose_name='Purchase Price'),
),
migrations.AddField(
model_name='purchaseorderlineitem',
name='purchase_price_currency',
field=djmoney.models.fields.CurrencyField(choices=common.currency.currency_code_mappings(), default=common.currency.currency_code_default(), editable=False, max_length=3),
field=djmoney.models.fields.CurrencyField(choices=common.currency.currency_code_mappings(), default='', editable=False, max_length=3),
),
]

View File

@@ -2,8 +2,6 @@
from django.db import migrations
import djmoney.models.fields
import common.currency
import common.settings
class Migration(migrations.Migration):
@@ -16,6 +14,6 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='purchaseorderlineitem',
name='purchase_price',
field=djmoney.models.fields.MoneyField(blank=True, decimal_places=4, default_currency=common.currency.currency_code_default(), help_text='Unit purchase price', max_digits=19, null=True, verbose_name='Purchase Price'),
field=djmoney.models.fields.MoneyField(blank=True, decimal_places=4, default_currency='', help_text='Unit purchase price', max_digits=19, null=True, verbose_name='Purchase Price'),
),
]

View File

@@ -2,7 +2,6 @@
from django.db import migrations
import common.currency
import common.settings
import djmoney.models.fields
@@ -16,11 +15,11 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='salesorderlineitem',
name='sale_price',
field=djmoney.models.fields.MoneyField(blank=True, decimal_places=4, default_currency=common.currency.currency_code_default(), help_text='Unit sale price', max_digits=19, null=True, verbose_name='Sale Price'),
field=djmoney.models.fields.MoneyField(blank=True, decimal_places=4, default_currency='', help_text='Unit sale price', max_digits=19, null=True, verbose_name='Sale Price'),
),
migrations.AddField(
model_name='salesorderlineitem',
name='sale_price_currency',
field=djmoney.models.fields.CurrencyField(choices=common.currency.currency_code_mappings(), default=common.currency.currency_code_default(), editable=False, max_length=3),
field=djmoney.models.fields.CurrencyField(choices=common.currency.currency_code_mappings(), default='', editable=False, max_length=3),
),
]

View File

@@ -16,11 +16,11 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='partsellpricebreak',
name='price',
field=djmoney.models.fields.MoneyField(decimal_places=4, default_currency=common.currency.currency_code_default(), help_text='Unit price at specified quantity', max_digits=19, null=True, verbose_name='Price'),
field=djmoney.models.fields.MoneyField(decimal_places=4, default_currency='', help_text='Unit price at specified quantity', max_digits=19, null=True, verbose_name='Price'),
),
migrations.AddField(
model_name='partsellpricebreak',
name='price_currency',
field=djmoney.models.fields.CurrencyField(choices=common.currency.currency_code_mappings(), default=common.currency.currency_code_default(), editable=False, max_length=3),
field=djmoney.models.fields.CurrencyField(choices=common.currency.currency_code_mappings(), default='', editable=False, max_length=3),
),
]

View File

@@ -3,7 +3,6 @@
import InvenTree.fields
import django.core.validators
import common.currency
import common.settings
from django.db import migrations, models
import django.db.models.deletion
import djmoney.models.fields
@@ -21,8 +20,8 @@ class Migration(migrations.Migration):
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('quantity', InvenTree.fields.RoundingDecimalField(decimal_places=5, default=1, help_text='Price break quantity', max_digits=15, validators=[django.core.validators.MinValueValidator(1)], verbose_name='Quantity')),
('price_currency', djmoney.models.fields.CurrencyField(choices=common.currency.currency_code_mappings(), default=common.currency.currency_code_default(), editable=False, max_length=3)),
('price', djmoney.models.fields.MoneyField(decimal_places=4, default_currency=common.currency.currency_code_default(), help_text='Unit price at specified quantity', max_digits=19, null=True, verbose_name='Price')),
('price_currency', djmoney.models.fields.CurrencyField(choices=common.currency.currency_code_mappings(), default='', editable=False, max_length=3)),
('price', djmoney.models.fields.MoneyField(decimal_places=4, default_currency='', help_text='Unit price at specified quantity', max_digits=19, null=True, verbose_name='Price')),
('part', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='internalpricebreaks', to='part.part', verbose_name='Part')),
],
options={

View File

@@ -8,7 +8,7 @@ import djmoney.models.validators
import InvenTree.fields
import common.currency
import common.settings
class Migration(migrations.Migration):

View File

@@ -16,11 +16,11 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='stockitem',
name='purchase_price',
field=djmoney.models.fields.MoneyField(decimal_places=4, default_currency=common.currency.currency_code_default(), help_text='Single unit purchase price at time of purchase', max_digits=19, null=True, verbose_name='Purchase Price'),
field=djmoney.models.fields.MoneyField(decimal_places=4, default_currency='', help_text='Single unit purchase price at time of purchase', max_digits=19, null=True, verbose_name='Purchase Price'),
),
migrations.AddField(
model_name='stockitem',
name='purchase_price_currency',
field=djmoney.models.fields.CurrencyField(choices=common.currency.all_currency_codes(), default=common.currency.currency_code_default(), editable=False, max_length=3),
field=djmoney.models.fields.CurrencyField(choices=common.currency.all_currency_codes(), default='', editable=False, max_length=3),
),
]

View File

@@ -2,7 +2,6 @@
from django.db import migrations
import djmoney.models.fields
import common.currency
class Migration(migrations.Migration):
@@ -15,6 +14,6 @@ class Migration(migrations.Migration):
migrations.AlterField(
model_name='stockitem',
name='purchase_price',
field=djmoney.models.fields.MoneyField(blank=True, decimal_places=4, default_currency=common.currency.currency_code_default(), help_text='Single unit purchase price at time of purchase', max_digits=19, null=True, verbose_name='Purchase Price'),
field=djmoney.models.fields.MoneyField(blank=True, decimal_places=4, default_currency='', help_text='Single unit purchase price at time of purchase', max_digits=19, null=True, verbose_name='Purchase Price'),
),
]

View File

@@ -6,6 +6,8 @@ from django.core.exceptions import ValidationError
from django.db.models import Sum
from django.test import override_settings
from djmoney.money import Money
from build.models import Build
from common.models import InvenTreeSetting
from company.models import Company
@@ -803,6 +805,27 @@ class StockTest(StockTestBase):
self.assertTrue(check_func())
def test_purchase_price(self):
"""Test purchase price field."""
from common.currency import currency_code_default
from common.settings import set_global_setting
part = Part.objects.filter(virtual=False).first()
for currency in ['AUD', 'USD', 'JPY']:
set_global_setting('INVENTREE_DEFAULT_CURRENCY', currency)
self.assertEqual(currency_code_default(), currency)
# Create stock item, do not specify currency - should get default
item = StockItem.objects.create(part=part, quantity=10)
self.assertEqual(item.purchase_price_currency, currency)
# Create stock item, specify currency
item = StockItem.objects.create(
part=part, quantity=10, purchase_price=Money(5, 'GBP')
)
self.assertEqual(item.purchase_price_currency, 'GBP')
class StockBarcodeTest(StockTestBase):
"""Run barcode tests for the stock app."""

View File

@@ -212,7 +212,8 @@ export function useStockFields({
icon: <IconCurrencyDollar />
},
purchase_price_currency: {
icon: <IconCoins />
icon: <IconCoins />,
default: globalSettings.getSetting('INVENTREE_DEFAULT_CURRENCY')
},
packaging: {
icon: <IconPackage />