Skip to content

Commit b9fb89e

Browse files
authored
Merge pull request #38 from itk-dev-rpa/release/2.0.0
Release/2.0.0
2 parents 7943fc5 + 07e62ab commit b9fb89e

File tree

7 files changed

+218
-27
lines changed

7 files changed

+218
-27
lines changed

changelog.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
## [2.0.0] - 2024-04-03
11+
12+
### Changed
13+
14+
#### KMD Nova
15+
16+
- Department and Caseworker classes added.
17+
- Ability to set security unit, department and caseworker on cases.
18+
- Better tests for cases.
19+
20+
### Fixed
21+
22+
- Security unit not set properly on Nova cases.
23+
1024
## [1.3.1] - 2024-02-21
1125

1226
### Fixed
@@ -67,7 +81,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6781

6882
- Initial release
6983

70-
[Unreleased] https://github.com/itk-dev-rpa/ITK-dev-shared-components/compare/1.3.1...HEAD
84+
[Unreleased] https://github.com/itk-dev-rpa/ITK-dev-shared-components/compare/2.0.0...HEAD
85+
[2.0.0] https://github.com/itk-dev-rpa/ITK-dev-shared-components/releases/tag/2.0.0
7186
[1.3.1] https://github.com/itk-dev-rpa/ITK-dev-shared-components/releases/tag/1.3.1
7287
[1.3.0] https://github.com/itk-dev-rpa/ITK-dev-shared-components/releases/tag/1.3.0
7388
[1.2.0] https://github.com/itk-dev-rpa/ITK-dev-shared-components/releases/tag/1.2.0

itk_dev_shared_components/kmd_nova/nova_cases.py

Lines changed: 92 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import requests
99

1010
from itk_dev_shared_components.kmd_nova.authentication import NovaAccess
11-
from itk_dev_shared_components.kmd_nova.nova_objects import NovaCase, CaseParty, JournalNote
11+
from itk_dev_shared_components.kmd_nova.nova_objects import NovaCase, CaseParty, JournalNote, Caseworker, Department
1212
from itk_dev_shared_components.kmd_nova.util import datetime_from_iso_string
1313

1414

@@ -83,7 +83,30 @@ def get_cases(nova_access: NovaAccess, cpr: str = None, case_number: str = None,
8383
},
8484
"sensitivity": {
8585
"sensitivity": True
86-
}
86+
},
87+
"caseworker": {
88+
"kspIdentity": {
89+
"novaUserId": True,
90+
"fullName": True,
91+
"racfId": True
92+
}
93+
},
94+
"responsibleDepartment": {
95+
"losIdentity": {
96+
"novaUnitId": True,
97+
"administrativeUnitId": True,
98+
"fullName": True,
99+
"userKey": True
100+
}
101+
},
102+
"securityUnit": {
103+
"losIdentity": {
104+
"novaUnitId": True,
105+
"administrativeUnitId": True,
106+
"fullName": True,
107+
"userKey": True
108+
}
109+
},
87110
}
88111
}
89112

