feat: add status and payment capability contracts
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
from datetime import UTC, datetime
|
||||
import unittest
|
||||
|
||||
from govoplan_core.core.application_status import (
|
||||
CAPABILITY_APPLICATION_STATUS_PROJECTION,
|
||||
application_status_projection_provider,
|
||||
)
|
||||
|
||||
|
||||
class _Provider:
|
||||
def tenant_id_for_tracking_id(self, session, *, tracking_id):
|
||||
return "tenant-1"
|
||||
|
||||
def public_access_challenge(self, session, *, tracking_id):
|
||||
return {"tracking_id": tracking_id, "mode": "permanent_link"}
|
||||
|
||||
def get_authenticated_projection(
|
||||
self, session, principal, *, tracking_id, observed_at
|
||||
):
|
||||
return {"tracking_id": tracking_id, "status": "submitted"}
|
||||
|
||||
def get_public_projection(self, session, *, tracking_id, token, observed_at):
|
||||
return {"tracking_id": tracking_id, "status": "submitted"}
|
||||
|
||||
def request_email_link(self, session, *, tracking_id, email, requested_at):
|
||||
return True
|
||||
|
||||
|
||||
class _Registry:
|
||||
def __init__(self, provider):
|
||||
self.provider = provider
|
||||
|
||||
def has_capability(self, name):
|
||||
return name == CAPABILITY_APPLICATION_STATUS_PROJECTION
|
||||
|
||||
def capability(self, name):
|
||||
return self.provider
|
||||
|
||||
|
||||
class ApplicationStatusContractTests(unittest.TestCase):
|
||||
def test_resolves_only_structurally_complete_provider(self):
|
||||
provider = _Provider()
|
||||
resolved = application_status_projection_provider(_Registry(provider))
|
||||
|
||||
self.assertIs(provider, resolved)
|
||||
self.assertEqual(
|
||||
"tenant-1",
|
||||
resolved.tenant_id_for_tracking_id(None, tracking_id="tracking-1"),
|
||||
)
|
||||
self.assertTrue(
|
||||
resolved.request_email_link(
|
||||
None,
|
||||
tracking_id="tracking-1",
|
||||
email="resident@example.test",
|
||||
requested_at=datetime(2026, 8, 19, tzinfo=UTC),
|
||||
)
|
||||
)
|
||||
|
||||
def test_rejects_incomplete_provider(self):
|
||||
self.assertIsNone(application_status_projection_provider(_Registry(object())))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@@ -0,0 +1,83 @@
|
||||
from datetime import UTC, datetime
|
||||
import unittest
|
||||
|
||||
from govoplan_core.core.institutional import EvidenceReference
|
||||
from govoplan_core.core.payments import (
|
||||
CAPABILITY_PAYMENT_REQUESTS,
|
||||
ManualPaymentReconciliationCommand,
|
||||
PaymentRequestCommand,
|
||||
payment_request_provider,
|
||||
)
|
||||
|
||||
|
||||
class _Provider:
|
||||
def request_payment(self, session, command):
|
||||
return {"payment_id": "payment-1", "status": "requested"}
|
||||
|
||||
def get_payment(self, session, *, tenant_id, payment_id):
|
||||
return {"payment_id": payment_id, "status": "requested"}
|
||||
|
||||
def reconcile_manual_payment(self, session, command):
|
||||
return {"payment_id": command.payment_id, "status": "paid"}
|
||||
|
||||
|
||||
class _Registry:
|
||||
def __init__(self, provider):
|
||||
self.provider = provider
|
||||
|
||||
def has_capability(self, name):
|
||||
return name == CAPABILITY_PAYMENT_REQUESTS
|
||||
|
||||
def capability(self, name):
|
||||
return self.provider
|
||||
|
||||
|
||||
class PaymentsContractTests(unittest.TestCase):
|
||||
def test_provider_preserves_request_and_evidence_contracts(self):
|
||||
provider = payment_request_provider(_Registry(_Provider()))
|
||||
now = datetime(2026, 8, 19, tzinfo=UTC)
|
||||
requested = provider.request_payment(
|
||||
None,
|
||||
PaymentRequestCommand(
|
||||
tenant_id="tenant-1",
|
||||
source_module="cases",
|
||||
source_resource_type="case",
|
||||
source_resource_id="case-1",
|
||||
amount_minor=3000,
|
||||
currency="EUR",
|
||||
subject="Resident parking permit fee",
|
||||
idempotency_key="case-1-fee",
|
||||
requested_at=now,
|
||||
requested_by_ref="account:officer-1",
|
||||
),
|
||||
)
|
||||
paid = provider.reconcile_manual_payment(
|
||||
None,
|
||||
ManualPaymentReconciliationCommand(
|
||||
tenant_id="tenant-1",
|
||||
payment_id=str(requested["payment_id"]),
|
||||
amount_minor=3000,
|
||||
currency="EUR",
|
||||
transaction_reference="BANK-2026-1",
|
||||
evidence_ref=EvidenceReference(
|
||||
kind="document",
|
||||
owner_module="files",
|
||||
evidence_id="file-1",
|
||||
tenant_id="tenant-1",
|
||||
version="1",
|
||||
checksum="a" * 64,
|
||||
),
|
||||
idempotency_key="bank-2026-1",
|
||||
received_at=now,
|
||||
recorded_at=now,
|
||||
recorded_by_ref="account:officer-1",
|
||||
),
|
||||
)
|
||||
self.assertEqual("paid", paid["status"])
|
||||
|
||||
def test_rejects_incomplete_provider(self):
|
||||
self.assertIsNone(payment_request_provider(_Registry(object())))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user