initial commit
This commit is contained in:
4
core/apps/contracts/models/__init__.py
Normal file
4
core/apps/contracts/models/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
from .attached_files import * # noqa
|
||||
from .contracts import * # noqa
|
||||
from .file_contents import * # noqa
|
||||
from .owners import * # noqa
|
||||
110
core/apps/contracts/models/attached_files.py
Normal file
110
core/apps/contracts/models/attached_files.py
Normal 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")
|
||||
70
core/apps/contracts/models/contracts.py
Normal file
70
core/apps/contracts/models/contracts.py
Normal 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"
|
||||
)
|
||||
]
|
||||
70
core/apps/contracts/models/file_contents.py
Normal file
70
core/apps/contracts/models/file_contents.py
Normal 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")
|
||||
279
core/apps/contracts/models/owners.py
Normal file
279
core/apps/contracts/models/owners.py
Normal 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"
|
||||
),
|
||||
]
|
||||
Reference in New Issue
Block a user