@@ -98,6 +121,7 @@ def get_cases(nova_access: NovaAccess, cpr: str = None, case_number: str = None,
98121
# Convert json to NovaCase objects
99122
cases = []
100123
for case_dict in response.json()['cases']:
124+
security_unit, responsible_department = _extract_departments(case_dict)
101125
case = NovaCase(
102126
uuid = case_dict['common']['uuid'],
103127
title = case_dict['caseAttributes']['title'],
@@ -110,14 +134,60 @@ def get_cases(nova_access: NovaAccess, cpr: str = None, case_number: str = None,
110134
note_count = case_dict['numberOfJournalNotes'],
111135
kle_number = case_dict['caseClassification']['kleNumber']['code'],
112136
proceeding_facet = case_dict['caseClassification']['proceedingFacet']['code'],
113-
sensitivity = case_dict["sensitivity"]["sensitivity"]
137+
sensitivity = case_dict["sensitivity"]["sensitivity"],
138+
caseworker = _extract_case_worker(case_dict),
139+
security_unit=security_unit,
140+
responsible_department=responsible_department
114141
)
115142

116143
cases.append(case)
117144

118145
return cases
119146

120147

148+
def _extract_departments(case_dict: dict) -> tuple[Department, Department]:
149+
"""Extract the departments from a HTTP request response.
150+
151+
Args:
152+
case_dict: The dictionary describing the case.
153+
154+
Returns:
155+
The security unit and the responsible department.
156+
"""
157+
security_unit = Department(
158+
id=case_dict['securityUnit']['losIdentity']['administrativeUnitId'],
159+
name=case_dict['securityUnit']['losIdentity']['fullName'],
160+
user_key=case_dict['securityUnit']['losIdentity']['userKey']
161+
)
162+
163+
responsible_department = Department(
164+
id=case_dict['responsibleDepartment']['losIdentity']['administrativeUnitId'],
165+
name=case_dict['responsibleDepartment']['losIdentity']['fullName'],
166+
user_key=case_dict['responsibleDepartment']['losIdentity']['userKey']
167+
)
168+
169+
return security_unit, responsible_department
170+
171+
172+
def _extract_case_worker(case_dict: dict) -> Caseworker | None:
173+
"""Extract the case worker from a HTTP request response.
174+
175+
Args:
176+
case_dict: The dictionary describing the case.
177+
178+
Returns:
179+
A case worker object describing the case worker if any.
180+
"""
181+
if 'caseworker' in case_dict:
182+
return Caseworker(
183+
uuid = case_dict['caseworker']['kspIdentity']['novaUserId'],
184+
name = case_dict['caseworker']['kspIdentity']['fullName'],
185+
ident = case_dict['caseworker']['kspIdentity']['racfId']
186+
)
187+
188+
return None
189+
190+
121191
def _extract_case_parties(case_dict: dict) -> list[CaseParty]:
122192
"""Extract the case parties from a HTTP request response.
123193
@@ -164,7 +234,7 @@ def _extract_journal_notes(case_dict: dict) -> list:
164234
return notes
165235

166236

167-
def add_case(case: NovaCase, nova_access: NovaAccess, security_unit_id: int = 818485, security_unit_name: str = "Borgerservice"):
237+
def add_case(case: NovaCase, nova_access: NovaAccess):
168238
"""Add a case to KMD Nova. The case will be created as 'Active'.
169239
170240
Args:
@@ -208,8 +278,16 @@ def add_case(case: NovaCase, nova_access: NovaAccess, security_unit_id: int = 81
208278
],
209279
"securityUnit": {
210280
"losIdentity": {
211-
"administrativeUnitId": security_unit_id,
212-
"fullName": security_unit_name,
281+
"administrativeUnitId": case.security_unit.id,
282+
"fullName": case.security_unit.name,
283+
"userKey": case.security_unit.user_key
284+
}
285+
},
286+
"responsibleDepartment": {
287+
"losIdentity": {
288+
"administrativeUnitId": case.responsible_department.id,
289+
"fullName": case.responsible_department.name,
290+
"userKey": case.responsible_department.user_key
213291
}
214292
},
215293
"SensitivityCtrlBy": "Bruger",
@@ -222,6 +300,14 @@ def add_case(case: NovaCase, nova_access: NovaAccess, security_unit_id: int = 81
222300
"AvailabilityCtrlBy": "Regler"
223301
}
224302

303+
if case.caseworker:
304+
payload['caseworker'] = {
305+
"kspIdentity": {
306+
"racfId": case.caseworker.ident,
307+
"fullName": case.caseworker.name
308+
}
309+
}
310+
225311
headers = {'Content-Type': 'application/json', 'Authorization': f"Bearer {nova_access.get_bearer_token()}"}
226312

227313
response = requests.post(url, params=params, headers=headers, json=payload, timeout=60)

itk_dev_shared_components/kmd_nova/nova_objects.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,22 @@
88
# pylint: disable=too-many-instance-attributes
99

1010

11+
@dataclass(slots=True, kw_only=True)
12+
class Department:
13+
"""A dataclass representing a department in a KMD Nova case."""
14+
id: int
15+
name: str
16+
user_key: str
17+
18+
19+
@dataclass(slots=True, kw_only=True)
20+
class Caseworker:
21+
"""A dataclass representing a caseworker in a KMD Nova case."""
22+
uuid: str
23+
name: str
24+
ident: str
25+
26+
1127
@dataclass(slots=True, kw_only=True)
1228
class CaseParty:
1329
"""A dataclass representing a case party in a KMD Nova case."""
@@ -51,8 +67,7 @@ class Task:
5167
uuid: str
5268
title: str
5369
description: Optional[str] = None
54-
case_worker_ident: Optional[str] = None
55-
case_worker_uuid: str
70+
caseworker: Caseworker
5671
status_code: Literal['N', 'S', 'F'] # Not Started, Started, Finished
5772
deadline: datetime
5873
created_date: Optional[datetime] = None
@@ -70,8 +85,11 @@ class NovaCase:
7085
active_code: Optional[str] = None
7186
progress_state: Literal["Opstaaet", "Oplyst", "Afgjort", "Bestilt", "Udfoert", "Afsluttet"]
7287
case_parties: list[CaseParty]
88+
caseworker: Optional[Caseworker] = None
7389
document_count: Optional[int] = 0
7490
note_count: Optional[int] = 0
7591
kle_number: str
7692
proceeding_facet: str
7793
sensitivity: Literal["Fortrolige", "IkkeFortrolige", "SærligFølsomme", "Følsomme"]
94+
responsible_department: Department
95+
security_unit: Department

itk_dev_shared_components/kmd_nova/nova_tasks.py

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import requests
77

88
from itk_dev_shared_components.kmd_nova.authentication import NovaAccess
9-
from itk_dev_shared_components.kmd_nova.nova_objects import Task
9+
from itk_dev_shared_components.kmd_nova.nova_objects import Task, Caseworker
1010
from itk_dev_shared_components.kmd_nova.util import datetime_from_iso_string, datetime_to_iso_string
1111

1212

@@ -35,7 +35,7 @@ def attach_task_to_case(case_uuid: str, task: Task, nova_access: NovaAccess) ->
3535
"caseUuid": case_uuid,
3636
"title": task.title,
3737
"description": task.description, # Optional
38-
"caseworkerPersonId": task.case_worker_uuid, # Optional
38+
"caseworkerPersonId": task.caseworker.uuid, # Optional
3939
"statusCode": task.status_code,
4040
"deadline": datetime_to_iso_string(task.deadline),
4141
"startDate": datetime_to_iso_string(task.started_date), # Optional
@@ -89,8 +89,7 @@ def get_tasks(case_uuid: str, nova_access: NovaAccess, limit: int = 100) -> list
8989
uuid = task_dict['taskUuid'],
9090
title = task_dict['taskTitle'],
9191
description = task_dict.get('taskDescription'),
92-
case_worker_ident = task_dict['caseWorker']['ident'] if 'caseWorker' in task_dict else None,
93-
case_worker_uuid = task_dict['caseWorker']['id'] if 'caseWorker' in task_dict else None,
92+
caseworker = _extract_caseworker(task_dict),
9493
status_code = task_dict['taskStatusCode'],
9594
deadline = datetime_from_iso_string(task_dict.get('taskDeadline')),
9695
created_date = datetime_from_iso_string(task_dict.get('taskCreateDate')),
@@ -102,6 +101,25 @@ def get_tasks(case_uuid: str, nova_access: NovaAccess, limit: int = 100) -> list
102101
return tasks
103102

104103

104+
def _extract_caseworker(task_dict: dict) -> Caseworker | None:
105+
"""Extract the case worker from a HTTP request response.
106+
107+
Args:
108+
case_dict: The dictionary describing the task.
109+
110+
Returns:
111+
A case worker object describing the case worker if any.
112+
"""
113+
if 'caseWorker' in task_dict:
114+
return Caseworker(
115+
uuid = task_dict['caseWorker']['id'],
116+
ident = task_dict['caseWorker']['ident'],
117+
name = task_dict['caseWorker']['name']
118+
)
119+
120+
return None
121+
122+
105123
def update_task(task: Task, case_uuid: str, nova_access: NovaAccess):
106124
"""Update a task that already exists in KMD Nova with new
107125
information.
@@ -125,7 +143,7 @@ def update_task(task: Task, case_uuid: str, nova_access: NovaAccess):
125143
"caseUuid": case_uuid,
126144
"title": task.title,
127145
"description": task.description,
128-
"caseworkerPersonId": task.case_worker_uuid,
146+
"caseworkerPersonId": task.caseworker.uuid,
129147
"statusCode": task.status_code,
130148
"deadline": datetime_to_iso_string(task.deadline),
131149
"startDate": datetime_to_iso_string(task.started_date),

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "itk_dev_shared_components"
7-
version = "1.3.1"
7+
version = "2.0.0"
88
authors = [
99
{ name="ITK Development", email="itk-rpa@mkb.aarhus.dk" },
1010
]

tests/test_nova_api/test_cases.py

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@
33
import os
44
import uuid
55
from datetime import datetime
6+
import time
67

78
from itk_dev_shared_components.kmd_nova.authentication import NovaAccess
8-
from itk_dev_shared_components.kmd_nova.nova_objects import NovaCase, CaseParty
9+
from itk_dev_shared_components.kmd_nova.nova_objects import NovaCase, CaseParty, Caseworker, Department
910
from itk_dev_shared_components.kmd_nova import nova_cases
1011

1112

@@ -57,6 +58,18 @@ def test_add_case(self):
5758
name="Test Test"
5859
)
5960

61+
caseworker = Caseworker(
62+
name='svcitkopeno svcitkopeno',
63+
ident='AZX0080',
64+
uuid='0bacdddd-5c61-4676-9a61-b01a18cec1d5'
65+
)
66+
67+
department = Department(
68+
id=818485,
69+
name="Borgerservice",
70+
user_key="4BBORGER"
71+
)
72+
6073
case = NovaCase(
6174
uuid=str(uuid.uuid4()),
6275
title=f"Test {datetime.now()}",
@@ -65,11 +78,35 @@ def test_add_case(self):
6578
case_parties=[party],
6679
kle_number="23.05.01",
6780
proceeding_facet="G01",
68-
sensitivity="Fortrolige"
81+
sensitivity="Fortrolige",
82+
caseworker=caseworker,
83+
responsible_department=department,
84+
security_unit=department
6985
)
7086

7187
nova_cases.add_case(case, self.nova_access)
7288

89+
# Wait up to 10 seconds for the case to be created in Nova
90+
for _ in range(10):
91+
time.sleep(1)
92+
cases = nova_cases.get_cases(self.nova_access, cpr=party.identification, case_title=case.title)
93+
if cases:
94+
break
95+
96+
self.assertEqual(len(cases), 1)
97+
98+
nova_case = cases[0]
99+
self.assertEqual(nova_case.uuid, case.uuid)
100+
self.assertEqual(nova_case.title, case.title)
101+
self.assertEqual(nova_case.progress_state, case.progress_state)
102+
self.assertEqual(nova_case.kle_number, case.kle_number)
103+
self.assertEqual(nova_case.proceeding_facet, case.proceeding_facet)
104+
self.assertEqual(nova_case.sensitivity, case.sensitivity)
105+
self.assertEqual(nova_case.caseworker.ident, case.caseworker.ident)
106+
self.assertEqual(nova_case.case_parties[0].identification, case.case_parties[0].identification)
107+
self.assertEqual(nova_case.responsible_department.id, case.responsible_department.id)
108+
self.assertEqual(nova_case.security_unit.id, case.security_unit.id)
109+
73110

74111
if __name__ == '__main__':
75112
unittest.main()

0 commit comments

Comments
 (0)