Skip to content

Commit dd02466

Browse files
authored
Merge pull request #443 from NHSDigital/release/2024-12-11
Release/2024 12 11
2 parents 9800ff2 + 0517252 commit dd02466

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+4788
-1846
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## 2024-12-11
4+
- [PI-650] Modify the Read Device endpoint for AS Devices
5+
- [PI-666] Create an ASID for AS Device and add as a DeviceKey
6+
- [PI-603] Update the spine_mhs questionnaire
7+
- [PI-645] Update the spine_mhs_message_sets questionnaire
8+
39
## 2024-12-05
410
- [PI-631] Generate Product Ids
511
- [PI-691] Allow devs to clear terminal after each Feature Test

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,21 +247,21 @@ Executing feature tests in integration mode will then give you confidence that t
247247
To execute the feature tests entirely locally (executing lambdas directly, and otherwise mocking databases and responses to a high standard) you can do:
248248

249249
```shell
250-
make test--feature-local
250+
make test--feature--local
251251
```
252252

253253
If you would like to pass `behave` flags, e.g. to \[stop after the first failure\]:
254254

255255
```shell
256-
make test--feature-local BEHAVE_FLAGS="--stop"
256+
make test--feature--local BEHAVE_FLAGS="--stop"
257257
```
258258

259259
#### Integration
260260

261261
To execute the feature tests across the entire stack (including Apigee and AWS) you can do
262262

263263
```shell
264-
make test--feature-integration
264+
make test--feature--integration
265265
```
266266

267267
### Generate the Feature Test Postman collection

VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2024.12.05
1+
2024.12.11

changelog/2024-12-11.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
- [PI-650] Modify the Read Device endpoint for AS Devices
2+
- [PI-666] Create an ASID for AS Device and add as a DeviceKey
3+
- [PI-603] Update the spine_mhs questionnaire
4+
- [PI-645] Update the spine_mhs_message_sets questionnaire

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[tool.poetry]
22
name = "connecting-party-manager"
3-
version = "2024.12.05"
3+
version = "2024.12.11"
44
description = "Repository for the Connecting Party Manager API and related services"
55
authors = ["NHS England"]
66
license = "LICENSE.md"

src/api/createDeviceAccreditedSystem/src/v1/steps.py

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@
77
read_product_team,
88
)
99
from domain.core.cpm_product import CpmProduct
10+
from domain.core.cpm_system_id import AsidId
1011
from domain.core.device import (
1112
Device,
1213
DeviceTagAddedEvent,
1314
QuestionnaireResponseUpdatedEvent,
1415
)
16+
from domain.core.device_key.v1 import DeviceKeyType
1517
from domain.core.device_reference_data import DeviceReferenceData
1618
from domain.core.error import (
1719
AccreditedSystemFatalError,
@@ -20,6 +22,7 @@
2022
)
2123
from domain.core.product_key import ProductKeyType
2224
from domain.core.questionnaire import Questionnaire, QuestionnaireResponse
25+
from domain.repository.cpm_system_id_repository import CpmSystemIdRepository
2326
from domain.repository.device_reference_data_repository import (
2427
DeviceReferenceDataRepository,
2528
)
@@ -85,28 +88,41 @@ def validate_spine_as_questionnaire_response(data, cache) -> QuestionnaireRespon
8588
)
8689

8790

91+
def create_party_key_tag(data, cache) -> DeviceTagAddedEvent:
92+
as_device: Device = data[create_as_device]
93+
return as_device.add_tag(party_key=data[get_party_key])
94+
95+
96+
def create_asid(data, cache) -> AsidId:
97+
repository = CpmSystemIdRepository[AsidId](
98+
table_name=cache["DYNAMODB_TABLE"],
99+
dynamodb_client=cache["DYNAMODB_CLIENT"],
100+
model=AsidId,
101+
)
102+
asid = repository.read()
103+
new_asid = AsidId.create(current_number=asid.latest_number)
104+
return new_asid
105+
106+
88107
def create_as_device(data, cache) -> Device:
89108
product: CpmProduct = data[read_product]
109+
asid: AsidId = data[create_asid]
90110
payload: CreateAsDeviceIncomingParams = data[parse_as_device_payload]
91111
party_key: str = data[get_party_key]
92112

