367 lines
14 KiB
Python
367 lines
14 KiB
Python
"""Models for external read-only registries."""
|
||
|
||
from __future__ import annotations
|
||
|
||
from apps.core.mixins import TimestampMixin, UUIDPrimaryKeyMixin
|
||
from apps.organization.models import Organization
|
||
from django.db import models
|
||
from django.utils.translation import gettext_lazy as _
|
||
|
||
|
||
class IndustrialProduct(UUIDPrimaryKeyMixin, TimestampMixin, models.Model):
|
||
organization = models.ForeignKey(
|
||
Organization,
|
||
on_delete=models.CASCADE,
|
||
related_name="industrial_products",
|
||
verbose_name=_("организация"),
|
||
)
|
||
product_name = models.CharField(
|
||
_("наименование продукции"), max_length=500, db_index=True
|
||
)
|
||
product_class = models.CharField(
|
||
_("класс продукции"), max_length=100, db_index=True
|
||
)
|
||
okpd2_code = models.CharField(_("код ОКПД2"), max_length=32, blank=True, default="")
|
||
tnved_code = models.CharField(_("код ТНВЭД"), max_length=32, blank=True, default="")
|
||
registry_number = models.CharField(
|
||
_("реестровый номер"), max_length=64, blank=True, default=""
|
||
)
|
||
|
||
class Meta:
|
||
ordering = ["product_name", "created_at"]
|
||
|
||
def __str__(self) -> str:
|
||
return f"{self.product_name} ({self.organization_id})"
|
||
|
||
|
||
class IndustrialCertificate(UUIDPrimaryKeyMixin, TimestampMixin, models.Model):
|
||
organization = models.ForeignKey(
|
||
Organization,
|
||
on_delete=models.CASCADE,
|
||
related_name="industrial_certificates",
|
||
verbose_name=_("организация"),
|
||
)
|
||
certificate_number = models.CharField(
|
||
_("номер сертификата"), max_length=100, db_index=True
|
||
)
|
||
issue_date = models.DateField(_("дата выдачи"), null=True, blank=True)
|
||
expiry_date = models.DateField(_("дата окончания"), null=True, blank=True)
|
||
certificate_file_url = models.TextField(
|
||
_("ссылка на файл сертификата"), blank=True, default=""
|
||
)
|
||
organisation_name = models.CharField(
|
||
_("наименование организации из источника"),
|
||
max_length=500,
|
||
blank=True,
|
||
default="",
|
||
)
|
||
ogrn = models.CharField(_("ОГРН"), max_length=15, blank=True, default="")
|
||
|
||
class Meta:
|
||
ordering = ["-issue_date", "certificate_number"]
|
||
|
||
def __str__(self) -> str:
|
||
return f"{self.certificate_number} ({self.organization_id})"
|
||
|
||
|
||
class ManufacturerRegistryEntry(UUIDPrimaryKeyMixin, TimestampMixin, models.Model):
|
||
organization = models.ForeignKey(
|
||
Organization,
|
||
on_delete=models.CASCADE,
|
||
related_name="manufacturer_registry_entries",
|
||
verbose_name=_("организация"),
|
||
)
|
||
full_legal_name = models.CharField(
|
||
_("полное наименование"), max_length=1024, db_index=True
|
||
)
|
||
inn = models.CharField(_("ИНН"), max_length=12, db_index=True)
|
||
ogrn = models.CharField(_("ОГРН"), max_length=15, blank=True, default="")
|
||
address = models.TextField(_("адрес"), blank=True, default="")
|
||
|
||
class Meta:
|
||
ordering = ["full_legal_name", "created_at"]
|
||
|
||
def __str__(self) -> str:
|
||
return f"{self.full_legal_name} ({self.organization_id})"
|
||
|
||
|
||
class ProsecutorCheck(UUIDPrimaryKeyMixin, TimestampMixin, models.Model):
|
||
organization = models.ForeignKey(
|
||
Organization,
|
||
on_delete=models.CASCADE,
|
||
related_name="prosecutor_checks",
|
||
verbose_name=_("организация"),
|
||
)
|
||
registration_number = models.CharField(
|
||
_("регистрационный номер"), max_length=64, db_index=True
|
||
)
|
||
law_type = models.CharField(_("тип закона"), max_length=32, db_index=True)
|
||
control_authority = models.CharField(_("контрольный орган"), max_length=255)
|
||
prosecutor_office = models.CharField(
|
||
_("прокуратура"), max_length=255, blank=True, default=""
|
||
)
|
||
start_date = models.DateField(_("дата начала"), db_index=True)
|
||
status = models.CharField(_("статус"), max_length=64, db_index=True)
|
||
|
||
class Meta:
|
||
ordering = ["-start_date", "registration_number"]
|
||
|
||
def __str__(self) -> str:
|
||
return f"{self.registration_number} ({self.organization_id})"
|
||
|
||
|
||
class PublicProcurement(UUIDPrimaryKeyMixin, TimestampMixin, models.Model):
|
||
organization = models.ForeignKey(
|
||
Organization,
|
||
on_delete=models.CASCADE,
|
||
related_name="public_procurements",
|
||
verbose_name=_("организация"),
|
||
)
|
||
purchase_number = models.CharField(_("номер закупки"), max_length=64, db_index=True)
|
||
law_type = models.CharField(_("тип закона"), max_length=32, db_index=True)
|
||
status = models.CharField(_("статус"), max_length=64, db_index=True)
|
||
contract_amount = models.DecimalField(
|
||
_("сумма контракта"),
|
||
max_digits=20,
|
||
decimal_places=2,
|
||
null=True,
|
||
blank=True,
|
||
)
|
||
contract_date = models.DateField(_("дата контракта"), db_index=True)
|
||
execution_start_date = models.DateField(
|
||
_("дата начала исполнения"), null=True, blank=True
|
||
)
|
||
execution_end_date = models.DateField(
|
||
_("дата окончания исполнения"), null=True, blank=True
|
||
)
|
||
purchase_name = models.TextField(_("предмет закупки"))
|
||
|
||
class Meta:
|
||
ordering = ["-contract_date", "purchase_number"]
|
||
|
||
def __str__(self) -> str:
|
||
return f"{self.purchase_number} ({self.organization_id})"
|
||
|
||
|
||
class ArbitrationCase(UUIDPrimaryKeyMixin, TimestampMixin, models.Model):
|
||
organization = models.ForeignKey(
|
||
Organization,
|
||
on_delete=models.CASCADE,
|
||
related_name="arbitration_cases",
|
||
verbose_name=_("организация"),
|
||
)
|
||
case_number = models.CharField(_("номер дела"), max_length=64, db_index=True)
|
||
court_name = models.CharField(_("суд"), max_length=255)
|
||
party_role = models.CharField(_("роль стороны"), max_length=64, db_index=True)
|
||
status = models.CharField(_("статус"), max_length=64, db_index=True)
|
||
decision_date = models.DateField(_("дата решения"), db_index=True)
|
||
|
||
class Meta:
|
||
ordering = ["-decision_date", "case_number"]
|
||
|
||
def __str__(self) -> str:
|
||
return f"{self.case_number} ({self.organization_id})"
|
||
|
||
|
||
class BankruptcyProcedure(UUIDPrimaryKeyMixin, TimestampMixin, models.Model):
|
||
organization = models.ForeignKey(
|
||
Organization,
|
||
on_delete=models.CASCADE,
|
||
related_name="bankruptcy_procedures",
|
||
verbose_name=_("организация"),
|
||
)
|
||
external_id = models.CharField(_("внешний ID"), max_length=255, db_index=True)
|
||
message_type = models.CharField(_("тип сообщения"), max_length=255, db_index=True)
|
||
message_date = models.DateField(
|
||
_("дата сообщения"), null=True, blank=True, db_index=True
|
||
)
|
||
case_number = models.CharField(
|
||
_("номер дела"), max_length=128, blank=True, default="", db_index=True
|
||
)
|
||
status = models.CharField(
|
||
_("статус"), max_length=64, blank=True, default="", db_index=True
|
||
)
|
||
source_url = models.TextField(_("ссылка на источник"), blank=True, default="")
|
||
|
||
class Meta:
|
||
ordering = ["-message_date", "case_number", "message_type"]
|
||
|
||
def __str__(self) -> str:
|
||
return f"{self.message_type} ({self.organization_id})"
|
||
|
||
|
||
class DefenseUnreliableSupplier(UUIDPrimaryKeyMixin, TimestampMixin, models.Model):
|
||
organization = models.ForeignKey(
|
||
Organization,
|
||
on_delete=models.CASCADE,
|
||
related_name="defense_unreliable_suppliers",
|
||
verbose_name=_("организация"),
|
||
)
|
||
external_id = models.CharField(_("внешний ID"), max_length=255, db_index=True)
|
||
registry_source = models.CharField(
|
||
_("источник реестра"), max_length=50, db_index=True
|
||
)
|
||
registry_number = models.CharField(
|
||
_("номер записи"), max_length=128, blank=True, default="", db_index=True
|
||
)
|
||
supplier_name = models.CharField(
|
||
_("наименование поставщика"), max_length=500, blank=True, default=""
|
||
)
|
||
reason = models.TextField(_("основание"), blank=True, default="")
|
||
included_at = models.DateField(
|
||
_("дата включения"), null=True, blank=True, db_index=True
|
||
)
|
||
status = models.CharField(
|
||
_("статус"), max_length=64, blank=True, default="", db_index=True
|
||
)
|
||
source_url = models.TextField(_("ссылка на источник"), blank=True, default="")
|
||
|
||
class Meta:
|
||
ordering = ["-included_at", "registry_source", "registry_number"]
|
||
|
||
def __str__(self) -> str:
|
||
return f"{self.registry_source}:{self.registry_number} ({self.organization_id})"
|
||
|
||
|
||
class InformationSecurityRegistryEntry(
|
||
UUIDPrimaryKeyMixin, TimestampMixin, models.Model
|
||
):
|
||
class PresenceStatus(models.TextChoices):
|
||
PRESENT = "present", _("В реестре")
|
||
ABSENT = "absent", _("Не в реестре")
|
||
|
||
organization = models.ForeignKey(
|
||
Organization,
|
||
on_delete=models.CASCADE,
|
||
related_name="information_security_registry_entries",
|
||
verbose_name=_("организация"),
|
||
)
|
||
external_id = models.CharField(
|
||
_("внешний ID"), max_length=255, blank=True, default="", db_index=True
|
||
)
|
||
registry_name = models.CharField(
|
||
_("название реестра"), max_length=255, db_index=True
|
||
)
|
||
presence_status = models.CharField(
|
||
_("статус присутствия"),
|
||
max_length=16,
|
||
choices=PresenceStatus.choices,
|
||
db_index=True,
|
||
)
|
||
entry_number = models.CharField(
|
||
_("регистрационный номер"),
|
||
max_length=64,
|
||
blank=True,
|
||
default="",
|
||
)
|
||
issued_at = models.DateField(_("дата выдачи"), null=True, blank=True)
|
||
expires_at = models.DateField(_("дата окончания"), null=True, blank=True)
|
||
|
||
class Meta:
|
||
verbose_name = _("запись реестра безопасности")
|
||
verbose_name_plural = _("записи реестра безопасности")
|
||
ordering = ["registry_name", "-issued_at"]
|
||
|
||
def __str__(self) -> str:
|
||
return f"{self.registry_name} ({self.organization_id})"
|
||
|
||
|
||
class LaborVacancy(UUIDPrimaryKeyMixin, TimestampMixin, models.Model):
|
||
organization = models.ForeignKey(
|
||
Organization,
|
||
on_delete=models.CASCADE,
|
||
related_name="labor_vacancies",
|
||
verbose_name=_("организация"),
|
||
)
|
||
external_id = models.CharField(_("внешний ID"), max_length=255, db_index=True)
|
||
vacancy_source = models.CharField(
|
||
_("источник вакансии"), max_length=50, db_index=True
|
||
)
|
||
title = models.CharField(_("название вакансии"), max_length=500, db_index=True)
|
||
status = models.CharField(
|
||
_("статус"), max_length=64, blank=True, default="", db_index=True
|
||
)
|
||
published_at = models.DateField(
|
||
_("дата публикации"), null=True, blank=True, db_index=True
|
||
)
|
||
salary_amount = models.DecimalField(
|
||
_("зарплата"),
|
||
max_digits=20,
|
||
decimal_places=2,
|
||
null=True,
|
||
blank=True,
|
||
)
|
||
source_url = models.TextField(_("ссылка на источник"), blank=True, default="")
|
||
|
||
class Meta:
|
||
ordering = ["-published_at", "title"]
|
||
|
||
def __str__(self) -> str:
|
||
return f"{self.title} ({self.organization_id})"
|
||
|
||
|
||
class FinancialReport(UUIDPrimaryKeyMixin, TimestampMixin, models.Model):
|
||
organization = models.ForeignKey(
|
||
Organization,
|
||
on_delete=models.CASCADE,
|
||
related_name="financial_reports",
|
||
verbose_name=_("организация"),
|
||
)
|
||
external_id = models.CharField(_("внешний ID"), max_length=255, db_index=True)
|
||
ogrn = models.CharField(_("ОГРН"), max_length=15, blank=True, default="")
|
||
file_name = models.CharField(_("имя файла"), max_length=255, blank=True, default="")
|
||
file_hash = models.CharField(_("хеш файла"), max_length=64, blank=True, default="")
|
||
load_batch = models.PositiveIntegerField(
|
||
_("ID пакета загрузки"), null=True, blank=True, db_index=True
|
||
)
|
||
status = models.CharField(
|
||
_("статус"), max_length=64, blank=True, default="", db_index=True
|
||
)
|
||
source = models.CharField(_("источник"), max_length=64, blank=True, default="")
|
||
error_message = models.TextField(_("сообщение об ошибке"), blank=True, default="")
|
||
|
||
class Meta:
|
||
ordering = ["-created_at", "external_id"]
|
||
|
||
def __str__(self) -> str:
|
||
return f"{self.external_id} ({self.organization_id})"
|
||
|
||
|
||
class FinancialReportLine(UUIDPrimaryKeyMixin, TimestampMixin, models.Model):
|
||
report = models.ForeignKey(
|
||
FinancialReport,
|
||
on_delete=models.CASCADE,
|
||
related_name="lines",
|
||
verbose_name=_("финансовый отчет"),
|
||
)
|
||
form_code = models.CharField(_("код формы"), max_length=10, db_index=True)
|
||
line_code = models.CharField(_("код строки"), max_length=10, db_index=True)
|
||
line_name = models.CharField(_("наименование строки"), max_length=255)
|
||
year = models.PositiveSmallIntegerField(_("год"), db_index=True)
|
||
period_start = models.BigIntegerField(
|
||
_("на начало периода"),
|
||
null=True,
|
||
blank=True,
|
||
)
|
||
period_end = models.BigIntegerField(
|
||
_("на конец периода"),
|
||
null=True,
|
||
blank=True,
|
||
)
|
||
|
||
class Meta:
|
||
ordering = ["year", "form_code", "line_code"]
|
||
constraints = [
|
||
models.UniqueConstraint(
|
||
fields=["report", "form_code", "line_code", "year"],
|
||
name="unique_external_financial_report_line_year",
|
||
),
|
||
]
|
||
indexes = [
|
||
models.Index(fields=["report", "form_code", "line_code"]),
|
||
models.Index(fields=["year", "line_code"]),
|
||
]
|
||
|
||
def __str__(self) -> str:
|
||
return f"{self.line_code} ({self.line_name[:30]}) - {self.year}"
|