diff --git a/InvenTree/InvenTree/api.py b/InvenTree/InvenTree/api.py index 2fc85ef653..2d04195d42 100644 --- a/InvenTree/InvenTree/api.py +++ b/InvenTree/InvenTree/api.py @@ -7,7 +7,7 @@ from __future__ import unicode_literals import logging -from django.utils.translation import ugettext as _ +from django.utils.translation import ugettext_lazy as _ from django.http import JsonResponse from django_filters.rest_framework import DjangoFilterBackend diff --git a/InvenTree/InvenTree/forms.py b/InvenTree/InvenTree/forms.py index 79cdf49c3d..52d1c8758f 100644 --- a/InvenTree/InvenTree/forms.py +++ b/InvenTree/InvenTree/forms.py @@ -123,6 +123,7 @@ class DeleteForm(forms.Form): confirm_delete = forms.BooleanField( required=False, initial=False, + label=_('Confirm delete'), help_text=_('Confirm item deletion') ) @@ -155,6 +156,7 @@ class SetPasswordForm(HelperForm): required=True, initial='', widget=forms.PasswordInput(attrs={'autocomplete': 'off'}), + label=_('Enter password'), help_text=_('Enter new password')) confirm_password = forms.CharField(max_length=100, @@ -162,6 +164,7 @@ class SetPasswordForm(HelperForm): required=True, initial='', widget=forms.PasswordInput(attrs={'autocomplete': 'off'}), + label=_('Confirm password'), help_text=_('Confirm new password')) class Meta: diff --git a/InvenTree/InvenTree/helpers.py b/InvenTree/InvenTree/helpers.py index 62e50bd52f..930204c58c 100644 --- a/InvenTree/InvenTree/helpers.py +++ b/InvenTree/InvenTree/helpers.py @@ -382,17 +382,17 @@ def extract_serial_numbers(serials, expected_quantity): if a < b: for n in range(a, b + 1): if n in numbers: - errors.append(_('Duplicate serial: {n}'.format(n=n))) + errors.append(_('Duplicate serial: {n}').format(n=n)) else: numbers.append(n) else: - errors.append(_("Invalid group: {g}".format(g=group))) + errors.append(_("Invalid group: {g}").format(g=group)) except ValueError: - errors.append(_("Invalid group: {g}".format(g=group))) + errors.append(_("Invalid group: {g}").format(g=group)) continue else: - errors.append(_("Invalid group: {g}".format(g=group))) + errors.append(_("Invalid group: {g}").format(g=group)) continue else: @@ -409,7 +409,7 @@ def extract_serial_numbers(serials, expected_quantity): # The number of extracted serial numbers must match the expected quantity if not expected_quantity == len(numbers): - raise ValidationError([_("Number of unique serial number ({s}) must match quantity ({q})".format(s=len(numbers), q=expected_quantity))]) + raise ValidationError([_("Number of unique serial number ({s}) must match quantity ({q})").format(s=len(numbers), q=expected_quantity)]) return numbers diff --git a/InvenTree/InvenTree/validators.py b/InvenTree/InvenTree/validators.py index 70322df062..f8199ef20b 100644 --- a/InvenTree/InvenTree/validators.py +++ b/InvenTree/InvenTree/validators.py @@ -60,7 +60,7 @@ def validate_part_ipn(value): match = re.search(pattern, value) if match is None: - raise ValidationError(_('IPN must match regex pattern') + " '{pat}'".format(pat=pattern)) + raise ValidationError(_('IPN must match regex pattern {pat}').format(pat=pattern)) def validate_build_order_reference(value): diff --git a/InvenTree/build/forms.py b/InvenTree/build/forms.py index 48be9a0ffa..b947e02887 100644 --- a/InvenTree/build/forms.py +++ b/InvenTree/build/forms.py @@ -117,6 +117,7 @@ class BuildOutputDeleteForm(HelperForm): confirm = forms.BooleanField( required=False, + label=_('Confirm'), help_text=_('Confirm deletion of build output') ) @@ -138,7 +139,7 @@ class UnallocateBuildForm(HelperForm): Form for auto-de-allocation of stock from a build """ - confirm = forms.BooleanField(required=False, help_text=_('Confirm unallocation of stock')) + confirm = forms.BooleanField(required=False, label=_('Confirm'), help_text=_('Confirm unallocation of stock')) output_id = forms.IntegerField( required=False, @@ -162,7 +163,7 @@ class UnallocateBuildForm(HelperForm): class AutoAllocateForm(HelperForm): """ Form for auto-allocation of stock to a build """ - confirm = forms.BooleanField(required=True, help_text=_('Confirm stock allocation')) + confirm = forms.BooleanField(required=True, label=_('Confirm'), help_text=_('Confirm stock allocation')) # Keep track of which build output we are interested in output = forms.ModelChoiceField( @@ -209,15 +210,17 @@ class CompleteBuildOutputForm(HelperForm): location = forms.ModelChoiceField( queryset=StockLocation.objects.all(), + label = _('Location'), help_text=_('Location of completed parts'), ) confirm_incomplete = forms.BooleanField( required=False, + label=_('Confirm incomplete'), help_text=_("Confirm completion with incomplete stock allocation") ) - confirm = forms.BooleanField(required=True, help_text=_('Confirm build completion')) + confirm = forms.BooleanField(required=True, label=_('Confirm'), help_text=_('Confirm build completion')) output = forms.ModelChoiceField( queryset=StockItem.objects.all(), # Queryset is narrowed in the view @@ -237,7 +240,7 @@ class CompleteBuildOutputForm(HelperForm): class CancelBuildForm(HelperForm): """ Form for cancelling a build """ - confirm_cancel = forms.BooleanField(required=False, help_text=_('Confirm build cancellation')) + confirm_cancel = forms.BooleanField(required=False, label=_('Confirm cancel'), help_text=_('Confirm build cancellation')) class Meta: model = Build @@ -251,7 +254,7 @@ class EditBuildItemForm(HelperForm): Form for creating (or editing) a BuildItem object. """ - quantity = RoundingDecimalFormField(max_digits=10, decimal_places=5, help_text=_('Select quantity of stock to allocate')) + quantity = RoundingDecimalFormField(max_digits=10, decimal_places=5, label=_('Quantity'), help_text=_('Select quantity of stock to allocate')) part_id = forms.IntegerField(required=False, widget=forms.HiddenInput()) diff --git a/InvenTree/build/migrations/0027_auto_20210403_1210.py b/InvenTree/build/migrations/0027_auto_20210404_2016.py similarity index 60% rename from InvenTree/build/migrations/0027_auto_20210403_1210.py rename to InvenTree/build/migrations/0027_auto_20210404_2016.py index 4f5947f70e..f4a2c1afde 100644 --- a/InvenTree/build/migrations/0027_auto_20210403_1210.py +++ b/InvenTree/build/migrations/0027_auto_20210404_2016.py @@ -1,7 +1,8 @@ -# Generated by Django 3.0.7 on 2021-04-03 12:10 +# Generated by Django 3.0.7 on 2021-04-04 20:16 import InvenTree.models from django.conf import settings +import django.core.validators from django.db import migrations, models import django.db.models.deletion @@ -9,8 +10,9 @@ import django.db.models.deletion class Migration(migrations.Migration): dependencies = [ - migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('stock', '0058_stockitem_packaging'), ('users', '0005_owner_model'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), ('build', '0026_auto_20210216_1539'), ] @@ -25,6 +27,11 @@ class Migration(migrations.Migration): name='completion_date', field=models.DateField(blank=True, null=True, verbose_name='Completion Date'), ), + migrations.AlterField( + model_name='build', + name='creation_date', + field=models.DateField(auto_now_add=True, verbose_name='Creation Date'), + ), migrations.AlterField( model_name='build', name='issued_by', @@ -35,6 +42,26 @@ class Migration(migrations.Migration): name='responsible', field=models.ForeignKey(blank=True, help_text='User responsible for this build order', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='builds_responsible', to='users.Owner', verbose_name='Responsible'), ), + migrations.AlterField( + model_name='builditem', + name='build', + field=models.ForeignKey(help_text='Build to allocate parts', on_delete=django.db.models.deletion.CASCADE, related_name='allocated_stock', to='build.Build', verbose_name='Build'), + ), + migrations.AlterField( + model_name='builditem', + name='install_into', + field=models.ForeignKey(blank=True, help_text='Destination stock item', limit_choices_to={'is_building': True}, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='items_to_install', to='stock.StockItem', verbose_name='Install into'), + ), + migrations.AlterField( + model_name='builditem', + name='quantity', + field=models.DecimalField(decimal_places=5, default=1, help_text='Stock quantity to allocate to build', max_digits=15, validators=[django.core.validators.MinValueValidator(0)], verbose_name='Quantity'), + ), + migrations.AlterField( + model_name='builditem', + name='stock_item', + field=models.ForeignKey(help_text='Source stock item', limit_choices_to={'belongs_to': None, 'sales_order': None}, on_delete=django.db.models.deletion.CASCADE, related_name='allocations', to='stock.StockItem', verbose_name='Stock Item'), + ), migrations.AlterField( model_name='buildorderattachment', name='attachment', diff --git a/InvenTree/build/models.py b/InvenTree/build/models.py index ad0149ed48..4ee8de0d73 100644 --- a/InvenTree/build/models.py +++ b/InvenTree/build/models.py @@ -216,7 +216,7 @@ class Build(MPTTModel): help_text=_('Batch code for this build output') ) - creation_date = models.DateField(auto_now_add=True, editable=False) + creation_date = models.DateField(auto_now_add=True, editable=False, verbose_name=_('Creation Date')) target_date = models.DateField( null=True, blank=True, @@ -1020,14 +1020,14 @@ class BuildItem(models.Model): try: # Allocated part must be in the BOM for the master part if self.stock_item.part not in self.build.part.getRequiredParts(recursive=False): - errors['stock_item'] = [_("Selected stock item not found in BOM for part '{p}'".format(p=self.build.part.full_name))] + errors['stock_item'] = [_("Selected stock item not found in BOM for part '{p}'").format(p=self.build.part.full_name)] # Allocated quantity cannot exceed available stock quantity if self.quantity > self.stock_item.quantity: - errors['quantity'] = [_("Allocated quantity ({n}) must not exceed available quantity ({q})".format( + errors['quantity'] = [_("Allocated quantity ({n}) must not exceed available quantity ({q})").format( n=normalize(self.quantity), q=normalize(self.stock_item.quantity) - ))] + )] # Allocated quantity cannot cause the stock item to be over-allocated if self.stock_item.quantity - self.stock_item.allocation_count() + self.quantity < self.quantity: @@ -1079,6 +1079,7 @@ class BuildItem(models.Model): Build, on_delete=models.CASCADE, related_name='allocated_stock', + verbose_name=_('Build'), help_text=_('Build to allocate parts') ) @@ -1086,6 +1087,7 @@ class BuildItem(models.Model): 'stock.StockItem', on_delete=models.CASCADE, related_name='allocations', + verbose_name=_('Stock Item'), help_text=_('Source stock item'), limit_choices_to={ 'sales_order': None, @@ -1098,6 +1100,7 @@ class BuildItem(models.Model): max_digits=15, default=1, validators=[MinValueValidator(0)], + verbose_name=_('Quantity'), help_text=_('Stock quantity to allocate to build') ) @@ -1106,6 +1109,7 @@ class BuildItem(models.Model): on_delete=models.SET_NULL, blank=True, null=True, related_name='items_to_install', + verbose_name=_('Install into'), help_text=_('Destination stock item'), limit_choices_to={ 'is_building': True, diff --git a/InvenTree/company/migrations/0032_auto_20210403_1210.py b/InvenTree/company/migrations/0032_auto_20210403_1837.py similarity index 61% rename from InvenTree/company/migrations/0032_auto_20210403_1210.py rename to InvenTree/company/migrations/0032_auto_20210403_1837.py index e3572eb3b6..41b6977d31 100644 --- a/InvenTree/company/migrations/0032_auto_20210403_1210.py +++ b/InvenTree/company/migrations/0032_auto_20210403_1837.py @@ -1,7 +1,12 @@ -# Generated by Django 3.0.7 on 2021-04-03 12:10 +# Generated by Django 3.0.7 on 2021-04-03 18:37 +import InvenTree.fields +import company.models import django.core.validators from django.db import migrations, models +import django.db.models.deletion +import markdownx.models +import stdimage.models class Migration(migrations.Migration): @@ -11,6 +16,11 @@ class Migration(migrations.Migration): ] operations = [ + migrations.AlterField( + model_name='company', + name='image', + field=stdimage.models.StdImageField(blank=True, null=True, upload_to=company.models.rename_company_image, verbose_name='Image'), + ), migrations.AlterField( model_name='company', name='is_customer', @@ -26,6 +36,16 @@ class Migration(migrations.Migration): name='is_supplier', field=models.BooleanField(default=True, help_text='Do you purchase items from this company?', verbose_name='is supplier'), ), + migrations.AlterField( + model_name='company', + name='link', + field=InvenTree.fields.InvenTreeURLField(blank=True, help_text='Link to external company information', verbose_name='Link'), + ), + migrations.AlterField( + model_name='company', + name='notes', + field=markdownx.models.MarkdownxField(blank=True, verbose_name='Notes'), + ), migrations.AlterField( model_name='supplierpart', name='base_cost', @@ -41,4 +61,9 @@ class Migration(migrations.Migration): name='packaging', field=models.CharField(blank=True, help_text='Part packaging', max_length=50, null=True, verbose_name='Packaging'), ), + migrations.AlterField( + model_name='supplierpricebreak', + name='part', + field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='pricebreaks', to='company.SupplierPart', verbose_name='Part'), + ), ] diff --git a/InvenTree/company/models.py b/InvenTree/company/models.py index e05d81a16a..17091dcbc3 100644 --- a/InvenTree/company/models.py +++ b/InvenTree/company/models.py @@ -114,7 +114,7 @@ class Company(models.Model): verbose_name=_('Contact'), blank=True, help_text=_('Point of contact')) - link = InvenTreeURLField(blank=True, help_text=_('Link to external company information')) + link = InvenTreeURLField(blank=True, verbose_name=_('Link'), help_text=_('Link to external company information')) image = StdImageField( upload_to=rename_company_image, @@ -122,9 +122,10 @@ class Company(models.Model): blank=True, variations={'thumbnail': (128, 128)}, delete_orphans=True, + verbose_name=_('Image'), ) - notes = MarkdownxField(blank=True) + notes = MarkdownxField(blank=True, verbose_name=_('Notes')) is_customer = models.BooleanField(default=False, verbose_name=_('is customer'), help_text=_('Do you sell items to this company?')) @@ -366,11 +367,11 @@ class SupplierPart(models.Model): help_text=_('Notes') ) - base_cost = models.DecimalField(max_digits=10, decimal_places=3, default=0, validators=[MinValueValidator(0)], verbose_name=('base cost'), help_text=_('Minimum charge (e.g. stocking fee)')) + base_cost = models.DecimalField(max_digits=10, decimal_places=3, default=0, validators=[MinValueValidator(0)], verbose_name=_('base cost'), help_text=_('Minimum charge (e.g. stocking fee)')) packaging = models.CharField(max_length=50, blank=True, null=True, verbose_name=_('Packaging'), help_text=_('Part packaging')) - multiple = models.PositiveIntegerField(default=1, validators=[MinValueValidator(1)], verbose_name=_('multiple'), help_text=('Order multiple')) + multiple = models.PositiveIntegerField(default=1, validators=[MinValueValidator(1)], verbose_name=_('multiple'), help_text=_('Order multiple')) # TODO - Reimplement lead-time as a charfield with special validation (pattern matching). # lead_time = models.DurationField(blank=True, null=True) @@ -530,7 +531,7 @@ class SupplierPriceBreak(common.models.PriceBreak): currency: Reference to the currency of this pricebreak (leave empty for base currency) """ - part = models.ForeignKey(SupplierPart, on_delete=models.CASCADE, related_name='pricebreaks') + part = models.ForeignKey(SupplierPart, on_delete=models.CASCADE, related_name='pricebreaks', verbose_name=_('Part'),) class Meta: unique_together = ("part", "quantity") diff --git a/InvenTree/company/templates/company/delete.html b/InvenTree/company/templates/company/delete.html index 191e07c2f3..3236a7a58d 100644 --- a/InvenTree/company/templates/company/delete.html +++ b/InvenTree/company/templates/company/delete.html @@ -1,14 +1,16 @@ {% extends "modal_delete_form.html" %} +{% load i18n %} + {% block pre_form_content %} -Are you sure you want to delete company '{{ company.name }}'? +{% blocktrans with company.name as name %}Are you sure you want to delete company '{{ name }}'?{% endblocktrans %}
{% if company.supplied_part_count > 0 %} -

There are {{ company.supplied_part_count }} parts sourced from this company.
-If this supplier is deleted, these supplier part entries will also be deleted.

+

{% blocktrans with company.supplied_part_count as count %}There are {{ count }} parts sourced from this company.
+If this supplier is deleted, these supplier part entries will also be deleted.{% endblocktrans %}