initial commit

This commit is contained in:
2025-08-05 10:26:39 +05:00
commit b7412bbef6
298 changed files with 10533 additions and 0 deletions

View File

@@ -0,0 +1,4 @@
from .attached_files import * # noqa
from .contracts import * # noqa
from .file_contents import * # noqa
from .owners import * # noqa

View File

@@ -0,0 +1,110 @@
from django.db import models
from django.utils.translation import gettext_lazy as _
from functools import cache
from django.core.validators import (
MinLengthValidator,
MaxLengthValidator,
)
from core.utils.base_model import UUIDPrimaryKeyBaseModel
from .contracts import ContractModel
from core.apps.contracts.validators.attached_files import (
ContractAttachedFileValidator,
allowed_chars_validator,
starts_with_letter_validator,
)
ALLOWED_FILE_EXTENTIONS: dict[str, list[str]] = {
'pdf': ['.pdf'],
'word': ['.doc', '.docx'],
'image': ['.jpg', '.jpeg', '.png', '.gif', '.bmp', '.webp'],
}
class ContractAttachedFileModel(UUIDPrimaryKeyBaseModel):
name = models.CharField(
_("name"),
max_length=150,
validators=[
MinLengthValidator(
3,
message=_(
"File name must be at " \
"least 3 characters long."
)
),
MaxLengthValidator(
150,
message=_(
"File name must be at " \
"most 150 characters long."
)
),
starts_with_letter_validator,
allowed_chars_validator,
],
)
contract = models.ForeignKey(
ContractModel,
on_delete=models.CASCADE,
verbose_name=_("Contract"),
related_name="attached_files",
)
allow_pdf = models.BooleanField(default=True)
allow_word = models.BooleanField(default=True)
allow_image = models.BooleanField(default=True)
@property
def allowed_types(self) -> str:
allowed_types: list[str] = []
if self.allow_pdf:
allowed_types.append("pdf")
if self.allow_word:
allowed_types.append("word")
if self.allow_image:
allowed_types.append("image")
if len(allowed_types) == 3:
return "All"
return ", ".join(allowed_type.upper() for allowed_type in allowed_types)
@property
@cache
def allowed_extensions(self) -> list[str]:
extensions: list[str] = []
if self.allow_pdf:
extensions += ALLOWED_FILE_EXTENTIONS['pdf']
if self.allow_word:
extensions += ALLOWED_FILE_EXTENTIONS['word']
if self.allow_image:
extensions += ALLOWED_FILE_EXTENTIONS['image']
return extensions
def __str__(self):
return self.name
@classmethod
def _create_fake(cls):
return cls.objects.create(
name="mock",
)
def clean(self) -> None:
super().clean()
validator = ContractAttachedFileValidator()
validator()
class Meta: # type: ignore
db_table = "contract_attached_files"
verbose_name = _("Contract Attached File")
verbose_name_plural = _("Contract Attached Files")
unique_together = ("name", "contract")

View File

@@ -0,0 +1,70 @@
from django.db import models
from django.utils.translation import gettext_lazy as _
from core.utils.base_model import UUIDPrimaryKeyBaseModel
from core.apps.contracts.validators.contracts import (
ContractValidator,
name_validator
)
class ContractModel(UUIDPrimaryKeyBaseModel):
name = models.CharField(
_("name"),
validators=[
name_validator,
],
max_length=255
)
identifier = models.CharField(
_("Identifier"),
null=False,
blank=False
)
allow_add_files = models.BooleanField(default=False)
allow_delete_files = models.BooleanField(default=False)
@property
def file_permissions(self) -> str:
permissions: list[str] = []
if self.allow_add_files:
permissions.append("add")
if self.allow_delete_files:
permissions.append("delete")
if len(permissions) == 2:
return "All"
return ", ".join(permission.capitalize() for permission in permissions)
def __str__(self):
return self.name
@classmethod
def _create_fake(cls):
return cls.objects.create(
name="mock",
)
def clean(self) -> None:
super().clean()
validator = ContractValidator(self)
validator()
class Meta: # type: ignore
db_table = "contracts"
verbose_name = _("Contract")
verbose_name_plural = _("Contracts")
indexes = [
models.Index(
fields=["name"],
name="contracts_name_inx"
)
]

View File

@@ -0,0 +1,70 @@
import os
from django.db import models
from django.utils.translation import gettext_lazy as _
from django.db.models.fields.files import FieldFile
from django.core.exceptions import ValidationError
from core.utils.base_model import UUIDPrimaryKeyBaseModel
from core.apps.contracts.models.attached_files import ContractAttachedFileModel
from core.apps.contracts.models.owners import ContractOwnerModel
class ContractFileContentModel(UUIDPrimaryKeyBaseModel):
file = models.ForeignKey(
ContractAttachedFileModel,
on_delete=models.CASCADE,
verbose_name=_("File"),
related_name="contents",
null=False,
blank=False,
)
contract_owner = models.ForeignKey(
ContractOwnerModel,
on_delete=models.CASCADE,
verbose_name=_("Contract Owner"),
null=False,
blank=False,
)
document = models.FileField(
_("Document"),
null=False,
blank=False,
)
@property
def owner_name(self) -> str:
return self.contract_owner.owner_name
def __str__(self):
return self.file.name
def validate_file(self, document: FieldFile):
try:
ext = os.path.splitext(document.name)[1].lower()
except IndexError:
raise ValidationError(f"Unsupported document name: {document.name}")
if ext.lower() not in self.file.allowed_extensions:
raise ValidationError(f"Unsupported document type: {ext.upper()}")
return document
@classmethod
def _create_fake(cls):
return cls.objects.create(
file=ContractAttachedFileModel._create_fake(), # type: ignore
owner=ContractOwnerModel._create_fake(), # type: ignore
document_url=(
"https://img.freepik.com/free-photo/closeup-scarlet-macaw-from-side"
"-view-scarlet-macaw-closeup-head_488145-3540.jpg?semt=ais_hybrid&w=740"
)
)
class Meta: # type: ignore
db_table = "contract_file_contents"
verbose_name = _("Contract File Content")
verbose_name_plural = _("Contract File Contents")

