itk-dev-shared-components 2.8.0__tar.gz → 2.9.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/PKG-INFO +2 -2
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/eflyt/eflyt_case.py +14 -10
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/graph/mail.py +21 -2
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/kmd_nova/nova_cases.py +21 -55
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/kmd_nova/nova_documents.py +16 -18
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/kmd_nova/nova_notes.py +1 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/kmd_nova/nova_objects.py +1 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/kmd_nova/nova_tasks.py +20 -3
- itk_dev_shared_components-2.9.0/itk_dev_shared_components/kmd_nova/util.py +72 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components.egg-info/PKG-INFO +2 -2
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/pyproject.toml +1 -1
- itk_dev_shared_components-2.8.0/itk_dev_shared_components/kmd_nova/util.py +0 -36
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/LICENSE +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/README.md +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/__init__.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/eflyt/__init__.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/eflyt/eflyt_login.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/eflyt/eflyt_search.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/eflyt/eflyt_util.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/graph/__init__.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/graph/authentication.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/graph/common.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/graph/file.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/graph/site.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/kmd_nova/__init__.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/kmd_nova/authentication.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/kmd_nova/cpr.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/misc/__init__.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/misc/address_lookup.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/misc/cpr_util.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/misc/cvr_lookup.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/misc/file_util.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/sap/__init__.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/sap/fmcacov.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/sap/gridview_util.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/sap/multi_session.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/sap/opret_kundekontakt.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/sap/sap_login.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/sap/sap_util.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/sap/tree_util.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/smtp/__init__.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components/smtp/smtp_util.py +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components.egg-info/SOURCES.txt +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components.egg-info/dependency_links.txt +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components.egg-info/requires.txt +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/itk_dev_shared_components.egg-info/top_level.txt +0 -0
- {itk_dev_shared_components-2.8.0 → itk_dev_shared_components-2.9.0}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: itk_dev_shared_components
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.9.0
|
|
4
4
|
Summary: Shared components to use in RPA projects
|
|
5
5
|
Author-email: ITK Development <itk-rpa@mkb.aarhus.dk>
|
|
6
6
|
Project-URL: Homepage, https://github.com/itk-dev-rpa/itk-dev-shared-components
|
|
@@ -130,7 +130,9 @@ def change_tab(browser: webdriver.Chrome, tab_index: int):
|
|
|
130
130
|
|
|
131
131
|
|
|
132
132
|
def approve_case(browser: webdriver.Chrome):
|
|
133
|
-
"""Approve a case
|
|
133
|
+
"""Approve a case.
|
|
134
|
+
If any person on the case is blocking approval, approve each person individually.
|
|
135
|
+
"""
|
|
134
136
|
change_tab(browser, 0)
|
|
135
137
|
|
|
136
138
|
deadline_field = browser.find_element(By.ID, "ctl00_ContentPlaceHolder2_ptFanePerson_ncPersonTab_txtDeadline")
|
|
@@ -142,20 +144,22 @@ def approve_case(browser: webdriver.Chrome):
|
|
|
142
144
|
browser.find_element(By.ID, "ctl00_ContentPlaceHolder2_ptFanePerson_stcPersonTab1_btnApproveYes").click()
|
|
143
145
|
|
|
144
146
|
approve_persons_button = browser.find_element(By.ID, "ctl00_ContentPlaceHolder2_ptFanePerson_stcPersonTab1_btnGodkendAlle")
|
|
145
|
-
if
|
|
147
|
+
if approve_persons_button.is_enabled():
|
|
148
|
+
approve_persons_button.click()
|
|
149
|
+
else:
|
|
150
|
+
# Approve each person individually
|
|
151
|
+
person_count = len(browser.find_elements(By.XPATH, '//table[@id="ctl00_ContentPlaceHolder2_GridViewMovingPersons"]//tr')) - 1
|
|
146
152
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
rows.pop(0)
|
|
153
|
+
for i in range(person_count):
|
|
154
|
+
browser.find_element(By.XPATH, f'//table[@id="ctl00_ContentPlaceHolder2_GridViewMovingPersons"]//tr[{i+2}]//td[2]').click()
|
|
150
155
|
|
|
151
|
-
for row in rows:
|
|
152
|
-
row.find_element(By.XPATH, "td[2]").click()
|
|
153
156
|
browser.find_element(By.ID, "ctl00_ContentPlaceHolder2_ptFanePerson_stcPersonTab1_btnGodkend").click()
|
|
154
157
|
approve_button = browser.find_element(By.ID, "ctl00_ContentPlaceHolder2_ptFanePerson_stcPersonTab1_btnApproveYes")
|
|
155
158
|
if approve_button.is_displayed():
|
|
156
159
|
approve_button.click()
|
|
157
|
-
|
|
158
|
-
|
|
160
|
+
|
|
161
|
+
# Go back to the case
|
|
162
|
+
browser.find_element(By.XPATH, '//table[@id="ctl00_ContentPlaceHolder2_GridViewMovingPersons"]//tr[1]//td[2]').click()
|
|
159
163
|
|
|
160
164
|
|
|
161
165
|
def check_all_approved(browser: webdriver.Chrome) -> bool:
|
|
@@ -167,7 +171,7 @@ def check_all_approved(browser: webdriver.Chrome) -> bool:
|
|
|
167
171
|
|
|
168
172
|
for row in rows:
|
|
169
173
|
row_status = row.find_element(By.XPATH, "td[6]").text
|
|
170
|
-
if row_status
|
|
174
|
+
if row_status not in ("Godkendt", "Afsluttet"):
|
|
171
175
|
return False
|
|
172
176
|
return True
|
|
173
177
|
|
|
@@ -122,14 +122,33 @@ def get_folder_id_from_path(user: str, folder_path: str, graph_access: GraphAcce
|
|
|
122
122
|
# Get child folders
|
|
123
123
|
for child_folder in child_folders:
|
|
124
124
|
endpoint = f"https://graph.microsoft.com/v1.0/users/{user}/mailFolders/{folder_id}/childFolders"
|
|
125
|
-
|
|
126
|
-
folder_id = _find_folder(response, child_folder)
|
|
125
|
+
folder_id = recursive_find_folder(endpoint, graph_access, child_folder)
|
|
127
126
|
if folder_id is None:
|
|
128
127
|
raise ValueError(f"Child folder '{child_folder}' not found under '{main_folder}' for user '{user}'.")
|
|
129
128
|
|
|
130
129
|
return folder_id
|
|
131
130
|
|
|
132
131
|
|
|
132
|
+
def recursive_find_folder(endpoint: str, graph_access: GraphAccess, target_folder: str) -> str:
|
|
133
|
+
"""Look for target folder at endpoint, recursively going through pagination if available and necessary.
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
endpoint: Graph endpoint to lookup folder.
|
|
137
|
+
graph_access: Access token for Graph API.
|
|
138
|
+
target_folder: ID of target folder.
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
Return folder ID.
|
|
142
|
+
"""
|
|
143
|
+
response = get_request(endpoint, graph_access).json()
|
|
144
|
+
folder_id = _find_folder(response, target_folder)
|
|
145
|
+
|
|
146
|
+
if folder_id is None and '@odata.nextLink' in response:
|
|
147
|
+
return recursive_find_folder(response['@odata.nextLink'], graph_access, target_folder)
|
|
148
|
+
|
|
149
|
+
return folder_id
|
|
150
|
+
|
|
151
|
+
|
|
133
152
|
def list_email_attachments(email: Email, graph_access: GraphAccess) -> tuple[Attachment]:
|
|
134
153
|
"""List all attachments of the given email. This function only gets the id, name and size
|
|
135
154
|
of the attachment. Use get_attachment_data to get the actual data of an attachment.
|
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
to the KMD Nova api."""
|
|
3
3
|
|
|
4
4
|
import uuid
|
|
5
|
-
import base64
|
|
6
5
|
import urllib.parse
|
|
7
6
|
|
|
8
7
|
import requests
|
|
9
8
|
|
|
10
9
|
from itk_dev_shared_components.kmd_nova.authentication import NovaAccess
|
|
11
|
-
from itk_dev_shared_components.kmd_nova.nova_objects import NovaCase, CaseParty,
|
|
12
|
-
from itk_dev_shared_components.kmd_nova.util import datetime_from_iso_string
|
|
10
|
+
from itk_dev_shared_components.kmd_nova.nova_objects import NovaCase, CaseParty, Department
|
|
11
|
+
from itk_dev_shared_components.kmd_nova.util import datetime_from_iso_string, extract_caseworker
|
|
13
12
|
|
|
14
13
|
|
|
15
14
|
def get_case(case_uuid: str, nova_access: NovaAccess) -> NovaCase:
|
|
@@ -125,7 +124,7 @@ def _get_nova_cases(nova_access: NovaAccess, payload: dict) -> list[NovaCase]:
|
|
|
125
124
|
kle_number = case_dict['caseClassification']['kleNumber']['code'],
|
|
126
125
|
proceeding_facet = case_dict['caseClassification']['proceedingFacet']['code'],
|
|
127
126
|
sensitivity = case_dict["sensitivity"]["sensitivity"],
|
|
128
|
-
caseworker =
|
|
127
|
+
caseworker = extract_caseworker(case_dict),
|
|
129
128
|
security_unit=security_unit,
|
|
130
129
|
responsible_department=responsible_department
|
|
131
130
|
)
|
|
@@ -189,6 +188,11 @@ def _create_payload(*, case_uuid: str = None, identification: str = None, identi
|
|
|
189
188
|
"novaUserId": True,
|
|
190
189
|
"fullName": True,
|
|
191
190
|
"racfId": True
|
|
191
|
+
},
|
|
192
|
+
"losIdentity": {
|
|
193
|
+
"novaUnitId": True,
|
|
194
|
+
"fullName": True,
|
|
195
|
+
"administrativeUnitId": True
|
|
192
196
|
}
|
|
193
197
|
},
|
|
194
198
|
"responsibleDepartment": {
|
|
@@ -235,29 +239,6 @@ def _extract_departments(case_dict: dict) -> tuple[Department, Department]:
|
|
|
235
239
|
return security_unit, responsible_department
|
|
236
240
|
|
|
237
241
|
|
|
238
|
-
def _extract_case_worker(case_dict: dict) -> Caseworker | None:
|
|
239
|
-
"""Extract the case worker from a HTTP request response.
|
|
240
|
-
If the case worker is in a unexpected format, None is returned.
|
|
241
|
-
|
|
242
|
-
Args:
|
|
243
|
-
case_dict: The dictionary describing the case.
|
|
244
|
-
|
|
245
|
-
Returns:
|
|
246
|
-
A case worker object describing the case worker if any.
|
|
247
|
-
"""
|
|
248
|
-
if 'caseworker' in case_dict:
|
|
249
|
-
try:
|
|
250
|
-
return Caseworker(
|
|
251
|
-
uuid = case_dict['caseworker']['kspIdentity']['novaUserId'],
|
|
252
|
-
name = case_dict['caseworker']['kspIdentity']['fullName'],
|
|
253
|
-
ident = case_dict['caseworker']['kspIdentity']['racfId']
|
|
254
|
-
)
|
|
255
|
-
except KeyError:
|
|
256
|
-
return None
|
|
257
|
-
|
|
258
|
-
return None
|
|
259
|
-
|
|
260
|
-
|
|
261
242
|
def _extract_case_parties(case_dict: dict) -> list[CaseParty]:
|
|
262
243
|
"""Extract the case parties from a HTTP request response.
|
|
263
244
|
|
|
@@ -281,29 +262,6 @@ def _extract_case_parties(case_dict: dict) -> list[CaseParty]:
|
|
|
281
262
|
return parties
|
|
282
263
|
|
|
283
264
|
|
|
284
|
-
def _extract_journal_notes(case_dict: dict) -> list:
|
|
285
|
-
"""Extract the journal notes from a HTTP request response.
|
|
286
|
-
|
|
287
|
-
Args:
|
|
288
|
-
case_dict: The dictionary describing the journal note.
|
|
289
|
-
|
|
290
|
-
Returns:
|
|
291
|
-
A journal note object describing the journal note.
|
|
292
|
-
"""
|
|
293
|
-
notes = []
|
|
294
|
-
for note_dict in case_dict['journalNotes']['journalNotes']:
|
|
295
|
-
note = JournalNote(
|
|
296
|
-
uuid = note_dict['uuid'],
|
|
297
|
-
title = note_dict['journalNoteAttributes']['title'],
|
|
298
|
-
journal_date = note_dict['journalNoteAttributes']['journalNoteDate'],
|
|
299
|
-
note_format = note_dict['journalNoteAttributes']['format'],
|
|
300
|
-
note = base64.b64decode(note_dict['journalNoteAttributes']['note']),
|
|
301
|
-
approved = note_dict['journalNoteAttributes'].get('approved', False)
|
|
302
|
-
)
|
|
303
|
-
notes.append(note)
|
|
304
|
-
return notes
|
|
305
|
-
|
|
306
|
-
|
|
307
265
|
def add_case(case: NovaCase, nova_access: NovaAccess):
|
|
308
266
|
"""Add a case to KMD Nova. The case will be created as 'Active'.
|
|
309
267
|
|
|
@@ -371,12 +329,20 @@ def add_case(case: NovaCase, nova_access: NovaAccess):
|
|
|
371
329
|
}
|
|
372
330
|
|
|
373
331
|
if case.caseworker:
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
"
|
|
377
|
-
|
|
332
|
+
if case.caseworker.type == 'user':
|
|
333
|
+
payload['caseworker'] = {
|
|
334
|
+
"kspIdentity": {
|
|
335
|
+
"racfId": case.caseworker.ident,
|
|
336
|
+
"fullName": case.caseworker.name
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
elif case.caseworker.type == 'group':
|
|
340
|
+
payload['caseworker'] = {
|
|
341
|
+
"losIdentity": {
|
|
342
|
+
"administrativeUnitId": case.caseworker.ident,
|
|
343
|
+
"fullName": case.caseworker.name
|
|
344
|
+
}
|
|
378
345
|
}
|
|
379
|
-
}
|
|
380
346
|
|
|
381
347
|
headers = {'Content-Type': 'application/json', 'Authorization': f"Bearer {nova_access.get_bearer_token()}"}
|
|
382
348
|
|
|
@@ -10,8 +10,8 @@ import urllib.parse
|
|
|
10
10
|
import requests
|
|
11
11
|
|
|
12
12
|
from itk_dev_shared_components.kmd_nova.authentication import NovaAccess
|
|
13
|
-
from itk_dev_shared_components.kmd_nova.nova_objects import Document
|
|
14
|
-
from itk_dev_shared_components.kmd_nova.
|
|
13
|
+
from itk_dev_shared_components.kmd_nova.nova_objects import Document
|
|
14
|
+
from itk_dev_shared_components.kmd_nova.util import datetime_from_iso_string, extract_caseworker
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
def get_documents(case_uuid: str, nova_access: NovaAccess) -> list[Document]:
|
|
@@ -56,16 +56,6 @@ def get_documents(case_uuid: str, nova_access: NovaAccess) -> list[Document]:
|
|
|
56
56
|
|
|
57
57
|
documents = []
|
|
58
58
|
for document_dict in response.json()['documents']:
|
|
59
|
-
|
|
60
|
-
if 'caseworker' in document_dict:
|
|
61
|
-
caseworker = Caseworker(
|
|
62
|
-
uuid = document_dict['caseworker']['kspIdentity']['novaUserId'],
|
|
63
|
-
name = document_dict['caseworker']['kspIdentity']['fullName'],
|
|
64
|
-
ident = document_dict['caseworker']['kspIdentity']['racfId']
|
|
65
|
-
)
|
|
66
|
-
else:
|
|
67
|
-
caseworker = None
|
|
68
|
-
|
|
69
59
|
doc = Document(
|
|
70
60
|
uuid = document_dict['documentUuid'],
|
|
71
61
|
document_number = document_dict['documentNumber'],
|
|
@@ -78,7 +68,7 @@ def get_documents(case_uuid: str, nova_access: NovaAccess) -> list[Document]:
|
|
|
78
68
|
file_extension = document_dict['fileExtension'],
|
|
79
69
|
category_name = document_dict.get('documentCategoryName'),
|
|
80
70
|
category_uuid = document_dict.get('documentCategoryUuid'),
|
|
81
|
-
caseworker=
|
|
71
|
+
caseworker=extract_caseworker(document_dict)
|
|
82
72
|
)
|
|
83
73
|
documents.append(doc)
|
|
84
74
|
|
|
@@ -197,12 +187,20 @@ def attach_document_to_case(case_uuid: str, document: Document, nova_access: Nov
|
|
|
197
187
|
}
|
|
198
188
|
|
|
199
189
|
if document.caseworker:
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
"
|
|
203
|
-
|
|
190
|
+
if document.caseworker.type == 'user':
|
|
191
|
+
payload['caseworker'] = {
|
|
192
|
+
"kspIdentity": {
|
|
193
|
+
"racfId": document.caseworker.ident,
|
|
194
|
+
"fullName": document.caseworker.name
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
elif document.caseworker.type == 'group':
|
|
198
|
+
payload['caseworker'] = {
|
|
199
|
+
"losIdentity": {
|
|
200
|
+
"administrativeUnitId": document.caseworker.ident,
|
|
201
|
+
"fullName": document.caseworker.name
|
|
202
|
+
}
|
|
204
203
|
}
|
|
205
|
-
}
|
|
206
204
|
|
|
207
205
|
headers = {'Content-Type': 'application/json', 'Authorization': f"Bearer {nova_access.get_bearer_token()}"}
|
|
208
206
|
response = requests.post(url, params=params, headers=headers, json=payload, timeout=60)
|
|
@@ -18,6 +18,7 @@ def add_text_note(case_uuid: str, note_title: str, note_text: str, caseworker: C
|
|
|
18
18
|
case_uuid: The uuid of the case to add the journal note to.
|
|
19
19
|
note_title: The title of the note.
|
|
20
20
|
note_text: The text content of the note.
|
|
21
|
+
caseworker: The author of the note.
|
|
21
22
|
approved: Whether the journal note should be marked as approved in Nova.
|
|
22
23
|
nova_access: The NovaAccess object used to authenticate.
|
|
23
24
|
|
|
@@ -35,7 +35,6 @@ def attach_task_to_case(case_uuid: str, task: Task, nova_access: NovaAccess) ->
|
|
|
35
35
|
"caseUuid": case_uuid,
|
|
36
36
|
"title": task.title,
|
|
37
37
|
"description": task.description, # Optional
|
|
38
|
-
"caseworkerPersonId": task.caseworker.uuid, # Optional
|
|
39
38
|
"statusCode": task.status_code,
|
|
40
39
|
"deadline": datetime_to_iso_string(task.deadline),
|
|
41
40
|
"startDate": datetime_to_iso_string(task.started_date), # Optional
|
|
@@ -43,6 +42,11 @@ def attach_task_to_case(case_uuid: str, task: Task, nova_access: NovaAccess) ->
|
|
|
43
42
|
"taskTypeName": "Aktivitet"
|
|
44
43
|
}
|
|
45
44
|
|
|
45
|
+
if task.caseworker.type == 'user':
|
|
46
|
+
payload["caseworkerPersonId"] = task.caseworker.uuid
|
|
47
|
+
elif task.caseworker.type == 'group':
|
|
48
|
+
payload["caseworkerGroupId"] = task.caseworker.uuid
|
|
49
|
+
|
|
46
50
|
headers = {'Content-Type': 'application/json', 'Authorization': f"Bearer {nova_access.get_bearer_token()}"}
|
|
47
51
|
response = requests.post(url, params=params, headers=headers, json=payload, timeout=60)
|
|
48
52
|
response.raise_for_status()
|
|
@@ -114,7 +118,16 @@ def _extract_caseworker(task_dict: dict) -> Caseworker | None:
|
|
|
114
118
|
return Caseworker(
|
|
115
119
|
uuid = task_dict['caseWorker']['id'],
|
|
116
120
|
ident = task_dict['caseWorker']['ident'],
|
|
117
|
-
name = task_dict['caseWorker']['name']
|
|
121
|
+
name = task_dict['caseWorker']['name'],
|
|
122
|
+
type='user'
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
if 'caseWorkerGroup' in task_dict:
|
|
126
|
+
return Caseworker(
|
|
127
|
+
uuid = task_dict['caseWorkerGroup']['id'],
|
|
128
|
+
ident = None,
|
|
129
|
+
name = task_dict['caseWorkerGroup']['name'],
|
|
130
|
+
type='group'
|
|
118
131
|
)
|
|
119
132
|
|
|
120
133
|
return None
|
|
@@ -143,7 +156,6 @@ def update_task(task: Task, case_uuid: str, nova_access: NovaAccess):
|
|
|
143
156
|
"caseUuid": case_uuid,
|
|
144
157
|
"title": task.title,
|
|
145
158
|
"description": task.description,
|
|
146
|
-
"caseworkerPersonId": task.caseworker.uuid,
|
|
147
159
|
"statusCode": task.status_code,
|
|
148
160
|
"deadline": datetime_to_iso_string(task.deadline),
|
|
149
161
|
"startDate": datetime_to_iso_string(task.started_date),
|
|
@@ -151,6 +163,11 @@ def update_task(task: Task, case_uuid: str, nova_access: NovaAccess):
|
|
|
151
163
|
"taskType": "Aktivitet"
|
|
152
164
|
}
|
|
153
165
|
|
|
166
|
+
if task.caseworker.type == 'user':
|
|
167
|
+
payload["caseworkerPersonId"] = task.caseworker.uuid
|
|
168
|
+
elif task.caseworker.type == 'group':
|
|
169
|
+
payload["caseworkerGroupId"] = task.caseworker.uuid
|
|
170
|
+
|
|
154
171
|
headers = {'Content-Type': 'application/json', 'Authorization': f"Bearer {nova_access.get_bearer_token()}"}
|
|
155
172
|
response = requests.put(url, params=params, headers=headers, json=payload, timeout=60)
|
|
156
173
|
response.raise_for_status()
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"""This module contains helper functions regarding the KMD Nova API."""
|
|
2
|
+
|
|
3
|
+
from datetime import datetime
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from itk_dev_shared_components.kmd_nova.nova_objects import Caseworker
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def datetime_from_iso_string(date_string: Optional[str]) -> Optional[datetime]:
|
|
10
|
+
"""A helper function to convert an ISO date string to a datetime.
|
|
11
|
+
If the date string is None, None is returned.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
date_string: A date string in ISO format.
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
A datetime object representing the date string.
|
|
18
|
+
"""
|
|
19
|
+
if not date_string:
|
|
20
|
+
return None
|
|
21
|
+
|
|
22
|
+
return datetime.fromisoformat(date_string)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def datetime_to_iso_string(datetime_: Optional[datetime]) -> Optional[str]:
|
|
26
|
+
"""A helper function to convert a datetime to an ISO formatted string.
|
|
27
|
+
If the the datetime is None, None is returned.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
datetime_: The datetime object to convert.
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
A datetime string in ISO format.
|
|
34
|
+
"""
|
|
35
|
+
if datetime_:
|
|
36
|
+
return datetime_.isoformat()
|
|
37
|
+
|
|
38
|
+
return None
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def extract_caseworker(response_dict: dict) -> Caseworker | None:
|
|
42
|
+
"""Extract the case worker from a HTTP request response.
|
|
43
|
+
If the case worker is in a unexpected format, None is returned.
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
response_dict: The dictionary describing the response object.
|
|
47
|
+
|
|
48
|
+
Returns:
|
|
49
|
+
A case worker object describing the case worker if any.
|
|
50
|
+
"""
|
|
51
|
+
try:
|
|
52
|
+
if 'caseworker' in response_dict:
|
|
53
|
+
if 'kspIdentity' in response_dict['caseworker']:
|
|
54
|
+
return Caseworker(
|
|
55
|
+
uuid = response_dict['caseworker']['kspIdentity']['novaUserId'],
|
|
56
|
+
name = response_dict['caseworker']['kspIdentity']['fullName'],
|
|
57
|
+
ident = response_dict['caseworker']['kspIdentity']['racfId'],
|
|
58
|
+
type='user'
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
if 'losIdentity' in response_dict['caseworker']:
|
|
62
|
+
return Caseworker(
|
|
63
|
+
uuid = response_dict['caseworker']['losIdentity']['novaUnitId'],
|
|
64
|
+
name = response_dict['caseworker']['losIdentity']['fullName'],
|
|
65
|
+
ident = str(response_dict['caseworker']['losIdentity']['administrativeUnitId']),
|
|
66
|
+
type='group'
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
except KeyError:
|
|
70
|
+
pass
|
|
71
|
+
|
|
72
|
+
return None
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: itk_dev_shared_components
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.9.0
|
|
4
4
|
Summary: Shared components to use in RPA projects
|
|
5
5
|
Author-email: ITK Development <itk-rpa@mkb.aarhus.dk>
|
|
6
6
|
Project-URL: Homepage, https://github.com/itk-dev-rpa/itk-dev-shared-components
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
"""This module contains helper functions regarding the KMD Nova API."""
|
|
2
|
-
|
|
3
|
-
from datetime import datetime
|
|
4
|
-
from typing import Optional
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def datetime_from_iso_string(date_string: Optional[str]) -> Optional[datetime]:
|
|
8
|
-
"""A helper function to convert an ISO date string to a datetime.
|
|
9
|
-
If the date string is None, None is returned.
|
|
10
|
-
|
|
11
|
-
Args:
|
|
12
|
-
date_string: A date string in ISO format.
|
|
13
|
-
|
|
14
|
-
Returns:
|
|
15
|
-
A datetime object representing the date string.
|
|
16
|
-
"""
|
|
17
|
-
if not date_string:
|
|
18
|
-
return None
|
|
19
|
-
|
|
20
|
-
return datetime.fromisoformat(date_string)
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
def datetime_to_iso_string(datetime_: Optional[datetime]) -> Optional[str]:
|
|
24
|
-
"""A helper function to convert a datetime to an ISO formatted string.
|
|
25
|
-
If the the datetime is None, None is returned.
|
|
26
|
-
|
|
27
|
-
Args:
|
|
28
|
-
datetime_: The datetime object to convert.
|
|
29
|
-
|
|
30
|
-
Returns:
|
|
31
|
-
A datetime string in ISO format.
|
|
32
|
-
"""
|
|
33
|
-
if datetime_:
|
|
34
|
-
return datetime_.isoformat()
|
|
35
|
-
|
|
36
|
-
return None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|