diff --git a/InvenTree/common/models.py b/InvenTree/common/models.py index b9b7d9e20d..8c670a279d 100644 --- a/InvenTree/common/models.py +++ b/InvenTree/common/models.py @@ -9,6 +9,7 @@ from __future__ import unicode_literals import os import decimal import math +import re from django.db import models, transaction from django.contrib.auth.models import User @@ -487,6 +488,26 @@ class InvenTreeSetting(BaseInvenTreeSetting): even if that key does not exist. """ + def validate_part_name_format(self): + """ + Validate part name format. + Make sure that each template container has a field of Part Model + """ + + jinja_template_regex = re.compile('{{.*?}}') + field_name_regex = re.compile('(?<=part\\.)[A-z]*') + for jinja_template in jinja_template_regex.findall(str(self)): + # make sure at least one and only one field is present inside the parser + field_name = field_name_regex.findall(jinja_template) + if len(field_name) < 1: + raise ValidationError({ + 'value': 'At least one field must be present inside a jinja template container i.e {{}}' + }) + + # TODO: Make sure that the field_name exists in Part model + + return True + """ Dict of all global settings values: @@ -702,6 +723,14 @@ class InvenTreeSetting(BaseInvenTreeSetting): 'validator': bool }, + 'PART_NAME_FORMAT': { + 'name': _('Part Name Display Format'), + 'description': _('Format to display the part name'), + 'default': "{{ part.IPN if part.IPN }} {{ '|' if part.IPN }} {{ part.name }} {{ '|' if part.revision }}" + " {{ part.revision }}", + 'validator': validate_part_name_format + }, + 'REPORT_DEBUG_MODE': { 'name': _('Debug Mode'), 'description': _('Generate reports in debug mode (HTML output)'), diff --git a/InvenTree/part/models.py b/InvenTree/part/models.py index 692c3b53b8..7a4834cd7a 100644 --- a/InvenTree/part/models.py +++ b/InvenTree/part/models.py @@ -24,6 +24,8 @@ from django.contrib.auth.models import User from django.db.models.signals import pre_delete from django.dispatch import receiver +from jinja2 import Template + from markdownx.models import MarkdownxField from django_cleanup import cleanup @@ -39,6 +41,7 @@ from datetime import datetime import hashlib from djmoney.contrib.exchange.models import convert_money from common.settings import currency_code_default +from common.models import InvenTreeSetting from InvenTree import helpers from InvenTree import validators @@ -556,7 +559,7 @@ class Part(MPTTModel): @property def full_name(self): - """ Format a 'full name' for this Part based on the format PART_NAME_FORMAT defined in part.settings file + """ Format a 'full name' for this Part based on the format PART_NAME_FORMAT defined in Inventree settings As a failsafe option, the following is done @@ -567,26 +570,13 @@ class Part(MPTTModel): Elements are joined by the | character """ - full_name = part_settings.PART_NAME_FORMAT - field_parser_regex_pattern = re.compile('{.*?}') - field_regex_pattern = re.compile('(?<=part\\.)[A-z]*') + # Add default_if_none to every jinja template variable + full_name_pattern = InvenTreeSetting.get_setting('PART_NAME_FORMAT') try: - - for field_parser in field_parser_regex_pattern.findall(part_settings.PART_NAME_FORMAT): - - # Each parser should contain a single field - field_name = field_regex_pattern.findall(field_parser)[0] - field_value = getattr(self, field_name) - - if field_value: - # replace the part.$field with field's value and remove the braces - parsed_value = field_parser.replace(f'part.{field_name}', field_value)[1:-1] - full_name = full_name.replace(field_parser, parsed_value) - - else: - # remove the field parser in full name - full_name = full_name.replace(field_parser, '') + context = {'part': self} + template_string = Template(full_name_pattern) + full_name = template_string.render(context) return full_name diff --git a/InvenTree/part/settings.py b/InvenTree/part/settings.py index c1d2f4c7e6..e345a9d88d 100644 --- a/InvenTree/part/settings.py +++ b/InvenTree/part/settings.py @@ -62,13 +62,3 @@ def part_trackable_default(): """ return InvenTreeSetting.get_setting('PART_TRACKABLE') - - -# CONSTANTS - -# Every brace pair is a field parser within which a field name of part has to be defined in the format part.$field_name -# When full name is constructed, It would be replaced by its value from the database and if the value is None, -# the entire field_parser i.e {.*} would be replaced with ''. -# Other characters inside and between the brace pairs would be copied as is. -PART_NAME_FORMAT = '{part.IPN | }{part.name}{ | part.revision}' - diff --git a/InvenTree/templates/InvenTree/settings/part.html b/InvenTree/templates/InvenTree/settings/part.html index 0ec5f56db6..ddd6fae1a9 100644 --- a/InvenTree/templates/InvenTree/settings/part.html +++ b/InvenTree/templates/InvenTree/settings/part.html @@ -17,6 +17,7 @@ {% include "InvenTree/settings/setting.html" with key="PART_IPN_REGEX" %} {% include "InvenTree/settings/setting.html" with key="PART_ALLOW_DUPLICATE_IPN" %} {% include "InvenTree/settings/setting.html" with key="PART_ALLOW_EDIT_IPN" %} + {% include "InvenTree/settings/setting.html" with key="PART_NAME_FORMAT" %} {% include "InvenTree/settings/setting.html" with key="PART_SHOW_PRICE_IN_FORMS" icon="fa-dollar-sign" %} {% include "InvenTree/settings/setting.html" with key="PART_SHOW_PRICE_IN_BOM" icon="fa-dollar-sign" %} {% include "InvenTree/settings/setting.html" with key="PART_SHOW_RELATED" icon="fa-random" %}