fc / apps /contracts /models /contract.py
jun2024's picture
Upload 2241 files
b4f2238 verified
Raw History Blame Contribute Delete
5.61 kB
"""Module for contract."""
from __future__ import annotations
import contextlib
from typing import TYPE_CHECKING, Any, ClassVar
from django.db import models
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from apps.core.models.enums import CaseType
if TYPE_CHECKING:
from django.db.models.fields.related_descriptors import RelatedManager
from apps.cases.models import Case
from .client_payment import ClientPaymentRecord
from .finalized_material import FinalizedMaterial
from .finance import ContractFinanceLog
from .folder_binding import ContractFolderBinding
from .party import ContractAssignment, ContractParty
from .payment import ContractPayment
from .supplementary import SupplementaryAgreement
class ContractStatus(models.TextChoices):
ACTIVE = "active", _("在办")
CLOSED = "closed", _("已结案")
ARCHIVED = "archived", _("已归档")
class FeeMode(models.TextChoices):
FIXED = "FIXED", _("固定收费")
SEMI_RISK = "SEMI_RISK", _("半风险收费")
FULL_RISK = "FULL_RISK", _("全风险收费")
CUSTOM = "CUSTOM", _("自定义")
class Contract(models.Model):
id: int
name: models.CharField = models.CharField(max_length=100, verbose_name=_("合同名称"))
case_type: models.CharField = models.CharField(max_length=32, choices=CaseType.choices, verbose_name=_("合同类型"))
status: models.CharField = models.CharField(
max_length=32, choices=ContractStatus.choices, default=ContractStatus.ACTIVE, verbose_name=_("合同状态")
)
specified_date: models.DateField = models.DateField(default=timezone.localdate, verbose_name=_("指定日期"))
start_date: models.DateField = models.DateField(blank=True, null=True, verbose_name=_("开始日期"))
end_date: models.DateField = models.DateField(blank=True, null=True, verbose_name=_("结束日期"))
is_archived: models.BooleanField = models.BooleanField(default=False, verbose_name=_("是否已建档"))
filing_number: models.CharField = models.CharField(
max_length=50,
blank=True,
null=True,
unique=True,
verbose_name=_("建档编号"),
help_text=_("格式: {年份}_{合同类型}_{HT}_{序号}"),
)
fee_mode: models.CharField = models.CharField(
max_length=16, choices=FeeMode.choices, default=FeeMode.FIXED, verbose_name=_("收费模式")
)
fixed_amount: models.DecimalField = models.DecimalField(
max_digits=14, decimal_places=2, blank=True, null=True, verbose_name=_("固定/前期律师费")
)
risk_rate: models.DecimalField = models.DecimalField(
max_digits=5, decimal_places=2, blank=True, null=True, verbose_name=_("风险比例(%)")
)
custom_terms: models.TextField = models.TextField(blank=True, null=True, verbose_name=_("自定义收费条款"))
law_firm_oa_url: models.URLField = models.URLField(
max_length=500,
blank=True,
null=True,
verbose_name=_("律所OA链接"),
help_text=_("跳转至律所OA系统中该合同的页面"),
)
law_firm_oa_case_number: models.CharField = models.CharField(
max_length=100,
blank=True,
null=True,
verbose_name=_("律所OA案件编号"),
help_text=_("律所OA系统中的案件编号"),
)
representation_stages: Any = models.JSONField(default=list, blank=True, verbose_name=_("代理阶段"))
if TYPE_CHECKING:
cases: RelatedManager[Case]
finance_logs: RelatedManager[ContractFinanceLog]
folder_binding: ContractFolderBinding
contract_parties: RelatedManager[ContractParty]
assignments: RelatedManager[ContractAssignment]
payments: RelatedManager[ContractPayment]
supplementary_agreements: RelatedManager[SupplementaryAgreement]
finalized_materials: RelatedManager[FinalizedMaterial]
client_payment_records: RelatedManager[ClientPaymentRecord]
class Meta:
verbose_name = _("合同")
verbose_name_plural = _("合同")
indexes: ClassVar = [
# 单字段索引 - 用于基本过滤
models.Index(fields=["case_type"]),
models.Index(fields=["status"]),
models.Index(fields=["is_archived"]),
models.Index(fields=["specified_date"]),
models.Index(fields=["-specified_date"]),
models.Index(fields=["filing_number"]),
# 复合索引 - 用于常见的组合查询
# 按案件类型和状态查询(常用于列表过滤)
models.Index(fields=["case_type", "status"]),
# 按状态和指定日期查询(常用于时间范围过滤)
models.Index(fields=["status", "-specified_date"]),
# 按是否建档和指定日期查询(常用于归档管理)
models.Index(fields=["is_archived", "-specified_date"]),
# 按案件类型、状态和指定日期查询(常用于复杂过滤)
models.Index(fields=["case_type", "status", "-specified_date"]),
]
def __str__(self) -> str:
return str(self.name)
def clean(self) -> None:
from apps.contracts.validators import normalize_representation_stages
from apps.core.exceptions import ValidationException
ctype = getattr(self, "case_type", None)
rep = getattr(self, "representation_stages", None)
with contextlib.suppress(ValidationException):
self.representation_stages = normalize_representation_stages(ctype, rep, strict=False)