pyxecm 3.0.1__py3-none-any.whl → 3.1.1__py3-none-any.whl
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.
Potentially problematic release.
This version of pyxecm might be problematic. Click here for more details.
- pyxecm/avts.py +4 -4
- pyxecm/coreshare.py +14 -15
- pyxecm/helper/data.py +2 -1
- pyxecm/helper/web.py +11 -11
- pyxecm/helper/xml.py +41 -10
- pyxecm/otac.py +1 -1
- pyxecm/otawp.py +19 -19
- pyxecm/otca.py +878 -70
- pyxecm/otcs.py +1716 -349
- pyxecm/otds.py +332 -153
- pyxecm/otkd.py +4 -4
- pyxecm/otmm.py +1 -1
- pyxecm/otpd.py +246 -30
- {pyxecm-3.0.1.dist-info → pyxecm-3.1.1.dist-info}/METADATA +2 -1
- pyxecm-3.1.1.dist-info/RECORD +82 -0
- pyxecm_api/app.py +45 -35
- pyxecm_api/auth/functions.py +2 -2
- pyxecm_api/auth/router.py +2 -3
- pyxecm_api/common/functions.py +67 -12
- pyxecm_api/settings.py +0 -8
- pyxecm_api/terminal/router.py +1 -1
- pyxecm_api/v1_csai/router.py +33 -18
- pyxecm_customizer/browser_automation.py +161 -79
- pyxecm_customizer/customizer.py +43 -25
- pyxecm_customizer/guidewire.py +422 -8
- pyxecm_customizer/k8s.py +23 -27
- pyxecm_customizer/knowledge_graph.py +498 -20
- pyxecm_customizer/m365.py +45 -44
- pyxecm_customizer/payload.py +1723 -1188
- pyxecm_customizer/payload_list.py +3 -0
- pyxecm_customizer/salesforce.py +122 -79
- pyxecm_customizer/servicenow.py +27 -7
- pyxecm_customizer/settings.py +3 -1
- pyxecm_customizer/successfactors.py +2 -2
- pyxecm_customizer/translate.py +1 -1
- pyxecm-3.0.1.dist-info/RECORD +0 -96
- pyxecm_api/agents/__init__.py +0 -7
- pyxecm_api/agents/app.py +0 -13
- pyxecm_api/agents/functions.py +0 -119
- pyxecm_api/agents/models.py +0 -10
- pyxecm_api/agents/otcm_knowledgegraph/__init__.py +0 -1
- pyxecm_api/agents/otcm_knowledgegraph/functions.py +0 -85
- pyxecm_api/agents/otcm_knowledgegraph/models.py +0 -61
- pyxecm_api/agents/otcm_knowledgegraph/router.py +0 -74
- pyxecm_api/agents/otcm_user_agent/__init__.py +0 -1
- pyxecm_api/agents/otcm_user_agent/models.py +0 -20
- pyxecm_api/agents/otcm_user_agent/router.py +0 -65
- pyxecm_api/agents/otcm_workspace_agent/__init__.py +0 -1
- pyxecm_api/agents/otcm_workspace_agent/models.py +0 -40
- pyxecm_api/agents/otcm_workspace_agent/router.py +0 -200
- {pyxecm-3.0.1.dist-info → pyxecm-3.1.1.dist-info}/WHEEL +0 -0
- {pyxecm-3.0.1.dist-info → pyxecm-3.1.1.dist-info}/entry_points.txt +0 -0
pyxecm_customizer/guidewire.py
CHANGED
|
@@ -48,6 +48,7 @@ class Guidewire:
|
|
|
48
48
|
def __init__(
|
|
49
49
|
self,
|
|
50
50
|
base_url: str,
|
|
51
|
+
as_url: str,
|
|
51
52
|
auth_type: str = "",
|
|
52
53
|
client_id: str = "",
|
|
53
54
|
client_secret: str = "",
|
|
@@ -62,6 +63,8 @@ class Guidewire:
|
|
|
62
63
|
Args:
|
|
63
64
|
base_url (str):
|
|
64
65
|
The base URL of the Guidewire Cloud API.
|
|
66
|
+
as_url (str):
|
|
67
|
+
The application server endpount the Guidewire system.
|
|
65
68
|
auth_type (str):
|
|
66
69
|
The authorization type, either "oauth" or "basic".
|
|
67
70
|
client_id (str, optional):
|
|
@@ -104,21 +107,33 @@ class Guidewire:
|
|
|
104
107
|
guidewire_config = {}
|
|
105
108
|
# Store the credentials and parameters in a config dictionary:
|
|
106
109
|
guidewire_config["baseUrl"] = base_url.rstrip("/")
|
|
110
|
+
guidewire_config["asUrl"] = as_url.rstrip("/")
|
|
107
111
|
guidewire_config["authType"] = auth_type
|
|
108
112
|
guidewire_config["clientId"] = client_id
|
|
109
113
|
guidewire_config["clientSecret"] = client_secret
|
|
110
114
|
guidewire_config["username"] = username
|
|
111
115
|
guidewire_config["password"] = password
|
|
112
|
-
guidewire_config["restUrl"] =
|
|
113
|
-
|
|
116
|
+
guidewire_config["restUrl"] = (
|
|
117
|
+
guidewire_config["baseUrl"] + "/rest"
|
|
118
|
+
if guidewire_config["baseUrl"]
|
|
119
|
+
else guidewire_config["asUrl"] + "/rest"
|
|
120
|
+
)
|
|
114
121
|
if token_url:
|
|
115
122
|
guidewire_config["tokenUrl"] = token_url
|
|
116
123
|
else:
|
|
117
|
-
guidewire_config["tokenUrl"] =
|
|
124
|
+
guidewire_config["tokenUrl"] = (
|
|
125
|
+
guidewire_config["baseUrl"] + "/oauth2/token"
|
|
126
|
+
if guidewire_config["baseUrl"]
|
|
127
|
+
else guidewire_config["asUrl"] + "/oauth2/token"
|
|
128
|
+
)
|
|
118
129
|
|
|
119
130
|
guidewire_config["adminUrl"] = guidewire_config["restUrl"] + "/admin/v1"
|
|
120
|
-
guidewire_config["claimUrl"] = guidewire_config["restUrl"] + "/claim/v1"
|
|
121
131
|
guidewire_config["accountUrl"] = guidewire_config["restUrl"] + "/account/v1"
|
|
132
|
+
guidewire_config["accountSearchUrl"] = guidewire_config["accountUrl"] + "/search/accounts"
|
|
133
|
+
guidewire_config["policyUrl"] = guidewire_config["restUrl"] + "/policy/v1"
|
|
134
|
+
guidewire_config["policySearchUrl"] = guidewire_config["policyUrl"] + "/search/policies"
|
|
135
|
+
guidewire_config["claimUrl"] = guidewire_config["restUrl"] + "/claim/v1"
|
|
136
|
+
guidewire_config["claimSearchUrl"] = guidewire_config["claimUrl"] + "/search/claims-v2"
|
|
122
137
|
|
|
123
138
|
self._config = guidewire_config
|
|
124
139
|
|
|
@@ -208,7 +223,9 @@ class Guidewire:
|
|
|
208
223
|
# Log an error if required credentials are missing
|
|
209
224
|
# Either username/password AND client credentials (for ROPC)
|
|
210
225
|
# OR just client credentials (for Client Credentials Grant)
|
|
211
|
-
self.logger.error(
|
|
226
|
+
self.logger.error(
|
|
227
|
+
"Authentication of type -> '%s' requires either client credentials or username/password.", auth_type
|
|
228
|
+
)
|
|
212
229
|
return False
|
|
213
230
|
|
|
214
231
|
if self._scope:
|
|
@@ -254,7 +271,9 @@ class Guidewire:
|
|
|
254
271
|
|
|
255
272
|
# end method definition
|
|
256
273
|
|
|
257
|
-
def do_request(
|
|
274
|
+
def do_request(
|
|
275
|
+
self, method: str, url: str, data: dict | None = None, json_data: dict | None = None, params: dict | None = None
|
|
276
|
+
) -> dict:
|
|
258
277
|
"""Send a request to the Guidewire REST API.
|
|
259
278
|
|
|
260
279
|
Args:
|
|
@@ -264,6 +283,8 @@ class Guidewire:
|
|
|
264
283
|
The API endpoint to call.
|
|
265
284
|
data (dict):
|
|
266
285
|
The request payload (if applicable).
|
|
286
|
+
json_data (dict | None, optional):
|
|
287
|
+
Request payload for the JSON parameter. Defaults to None.
|
|
267
288
|
params (dict):
|
|
268
289
|
The URL parameters (if applicable).
|
|
269
290
|
|
|
@@ -274,7 +295,7 @@ class Guidewire:
|
|
|
274
295
|
"""
|
|
275
296
|
|
|
276
297
|
response = self._session.request(
|
|
277
|
-
method=method, url=url, headers=self.request_header(), data=data, params=params
|
|
298
|
+
method=method, url=url, headers=self.request_header(), data=data, json=json_data, params=params
|
|
278
299
|
)
|
|
279
300
|
|
|
280
301
|
return response.json() if response.content else {}
|
|
@@ -330,6 +351,92 @@ class Guidewire:
|
|
|
330
351
|
|
|
331
352
|
# end method definition
|
|
332
353
|
|
|
354
|
+
def get_result_value(
|
|
355
|
+
self,
|
|
356
|
+
response: dict,
|
|
357
|
+
key: str,
|
|
358
|
+
index: int = 0,
|
|
359
|
+
show_error: bool = True,
|
|
360
|
+
) -> str | None:
|
|
361
|
+
"""Read an item value from the Guidewire REST API response.
|
|
362
|
+
|
|
363
|
+
Args:
|
|
364
|
+
response (dict):
|
|
365
|
+
Guidewire REST API response object.
|
|
366
|
+
key (str):
|
|
367
|
+
Key to find (e.g., "id", "name").
|
|
368
|
+
index (int, optional):
|
|
369
|
+
Index to use if a list of results is delivered (1st element has index 0).
|
|
370
|
+
Defaults to 0.
|
|
371
|
+
show_error (bool, optional):
|
|
372
|
+
Whether an error or just a warning should be logged. Defaults to True.
|
|
373
|
+
|
|
374
|
+
Returns:
|
|
375
|
+
str | None:
|
|
376
|
+
Value of the item with the given key, or None if no value is found.
|
|
377
|
+
|
|
378
|
+
"""
|
|
379
|
+
|
|
380
|
+
# First do some sanity checks:
|
|
381
|
+
if not response:
|
|
382
|
+
self.logger.debug("Empty Guidewire response - no results found!")
|
|
383
|
+
return None
|
|
384
|
+
|
|
385
|
+
# To support also iterators that yield from results,
|
|
386
|
+
# we wrap an "attributes" element into a "data" element
|
|
387
|
+
# to make the following code work like for direct REST responses:
|
|
388
|
+
if "attributes" in response:
|
|
389
|
+
response = {"data": response}
|
|
390
|
+
|
|
391
|
+
if "data" not in response:
|
|
392
|
+
if show_error:
|
|
393
|
+
self.logger.error("No 'data' key in Guidewire REST response -> %s. Returning None.", str(response))
|
|
394
|
+
return None
|
|
395
|
+
|
|
396
|
+
results = response["data"]
|
|
397
|
+
if not results:
|
|
398
|
+
self.logger.debug("No results found in the Guidewire response! Empty 'data' element.")
|
|
399
|
+
return None
|
|
400
|
+
|
|
401
|
+
# check if results is a list or a dict (both is possible - iterator responses will be dict):
|
|
402
|
+
if isinstance(results, dict):
|
|
403
|
+
# result is a dict - we don't need index value
|
|
404
|
+
|
|
405
|
+
attributes = results.get("attributes", {})
|
|
406
|
+
if key in attributes:
|
|
407
|
+
return attributes[key]
|
|
408
|
+
else:
|
|
409
|
+
self.logger.error(
|
|
410
|
+
"Key -> '%s' is not in result attributes!",
|
|
411
|
+
key,
|
|
412
|
+
)
|
|
413
|
+
return None
|
|
414
|
+
|
|
415
|
+
elif isinstance(results, list):
|
|
416
|
+
# result is a list - we need a valid index:
|
|
417
|
+
if index > len(results) - 1:
|
|
418
|
+
self.logger.error(
|
|
419
|
+
"Illegal Index -> %s given. List has only -> %s elements!",
|
|
420
|
+
str(index),
|
|
421
|
+
str(len(results)),
|
|
422
|
+
)
|
|
423
|
+
return None
|
|
424
|
+
data = results[index]
|
|
425
|
+
attributes = data.get("attributes", {})
|
|
426
|
+
if key not in attributes:
|
|
427
|
+
if show_error:
|
|
428
|
+
self.logger.error("Key -> '%s' is not in result attributes -> %s!", key, attributes)
|
|
429
|
+
return None
|
|
430
|
+
return attributes[key]
|
|
431
|
+
else:
|
|
432
|
+
self.logger.error(
|
|
433
|
+
"Result needs to be a list or dict but it is -> %s",
|
|
434
|
+
str(type(results)),
|
|
435
|
+
)
|
|
436
|
+
return None
|
|
437
|
+
|
|
438
|
+
# end method definition
|
|
439
|
+
|
|
333
440
|
def get_groups(
|
|
334
441
|
self,
|
|
335
442
|
fields: list | None = None,
|
|
@@ -1020,7 +1127,7 @@ class Guidewire:
|
|
|
1020
1127
|
* cn - contains
|
|
1021
1128
|
- "value": the filue to filter for. Either literal or list of values
|
|
1022
1129
|
page_size (int, optional):
|
|
1023
|
-
The maximum number of
|
|
1130
|
+
The maximum number of accounts to return.
|
|
1024
1131
|
|
|
1025
1132
|
Returns:
|
|
1026
1133
|
iter:
|
|
@@ -1075,6 +1182,79 @@ class Guidewire:
|
|
|
1075
1182
|
|
|
1076
1183
|
# end method definition
|
|
1077
1184
|
|
|
1185
|
+
def search_account(self, attributes: dict) -> dict:
|
|
1186
|
+
"""Search accounts based on its attributes.
|
|
1187
|
+
|
|
1188
|
+
Args:
|
|
1189
|
+
attributes (dict):
|
|
1190
|
+
The attribute to search the value in. Possible key values:
|
|
1191
|
+
* "accountNumber"
|
|
1192
|
+
* "addressLine1"
|
|
1193
|
+
* "addressLine2"
|
|
1194
|
+
* "city"
|
|
1195
|
+
* "country"
|
|
1196
|
+
* "companyName"
|
|
1197
|
+
|
|
1198
|
+
Returns:
|
|
1199
|
+
dict:
|
|
1200
|
+
JSON response containing account details.
|
|
1201
|
+
|
|
1202
|
+
Example:
|
|
1203
|
+
{
|
|
1204
|
+
'count': 2,
|
|
1205
|
+
'data': [
|
|
1206
|
+
{
|
|
1207
|
+
'attributes': {
|
|
1208
|
+
'accountHolder': {
|
|
1209
|
+
'displayName': 'Armstrong and Company',
|
|
1210
|
+
'id': 'test_pc:1',
|
|
1211
|
+
'type': 'AccountContact',
|
|
1212
|
+
'uri': '/account/v1/accounts/pc:ds:1/contacts/test_pc:1'
|
|
1213
|
+
},
|
|
1214
|
+
'accountNumber': 'C000212105',
|
|
1215
|
+
'accountStatus': {...},
|
|
1216
|
+
'businessOperationsDescription': 'business description',
|
|
1217
|
+
'createdDate': '2025-07-14T03:59:30.055Z',
|
|
1218
|
+
'frozen': False,
|
|
1219
|
+
'id': 'pc:ds:1',
|
|
1220
|
+
'industryCode': {...},
|
|
1221
|
+
'numberOfContacts': '8',
|
|
1222
|
+
'organizationType': {...},
|
|
1223
|
+
'preferredCoverageCurrency': {...},
|
|
1224
|
+
'preferredSettlementCurrency': {...},
|
|
1225
|
+
'primaryLanguage': {...},
|
|
1226
|
+
'primaryLocale': {...},
|
|
1227
|
+
'primaryLocation': {...},
|
|
1228
|
+
'producerCodes': [...]
|
|
1229
|
+
},
|
|
1230
|
+
'checksum': '2',
|
|
1231
|
+
'links': {
|
|
1232
|
+
'do-not-destroy': {...},
|
|
1233
|
+
'freeze': {...},
|
|
1234
|
+
'merge': {...},
|
|
1235
|
+
'move-policies': {...},
|
|
1236
|
+
'move-submissions': {...},
|
|
1237
|
+
'self': {...}
|
|
1238
|
+
}
|
|
1239
|
+
},
|
|
1240
|
+
{...}
|
|
1241
|
+
],
|
|
1242
|
+
'links': {
|
|
1243
|
+
'first': {...},
|
|
1244
|
+
'self': {...}
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
"""
|
|
1249
|
+
|
|
1250
|
+
body = {"data": {"attributes": attributes}}
|
|
1251
|
+
|
|
1252
|
+
request_url = self.config()["accountSearchUrl"]
|
|
1253
|
+
|
|
1254
|
+
return self.do_request(method="POST", json_data=body, url=request_url)
|
|
1255
|
+
|
|
1256
|
+
# end method definition
|
|
1257
|
+
|
|
1078
1258
|
def add_account(self, account_data: dict) -> dict:
|
|
1079
1259
|
"""Create a new account.
|
|
1080
1260
|
|
|
@@ -1134,6 +1314,218 @@ class Guidewire:
|
|
|
1134
1314
|
|
|
1135
1315
|
# end method definition
|
|
1136
1316
|
|
|
1317
|
+
def get_policies(
|
|
1318
|
+
self,
|
|
1319
|
+
fields: list | None = None,
|
|
1320
|
+
filters: list | None = None,
|
|
1321
|
+
page_size: int = 25,
|
|
1322
|
+
next_page_url: str | None = None,
|
|
1323
|
+
) -> dict | None:
|
|
1324
|
+
"""Retrieve a list of policies.
|
|
1325
|
+
|
|
1326
|
+
Args:
|
|
1327
|
+
fields (list | None, optional):
|
|
1328
|
+
The list of fields in the results. If None, all default
|
|
1329
|
+
fields are returned.
|
|
1330
|
+
Fields for Guidewire accounts:
|
|
1331
|
+
- *all = return all fields
|
|
1332
|
+
- *default = return just the default list of fields
|
|
1333
|
+
- *summary = return the fields defined for giving a summary
|
|
1334
|
+
- *detail = details
|
|
1335
|
+
- displayName
|
|
1336
|
+
- groupType
|
|
1337
|
+
- id
|
|
1338
|
+
- loadFactor
|
|
1339
|
+
- name
|
|
1340
|
+
- organization
|
|
1341
|
+
- parent
|
|
1342
|
+
- securityZone
|
|
1343
|
+
- supervisor
|
|
1344
|
+
filters (list | None, optional):
|
|
1345
|
+
List of dictionaries with three keys each:
|
|
1346
|
+
- "attribute" - name of the attribute to use for the filter (available attributes see above)
|
|
1347
|
+
- "op" - operator:
|
|
1348
|
+
* eq - equal
|
|
1349
|
+
* ne - not equal
|
|
1350
|
+
* lt - less than - also usable for dates (before)
|
|
1351
|
+
* gt - greater than - also usable for dates (after)
|
|
1352
|
+
* le - less or equal
|
|
1353
|
+
* ge - greater or equal
|
|
1354
|
+
* in - is in list
|
|
1355
|
+
* ni - is NOT in list
|
|
1356
|
+
* sw - starts with
|
|
1357
|
+
* cn - contains
|
|
1358
|
+
- "value": the value to filter for. Either literal or list of values
|
|
1359
|
+
page_size (int, optional):
|
|
1360
|
+
The maximum number of groups to return.
|
|
1361
|
+
next_page_url (str, optional):
|
|
1362
|
+
The Guidewire URL to retrieve the next page of Guidewire groups (pagination).
|
|
1363
|
+
This is used for the iterator get_groups_iterator() below.
|
|
1364
|
+
|
|
1365
|
+
Returns:
|
|
1366
|
+
dict | None:
|
|
1367
|
+
JSON response containing claim data.
|
|
1368
|
+
|
|
1369
|
+
"""
|
|
1370
|
+
|
|
1371
|
+
if not next_page_url:
|
|
1372
|
+
request_url = self.config()["policyUrl"] + "/policies"
|
|
1373
|
+
|
|
1374
|
+
encoded_query = self.process_parameters(fields=fields, filters=filters, page_size=page_size)
|
|
1375
|
+
if encoded_query:
|
|
1376
|
+
request_url += "?" + encoded_query
|
|
1377
|
+
else:
|
|
1378
|
+
request_url = self.config()["restUrl"] + next_page_url
|
|
1379
|
+
|
|
1380
|
+
return self.do_request(method="GET", url=request_url)
|
|
1381
|
+
|
|
1382
|
+
# end method definition
|
|
1383
|
+
|
|
1384
|
+
def get_policies_iterator(
|
|
1385
|
+
self, fields: list | None = None, filters: list | None = None, page_size: int = 25
|
|
1386
|
+
) -> iter:
|
|
1387
|
+
"""Get an iterator object that can be used to traverse all Guidewire policies.
|
|
1388
|
+
|
|
1389
|
+
Returning a generator avoids loading a large number of nodes into memory at once. Instead you
|
|
1390
|
+
can iterate over the potential large list of groups.
|
|
1391
|
+
|
|
1392
|
+
Example usage:
|
|
1393
|
+
policies = guidewire_object.get_policies_iterator()
|
|
1394
|
+
for policy in policies:
|
|
1395
|
+
logger.info("Traversing Guidewire policy -> '%s'...", policy.get("attributes", {}).get("displayName"))
|
|
1396
|
+
|
|
1397
|
+
Args:
|
|
1398
|
+
fields (list | None, optional):
|
|
1399
|
+
The list of fields in the results. If None, all default
|
|
1400
|
+
fields are returned.
|
|
1401
|
+
Fields for Guidewire accounts:
|
|
1402
|
+
- *all = return all fields
|
|
1403
|
+
- *default = return just the default list of fields
|
|
1404
|
+
- *summary = return the fields defined for giving a summary
|
|
1405
|
+
- *detail = details
|
|
1406
|
+
- displayName
|
|
1407
|
+
- groupType
|
|
1408
|
+
- id
|
|
1409
|
+
- loadFactor
|
|
1410
|
+
- name
|
|
1411
|
+
- organization
|
|
1412
|
+
- parent
|
|
1413
|
+
- securityZone
|
|
1414
|
+
- supervisor
|
|
1415
|
+
filters (list | None, optional):
|
|
1416
|
+
List of dictionaries with three keys each:
|
|
1417
|
+
- "attribute" - name of the attribute to use for the filter (available attributes see above)
|
|
1418
|
+
- "op" - operator:
|
|
1419
|
+
* eq - equal
|
|
1420
|
+
* ne - not equal
|
|
1421
|
+
* lt - less than - also usable for dates (before)
|
|
1422
|
+
* gt - greater than - also usable for dates (after)
|
|
1423
|
+
* le - less or equal
|
|
1424
|
+
* ge - greater or equal
|
|
1425
|
+
* in - is in list
|
|
1426
|
+
* ni - is NOT in list
|
|
1427
|
+
* sw - starts with
|
|
1428
|
+
* cn - contains
|
|
1429
|
+
- "value": the value to filter for. Either literal or list of values
|
|
1430
|
+
page_size (int, optional):
|
|
1431
|
+
The maximum number of policies to return.
|
|
1432
|
+
|
|
1433
|
+
Returns:
|
|
1434
|
+
iter:
|
|
1435
|
+
A generator yielding one Guidewire account per iteration.
|
|
1436
|
+
If the REST API fails, returns no value.
|
|
1437
|
+
|
|
1438
|
+
"""
|
|
1439
|
+
|
|
1440
|
+
next_page_url = None
|
|
1441
|
+
|
|
1442
|
+
while True:
|
|
1443
|
+
response = self.get_policies(
|
|
1444
|
+
fields=fields, filters=filters, page_size=page_size, next_page_url=next_page_url
|
|
1445
|
+
)
|
|
1446
|
+
if not response or "data" not in response:
|
|
1447
|
+
# Don't return None! Plain return is what we need for iterators.
|
|
1448
|
+
# Natural Termination: If the generator does not yield, it behaves
|
|
1449
|
+
# like an empty iterable when used in a loop or converted to a list:
|
|
1450
|
+
return
|
|
1451
|
+
|
|
1452
|
+
# Yield users one at a time:
|
|
1453
|
+
yield from response["data"]
|
|
1454
|
+
|
|
1455
|
+
# See if we have an additional result page.
|
|
1456
|
+
# If not terminate the iterator and return
|
|
1457
|
+
# no value.
|
|
1458
|
+
next_page_url = response.get("links", {}).get("next", {}).get("href")
|
|
1459
|
+
if not next_page_url:
|
|
1460
|
+
# Don't return None! Plain return is what we need for iterators.
|
|
1461
|
+
# Natural Termination: If the generator does not yield, it behaves
|
|
1462
|
+
# like an empty iterable when used in a loop or converted to a list:
|
|
1463
|
+
return
|
|
1464
|
+
|
|
1465
|
+
# end method definition
|
|
1466
|
+
|
|
1467
|
+
def search_policy(self, attributes: dict) -> dict:
|
|
1468
|
+
"""Search a specific policy based on its attributes.
|
|
1469
|
+
|
|
1470
|
+
See: https://docs.guidewire.com/cloud/pc/202407/apiref/generated/Policy%20API/search-policies--post
|
|
1471
|
+
|
|
1472
|
+
Args:
|
|
1473
|
+
attributes (dict):
|
|
1474
|
+
The attribute to search the value in. Possible key values:
|
|
1475
|
+
* "policyNumber" (str)
|
|
1476
|
+
* "city" (str)
|
|
1477
|
+
* "state" (dict with keys "code", "name"), e.g. {"code": "GA", "name": "Georgia"}
|
|
1478
|
+
* "country" (str)
|
|
1479
|
+
* "postalCode" (str)
|
|
1480
|
+
* "street" (str)
|
|
1481
|
+
* "companyName" (str)
|
|
1482
|
+
* "firstName" (str)
|
|
1483
|
+
* "lastName" (str)
|
|
1484
|
+
* "officialId" (str)
|
|
1485
|
+
|
|
1486
|
+
Returns:
|
|
1487
|
+
dict:
|
|
1488
|
+
JSON response containing account details.
|
|
1489
|
+
|
|
1490
|
+
Example:
|
|
1491
|
+
{
|
|
1492
|
+
'count': 1,
|
|
1493
|
+
'data': [
|
|
1494
|
+
{
|
|
1495
|
+
'attributes': {
|
|
1496
|
+
'accountNumber': 'C000212105',
|
|
1497
|
+
'effectiveDate': '2025-07-14T04:01:00.000Z',
|
|
1498
|
+
'expirationDate': '2026-07-14T04:01:00.000Z',
|
|
1499
|
+
'insuredName': 'Armstrong and Company',
|
|
1500
|
+
'policyAddress': '142 Central Ave, Metter, GA 30439',
|
|
1501
|
+
'policyId': 'pc:Sn09Itxh7Btpc8izhUrtc',
|
|
1502
|
+
'policyNumber': '5050680845',
|
|
1503
|
+
'producerOfRecordName': 'Armstrong and Company',
|
|
1504
|
+
'producerOfServiceName': 'Armstrong and Company',
|
|
1505
|
+
'product': {
|
|
1506
|
+
'displayName': 'Manual Products',
|
|
1507
|
+
'id': 'Manual'
|
|
1508
|
+
}
|
|
1509
|
+
},
|
|
1510
|
+
'links': {...}
|
|
1511
|
+
}
|
|
1512
|
+
],
|
|
1513
|
+
'links': {
|
|
1514
|
+
'first': {'href': '/policy/v1/search/policies', 'methods': ['post']},
|
|
1515
|
+
'self': {'href': '/policy/v1/search/policies', 'methods': ['post']}
|
|
1516
|
+
}
|
|
1517
|
+
}
|
|
1518
|
+
|
|
1519
|
+
"""
|
|
1520
|
+
|
|
1521
|
+
body = {"data": {"attributes": attributes}}
|
|
1522
|
+
|
|
1523
|
+
request_url = self.config()["policySearchUrl"]
|
|
1524
|
+
|
|
1525
|
+
return self.do_request(method="POST", json_data=body, url=request_url)
|
|
1526
|
+
|
|
1527
|
+
# end method definition
|
|
1528
|
+
|
|
1137
1529
|
def get_claims(
|
|
1138
1530
|
self,
|
|
1139
1531
|
fields: list | None = None,
|
|
@@ -1299,6 +1691,28 @@ class Guidewire:
|
|
|
1299
1691
|
|
|
1300
1692
|
# end method definition
|
|
1301
1693
|
|
|
1694
|
+
def search_claim(self, attributes: dict) -> dict:
|
|
1695
|
+
"""Search a specific claim based on its attributes.
|
|
1696
|
+
|
|
1697
|
+
Args:
|
|
1698
|
+
attributes (dict):
|
|
1699
|
+
The attribute to search the value in. Possible key values:
|
|
1700
|
+
* TBD
|
|
1701
|
+
|
|
1702
|
+
Returns:
|
|
1703
|
+
dict:
|
|
1704
|
+
JSON response containing account details.
|
|
1705
|
+
|
|
1706
|
+
"""
|
|
1707
|
+
|
|
1708
|
+
body = {"data": {"attributes": attributes}}
|
|
1709
|
+
|
|
1710
|
+
request_url = self.config()["claimSearchUrl"]
|
|
1711
|
+
|
|
1712
|
+
return self.do_request(method="POST", json_data=body, url=request_url)
|
|
1713
|
+
|
|
1714
|
+
# end method definition
|
|
1715
|
+
|
|
1302
1716
|
def add_claim(self, claim_data: dict) -> dict:
|
|
1303
1717
|
"""Create a new claim.
|
|
1304
1718
|
|
pyxecm_customizer/k8s.py
CHANGED
|
@@ -205,7 +205,7 @@ class K8s:
|
|
|
205
205
|
self.logger.debug("Pod -> '%s' not found (may be deleted).", pod_name)
|
|
206
206
|
return None
|
|
207
207
|
else:
|
|
208
|
-
self.logger.error("Failed to get
|
|
208
|
+
self.logger.error("Failed to get pod -> '%s'!", pod_name)
|
|
209
209
|
return None # Unexpected error, return None
|
|
210
210
|
return response
|
|
211
211
|
|
|
@@ -306,8 +306,9 @@ class K8s:
|
|
|
306
306
|
|
|
307
307
|
except ApiException:
|
|
308
308
|
self.logger.error(
|
|
309
|
-
"Failed to wait for pod -> '%s'",
|
|
309
|
+
"Failed to wait for pod -> '%s' to reach state -> '%s'.",
|
|
310
310
|
pod_name,
|
|
311
|
+
condition_name,
|
|
311
312
|
)
|
|
312
313
|
|
|
313
314
|
# end method definition
|
|
@@ -320,7 +321,7 @@ class K8s:
|
|
|
320
321
|
time_retry: int = 10,
|
|
321
322
|
container: str | None = None,
|
|
322
323
|
timeout: int = 60,
|
|
323
|
-
) -> str:
|
|
324
|
+
) -> str | None:
|
|
324
325
|
"""Execute a command inside a Kubernetes Pod (similar to kubectl exec on command line).
|
|
325
326
|
|
|
326
327
|
See: https://github.com/kubernetes-client/python/blob/master/kubernetes/docs/CoreV1Api.md#connect_get_namespaced_pod_exec
|
|
@@ -342,14 +343,15 @@ class K8s:
|
|
|
342
343
|
Each time a response is found in stdout or stderr we wait another timeout duration [60]
|
|
343
344
|
|
|
344
345
|
Returns:
|
|
345
|
-
str:
|
|
346
|
+
str | None:
|
|
346
347
|
Response of the command or None if the call fails.
|
|
347
348
|
|
|
348
349
|
"""
|
|
349
350
|
|
|
350
351
|
pod = self.get_pod(pod_name=pod_name)
|
|
351
352
|
if not pod:
|
|
352
|
-
self.logger.error("Pod -> '%s' does not exist", pod_name)
|
|
353
|
+
self.logger.error("Pod -> '%s' does not exist. Cannot execute command -> %s", pod_name, command)
|
|
354
|
+
return None
|
|
353
355
|
|
|
354
356
|
self.logger.debug("Execute command -> %s in pod -> '%s'", command, pod_name)
|
|
355
357
|
|
|
@@ -391,10 +393,10 @@ class K8s:
|
|
|
391
393
|
return response
|
|
392
394
|
|
|
393
395
|
self.logger.error(
|
|
394
|
-
"Failed to execute command
|
|
395
|
-
max_retry,
|
|
396
|
+
"Failed to execute command -> %s in pod -> '%s' after %d retries; error -> %s",
|
|
396
397
|
command,
|
|
397
398
|
pod_name,
|
|
399
|
+
max_retry,
|
|
398
400
|
str(exception),
|
|
399
401
|
)
|
|
400
402
|
|
|
@@ -409,7 +411,7 @@ class K8s:
|
|
|
409
411
|
commands: list,
|
|
410
412
|
timeout: int = 30,
|
|
411
413
|
write_stderr_to_error_log: bool = True,
|
|
412
|
-
) -> str:
|
|
414
|
+
) -> str | None:
|
|
413
415
|
"""Execute a command inside a Kubernetes pod (similar to kubectl exec on command line).
|
|
414
416
|
|
|
415
417
|
Other than exec_pod_command() method above this is an interactive execution using
|
|
@@ -432,19 +434,20 @@ class K8s:
|
|
|
432
434
|
Default is write to error log (True).
|
|
433
435
|
|
|
434
436
|
Returns:
|
|
435
|
-
str:
|
|
437
|
+
str | None:
|
|
436
438
|
Response of the command or None if the call fails.
|
|
437
439
|
|
|
438
440
|
"""
|
|
439
441
|
|
|
440
|
-
pod = self.get_pod(pod_name=pod_name)
|
|
441
|
-
if not pod:
|
|
442
|
-
self.logger.error("Pod -> '%s' does not exist", pod_name)
|
|
443
|
-
|
|
444
442
|
if not commands:
|
|
445
443
|
self.logger.error("No commands to execute on pod ->'%s'!", pod_name)
|
|
446
444
|
return None
|
|
447
445
|
|
|
446
|
+
pod = self.get_pod(pod_name=pod_name)
|
|
447
|
+
if not pod:
|
|
448
|
+
self.logger.error("Pod -> '%s' does not exist. Cannot execute commands -> %s", pod_name, commands)
|
|
449
|
+
return None
|
|
450
|
+
|
|
448
451
|
# Get first command - this should be the shell:
|
|
449
452
|
command = commands.pop(0)
|
|
450
453
|
|
|
@@ -499,7 +502,7 @@ class K8s:
|
|
|
499
502
|
|
|
500
503
|
# end method definition
|
|
501
504
|
|
|
502
|
-
def delete_pod(self, pod_name: str) -> None:
|
|
505
|
+
def delete_pod(self, pod_name: str) -> V1Pod | None:
|
|
503
506
|
"""Delete a pod in the configured namespace (the namespace is defined in the class constructor).
|
|
504
507
|
|
|
505
508
|
See: https://github.com/kubernetes-client/python/blob/master/kubernetes/docs/CoreV1Api.md#delete_namespaced_pod
|
|
@@ -509,21 +512,14 @@ class K8s:
|
|
|
509
512
|
The name of the Kubernetes pod in the current namespace.
|
|
510
513
|
|
|
511
514
|
Returns:
|
|
512
|
-
|
|
513
|
-
- api_version: The Kubernetes API version.
|
|
514
|
-
- kind: The Kubernetes object kind, which is always "Status".
|
|
515
|
-
- metadata: Additional metadata about the status object, such as the resource version.
|
|
516
|
-
- status: The status of the operation, which is either "Success" or an error status.
|
|
517
|
-
- message: A human-readable message explaining the status.
|
|
518
|
-
- reason: A short string that describes the reason for the status.
|
|
519
|
-
- code: An HTTP status code that corresponds to the status.
|
|
520
|
-
See: https://github.com/kubernetes-client/python/blob/master/kubernetes/docs/V1Status.md
|
|
515
|
+
V1Pod (object) or None if the call fails.
|
|
521
516
|
|
|
522
517
|
"""
|
|
523
518
|
|
|
524
519
|
pod = self.get_pod(pod_name=pod_name)
|
|
525
520
|
if not pod:
|
|
526
|
-
self.logger.error("Pod -> '%s' does not exist!", pod_name)
|
|
521
|
+
self.logger.error("Pod -> '%s' does not exist! Cannot delete it.", pod_name)
|
|
522
|
+
return None
|
|
527
523
|
|
|
528
524
|
try:
|
|
529
525
|
response = self.get_core_v1_api().delete_namespaced_pod(
|
|
@@ -1105,7 +1101,7 @@ class K8s:
|
|
|
1105
1101
|
rule_index += 1
|
|
1106
1102
|
|
|
1107
1103
|
if not host:
|
|
1108
|
-
self.logger.error("Cannot find host
|
|
1104
|
+
self.logger.error("Cannot find host to upgrade the Kubernetes Ingress -> '%s'", ingress_name)
|
|
1109
1105
|
return None
|
|
1110
1106
|
|
|
1111
1107
|
body = [
|
|
@@ -1351,7 +1347,7 @@ class K8s:
|
|
|
1351
1347
|
body,
|
|
1352
1348
|
pretty="true",
|
|
1353
1349
|
)
|
|
1354
|
-
self.logger.
|
|
1350
|
+
self.logger.debug("Triggered restart of deployment -> '%s'.", deployment_name)
|
|
1355
1351
|
|
|
1356
1352
|
except ApiException as api_exception:
|
|
1357
1353
|
self.logger.error(
|
|
@@ -1484,7 +1480,7 @@ class K8s:
|
|
|
1484
1480
|
|
|
1485
1481
|
try:
|
|
1486
1482
|
self.get_apps_v1_api().patch_namespaced_stateful_set(sts_name, self.get_namespace(), body, pretty="true")
|
|
1487
|
-
self.logger.
|
|
1483
|
+
self.logger.debug("Triggered restart of stateful set -> '%s'.", sts_name)
|
|
1488
1484
|
|
|
1489
1485
|
except ApiException as api_exception:
|
|
1490
1486
|
self.logger.error("Failed to restart stateful set -> '%s'; error -> %s!", sts_name, str(api_exception))
|