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 models import BaseModel, form
|
||||
from utils import validate_tin, validate_snils
|
||||
|
||||
|
||||
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_MANY_SELECTED = "The number of selected items is more than the maximum allowed."
|
||||
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."
|
||||
TIN_VALIDATION_FAILED = "The TIN validation process failed."
|
||||
SNILS_VALIDATION_FAILED = "The SNILS validation process failed."
|
||||
|
||||
|
||||
class BaseValue(BaseModel):
|
||||
|
@ -35,6 +39,17 @@ class TextValue(BaseValue):
|
|||
if question.max_length and len(self.value) > question.max_length:
|
||||
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):
|
||||
question_type: form.QuestionType = form.QuestionType.selector
|
||||
|
|
|
@ -21,6 +21,11 @@ class QuestionType(IntEnum):
|
|||
selector = 2
|
||||
|
||||
|
||||
class TextValidator(IntEnum):
|
||||
tin = 1
|
||||
snils = 2
|
||||
|
||||
|
||||
class BaseQuestion(BaseModel):
|
||||
id: UUID = Field(default_factory=uuid4)
|
||||
question_type: QuestionType
|
||||
|
@ -39,25 +44,33 @@ class Option(BaseModel):
|
|||
|
||||
class TextQuestion(BaseQuestion):
|
||||
question_type: QuestionType = QuestionType.text
|
||||
validator: TextValidator | None = None
|
||||
min_length: int | None = None
|
||||
max_length: int | None = None
|
||||
|
||||
@field_validator("min_length")
|
||||
@classmethod
|
||||
def validate_min_length(cls, v, info):
|
||||
if v is not None and v < 0:
|
||||
validator = info.data.get("validator")
|
||||
if v is not None:
|
||||
if v < 0:
|
||||
raise ValueError(FormError.MIN_LENGTH_ERR.value)
|
||||
if validator is not None:
|
||||
return None
|
||||
return v
|
||||
|
||||
@field_validator("max_length")
|
||||
@classmethod
|
||||
def validate_max_length(cls, v, info):
|
||||
min_length = info.data.get("min_length")
|
||||
validator = info.data.get("validator")
|
||||
if v is not None:
|
||||
if v <= 0:
|
||||
raise ValueError(FormError.MAX_LENGTH_TOO_SMALL.value)
|
||||
if min_length is not None and v < min_length:
|
||||
raise ValueError(FormError.MAX_LENGTH_LESS_THAN_MIN_LENGTH.value)
|
||||
if validator is not None:
|
||||
return None
|
||||
return v
|
||||
|
||||
|
||||
|
@ -89,9 +102,8 @@ class SelectorQuestion(BaseQuestion):
|
|||
Question: TypeAlias = SelectorQuestion | TextQuestion
|
||||
|
||||
|
||||
class FormData(BaseModel):
|
||||
name: str = Field(min_length=1)
|
||||
description: str | None = Field(None, min_length=1)
|
||||
class Page(BaseModel):
|
||||
text: str | None = Field(None, min_length=1)
|
||||
questions: list[Question] = []
|
||||
|
||||
@field_validator("questions")
|
||||
|
@ -107,6 +119,18 @@ class FormData(BaseModel):
|
|||
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):
|
||||
id: int
|
||||
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