feat(poll): retire responses without erasing history

This commit is contained in:
2026-07-22 03:32:05 +02:00
parent 8292c9d709
commit 8ceb3935f5
3 changed files with 192 additions and 0 deletions

View File

@@ -9,6 +9,8 @@ from govoplan_core.core.poll import (
PollCapabilityError,
PollOptionOrderCommand,
PollOptionUpdateCommand,
PollResponseRetirementCommand,
PollResponseRetirementProvider,
PollSchedulingProvider,
)
from govoplan_core.db.base import Base
@@ -132,6 +134,62 @@ class PollResponseEditingTests(unittest.TestCase):
)
self.assertEqual(len(first.answers), 2)
def test_provider_retires_response_from_live_results_but_keeps_audit_history(self) -> None:
poll = self._poll()
response = self._submit_both(poll, "person-1")
response.metadata_ = {
"invitation_id": "invitation-1",
"participant_email": "alice@example.test",
}
provider = SqlPollSchedulingProvider()
command = PollResponseRetirementCommand(
respondent_ids=("person-1", "alice@example.test"),
invitation_id="invitation-1",
reason="scheduling_participant_removed",
idempotency_key="scheduling:request-1:participant-1:removed",
metadata={
"source_module": "scheduling",
"source_resource_type": "participant",
"source_resource_id": "participant-1",
},
)
self.assertIsInstance(provider, PollResponseRetirementProvider)
retired = provider.retire_responses(
self.session,
tenant_id="tenant-1",
poll_id=poll.id,
command=command,
)
self.assertEqual(retired.response_ids, (response.id,))
self.assertEqual(retired.newly_retired_count, 1)
self.assertFalse(retired.replayed)
self.assertIsNotNone(response.deleted_at)
self.assertEqual(len(response.answers), 2)
self.assertEqual(
response.metadata_["response_retirement"]["idempotency_key"],
command.idempotency_key,
)
self.assertEqual(
provider.list_responses(
self.session,
tenant_id="tenant-1",
poll_id=poll.id,
),
(),
)
replayed = provider.retire_responses(
self.session,
tenant_id="tenant-1",
poll_id=poll.id,
command=command,
)
self.assertTrue(replayed.replayed)
self.assertEqual(replayed.newly_retired_count, 0)
self.assertEqual(replayed.response_ids, (response.id,))
def test_fully_invalidated_response_is_no_longer_active_or_counted(self) -> None:
poll = self._poll()
response = submit_poll_response(