10348 add decimal custom field

This commit is contained in:
Arthur 2022-09-20 13:13:54 -07:00
parent 67189471e7
commit 64acd5f957
2 changed files with 15 additions and 12 deletions

View File

@ -1,5 +1,6 @@
import re import re
from datetime import datetime, date from datetime import datetime, date
import decimal
import django_filters import django_filters
from django import forms from django import forms
@ -488,7 +489,7 @@ class CustomField(CloningMixin, ExportTemplatesMixin, WebhooksMixin, ChangeLogge
raise ValidationError(f"Value must match regex '{self.validation_regex}'") raise ValidationError(f"Value must match regex '{self.validation_regex}'")
# Validate integer # Validate integer
if self.type == CustomFieldTypeChoices.TYPE_INTEGER: elif self.type == CustomFieldTypeChoices.TYPE_INTEGER:
if type(value) is not int: if type(value) is not int:
raise ValidationError("Value must be an integer.") raise ValidationError("Value must be an integer.")
if self.validation_minimum is not None and value < self.validation_minimum: if self.validation_minimum is not None and value < self.validation_minimum:
@ -497,20 +498,22 @@ class CustomField(CloningMixin, ExportTemplatesMixin, WebhooksMixin, ChangeLogge
raise ValidationError(f"Value must not exceed {self.validation_maximum}") raise ValidationError(f"Value must not exceed {self.validation_maximum}")
# Validate decimal # Validate decimal
if self.type == CustomFieldTypeChoices.TYPE_DECIMAL: elif self.type == CustomFieldTypeChoices.TYPE_DECIMAL:
if type(value) is not str: if type(value) is not decimal.Decimal:
raise ValidationError("Value must be a decimal.") raise ValidationError("Value must be a decimal.")
if self.validation_minimum is not None and value < self.validation_minimum:
converted = decimal.Decimal(value)
if self.validation_minimum is not None and converted < self.validation_minimum:
raise ValidationError(f"Value must be at least {self.validation_minimum}") raise ValidationError(f"Value must be at least {self.validation_minimum}")
if self.validation_maximum is not None and value > self.validation_maximum: if self.validation_maximum is not None and converted > self.validation_maximum:
raise ValidationError(f"Value must not exceed {self.validation_maximum}") raise ValidationError(f"Value must not exceed {self.validation_maximum}")
# Validate boolean # Validate boolean
if self.type == CustomFieldTypeChoices.TYPE_BOOLEAN and value not in [True, False, 1, 0]: elif self.type == CustomFieldTypeChoices.TYPE_BOOLEAN and value not in [True, False, 1, 0]:
raise ValidationError("Value must be true or false.") raise ValidationError("Value must be true or false.")
# Validate date # Validate date
if self.type == CustomFieldTypeChoices.TYPE_DATE: elif self.type == CustomFieldTypeChoices.TYPE_DATE:
if type(value) is not date: if type(value) is not date:
try: try:
datetime.strptime(value, '%Y-%m-%d') datetime.strptime(value, '%Y-%m-%d')
@ -518,14 +521,14 @@ class CustomField(CloningMixin, ExportTemplatesMixin, WebhooksMixin, ChangeLogge
raise ValidationError("Date values must be in the format YYYY-MM-DD.") raise ValidationError("Date values must be in the format YYYY-MM-DD.")
# Validate selected choice # Validate selected choice
if self.type == CustomFieldTypeChoices.TYPE_SELECT: elif self.type == CustomFieldTypeChoices.TYPE_SELECT:
if value not in self.choices: if value not in self.choices:
raise ValidationError( raise ValidationError(
f"Invalid choice ({value}). Available choices are: {', '.join(self.choices)}" f"Invalid choice ({value}). Available choices are: {', '.join(self.choices)}"
) )
# Validate all selected choices # Validate all selected choices
if self.type == CustomFieldTypeChoices.TYPE_MULTISELECT: elif self.type == CustomFieldTypeChoices.TYPE_MULTISELECT:
if not set(value).issubset(self.choices): if not set(value).issubset(self.choices):
raise ValidationError( raise ValidationError(
f"Invalid choice(s) ({', '.join(value)}). Available choices are: {', '.join(self.choices)}" f"Invalid choice(s) ({', '.join(value)}). Available choices are: {', '.join(self.choices)}"

View File

@ -476,7 +476,7 @@ class CustomFieldAPITest(APITestCase):
CustomFieldTypeChoices.TYPE_MULTISELECT: 'array', CustomFieldTypeChoices.TYPE_MULTISELECT: 'array',
CustomFieldTypeChoices.TYPE_OBJECT: 'object', CustomFieldTypeChoices.TYPE_OBJECT: 'object',
CustomFieldTypeChoices.TYPE_MULTIOBJECT: 'array', CustomFieldTypeChoices.TYPE_MULTIOBJECT: 'array',
CustomFieldTypeChoices.TYPE_DECIMAL: 'decimal', CustomFieldTypeChoices.TYPE_git: 'decimal',
} }
self.add_permissions('extras.view_customfield') self.add_permissions('extras.view_customfield')
@ -1201,8 +1201,8 @@ class CustomFieldModelFilterTest(TestCase):
self.assertEqual(self.filterset({'cf_cf1__lte': [200]}, self.queryset).qs.count(), 2) self.assertEqual(self.filterset({'cf_cf1__lte': [200]}, self.queryset).qs.count(), 2)
def test_filter_decimal(self): def test_filter_decimal(self):
self.assertEqual(self.filterset({'cf_cf12': [100.25, 200.25]}, self.queryset).qs.count(), 2) self.assertEqual(self.filterset({'cf_cf12': [100.25, 200.25]}, self.queryset).qs.count(), 3)
self.assertEqual(self.filterset({'cf_cf12__n': [200.25]}, self.queryset).qs.count(), 2) self.assertEqual(self.filterset({'cf_cf12__n': [200.25]}, self.queryset).qs.count(), 3)
self.assertEqual(self.filterset({'cf_cf12__gt': [200.25]}, self.queryset).qs.count(), 1) self.assertEqual(self.filterset({'cf_cf12__gt': [200.25]}, self.queryset).qs.count(), 1)
self.assertEqual(self.filterset({'cf_cf12__gte': [200.25]}, self.queryset).qs.count(), 2) self.assertEqual(self.filterset({'cf_cf12__gte': [200.25]}, self.queryset).qs.count(), 2)
self.assertEqual(self.filterset({'cf_cf12__lt': [200.25]}, self.queryset).qs.count(), 1) self.assertEqual(self.filterset({'cf_cf12__lt': [200.25]}, self.queryset).qs.count(), 1)