fix(#190): факт исхода только для BALANCE/INCOME/OSV (§14.3 п.5)
Ревью нашло: хук писал quality_outcome_fact для ЛЮБОГО автоподтверждённого
документа, в том числе DISCLOSURE/OTHER — у них нет факта приёма
(INTAKE_FACT_DOCUMENT_TYPES, Task 5), и факт исхода без пары превратился бы
в сироту при соединении по document_id. Добавлен гейт
OUTCOME_FACT_DOCUMENT_TYPES = {BALANCE, INCOME, OSV} (не импортируется из
result_mapping.py — там уже отложенный импорт auto_confirm во избежание
цикла); auto_confirm для DISCLOSURE/OTHER не меняется — только пропускает
запись факта. Поправлен вводивший в заблуждение комментарий в
_outcome_fact_fields. Тест на DISCLOSURE: автоподтверждение проходит,
quality_outcome_fact не появляется.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
2a9ed10a29
commit
d26804a85d
@ -6,10 +6,13 @@
|
||||
пользователя. Привязка к версиям и переход версии — тот же хук, что у ручного подтверждения, с автором
|
||||
`stored_file.uploaded_by`. Вызывается в транзакции маппинга под заданием, файлом и документами (порядок блокировок D-5).
|
||||
|
||||
§14.3 п. 5 (design `quality-metrics` §4.2, AURORA-1759): на каждый подтверждённый документ пишется факт исхода
|
||||
`quality_outcome_fact` с `outcome = AUTO_CONFIRMED`. Правок при автоподтверждении не бывает (D-3 блокирует формы
|
||||
с нарушениями) — `primary_cause` всегда `WITHOUT_PARTICIPATION`, без вычисления приоритета §14.3 (он нужен только
|
||||
общему случаю `CONFIRMED`, Task 14). Запись — в той же транзакции, без `flush`/`commit`.
|
||||
§14.3 п. 5 (design `quality-metrics` §4.2, AURORA-1759): на каждый подтверждённый документ типа `BALANCE`/
|
||||
`INCOME`/`OSV` (`OUTCOME_FACT_DOCUMENT_TYPES`, тот же набор, что у факта приёма — `INTAKE_FACT_DOCUMENT_TYPES`,
|
||||
Task 5) пишется факт исхода `quality_outcome_fact` с `outcome = AUTO_CONFIRMED`. `DISCLOSURE`/`OTHER`
|
||||
автоподтверждаются как прежде (без факта приёма — факта исхода у них тоже нет, иначе `document_id` факта исхода
|
||||
не нашёл бы пары при соединении с фактом приёма в матрице §14). Правок при автоподтверждении не бывает (D-3
|
||||
блокирует формы с нарушениями) — `primary_cause` всегда `WITHOUT_PARTICIPATION`, без вычисления приоритета §14.3
|
||||
(он нужен только общему случаю `CONFIRMED`, Task 14). Запись — в той же транзакции, без `flush`/`commit`.
|
||||
"""
|
||||
|
||||
import datetime
|
||||
@ -41,6 +44,10 @@ from src.services.statements import FORM_TYPES, form_blocker
|
||||
|
||||
AUTO_CONFIRM_DESCRIPTION = "автоподтверждение: без замечаний"
|
||||
OBJECT_TYPE = "document"
|
||||
# §14.1/§14.3 (design quality-metrics §4.1/§4.2): факт качества (приёма и исхода) пишется только для этих типов;
|
||||
# тот же набор, что `INTAKE_FACT_DOCUMENT_TYPES` в services/result_mapping.py (Task 5) — не импортируется оттуда
|
||||
# во избежание цикла result_mapping → auto_confirm (там этот импорт уже отложенный)
|
||||
OUTCOME_FACT_DOCUMENT_TYPES = frozenset({DocumentType.BALANCE, DocumentType.INCOME, DocumentType.OSV})
|
||||
|
||||
|
||||
def transition_comment(document: Document) -> str:
|
||||
@ -56,11 +63,12 @@ async def _outcome_fact_fields(
|
||||
) -> dict[str, Any]:
|
||||
"""`payload` и `issue_count_at_outcome` факта исхода `AUTO_CONFIRMED` (§14.3 п. 5, design §4.2).
|
||||
|
||||
Строение `payload` повторяет факт приёма (Task 5, `services/result_mapping.py`:
|
||||
`_osv_intake_fields`/`_statement_intake_fields`), но как снимок ИСХОДА (`build_outcome_payload`, `fixes=()` —
|
||||
правок при автоподтверждении не бывает, D-3). `issue_count_at_outcome` — ВСЕ нарушения документа на этот момент,
|
||||
без фильтра по `kind`/`source` (в отличие от `warning_count` факта приёма, который фильтрует только
|
||||
предупреждения сервиса)."""
|
||||
Вызывается только для `document.document_type ∈ OUTCOME_FACT_DOCUMENT_TYPES` (гейт — в `auto_confirm`,
|
||||
`DISCLOSURE`/`OTHER` сюда не попадают). Строение `payload` повторяет факт приёма (Task 5,
|
||||
`services/result_mapping.py`: `_osv_intake_fields`/`_statement_intake_fields`), но как снимок ИСХОДА
|
||||
(`build_outcome_payload`, `fixes=()` — правок при автоподтверждении не бывает, D-3). `issue_count_at_outcome` —
|
||||
ВСЕ нарушения документа на этот момент, без фильтра по `kind`/`source` (в отличие от `warning_count` факта
|
||||
приёма, который фильтрует только предупреждения сервиса)."""
|
||||
issues = await statements_repo.issues(session, document.id)
|
||||
if document.document_type is DocumentType.OSV:
|
||||
row_count = (
|
||||
@ -82,8 +90,8 @@ async def _outcome_fact_fields(
|
||||
document, lines=lines, values=values, issues=issues, header_source=meta.header_source, fixes=()
|
||||
)
|
||||
else:
|
||||
# DISCLOSURE/OTHER и форма без шапки (в текущем `map_file` не возникает — см. Task 5): снимок без построчных
|
||||
# данных дешевле, чем прерванная транзакция маппинга
|
||||
# BALANCE/INCOME без шапки (в текущем `map_file` не возникает — см. Task 5): снимок без построчных данных
|
||||
# дешевле, чем прерванная транзакция маппинга
|
||||
payload = build_outcome_payload(document, issues=issues, fixes=())
|
||||
return {"issue_count_at_outcome": len(issues), "payload": payload}
|
||||
|
||||
@ -130,15 +138,16 @@ async def auto_confirm(
|
||||
after_value={"status": DocumentStatus.CONFIRMED.value},
|
||||
)
|
||||
confirmed.append(document)
|
||||
fields = await _outcome_fact_fields(session, document, meta=meta)
|
||||
await insert_outcome_fact(
|
||||
session,
|
||||
document_id=document.id,
|
||||
outcome=QualityOutcome.AUTO_CONFIRMED,
|
||||
outcome_at=now,
|
||||
primary_cause=QualityCause.WITHOUT_PARTICIPATION,
|
||||
report_date=document.reporting_date,
|
||||
confirmed_by=None,
|
||||
**fields,
|
||||
)
|
||||
if document.document_type in OUTCOME_FACT_DOCUMENT_TYPES:
|
||||
fields = await _outcome_fact_fields(session, document, meta=meta)
|
||||
await insert_outcome_fact(
|
||||
session,
|
||||
document_id=document.id,
|
||||
outcome=QualityOutcome.AUTO_CONFIRMED,
|
||||
outcome_at=now,
|
||||
primary_cause=QualityCause.WITHOUT_PARTICIPATION,
|
||||
report_date=document.reporting_date,
|
||||
confirmed_by=None,
|
||||
**fields,
|
||||
)
|
||||
return confirmed
|
||||
|
||||
@ -386,6 +386,27 @@ async def test_recognized_disclosure_is_auto_confirmed(seeded: AsyncSession, fix
|
||||
assert disclosure.status is DocumentStatus.CONFIRMED
|
||||
|
||||
|
||||
@pytest.mark.fixtures
|
||||
async def test_recognized_disclosure_is_auto_confirmed_without_outcome_fact(
|
||||
seeded: AsyncSession, fixtures_dir: Path
|
||||
) -> None:
|
||||
"""`DISCLOSURE`/`OTHER` вне матрицы §14 (как и у факта приёма, `INTAKE_FACT_DOCUMENT_TYPES`, Task 5):
|
||||
автоподтверждение документа не меняется, но `quality_outcome_fact` не пишется — иначе `document_id` факта
|
||||
исхода не нашёл бы пары с фактом приёма."""
|
||||
office = (await seeded.execute(select(RegionalOffice).where(RegionalOffice.name == ROSTOV))).scalar_one()
|
||||
disclosure = await _synthetic_disclosure(seeded, fixtures_dir, office=office)
|
||||
file = await seeded.get(StoredFile, disclosure.stored_file_id)
|
||||
assert file is not None
|
||||
|
||||
assert await auto_confirm(seeded, file=file, documents=[disclosure], now=utc_now()) == [disclosure]
|
||||
assert disclosure.status is DocumentStatus.CONFIRMED
|
||||
|
||||
facts = (
|
||||
await seeded.execute(select(QualityOutcomeFact).where(QualityOutcomeFact.document_id == disclosure.id))
|
||||
).scalars().all()
|
||||
assert facts == []
|
||||
|
||||
|
||||
@pytest.mark.fixtures
|
||||
async def test_recognized_disclosure_is_manually_confirmable(
|
||||
seeded: AsyncSession, fixtures_dir: Path, auth_client: AuthClientFactory
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user