File size: 3,630 Bytes
b4f2238
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
"""保全措施法律约束校验器."""

from __future__ import annotations

import logging
from typing import ClassVar

from django.utils.translation import gettext_lazy as _

from .models import PreservationMeasure

logger = logging.getLogger(__name__)


class MeasureValidator:
    """保全措施法律约束校验器.

    对提取的保全措施进行法律约束和逻辑一致性校验,
    仅追加 ``pending_note``,不修改其他字段。
    """

    # 法定期限上限(天数, 提示文案)
    DURATION_LIMITS: ClassVar[dict[str, tuple[int, str]]] = {
        "查封": (1095, str(_("不动产查封最长3年"))),
        "冻结": (365, str(_("银行存款冻结最长1年"))),
        "扣押": (730, str(_("动产扣押最长2年"))),
    }

    # ---- 校验提示文案 ----
    _MSG_DATE_INVERTED: str = str(_("到期日期早于起算日期,请人工核实"))
    _MSG_DURATION_EXCEEDED: str = str(_("期限超过法定上限({limit_desc}),请人工核实"))
    _MSG_PENDING_HAS_END_DATE: str = str(_("轮候状态不应有确定到期日期,请人工核实"))

    # 多条提示之间的分隔符
    _SEP: str = ";"

    # ------------------------------------------------------------------
    # public
    # ------------------------------------------------------------------

    def validate(self, measure: PreservationMeasure) -> PreservationMeasure:
        """校验单个措施,追加校验提示到 ``pending_note``,不修改原始数据."""
        warnings: list[str] = []

        self._check_date_order(measure, warnings)
        self._check_duration_limit(measure, warnings)
        self._check_pending_end_date(measure, warnings)

        if warnings:
            existing = measure.pending_note or ""
            suffix = self._SEP.join(warnings)
            measure.pending_note = f"{existing}{self._SEP}{suffix}" if existing else suffix

        return measure

    def validate_all(self, measures: list[PreservationMeasure]) -> list[PreservationMeasure]:
        """批量校验."""
        return [self.validate(m) for m in measures]

    # ------------------------------------------------------------------
    # private checks
    # ------------------------------------------------------------------

    def _check_date_order(
        self,
        measure: PreservationMeasure,
        warnings: list[str],
    ) -> None:
        """规则 1:end_date < start_date → 追加提示."""
        if measure.start_date is not None and measure.end_date is not None and measure.end_date < measure.start_date:
            warnings.append(self._MSG_DATE_INVERTED)

    def _check_duration_limit(
        self,
        measure: PreservationMeasure,
        warnings: list[str],
    ) -> None:
        """规则 2/3/4:期限超过法定上限 → 追加提示."""
        if measure.start_date is None or measure.end_date is None:
            return

        actual_days = (measure.end_date - measure.start_date).days

        for keyword, (max_days, limit_desc) in self.DURATION_LIMITS.items():
            if keyword in measure.measure_type and actual_days > max_days:
                warnings.append(self._MSG_DURATION_EXCEEDED.format(limit_desc=limit_desc))
                break  # 每个措施只匹配一种类型

    def _check_pending_end_date(
        self,
        measure: PreservationMeasure,
        warnings: list[str],
    ) -> None:
        """规则 5:is_pending=True 且 end_date 不为 None → 追加提示."""
        if measure.is_pending and measure.end_date is not None:
            warnings.append(self._MSG_PENDING_HAS_END_DATE)