mirror of
https://github.com/grey-cat-1908/formaptix-server.git
synced 2024-09-22 19:52:00 +03:00
fixes && TIN and SNILS support
This commit is contained in:
parent
d891d9de86
commit
cc7c6aace1
4 changed files with 121 additions and 5 deletions
|
@ -5,6 +5,7 @@ from typing import TypeAlias, Annotated
|
||||||
from pydantic import field_validator, field_serializer, Field
|
from pydantic import field_validator, field_serializer, Field
|
||||||
|
|
||||||
from models import BaseModel, form
|
from models import BaseModel, form
|
||||||
|
from utils import validate_tin, validate_snils
|
||||||
|
|
||||||
|
|
||||||
class AnswerError(Enum):
|
class AnswerError(Enum):
|
||||||
|
@ -13,7 +14,10 @@ class AnswerError(Enum):
|
||||||
TOO_FEW_SELECTED = "The number of selected items is less than the minimum required."
|
TOO_FEW_SELECTED = "The number of selected items is less than the minimum required."
|
||||||
TOO_MANY_SELECTED = "The number of selected items is more than the maximum allowed."
|
TOO_MANY_SELECTED = "The number of selected items is more than the maximum allowed."
|
||||||
DUPLICATE_QUESTIONS = "Each value must correspond to a different question."
|
DUPLICATE_QUESTIONS = "Each value must correspond to a different question."
|
||||||
|
REQUIRED_QUIESTION_NOT_ANSWERED = "The required question was not answered."
|
||||||
INCORRECT_IDS = "The ids for some questions are incorrect."
|
INCORRECT_IDS = "The ids for some questions are incorrect."
|
||||||
|
TIN_VALIDATION_FAILED = "The TIN validation process failed."
|
||||||
|
SNILS_VALIDATION_FAILED = "The SNILS validation process failed."
|
||||||
|
|
||||||
|
|
||||||
class BaseValue(BaseModel):
|
class BaseValue(BaseModel):
|
||||||
|
@ -35,6 +39,17 @@ class TextValue(BaseValue):
|
||||||
if question.max_length and len(self.value) > question.max_length:
|
if question.max_length and len(self.value) > question.max_length:
|
||||||
raise ValueError(AnswerError.TOO_LONG.value)
|
raise ValueError(AnswerError.TOO_LONG.value)
|
||||||
|
|
||||||
|
if (
|
||||||
|
question.validator == form.TextValidator.tin
|
||||||
|
and validate_tin(self.value) is False
|
||||||
|
):
|
||||||
|
raise ValueError(AnswerError.TIN_VALIDATION_FAILED.value)
|
||||||
|
if (
|
||||||
|
question.validator == form.TextValidator.snils
|
||||||
|
and validate_snils(self.value) is False
|
||||||
|
):
|
||||||
|
raise ValueError(AnswerError.SNILS_VALIDATION_FAILED.value)
|
||||||
|
|
||||||
|
|
||||||
class SelectorValue(BaseValue):
|
class SelectorValue(BaseValue):
|
||||||
question_type: form.QuestionType = form.QuestionType.selector
|
question_type: form.QuestionType = form.QuestionType.selector
|
||||||
|
|
|
@ -21,6 +21,11 @@ class QuestionType(IntEnum):
|
||||||
selector = 2
|
selector = 2
|
||||||
|
|
||||||
|
|
||||||
|
class TextValidator(IntEnum):
|
||||||
|
tin = 1
|
||||||
|
snils = 2
|
||||||
|
|
||||||
|
|
||||||
class BaseQuestion(BaseModel):
|
class BaseQuestion(BaseModel):
|
||||||
id: UUID = Field(default_factory=uuid4)
|
id: UUID = Field(default_factory=uuid4)
|
||||||
question_type: QuestionType
|
question_type: QuestionType
|
||||||
|
@ -39,25 +44,33 @@ class Option(BaseModel):
|
||||||
|
|
||||||
class TextQuestion(BaseQuestion):
|
class TextQuestion(BaseQuestion):
|
||||||
question_type: QuestionType = QuestionType.text
|
question_type: QuestionType = QuestionType.text
|
||||||
|
validator: TextValidator | None = None
|
||||||
min_length: int | None = None
|
min_length: int | None = None
|
||||||
max_length: int | None = None
|
max_length: int | None = None
|
||||||
|
|
||||||
@field_validator("min_length")
|
@field_validator("min_length")
|
||||||
@classmethod
|
@classmethod
|
||||||
def validate_min_length(cls, v, info):
|
def validate_min_length(cls, v, info):
|
||||||
if v is not None and v < 0:
|
validator = info.data.get("validator")
|
||||||
raise ValueError(FormError.MIN_LENGTH_ERR.value)
|
if v is not None:
|
||||||
|
if v < 0:
|
||||||
|
raise ValueError(FormError.MIN_LENGTH_ERR.value)
|
||||||
|
if validator is not None:
|
||||||
|
return None
|
||||||
return v
|
return v
|
||||||
|
|
||||||
@field_validator("max_length")
|
@field_validator("max_length")
|
||||||
@classmethod
|
@classmethod
|
||||||
def validate_max_length(cls, v, info):
|
def validate_max_length(cls, v, info):
|
||||||
min_length = info.data.get("min_length")
|
min_length = info.data.get("min_length")
|
||||||
|
validator = info.data.get("validator")
|
||||||
if v is not None:
|
if v is not None:
|
||||||
if v <= 0:
|
if v <= 0:
|
||||||
raise ValueError(FormError.MAX_LENGTH_TOO_SMALL.value)
|
raise ValueError(FormError.MAX_LENGTH_TOO_SMALL.value)
|
||||||
if min_length is not None and v < min_length:
|
if min_length is not None and v < min_length:
|
||||||
raise ValueError(FormError.MAX_LENGTH_LESS_THAN_MIN_LENGTH.value)
|
raise ValueError(FormError.MAX_LENGTH_LESS_THAN_MIN_LENGTH.value)
|
||||||
|
if validator is not None:
|
||||||
|
return None
|
||||||
return v
|
return v
|
||||||
|
|
||||||
|
|
||||||
|
@ -89,9 +102,8 @@ class SelectorQuestion(BaseQuestion):
|
||||||
Question: TypeAlias = SelectorQuestion | TextQuestion
|
Question: TypeAlias = SelectorQuestion | TextQuestion
|
||||||
|
|
||||||
|
|
||||||
class FormData(BaseModel):
|
class Page(BaseModel):
|
||||||
name: str = Field(min_length=1)
|
text: str | None = Field(None, min_length=1)
|
||||||
description: str | None = Field(None, min_length=1)
|
|
||||||
questions: list[Question] = []
|
questions: list[Question] = []
|
||||||
|
|
||||||
@field_validator("questions")
|
@field_validator("questions")
|
||||||
|
@ -107,6 +119,18 @@ class FormData(BaseModel):
|
||||||
return v
|
return v
|
||||||
|
|
||||||
|
|
||||||
|
class FormData(BaseModel):
|
||||||
|
name: str = Field(min_length=1)
|
||||||
|
pages: list[Page] = []
|
||||||
|
|
||||||
|
@property
|
||||||
|
def questions(self) -> list[Question]:
|
||||||
|
questions = []
|
||||||
|
for page in self.pages:
|
||||||
|
questions.extend(page.questions)
|
||||||
|
return questions
|
||||||
|
|
||||||
|
|
||||||
class Form(BaseModel):
|
class Form(BaseModel):
|
||||||
id: int
|
id: int
|
||||||
data: FormData
|
data: FormData
|
||||||
|
|
1
utils/__init__.py
Normal file
1
utils/__init__.py
Normal file
|
@ -0,0 +1 @@
|
||||||
|
from .validator import *
|
76
utils/validator.py
Normal file
76
utils/validator.py
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
def validate_tin(value: str) -> bool:
|
||||||
|
if len(value) != 10 and len(value) != 12:
|
||||||
|
return False
|
||||||
|
|
||||||
|
value = list(map(int, value))
|
||||||
|
|
||||||
|
if len(value) == 10:
|
||||||
|
checksum = (
|
||||||
|
(
|
||||||
|
2 * value[0]
|
||||||
|
+ 4 * value[1]
|
||||||
|
+ 10 * value[2]
|
||||||
|
+ 3 * value[3]
|
||||||
|
+ 5 * value[4]
|
||||||
|
+ 9 * value[5]
|
||||||
|
+ 4 * value[6]
|
||||||
|
+ 6 * value[7]
|
||||||
|
+ 8 * value[8]
|
||||||
|
)
|
||||||
|
% 11
|
||||||
|
% 10
|
||||||
|
)
|
||||||
|
return value[9] == checksum
|
||||||
|
if len(value) == 12:
|
||||||
|
checksum1 = (
|
||||||
|
(
|
||||||
|
7 * value[0]
|
||||||
|
+ 2 * value[1]
|
||||||
|
+ 4 * value[2]
|
||||||
|
+ 10 * value[3]
|
||||||
|
+ 3 * value[4]
|
||||||
|
+ 5 * value[5]
|
||||||
|
+ 9 * value[6]
|
||||||
|
+ 4 * value[7]
|
||||||
|
+ 6 * value[8]
|
||||||
|
+ 8 * value[9]
|
||||||
|
)
|
||||||
|
% 11
|
||||||
|
% 10
|
||||||
|
)
|
||||||
|
checksum2 = (
|
||||||
|
(
|
||||||
|
3 * value[0]
|
||||||
|
+ 7 * value[1]
|
||||||
|
+ 2 * value[2]
|
||||||
|
+ 4 * value[3]
|
||||||
|
+ 10 * value[4]
|
||||||
|
+ 3 * value[5]
|
||||||
|
+ 5 * value[6]
|
||||||
|
+ 9 * value[7]
|
||||||
|
+ 4 * value[8]
|
||||||
|
+ 6 * value[9]
|
||||||
|
+ 8 * value[10]
|
||||||
|
)
|
||||||
|
% 11
|
||||||
|
% 10
|
||||||
|
)
|
||||||
|
return value[10] == checksum1 and value[11] == checksum2
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def validate_snils(value: str) -> bool:
|
||||||
|
if len(value) == 11:
|
||||||
|
checksum = 0
|
||||||
|
for i in range(9):
|
||||||
|
checksum += int(value[i]) * (9 - i)
|
||||||
|
|
||||||
|
if checksum > 101:
|
||||||
|
checksum = checksum % 101
|
||||||
|
if checksum == 100 or checksum == 101:
|
||||||
|
checksum = 0
|
||||||
|
|
||||||
|
return checksum == int(value[9:])
|
||||||
|
|
||||||
|
return False
|
Loading…
Reference in a new issue