93-
# Create a new Device dictionary excluding 'questionnaire_responses'
94-
# Ticket PI-666 adds ASID generation. This will need to be sent across in the arguments instead of an empty string.
95113
device_payload = payload.dict(exclude={"questionnaire_responses"})
96114
return product.create_device(
97-
name=EprNameTemplate.AS_DEVICE.format(party_key=party_key, asid=""),
115+
name=EprNameTemplate.AS_DEVICE.format(party_key=party_key, asid=asid.__root__),
98116
**device_payload
99117
)
100118

101119

102-
def create_party_key_tag(data, cache) -> DeviceTagAddedEvent:
103-
as_device: Device = data[create_as_device]
104-
return as_device.add_tag(party_key=data[get_party_key])
105-
106-
107120
def create_device_keys(data, cache) -> Device:
108-
# We will need to add some keys in the future, ASID?
109121
as_device: Device = data[create_as_device]
122+
asid: AsidId = data[create_asid]
123+
as_device.add_key(
124+
key_type=DeviceKeyType.ACCREDITED_SYSTEM_ID, key_value=asid.__root__
125+
)
110126
return as_device
111127

112128

@@ -139,6 +155,16 @@ def write_device(data: dict[str, Device], cache) -> Device:
139155
return repo.write(as_device)
140156

141157

158+
def write_asid(data: dict[str, AsidId], cache) -> str:
159+
repository = CpmSystemIdRepository[AsidId](
160+
table_name=cache["DYNAMODB_TABLE"],
161+
dynamodb_client=cache["DYNAMODB_CLIENT"],
162+
model=AsidId,
163+
)
164+
asid: AsidId = data[create_asid]
165+
return repository.create_or_update(asid)
166+
167+
142168
def set_http_status(data, cache) -> tuple[HTTPStatus, dict]:
143169
as_device: Device = data[create_as_device]
144170
return HTTPStatus.CREATED, as_device.state_exclude_tags()
@@ -170,11 +196,13 @@ def get_party_key(data, cache) -> str:
170196
read_device_reference_data,
171197
read_spine_as_questionnaire,
172198
validate_spine_as_questionnaire_response,
199+
create_asid,
173200
create_as_device,
174201
create_party_key_tag,
175202
create_device_keys,
176203
add_device_reference_data_id,
177204
add_spine_as_questionnaire_response,
178205
write_device,
206+
write_asid,
179207
set_http_status,
180208
]

src/api/createDeviceAccreditedSystem/tests/test_index.py

Lines changed: 100 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from domain.core.cpm_product import CpmProduct
1111
from domain.core.cpm_system_id import ProductId
1212
from domain.core.device import Device
13+
from domain.core.device_key.v1 import DeviceKey, DeviceKeyType
1314
from domain.core.product_key import ProductKeyType
1415
from domain.core.root import Root
1516
from domain.repository.cpm_product_repository import CpmProductRepository
@@ -34,6 +35,7 @@
3435
PRODUCT_TEAM_NAME = "My Product Team"
3536
PRODUCT_NAME = "My Product"
3637
VERSION = 1
38+
PARTY_KEY = "ABC1234-987654"
3739

