From 2cfed0c33dca788fc6bb9fa55fa1aed86fe7d637 Mon Sep 17 00:00:00 2001 From: Daniel Roth Date: Fri, 3 Jul 2026 16:15:44 +0000 Subject: [PATCH] =?UTF-8?q?Abri=20amend=5Fjob=20amends=20an=20OpenHousing?= =?UTF-8?q?=20appointment=20and=20returns=20the=20echoed=20booking=20?= =?UTF-8?q?=F0=9F=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Fable 5 --- domain/abri/models.py | 20 +++++++++++- infrastructure/abri/abri_client.py | 5 +++ ...i_relay_amendoptiappt_success_response.xml | 3 ++ tests/infrastructure/abri/test_abri_client.py | 32 +++++++++++++++++++ 4 files changed, 59 insertions(+), 1 deletion(-) create mode 100644 tests/abri/abri_relay_amendoptiappt_success_response.xml diff --git a/domain/abri/models.py b/domain/abri/models.py index e160c3e3b..0444ec1cc 100644 --- a/domain/abri/models.py +++ b/domain/abri/models.py @@ -1,6 +1,6 @@ from dataclasses import dataclass from datetime import date -from typing import Literal, NewType, Union +from typing import Literal, NewType, Optional, Union PlaceRef = NewType("PlaceRef", str) @@ -30,3 +30,21 @@ class AbriRequestRejected: LogJobResult = Union[JobLogged, AbriRequestRejected] + + +@dataclass(frozen=True) +class AmendJobRequest: + job_no: str + appointment_date: date + appointment_time: SlotCode + resource: Optional[str] = None + + +@dataclass(frozen=True) +class AppointmentAmended: + job_no: str + appointment_date: str + appointment_time: str + + +AmendJobResult = Union[AppointmentAmended, AbriRequestRejected] diff --git a/infrastructure/abri/abri_client.py b/infrastructure/abri/abri_client.py index 72a3c4767..4342ba946 100644 --- a/infrastructure/abri/abri_client.py +++ b/infrastructure/abri/abri_client.py @@ -5,6 +5,8 @@ import requests from domain.abri.models import ( AbriRequestRejected, + AmendJobRequest, + AmendJobResult, JobLogged, LogJobRequest, LogJobResult, @@ -45,6 +47,9 @@ class AbriClient: return self._parse_job_logged(outcome) + def amend_job(self, request: AmendJobRequest) -> AmendJobResult: + raise NotImplementedError + def _exchange( self, request_type: str, parameters: List[Tuple[str, str]] ) -> Union[ET.Element, AbriRequestRejected]: diff --git a/tests/abri/abri_relay_amendoptiappt_success_response.xml b/tests/abri/abri_relay_amendoptiappt_success_response.xml new file mode 100644 index 000000000..def7734c3 --- /dev/null +++ b/tests/abri/abri_relay_amendoptiappt_success_response.xml @@ -0,0 +1,3 @@ + + + diff --git a/tests/infrastructure/abri/test_abri_client.py b/tests/infrastructure/abri/test_abri_client.py index 133c74d8f..7c205ab7d 100644 --- a/tests/infrastructure/abri/test_abri_client.py +++ b/tests/infrastructure/abri/test_abri_client.py @@ -8,6 +8,8 @@ import requests from domain.abri.models import ( AbriRequestRejected, + AmendJobRequest, + AppointmentAmended, JobLogged, LogJobRequest, PlaceRef, @@ -50,6 +52,14 @@ def _spec_example_request() -> LogJobRequest: ) +def _spec_example_amend_request() -> AmendJobRequest: + return AmendJobRequest( + job_no="AC0439951", + appointment_date=date(2026, 6, 19), + appointment_time="PM", + ) + + @pytest.fixture() def mock_session() -> MagicMock: return MagicMock() @@ -192,3 +202,25 @@ def test_log_job_raises_retriable_parse_error_on_an_unexpectedly_shaped_response # Act / Assert with pytest.raises(AbriResponseParseError): client.log_job(_spec_example_request()) + + +# --- amend_job: success --- + + +def test_amend_job_returns_appointment_amended_echoing_the_response_attributes( + client: AbriClient, mock_session: MagicMock +) -> None: + # Arrange + mock_session.post.return_value.content = _load_fixture( + "abri_relay_amendoptiappt_success_response.xml" + ) + + # Act + result = client.amend_job(_spec_example_amend_request()) + + # Assert + assert result == AppointmentAmended( + job_no="AC0439951", + appointment_date="24/06/2026", + appointment_time="PM", + )