"""Чистые снимки payload фактов качества (§14.1): форма для ОБ/ОФР и для ОСВ.""" import uuid from decimal import Decimal from src.domain.quality_facts import build_intake_payload, build_outcome_payload from src.models.enums import ( DocumentIssueKind, DocumentStatus, DocumentType, IssueSeverity, IssueSource, StatementLineStatus, ) from src.models.files import Document from src.models.statements import DocumentIssue, FinancialStatementLine, FinancialStatementValue ROW_COUNT = 4_200 def make_document(document_type: DocumentType = DocumentType.BALANCE) -> Document: return Document( id=uuid.uuid4(), document_type=document_type, status=DocumentStatus.RECOGNIZED, ) def test_build_intake_payload_statement_has_lines_and_values(): document = make_document(document_type=DocumentType.BALANCE) payload = build_intake_payload(document, lines=[...], values=[...], issues=[]) assert "lines" in payload and "values" in payload assert "osv_warnings" not in payload def test_build_intake_payload_osv_has_no_lines_or_values(): document = make_document(document_type=DocumentType.OSV) payload = build_intake_payload(document, osv_warnings=["OSV_SOMETHING"]) assert "lines" not in payload and "values" not in payload assert payload["osv_warnings"] == ["OSV_SOMETHING"] def test_build_intake_payload_statement_serializes_line_value_and_issue_fields(): document = make_document(document_type=DocumentType.INCOME) line_id = uuid.uuid4() column_id = uuid.uuid4() line = FinancialStatementLine( id=line_id, source_ref="row:3", row_index=3, line_code="2110", line_code_text="2110", line_status=StatementLineStatus.ok, needs_review=True, ) value = FinancialStatementValue( line_id=line_id, column_id=column_id, amount=Decimal("1500.00"), string_value=None, source_text="1 500", confidence=Decimal("95.00"), is_recognized=True, needs_review=False, ) issue = DocumentIssue( document_id=document.id, kind=DocumentIssueKind.relation, code="RELATION_BROKEN", severity=IssueSeverity.error, message="нарушено", source=IssueSource.core, relation="2110 = 2120", codes=["2110"], ) payload = build_intake_payload(document, lines=[line], values=[value], issues=[issue]) assert payload["lines"] == [ { "id": str(line_id), "ref": "row:3", "row_index": 3, "line_code": "2110", "line_code_text": "2110", "line_status": "ok", "needs_review": True, } ] assert payload["values"] == [ { "line_ref": "row:3", "column": str(column_id), "amount": "1500.00", "string_value": None, "source_text": "1 500", "confidence": 95.0, "is_recognized": True, "needs_review": False, } ] assert payload["issues"] == [ { "kind": "relation", "code": "RELATION_BROKEN", "severity": "error", "source": "core", "field": None, "relation": "2110 = 2120", "codes": ["2110"], "line_ids": None, } ] def test_build_outcome_payload_statement_has_fixes_and_no_osv_warnings(): document = make_document(document_type=DocumentType.BALANCE) fix = {"what": "line_code", "was": "2110", "became": "2120", "source": "service", "rule": "§5"} payload = build_outcome_payload(document, lines=[], values=[], issues=[], fixes=[fix]) assert payload["fixes"] == [fix] assert "lines" in payload and "values" in payload assert "osv_warnings" not in payload def test_build_outcome_payload_osv_has_fixes_and_no_lines(): document = make_document(document_type=DocumentType.OSV) fix = {"what": "period", "was": "2024 Q1", "became": "2024 Q2", "source": "ours", "rule": "§5"} payload = build_outcome_payload(document, osv_warnings=["OSV_SOMETHING"], fixes=[fix]) assert payload["osv_warnings"] == ["OSV_SOMETHING"] assert payload["fixes"] == [fix] assert "lines" not in payload and "values" not in payload def test_build_intake_payload_includes_header_source_for_statement(): document = make_document(document_type=DocumentType.BALANCE) header_source = {"inn": {"text": "7701234567", "confidence": Decimal("100.00")}} payload = build_intake_payload(document, lines=[], values=[], header_source=header_source) assert payload["header"]["header_source"] == {"inn": {"text": "7701234567", "confidence": "100.00"}} def test_build_outcome_payload_includes_header_source_for_statement(): document = make_document(document_type=DocumentType.INCOME) header_source = {"okpo": {"text": "12345678", "confidence": None}} payload = build_outcome_payload(document, lines=[], values=[], fixes=[], header_source=header_source) assert payload["header"]["header_source"] == {"okpo": {"text": "12345678", "confidence": None}} def test_build_intake_payload_includes_osv_row_count(): document = make_document(document_type=DocumentType.OSV) payload = build_intake_payload(document, osv_warnings=["OSV_SOMETHING"], osv_row_count=ROW_COUNT) assert payload["row_count"] == ROW_COUNT assert payload["osv_warnings"] == ["OSV_SOMETHING"] def test_build_outcome_payload_includes_osv_row_count(): document = make_document(document_type=DocumentType.OSV) payload = build_outcome_payload(document, osv_warnings=[], fixes=[], osv_row_count=0) assert payload["row_count"] == 0 def test_header_source_and_row_count_absent_when_kwargs_omitted(): balance = build_intake_payload(make_document(document_type=DocumentType.BALANCE), lines=[], values=[]) assert "header_source" not in balance["header"] osv = build_intake_payload(make_document(document_type=DocumentType.OSV), osv_warnings=[]) assert "row_count" not in osv outcome_osv = build_outcome_payload(make_document(document_type=DocumentType.OSV), osv_warnings=[], fixes=[]) assert "row_count" not in outcome_osv