View File

@@ -0,0 +1,279 @@
from typing import Self
from django.db import models
from django.utils.translation import gettext_lazy as _
from core.apps.contracts.models.contracts import ContractModel
from core.apps.contracts.choices.contracts import ContractOwnerStatus
from core.utils.base_model import UUIDPrimaryKeyBaseModel
from core.apps.contracts.validators.owners import (
ContractOwnerValidator,
LegalEntityValidator,
IndividualValidator,
name_validator,
bin_code_validator,
phone_validator,
person_code_validator,
full_name_validator,
iin_code_validator,
)
class LegalEntityModel(UUIDPrimaryKeyBaseModel):
name = models.CharField(
_("Name"),
validators=[
name_validator,
],
max_length=255,
null=False,
blank=False,
)
role = models.CharField(
_("Role"),
null=False,
blank=False
)
bin_code = models.CharField(
_("BIN code"),
validators=[
bin_code_validator,
],
max_length=14,
null=True,
blank=True,
)
identifier = models.CharField(
_("Identifier"),
max_length=255,
null=True,
blank=True
)
phone = models.CharField(
_("Phone"),
validators=[
phone_validator
],
max_length=25,
null=False,
blank=False
)
def __str__(self):
return self.name
@classmethod
def _create_fake(cls):
return cls.objects.create(
name="mock",
)
@property
def entity_code(self) -> str:
if self.bin_code is not None:
return f"BIN code: {self.bin_code}"
else:
return f"Identifier: {self.identifier}"
def clean(self) -> None:
super().clean()
validator = LegalEntityValidator(self)
validator()
class Meta: # type: ignore
db_table = "legal_entities"
verbose_name = _("Legal Entity")
verbose_name_plural = _("Legal Entities")
class IndividualModel(UUIDPrimaryKeyBaseModel):
full_name = models.CharField(
_("name"),
validators=[
full_name_validator,
],
max_length=512,
null=False,
blank=False
)
iin_code = models.CharField(
_("IIN code"),
max_length=14,
validators=[
iin_code_validator,
],
null=True,
blank=True,
unique=True
)
person_code = models.CharField(
_("Person Code (if no IIN code)"),
validators=[
person_code_validator,
],
max_length=64,
null=True,
blank=True,
unique=True
)
phone = models.CharField(
_("Phone"),
validators=[
phone_validator,
],
null=False,
blank=False
)
use_face_id = models.BooleanField(
_("Use FaceID"),
null=False,
blank=False,
default=False
)
def __str__(self):
return self.full_name
@classmethod
def _create_fake(cls):
return cls.objects.create(
name="mock",
)
@property
def individual_code(self) -> str:
if self.iin_code is not None:
return f"IIN Code: {self.iin_code}"
else:
return f"Person Code: {self.person_code}"
def clean(self):
super().clean()
validator = IndividualValidator(self)
validator()
class Meta: # type: ignore
db_table = "individuals"
verbose_name = _("Individual")
verbose_name_plural = _("Individuals")
indexes = [
models.Index(
fields=["full_name"],
name="individuals_fullname_inx"
),
models.Index(
fields=["iin_code"],
name="individuals_iin_inx"
),
models.Index(
fields=["person_code"],
name="individuals_code_inx"
),
models.Index(
fields=["phone"],
name="individuals_phone_inx"
),
]
class ContractOwnerModel(UUIDPrimaryKeyBaseModel):
legal_entity = models.OneToOneField(
LegalEntityModel,
related_name="owner",
verbose_name=_("Legal Entity"),
on_delete=models.PROTECT,
null=True,
blank=True
)
individual = models.OneToOneField(
IndividualModel,
related_name="owner",
verbose_name=_("Individual"),
on_delete=models.PROTECT,
null=True,
blank=True,
)
status = models.CharField(
_("Owner Status"),
max_length=255,
choices=ContractOwnerStatus,
default=ContractOwnerStatus.PENDING,
null=False,
blank=True,
)
contract = models.ForeignKey(
ContractModel,
verbose_name=_("Contract"),
related_name="owners",
on_delete=models.PROTECT,
null=False,
blank=False
)
def clean(self) -> None:
super().clean()
validator = ContractOwnerValidator(self)
validator()
def __str__(self) -> str:
return str(self.legal_entity or self.individual)
@property
def owner_name(self) -> str:
if self.legal_entity is not None:
return str(self.legal_entity)
else:
return str(self.individual)
@property
def owner_identity(self) -> str:
if self.legal_entity is not None:
return _("Legal Entity")
else:
return _("Individual")
@classmethod
def _create_fake(cls, mock_individual: bool = True) -> Self:
kwargs: dict[str, IndividualModel | LegalEntityModel] = dict()
if mock_individual:
kwargs["individual"] = IndividualModel._create_fake() # type: ignore
else:
kwargs["legal_entity"] = LegalEntityModel._create_fake() # type: ignore
return cls.objects.create(
**kwargs
)
class Meta: # type: ignore
db_table = "contract_owners"
verbose_name = _("Contract Owner")
verbose_name_plural = _("Contract Owners")
constraints = [
models.UniqueConstraint(
fields=["individual", "contract"],
name="unique_individual_contract"
),
models.UniqueConstraint(
fields=["legal_entity", "contract"],
name="unique_legal_entity_contract"
),
]