"""Статус документа и конверта (спека «Шаг 8 — статус документа и конверта»). Одна функция на сервис и ядро: вход не зависит от источника строк. """ from collections.abc import Sequence from dataclasses import dataclass from arm_statements.model import ( DocStatus, DocumentType, EnvelopeStatus, LineStatus, PeriodKind, Severity, StatementDocument, StatementWarning, ) _ACCEPTABLE_LINES = frozenset({LineStatus.OK, LineStatus.DETAIL}) @dataclass(frozen=True, slots=True) class StatusLine: line_status: LineStatus needs_review: bool @dataclass(frozen=True, slots=True) class StatusValue: line_status: LineStatus needs_review: bool @dataclass(frozen=True, slots=True) class StatusInput: document_type: DocumentType layout_found: bool has_organization_or_inn: bool period_known: bool needs_review_fields: tuple[str, ...] lines: tuple[StatusLine, ...] values: tuple[StatusValue, ...] hard_failures: int accepted: bool warning_severities: tuple[Severity, ...] def document_status(data: StatusInput) -> DocStatus: """`DISCLOSURE` — всегда `done`; иначе `done` только при выполнении всех условий спеки.""" if data.document_type is DocumentType.DISCLOSURE: return DocStatus.DONE done = ( data.layout_found and data.has_organization_or_inn and data.period_known and all(line.line_status in _ACCEPTABLE_LINES for line in data.lines) and not any(line.needs_review for line in data.lines) # значения строк detail в статус не входят (Р-23) and not any(v.needs_review for v in data.values if v.line_status is not LineStatus.DETAIL) and not data.needs_review_fields and (data.hard_failures == 0 or data.accepted) and Severity.ERROR not in data.warning_severities ) return DocStatus.DONE if done else DocStatus.NEEDS_CHECK def envelope_status( document_statuses: Sequence[DocStatus], file_warnings: Sequence[StatementWarning] ) -> EnvelopeStatus: if not document_statuses: return EnvelopeStatus.ERROR if all(s is DocStatus.DONE for s in document_statuses) and all( w.severity is not Severity.ERROR for w in file_warnings ): return EnvelopeStatus.DONE return EnvelopeStatus.NEEDS_CHECK def status_input(document: StatementDocument) -> StatusInput: """Вход функции статуса из документа шагов 2–8.""" header = document.header period_known = header.report_date.value is not None or any( c.period_kind is PeriodKind.ABSOLUTE and c.period_date is not None for c in document.columns ) return StatusInput( document_type=document.document_type, layout_found=document.lines != (), has_organization_or_inn=header.organization_name.value is not None or header.inn.value is not None, period_known=period_known, needs_review_fields=header.needs_review_fields, lines=tuple(StatusLine(line.line_status, line.needs_review) for line in document.lines), values=tuple(StatusValue(line.line_status, v.needs_review) for line in document.lines for v in line.values), hard_failures=0 if document.checks is None else len(document.checks.relations_failed), accepted=False, warning_severities=tuple(w.severity for w in document.warnings), )