132 lines
4.0 KiB
Python
132 lines
4.0 KiB
Python
"""Models for the canonical organizations directory."""
|
|
|
|
import uuid
|
|
|
|
from django.db import models
|
|
from django.db.models import Q
|
|
from django.utils.translation import gettext_lazy as _
|
|
|
|
from organizations.name_normalization import normalize_organization_name
|
|
|
|
|
|
class Organization(models.Model):
|
|
"""Canonical organization without source-specific relations."""
|
|
|
|
uid = models.UUIDField(
|
|
_("UID"),
|
|
primary_key=True,
|
|
default=uuid.uuid4,
|
|
editable=False,
|
|
)
|
|
name = models.CharField(
|
|
_("наименование"),
|
|
max_length=1024,
|
|
db_index=True,
|
|
help_text=_("Наименование организации или ИП"),
|
|
)
|
|
inn = models.CharField(
|
|
_("ИНН"),
|
|
max_length=12,
|
|
blank=True,
|
|
db_index=True,
|
|
help_text=_("ИНН ЮЛ или ИП"),
|
|
)
|
|
kpp = models.CharField(
|
|
_("КПП"),
|
|
max_length=9,
|
|
blank=True,
|
|
db_index=True,
|
|
help_text=_("КПП только для юридических лиц"),
|
|
)
|
|
ogrn = models.CharField(
|
|
_("ОГРН"),
|
|
max_length=13,
|
|
blank=True,
|
|
db_index=True,
|
|
help_text=_("ОГРН только для юридических лиц"),
|
|
)
|
|
ogrip = models.CharField(
|
|
_("ОГРИП"),
|
|
max_length=15,
|
|
blank=True,
|
|
db_index=True,
|
|
help_text=_("ОГРИП только для индивидуальных предпринимателей"),
|
|
)
|
|
|
|
class Meta:
|
|
db_table = "organizations_organization"
|
|
verbose_name = _("организация")
|
|
verbose_name_plural = _("организации")
|
|
ordering = ["name"]
|
|
indexes = [
|
|
models.Index(fields=["inn", "kpp"]),
|
|
models.Index(fields=["inn", "ogrn"]),
|
|
models.Index(fields=["inn", "ogrip"]),
|
|
]
|
|
constraints = [
|
|
models.UniqueConstraint(
|
|
fields=["inn", "kpp"],
|
|
condition=~Q(inn="") & ~Q(kpp=""),
|
|
name="unique_org_inn_kpp_not_blank",
|
|
),
|
|
models.UniqueConstraint(
|
|
fields=["inn"],
|
|
condition=~Q(inn="") & Q(kpp="") & Q(ogrip=""),
|
|
name="unique_org_inn_without_kpp",
|
|
),
|
|
models.UniqueConstraint(
|
|
fields=["ogrip"],
|
|
condition=~Q(ogrip=""),
|
|
name="unique_organizations_ogrip_not_blank",
|
|
),
|
|
models.CheckConstraint(
|
|
check=Q(ogrip="") | (Q(kpp="") & Q(ogrn="")),
|
|
name="check_entrepreneur_has_no_kpp_ogrn",
|
|
),
|
|
]
|
|
|
|
def __str__(self) -> str:
|
|
identifier = self.inn or self.ogrn or self.ogrip
|
|
if identifier:
|
|
return f"{self.name} ({identifier})"
|
|
return self.name
|
|
|
|
@property
|
|
def normalized_name(self) -> str:
|
|
return normalize_organization_name(self.name)
|
|
|
|
|
|
class OrganizationDataSnapshot(models.Model):
|
|
"""Precomputed API v2 data payload for one canonical organization."""
|
|
|
|
organization = models.OneToOneField(
|
|
Organization,
|
|
on_delete=models.CASCADE,
|
|
primary_key=True,
|
|
related_name="data_snapshot",
|
|
verbose_name=_("организация"),
|
|
)
|
|
data = models.JSONField(
|
|
_("данные источников"),
|
|
default=dict,
|
|
help_text=_("Готовый JSON data для API v2"),
|
|
)
|
|
registries = models.JSONField(
|
|
_("реестры"),
|
|
default=list,
|
|
help_text=_("Готовый JSON registries для API v2"),
|
|
)
|
|
updated_at = models.DateTimeField(
|
|
_("дата обновления"),
|
|
auto_now=True,
|
|
db_index=True,
|
|
)
|
|
|
|
class Meta:
|
|
db_table = "organizations_data_snapshot"
|
|
verbose_name = _("снапшот данных организации")
|
|
verbose_name_plural = _("снапшоты данных организаций")
|
|
|
|
def __str__(self) -> str:
|
|
return f"Snapshot for {self.organization_id}"
|