refactor(consolidations): on_document_confirmed принимает автора и комментарий перехода (#64)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
d9324f2a38
commit
ff65f2108b
@ -197,18 +197,22 @@ async def unbind_entity(session: AsyncSession, *, version_id: uuid.UUID, entity_
|
|||||||
return _rowcount(result)
|
return _rowcount(result)
|
||||||
|
|
||||||
|
|
||||||
async def on_document_confirmed(
|
async def on_document_confirmed( # noqa: PLR0913 - автор и комментарий перехода задаёт вызывающий (OQ-157)
|
||||||
session: AsyncSession,
|
session: AsyncSession,
|
||||||
audit: AuditService,
|
audit: AuditService,
|
||||||
*,
|
*,
|
||||||
document: Document,
|
document: Document,
|
||||||
user_id: uuid.UUID,
|
changed_by: uuid.UUID | None,
|
||||||
now: datetime.datetime,
|
now: datetime.datetime,
|
||||||
|
comment: str | None = None,
|
||||||
) -> list[uuid.UUID]:
|
) -> list[uuid.UUID]:
|
||||||
"""Хук подтверждения (spec «Подтверждение документа»): привязывает уже `CONFIRMED` документ ко всем версиям «в
|
"""Хук подтверждения (spec «Подтверждение документа», osv-result-mapping «Автоподтверждение чистого документа»):
|
||||||
работе», которым он подходит, заменяя привязанный документ того же ключа (R-1); версия из `INITIATED` /
|
привязывает уже `CONFIRMED` документ ко всем версиям «в работе», которым он подходит, заменяя привязанный документ
|
||||||
`DOCUMENTS_PROCESSING` переходит в `DATA_CORRECTION` (`changed_by = user_id`, D-6). Возвращает id версий,
|
того же ключа (R-1); версия из `INITIATED` / `DOCUMENTS_PROCESSING` переходит в `DATA_CORRECTION` с `changed_by` и
|
||||||
получивших привязку (по возрастанию).
|
`comment` вызывающего (ручное подтверждение — пользователь и `None`, автоподтверждение — загрузивший файл и
|
||||||
|
«автоподтверждение документа …», D-2). `changed_by is None` (файл без `uploaded_by`) — привязка создаётся, переход
|
||||||
|
пропускается с записью в лог (`consolidation_status_history.changed_by` NOT NULL). Возвращает id версий, получивших
|
||||||
|
привязку (по возрастанию).
|
||||||
|
|
||||||
Вызывать после блокировки файла и документа (D-9): версии блокирует `repo.lock_versions_for_entity` — advisory ГК
|
Вызывать после блокировки файла и документа (D-9): версии блокирует `repo.lock_versions_for_entity` — advisory ГК
|
||||||
(создание версии ∥ подтверждение) и `FOR UPDATE` надмножества версий ГК (правка периметра ∥ подтверждение, R-2).
|
(создание версии ∥ подтверждение) и `FOR UPDATE` надмножества версий ГК (правка периметра ∥ подтверждение, R-2).
|
||||||
@ -227,13 +231,21 @@ async def on_document_confirmed(
|
|||||||
continue
|
continue
|
||||||
await _bind(session, version.id, document)
|
await _bind(session, version.id, document)
|
||||||
if version.status in MOVES_TO_CORRECTION:
|
if version.status in MOVES_TO_CORRECTION:
|
||||||
|
if changed_by is None:
|
||||||
|
logger.info(
|
||||||
|
"Переход версии по подтверждению пропущен: нет автора (changed_by обязателен). "
|
||||||
|
"version_id={version_id}, document_id={document_id}",
|
||||||
|
version_id=version.id,
|
||||||
|
document_id=document.id,
|
||||||
|
)
|
||||||
|
else:
|
||||||
await transition(
|
await transition(
|
||||||
session,
|
session,
|
||||||
audit,
|
audit,
|
||||||
version=version,
|
version=version,
|
||||||
to=ConsolidationStatus.DATA_CORRECTION,
|
to=ConsolidationStatus.DATA_CORRECTION,
|
||||||
changed_by=user_id,
|
changed_by=changed_by,
|
||||||
comment=None,
|
comment=comment,
|
||||||
now=now,
|
now=now,
|
||||||
)
|
)
|
||||||
bound.append(version.id)
|
bound.append(version.id)
|
||||||
|
|||||||
@ -273,7 +273,7 @@ class DocumentService:
|
|||||||
meta.reviewed_at = now
|
meta.reviewed_at = now
|
||||||
await self._session.flush()
|
await self._session.flush()
|
||||||
await consolidation_documents.on_document_confirmed(
|
await consolidation_documents.on_document_confirmed(
|
||||||
self._session, self._audit.service, document=document, user_id=self._audit.user_id, now=now
|
self._session, self._audit.service, document=document, changed_by=self._audit.user_id, now=now
|
||||||
)
|
)
|
||||||
await self._audit.record(
|
await self._audit.record(
|
||||||
action=AuditAction.DOCUMENT_CONFIRM,
|
action=AuditAction.DOCUMENT_CONFIRM,
|
||||||
|
|||||||
@ -473,7 +473,7 @@ async def test_on_document_confirmed_returns_bound_versions(seeded: AsyncSession
|
|||||||
user = await _user(seeded)
|
user = await _user(seeded)
|
||||||
|
|
||||||
bound = await consolidation_documents.on_document_confirmed(
|
bound = await consolidation_documents.on_document_confirmed(
|
||||||
seeded, AuditService(seeded), document=document, user_id=user.id, now=utc_now()
|
seeded, AuditService(seeded), document=document, changed_by=user.id, now=utc_now()
|
||||||
)
|
)
|
||||||
|
|
||||||
assert bound == sorted([q2.id, q3.id])
|
assert bound == sorted([q2.id, q3.id])
|
||||||
@ -481,6 +481,49 @@ async def test_on_document_confirmed_returns_bound_versions(seeded: AsyncSession
|
|||||||
assert await _bound(seeded, q4.id) == set()
|
assert await _bound(seeded, q4.id) == set()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.integration
|
||||||
|
async def test_on_document_confirmed_without_changed_by_binds_but_keeps_status(seeded: AsyncSession) -> None:
|
||||||
|
"""Автоподтверждение файла без `uploaded_by` (OQ-157, D-2): привязка есть, перехода версии нет."""
|
||||||
|
group, entities = await _group(seeded)
|
||||||
|
version = await _version(seeded, group, entities)
|
||||||
|
document = await _confirmed(seeded, entities[0], quarter=Q2)
|
||||||
|
history = len(await _history(seeded, version.id))
|
||||||
|
|
||||||
|
bound = await consolidation_documents.on_document_confirmed(
|
||||||
|
seeded, AuditService(seeded), document=document, changed_by=None, now=utc_now()
|
||||||
|
)
|
||||||
|
|
||||||
|
assert bound == [version.id]
|
||||||
|
assert document.id in await _bound(seeded, version.id)
|
||||||
|
assert await _status(seeded, version.id) is ConsolidationStatus.INITIATED
|
||||||
|
assert len(await _history(seeded, version.id)) == history
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.integration
|
||||||
|
async def test_on_document_confirmed_writes_comment_to_history(seeded: AsyncSession) -> None:
|
||||||
|
"""Комментарий перехода от вызывающего (автоподтверждение) попадает в историю статусов."""
|
||||||
|
group, entities = await _group(seeded)
|
||||||
|
version = await _version(seeded, group, entities)
|
||||||
|
user = await _user(seeded)
|
||||||
|
document = await _confirmed(seeded, entities[0], quarter=Q2)
|
||||||
|
|
||||||
|
await consolidation_documents.on_document_confirmed(
|
||||||
|
seeded,
|
||||||
|
AuditService(seeded),
|
||||||
|
document=document,
|
||||||
|
changed_by=user.id,
|
||||||
|
comment="автоподтверждение документа OSV 60",
|
||||||
|
now=utc_now(),
|
||||||
|
)
|
||||||
|
|
||||||
|
last = (await _history(seeded, version.id))[-1]
|
||||||
|
assert (last.to_status, last.changed_by, last.comment) == (
|
||||||
|
ConsolidationStatus.DATA_CORRECTION,
|
||||||
|
user.id,
|
||||||
|
"автоподтверждение документа OSV 60",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# --- подхват ----------------------------------------------------------------------------------------------------------
|
# --- подхват ----------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
@ -700,7 +743,7 @@ async def _confirm_in(session: AsyncSession, data: dict[str, Any]) -> list[uuid.
|
|||||||
document.confirmed_at = now
|
document.confirmed_at = now
|
||||||
await session.flush()
|
await session.flush()
|
||||||
return await consolidation_documents.on_document_confirmed(
|
return await consolidation_documents.on_document_confirmed(
|
||||||
session, AuditService(session), document=document, user_id=data["user_id"], now=now
|
session, AuditService(session), document=document, changed_by=data["user_id"], now=now
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user