3840
QUESTIONNAIRE_DATA = {
3941
"ODS Code": "FH15R",
@@ -68,7 +70,7 @@ def mock_epr_product_with_one_message_set_drd() -> (
6870
product = product_team.create_cpm_product(
6971
name=PRODUCT_NAME, product_id=PRODUCT_ID
7072
)
71-
product.add_key(key_type=ProductKeyType.PARTY_KEY, key_value="ABC1234-987654")
73+
product.add_key(key_type=ProductKeyType.PARTY_KEY, key_value=PARTY_KEY)
7274
product_repo = CpmProductRepository(
7375
table_name=TABLE_NAME, dynamodb_client=client
7476
)
@@ -78,10 +80,22 @@ def mock_epr_product_with_one_message_set_drd() -> (
7880
QuestionnaireInstance.SPINE_MHS_MESSAGE_SETS
7981
)
8082
questionnaire_response_1 = mhs_message_set_questionnaire.validate(
81-
data={"Interaction ID": "urn:foo1", "MHS SN": "bar", "MHS IN": "baz"}
83+
data={
84+
"Interaction ID": "bar:baz",
85+
"MHS SN": "bar",
86+
"MHS IN": "baz",
87+
"MHS CPA ID": f"{PARTY_KEY}:bar:baz",
88+
"Unique Identifier": f"{PARTY_KEY}:bar:baz",
89+
}
8290
)
8391
questionnaire_response_2 = mhs_message_set_questionnaire.validate(
84-
data={"Interaction ID": "urn:foo2", "MHS SN": "bar2", "MHS IN": "baz2"}
92+
data={
93+
"Interaction ID": "bar2:baz2",
94+
"MHS SN": "bar2",
95+
"MHS IN": "baz2",
96+
"MHS CPA ID": f"{PARTY_KEY}:bar2:baz2",
97+
"Unique Identifier": f"{PARTY_KEY}:bar2:baz2",
98+
}
8599
)
86100

87101
# Set up DeviceReferenceData in DB
@@ -123,7 +137,7 @@ def mock_epr_product_with_message_sets_drd() -> (
123137
product = product_team.create_cpm_product(
124138
name=PRODUCT_NAME, product_id=PRODUCT_ID
125139
)
126-
product.add_key(key_type=ProductKeyType.PARTY_KEY, key_value="ABC1234-987654")
140+
product.add_key(key_type=ProductKeyType.PARTY_KEY, key_value=PARTY_KEY)
127141
product_repo = CpmProductRepository(
128142
table_name=TABLE_NAME, dynamodb_client=client
129143
)
@@ -134,10 +148,22 @@ def mock_epr_product_with_message_sets_drd() -> (
134148
)
135149

136150
questionnaire_response_1 = mhs_message_set_questionnaire.validate(
137-
data={"Interaction ID": "urn:foo1", "MHS SN": "bar", "MHS IN": "baz"}
151+
data={
152+
"Interaction ID": "bar:baz",
153+
"MHS SN": "bar",
154+
"MHS IN": "baz",
155+
"MHS CPA ID": f"{PARTY_KEY}:bar:baz",
156+
"Unique Identifier": f"{PARTY_KEY}:bar:baz",
157+
}
138158
)
139159
questionnaire_response_2 = mhs_message_set_questionnaire.validate(
140-
data={"Interaction ID": "urn:foo2", "MHS SN": "bar2", "MHS IN": "baz2"}
160+
data={
161+
"Interaction ID": "bar2:baz2",
162+
"MHS SN": "bar2",
163+
"MHS IN": "baz2",
164+
"MHS CPA ID": f"{PARTY_KEY}:bar2:baz2",
165+
"Unique Identifier": f"{PARTY_KEY}:bar2:baz2",
166+
}
141167
)
142168
# Set up DeviceReferenceData in DB
143169
device_reference_data_mhs = product.create_device_reference_data(
@@ -196,7 +222,7 @@ def mock_epr_product_with_more_than_two_message_sets_drd() -> (
196222
product = product_team.create_cpm_product(
197223
name=PRODUCT_NAME, product_id=PRODUCT_ID
198224
)
199-
product.add_key(key_type=ProductKeyType.PARTY_KEY, key_value="ABC1234-987654")
225+
product.add_key(key_type=ProductKeyType.PARTY_KEY, key_value=PARTY_KEY)
200226
product_repo = CpmProductRepository(
201227
table_name=TABLE_NAME, dynamodb_client=client
202228
)
@@ -206,10 +232,22 @@ def mock_epr_product_with_more_than_two_message_sets_drd() -> (
206232
QuestionnaireInstance.SPINE_MHS_MESSAGE_SETS
207233
)
208234
questionnaire_response_1 = mhs_message_set_questionnaire_1.validate(
209-
data={"Interaction ID": "urn:foo1", "MHS SN": "bar", "MHS IN": "baz"}
235+
data={
236+
"Interaction ID": "bar:baz",
237+
"MHS SN": "bar",
238+
"MHS IN": "baz",
239+
"MHS CPA ID": f"{PARTY_KEY}:bar:baz",
240+
"Unique Identifier": f"{PARTY_KEY}:bar:baz",
241+
}
210242
)
211243
questionnaire_response_2 = mhs_message_set_questionnaire_1.validate(
212-
data={"Interaction ID": "urn:foo2", "MHS SN": "bar2", "MHS IN": "baz2"}
244+
data={
245+
"Interaction ID": "bar2:baz2",
246+
"MHS SN": "bar2",
247+
"MHS IN": "baz2",
248+
"MHS CPA ID": f"{PARTY_KEY}:bar2:baz2",
249+
"Unique Identifier": f"{PARTY_KEY}:bar2:baz2",
250+
}
213251
)
214252

215253
# Set up DeviceReferenceData in DB
@@ -223,10 +261,22 @@ def mock_epr_product_with_more_than_two_message_sets_drd() -> (
223261
QuestionnaireInstance.SPINE_MHS_MESSAGE_SETS
224262
)
225263
questionnaire_response_3 = mhs_message_set_questionnaire_2.validate(
226-
data={"Interaction ID": "urn:foo3", "MHS SN": "bar3", "MHS IN": "baz3"}
264+
data={
265+
"Interaction ID": "bar3:baz3",
266+
"MHS SN": "bar3",
267+
"MHS IN": "baz3",
268+
"MHS CPA ID": f"{PARTY_KEY}:bar3:baz3",
269+
"Unique Identifier": f"{PARTY_KEY}:bar3:baz3",
270+
}
227271
)
228272
questionnaire_response_4 = mhs_message_set_questionnaire_2.validate(
229-
data={"Interaction ID": "urn:foo4", "MHS SN": "bar4", "MHS IN": "baz4"}
273+
data={
274+
"Interaction ID": "bar4:baz4",
275+
"MHS SN": "bar4",
276+
"MHS IN": "baz4",
277+
"MHS CPA ID": f"{PARTY_KEY}:bar4:baz4",
278+
"Unique Identifier": f"{PARTY_KEY}:bar4:baz4",
279+
}
230280
)
231281

232282
# Set up DeviceReferenceData in DB
@@ -286,7 +336,7 @@ def mock_epr_product_with_two_message_sets_the_same_drd() -> (
286336
product = product_team.create_cpm_product(
287337
name=PRODUCT_NAME, product_id=PRODUCT_ID
288338
)
289-
product.add_key(key_type=ProductKeyType.PARTY_KEY, key_value="ABC1234-987654")
339+
product.add_key(key_type=ProductKeyType.PARTY_KEY, key_value=PARTY_KEY)
290340
product_repo = CpmProductRepository(
291341
table_name=TABLE_NAME, dynamodb_client=client
292342
)
@@ -296,10 +346,22 @@ def mock_epr_product_with_two_message_sets_the_same_drd() -> (
296346
QuestionnaireInstance.SPINE_MHS_MESSAGE_SETS
297347
)
298348
questionnaire_response_1 = mhs_message_set_questionnaire_1.validate(
299-
data={"Interaction ID": "urn:foo1", "MHS SN": "bar", "MHS IN": "baz"}
349+
data={
350+
"Interaction ID": "bar:baz",
351+
"MHS SN": "bar",
352+
"MHS IN": "baz",
353+
"MHS CPA ID": f"{PARTY_KEY}:bar:baz",
354+
"Unique Identifier": f"{PARTY_KEY}:bar:baz",
355+
}
300356
)
301357
questionnaire_response_2 = mhs_message_set_questionnaire_1.validate(
302-
data={"Interaction ID": "urn:foo2", "MHS SN": "bar2", "MHS IN": "baz2"}
358+
data={
359+
"Interaction ID": "bar2:baz2",
360+
"MHS SN": "ba2r",
361+
"MHS IN": "baz2",
362+
"MHS CPA ID": f"{PARTY_KEY}:bar2:baz2",
363+
"Unique Identifier": f"{PARTY_KEY}:bar2:baz2",
364+
}
303365
)
304366

305367
# Set up DeviceReferenceData in DB
@@ -313,10 +375,22 @@ def mock_epr_product_with_two_message_sets_the_same_drd() -> (
313375
QuestionnaireInstance.SPINE_MHS_MESSAGE_SETS
314376
)
315377
questionnaire_response_3 = mhs_message_set_questionnaire_2.validate(
316-
data={"Interaction ID": "urn:foo3", "MHS SN": "bar3", "MHS IN": "baz3"}
378+
data={
379+
"Interaction ID": "bar3:baz3",
380+
"MHS SN": "bar3",
381+
"MHS IN": "baz3",
382+
"MHS CPA ID": f"{PARTY_KEY}:bar3:baz3",
383+
"Unique Identifier": f"{PARTY_KEY}:bar3:baz3",
384+
}
317385
)
318386
questionnaire_response_4 = mhs_message_set_questionnaire_2.validate(
319-
data={"Interaction ID": "urn:foo4", "MHS SN": "bar4", "MHS IN": "baz4"}
387+
data={
388+
"Interaction ID": "bar4:baz4",
389+
"MHS SN": "bar4",
390+
"MHS IN": "baz4",
391+
"MHS CPA ID": f"{PARTY_KEY}:bar4:baz4",
392+
"Unique Identifier": f"{PARTY_KEY}:bar4:baz4",
393+
}
320394
)
321395

322396
# Set up DeviceReferenceData in DB
@@ -389,7 +463,7 @@ def mock_epr_product_without_message_set_drd() -> (
389463
product = product_team.create_cpm_product(
390464
name=PRODUCT_NAME, product_id=PRODUCT_ID
391465
)
392-
product.add_key(key_type=ProductKeyType.PARTY_KEY, key_value="ABC1234-987654")
466+
product.add_key(key_type=ProductKeyType.PARTY_KEY, key_value=PARTY_KEY)
393467
product_repo = CpmProductRepository(
394468
table_name=TABLE_NAME, dynamodb_client=client
395469
)
@@ -425,7 +499,7 @@ def test_index() -> None:
425499
device = Device(**_device)
426500
assert device.product_team_id == product.product_team_id
427501
assert device.product_id == product.id
428-
assert device.name == "ABC1234-987654/ - Accredited System"
502+
assert device.name == "ABC1234-987654/200000100000 - Accredited System"
429503
assert device.ods_code == ODS_CODE
430504
assert device.created_on.date() == datetime.today().date()
431505
assert device.updated_on.date() == datetime.today().date()
@@ -448,9 +522,16 @@ def test_index() -> None:
448522
)
449523

450524
# Check party_key is added to tags in the created device
451-
expected_party_key = (str(ProductKeyType.PARTY_KEY), "abc1234-987654")
525+
expected_party_key = (str(ProductKeyType.PARTY_KEY), PARTY_KEY.lower())
452526
assert any(expected_party_key in tag.__root__ for tag in created_device.tags)
453527

528+
# Check an ASID is generated and added to the keys.
529+
assert isinstance(created_device.keys[0], DeviceKey)
530+
assert created_device.keys[0].__dict__ == {
531+
"key_type": DeviceKeyType.ACCREDITED_SYSTEM_ID,
532+
"key_value": "200000100000",
533+
}
534+
454535

455536
@pytest.mark.parametrize(
456537
["body", "path_parameters", "error_code", "status_code"],

0 commit comments

Comments
 (0)