pyxecm 2.0.0__py3-none-any.whl → 2.0.2__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.

Files changed (50) hide show
  1. pyxecm/__init__.py +2 -1
  2. pyxecm/avts.py +79 -33
  3. pyxecm/customizer/api/app.py +45 -796
  4. pyxecm/customizer/api/auth/__init__.py +1 -0
  5. pyxecm/customizer/api/{auth.py → auth/functions.py} +2 -64
  6. pyxecm/customizer/api/auth/router.py +78 -0
  7. pyxecm/customizer/api/common/__init__.py +1 -0
  8. pyxecm/customizer/api/common/functions.py +47 -0
  9. pyxecm/customizer/api/{metrics.py → common/metrics.py} +1 -1
  10. pyxecm/customizer/api/common/models.py +21 -0
  11. pyxecm/customizer/api/{payload_list.py → common/payload_list.py} +6 -1
  12. pyxecm/customizer/api/common/router.py +72 -0
  13. pyxecm/customizer/api/settings.py +25 -0
  14. pyxecm/customizer/api/terminal/__init__.py +1 -0
  15. pyxecm/customizer/api/terminal/router.py +87 -0
  16. pyxecm/customizer/api/v1_csai/__init__.py +1 -0
  17. pyxecm/customizer/api/v1_csai/router.py +87 -0
  18. pyxecm/customizer/api/v1_maintenance/__init__.py +1 -0
  19. pyxecm/customizer/api/v1_maintenance/functions.py +100 -0
  20. pyxecm/customizer/api/v1_maintenance/models.py +12 -0
  21. pyxecm/customizer/api/v1_maintenance/router.py +76 -0
  22. pyxecm/customizer/api/v1_otcs/__init__.py +1 -0
  23. pyxecm/customizer/api/v1_otcs/functions.py +61 -0
  24. pyxecm/customizer/api/v1_otcs/router.py +179 -0
  25. pyxecm/customizer/api/v1_payload/__init__.py +1 -0
  26. pyxecm/customizer/api/v1_payload/functions.py +179 -0
  27. pyxecm/customizer/api/v1_payload/models.py +51 -0
  28. pyxecm/customizer/api/v1_payload/router.py +499 -0
  29. pyxecm/customizer/browser_automation.py +567 -324
  30. pyxecm/customizer/customizer.py +204 -430
  31. pyxecm/customizer/guidewire.py +907 -43
  32. pyxecm/customizer/k8s.py +243 -56
  33. pyxecm/customizer/m365.py +104 -15
  34. pyxecm/customizer/payload.py +1943 -885
  35. pyxecm/customizer/pht.py +19 -2
  36. pyxecm/customizer/servicenow.py +22 -5
  37. pyxecm/customizer/settings.py +9 -6
  38. pyxecm/helper/xml.py +69 -0
  39. pyxecm/otac.py +1 -1
  40. pyxecm/otawp.py +2104 -1535
  41. pyxecm/otca.py +569 -0
  42. pyxecm/otcs.py +202 -38
  43. pyxecm/otds.py +35 -13
  44. {pyxecm-2.0.0.dist-info → pyxecm-2.0.2.dist-info}/METADATA +6 -32
  45. pyxecm-2.0.2.dist-info/RECORD +76 -0
  46. {pyxecm-2.0.0.dist-info → pyxecm-2.0.2.dist-info}/WHEEL +1 -1
  47. pyxecm-2.0.0.dist-info/RECORD +0 -54
  48. /pyxecm/customizer/api/{models.py → auth/models.py} +0 -0
  49. {pyxecm-2.0.0.dist-info → pyxecm-2.0.2.dist-info}/licenses/LICENSE +0 -0
  50. {pyxecm-2.0.0.dist-info → pyxecm-2.0.2.dist-info}/top_level.txt +0 -0
@@ -10,34 +10,56 @@ __maintainer__ = "Dr. Marc Diefenbruch"
10
10
  __email__ = "mdiefenb@opentext.com"
11
11
 
12
12
  import logging
13
+ import platform
14
+ import sys
15
+ import urllib.parse
16
+ from importlib.metadata import version
13
17
 
14
18
  import requests
19
+ from requests.auth import HTTPBasicAuth
15
20
 
16
- default_logger = logging.getLogger("pyxecm.customizer.guidewire")
21
+ APP_NAME = "pyxecm"
22
+ APP_VERSION = version("pyxecm")
23
+ MODULE_NAME = APP_NAME + ".customizer.guidewire"
24
+
25
+ PYTHON_VERSION = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
26
+ OS_INFO = f"{platform.system()} {platform.release()}"
27
+ ARCH_INFO = platform.machine()
28
+ REQUESTS_VERSION = requests.__version__
29
+
30
+ USER_AGENT = (
31
+ f"{APP_NAME}/{APP_VERSION} ({MODULE_NAME}/{APP_VERSION}; "
32
+ f"Python/{PYTHON_VERSION}; {OS_INFO}; {ARCH_INFO}; Requests/{REQUESTS_VERSION})"
33
+ )
34
+
35
+ default_logger = logging.getLogger(MODULE_NAME)
17
36
 
18
37
 
19
38
  class Guidewire:
20
39
  """Class Guidewire is used to retrieve and automate stettings and objects in Guidewire."""
21
40
 
22
- logger: logging.Logger = default_logger
23
41
  _config: dict
24
42
  _scope = None
25
- _token = None
43
+ _access_token = None
26
44
 
27
45
  def __init__(
28
46
  self,
29
47
  base_url: str,
48
+ auth_type: str,
30
49
  client_id: str = "",
31
50
  client_secret: str = "",
32
51
  username: str = "",
33
52
  password: str = "",
34
53
  scope: str = "",
54
+ logger: logging.Logger = default_logger,
35
55
  ) -> None:
36
56
  """Initialize the Guidewire API client.
37
57
 
38
58
  Args:
39
59
  base_url (str):
40
60
  The base URL of the Guidewire Cloud API.
61
+ auth_type (str):
62
+ The authorization type, either "oauth" or "basic".
41
63
  client_id (str):
42
64
  The Client ID for authentication (optional, required for client credential flow).
43
65
  client_secret (str):
@@ -48,24 +70,37 @@ class Guidewire:
48
70
  The password for authentication (optional, required for password-based authentication).
49
71
  scope (str):
50
72
  The OAuth2 scope (optional).
73
+ logger:
74
+ The logging object used for all log messages. Default is default_logger.
51
75
 
52
76
  """
53
77
 
78
+ if logger != default_logger:
79
+ self.logger = logger.getChild("guidewire")
80
+ for logfilter in logger.filters:
81
+ self.logger.addFilter(logfilter)
82
+
54
83
  self._scope = scope
55
- self._token = None
56
84
 
57
85
  guidewire_config = {}
58
86
  # Store the credentials and parameters in a config dictionary:
87
+ guidewire_config["baseUrl"] = base_url.rstrip("/")
88
+ guidewire_config["authType"] = auth_type
59
89
  guidewire_config["clientId"] = client_id
60
90
  guidewire_config["clientSecret"] = client_secret
61
91
  guidewire_config["username"] = username
62
92
  guidewire_config["password"] = password
63
- guidewire_config["baseUrl"] = base_url.rstrip("/")
64
- guidewire_config["cloudAPIUrl"] = guidewire_config["baseUrl"] + "/api/v1"
65
- guidewire_config["tokenUrl"] = guidewire_config["cloudAPIUrl"] + "/oauth2/token"
93
+ guidewire_config["restUrl"] = guidewire_config["baseUrl"] + "/rest" # "/api/v1"
94
+ guidewire_config["tokenUrl"] = guidewire_config["restUrl"] + "/oauth2/token"
95
+
96
+ guidewire_config["adminUrl"] = guidewire_config["restUrl"] + "/admin/v1"
97
+ guidewire_config["claimUrl"] = guidewire_config["restUrl"] + "/claim/v1"
98
+ guidewire_config["accountUrl"] = guidewire_config["restUrl"] + "/account/v1"
66
99
 
67
100
  self._config = guidewire_config
68
101
 
102
+ self._session = requests.Session()
103
+
69
104
  # end method definition
70
105
 
71
106
  def config(self) -> dict:
@@ -81,15 +116,29 @@ class Guidewire:
81
116
 
82
117
  # end method definition
83
118
 
84
- def authenticate(self) -> bool:
119
+ def authenticate(self, auth_type: str) -> HTTPBasicAuth | str | None:
85
120
  """Authenticate with the Guidewire API using either client credentials or username/password.
86
121
 
122
+ Args:
123
+ auth_type (str):
124
+ The Authorization type. This can be "basic" or "oauth".
125
+
87
126
  Returns:
88
127
  bool:
89
128
  True if authentication is successful, False otherwise.
90
129
 
91
130
  """
92
131
 
132
+ self._session.headers.update(self.request_header())
133
+
134
+ if auth_type == "basic":
135
+ username = self.config()["username"]
136
+ password = self.config()["password"]
137
+ if not self._session:
138
+ self._session = requests.Session()
139
+ self._session.auth = HTTPBasicAuth(username, password)
140
+ return self._session.auth
141
+
93
142
  request_url = self.config()["tokenUrl"]
94
143
 
95
144
  if self.config()["clientId"] and self.config()["clientSecret"]:
@@ -122,33 +171,42 @@ class Guidewire:
122
171
 
123
172
  # end method definition
124
173
 
125
- def request_headers(self) -> dict:
174
+ def request_header(self, content_type: str = "application/json") -> dict:
126
175
  """Generate request headers including authentication token.
127
176
 
177
+ Args:
178
+ content_type (str, optional):
179
+ Custom content type for the request.
180
+ Typical value for Guidewire is application/json.
181
+
128
182
  Returns:
129
183
  dict:
130
184
  A dictionary containing authorization headers.
131
185
 
132
186
  """
133
187
 
134
- if not self._token:
135
- self.logger.error("Authentication required. Call authenticate() first.")
136
- return None
137
-
138
- return {
139
- "Authorization": "Bearer {}".format(self._token),
140
- "Content-Type": "application/json",
188
+ request_header = {
189
+ "User-Agent": USER_AGENT,
190
+ "Content-Type": content_type,
141
191
  }
142
192
 
193
+ if self.config()["authType"] == "oauth":
194
+ if not self._access_token:
195
+ self.logger.error("Authentication required. Call authenticate() first.")
196
+ return None
197
+ request_header["Authorization"] = ("Bearer {}".format(self._access_token),)
198
+
199
+ return request_header
200
+
143
201
  # end method definition
144
202
 
145
- def do_request(self, method: str, endpoint: str, data: dict | None = None, params: dict | None = None) -> dict:
203
+ def do_request(self, method: str, url: str, data: dict | None = None, params: dict | None = None) -> dict:
146
204
  """Send a request to the Guidewire REST API.
147
205
 
148
206
  Args:
149
207
  method (str):
150
208
  The HTTP method to use (GET, POST, PUT, DELETE).
151
- endpoint (str):
209
+ url (str):
152
210
  The API endpoint to call.
153
211
  data (dict):
154
212
  The request payload (if applicable).
@@ -161,22 +219,706 @@ class Guidewire:
161
219
 
162
220
  """
163
221
 
164
- request_url = "{}{}".format(self.base_url, endpoint)
165
- response = requests.request(method, request_url, headers=self._headers(), json=data, params=params)
222
+ response = self._session.request(
223
+ method=method, url=url, headers=self.request_header(), data=data, params=params
224
+ )
166
225
 
167
226
  return response.json() if response.content else {}
168
227
 
169
228
  # end method definition
170
229
 
171
- def get_accounts(self) -> dict:
230
+ def process_parameters(
231
+ self, fields: list | None = None, filters: list | None = None, page_size: int | None = 25
232
+ ) -> str | None:
233
+ """Determine the request parameters (filters, fields).
234
+
235
+ Args:
236
+ fields (list | None, optional):
237
+ List of filter values. Defaults to None.
238
+ filters (list | None, optional):
239
+ List of filter values. Defaults to None.
240
+ page_size (int, optional):
241
+ The maximum number of groups to return.
242
+
243
+ Returns:
244
+ str | None:
245
+ Encoded URL parameters for the request URL.
246
+
247
+ """
248
+
249
+ query = {}
250
+
251
+ if fields:
252
+ fields = ",".join(fields)
253
+ query["fields"] = fields
254
+
255
+ for filter_dict in filters or []:
256
+ if "op" not in filter_dict:
257
+ filter_dict["op"] = "eq"
258
+ if "attribute" not in filter_dict:
259
+ self.logger.error("Missing attribute in filter condition!")
260
+ return None
261
+ if "value" not in filter_dict:
262
+ self.logger.error("Missing value(s) in filter condition!")
263
+ return None
264
+ elif isinstance(filter_dict["value"], list):
265
+ filter_dict["value"] = ",".join(filter_dict["value"])
266
+ query["filter"] = (
267
+ filter_dict.get("attribute") + ":" + filter_dict.get("op") + ":" + filter_dict.get("value")
268
+ )
269
+
270
+ if page_size:
271
+ query["pageSize"] = page_size
272
+
273
+ encoded_query = urllib.parse.urlencode(query=query, doseq=True)
274
+
275
+ return encoded_query
276
+
277
+ # end method definition
278
+
279
+ def get_groups(
280
+ self,
281
+ fields: list | None = None,
282
+ filters: list | None = None,
283
+ page_size: int = 25,
284
+ next_page_url: str | None = None,
285
+ ) -> dict:
286
+ """Retrieve a list of Guidewire groups.
287
+
288
+ Args:
289
+ fields (list):
290
+ The list of fields in the results. If None, all default
291
+ fields are returned.
292
+ Fields for Guidewire accounts:
293
+ - *all = return all fields
294
+ - *default = return just the default list of fields
295
+ - *summary = return the fields defined for giving a summary
296
+ - *detail = details
297
+ - displayName
298
+ - groupType
299
+ - id
300
+ - loadFactor
301
+ - name
302
+ - organization
303
+ - parent
304
+ - securityZone
305
+ - supervisor
306
+ filters (list):
307
+ List of dictionaries with three keys each:
308
+ - "attribute" - name of the attribute to use for the filter (available attributes see above)
309
+ - "op" - operator:
310
+ * eq - equal
311
+ * ne - not equal
312
+ * lt - less than - also usable for dates (before)
313
+ * gt - greater than - also usable for dates (after)
314
+ * le - less or equal
315
+ * ge - greater or equal
316
+ * in - is in list
317
+ * ni - is NOT in list
318
+ * sw - starts with
319
+ * cn - contains
320
+ - "value": the value to filter for. Either literal or list of values
321
+ page_size (int, optional):
322
+ The maximum number of groups to return.
323
+ next_page_url (str, optional):
324
+ The Guidewire URL to retrieve the next page of Guidewire groups (pagination).
325
+ This is used for the iterator get_groups_iterator() below.
326
+
327
+ Returns:
328
+ dict:
329
+ JSON response containing account data. None in case of an error.
330
+
331
+ Example reponse:
332
+ {
333
+ 'count': 25,
334
+ 'data': [
335
+ {
336
+ 'attributes': {
337
+ 'displayName': 'Actuary Unit',
338
+ 'groupType': {...},
339
+ 'id': 'pc:S_I-NOU3hb3FU0qTfu8fd',
340
+ 'loadFactor': 100,
341
+ 'name': 'Actuary Unit',
342
+ 'organization': {...},
343
+ 'parent': {...},
344
+ 'securityZone': {...},
345
+ 'supervisor': {...}
346
+ },
347
+ 'checksum': '0',
348
+ 'links': {
349
+ 'self': {...}
350
+ }
351
+ },
352
+ ...
353
+ ],
354
+ 'links': {
355
+ 'first': {
356
+ 'href': '/admin/v1/groups?fields=%2Adefault',
357
+ 'methods': ['get']
358
+ },
359
+ 'next': {
360
+ 'href': '/admin/v1/groups?fields=%2Adefault&pageOffset=25',
361
+ 'methods': ['get']
362
+ },
363
+ 'self': {...}
364
+ }
365
+ }
366
+
367
+ """
368
+
369
+ if not next_page_url:
370
+ request_url = self.config()["adminUrl"] + "/groups"
371
+
372
+ encoded_query = self.process_parameters(fields=fields, filters=filters, page_size=page_size)
373
+ if encoded_query:
374
+ request_url += "?" + encoded_query
375
+ else:
376
+ request_url = self.config()["restUrl"] + next_page_url
377
+
378
+ return self.do_request(method="GET", url=request_url)
379
+
380
+ # end method definition
381
+
382
+ def get_groups_iterator(self, fields: list | None = None, filters: list | None = None, page_size: int = 25) -> iter:
383
+ """Get an iterator object that can be used to traverse all Guidewire groups.
384
+
385
+ Returning a generator avoids loading a large number of nodes into memory at once. Instead you
386
+ can iterate over the potential large list of groups.
387
+
388
+ Example usage:
389
+ groups = guidewire_object.get_groups_iterator()
390
+ for group in groups:
391
+ logger.info("Traversing Guidewire group -> '%s'...", group.get("attributes", {}).get("displayName"))
392
+
393
+ Returns:
394
+ iter:
395
+ A generator yielding one Guidewire group per iteration.
396
+ If the REST API fails, returns no value.
397
+
398
+ """
399
+
400
+ next_page_url = None
401
+
402
+ while True:
403
+ response = self.get_groups(fields=fields, filters=filters, page_size=page_size, next_page_url=next_page_url)
404
+ if not response or "data" not in response:
405
+ # Don't return None! Plain return is what we need for iterators.
406
+ # Natural Termination: If the generator does not yield, it behaves
407
+ # like an empty iterable when used in a loop or converted to a list:
408
+ return
409
+
410
+ # Yield users one at a time:
411
+ yield from response["data"]
412
+
413
+ # See if we have an additional result page.
414
+ # If not terminate the iterator and return
415
+ # no value.
416
+ next_page_url = response.get("links", {}).get("next", {}).get("href")
417
+ if not next_page_url:
418
+ # Don't return None! Plain return is what we need for iterators.
419
+ # Natural Termination: If the generator does not yield, it behaves
420
+ # like an empty iterable when used in a loop or converted to a list:
421
+ return
422
+
423
+ # end method definition
424
+
425
+ def get_group(self, group_id: str) -> dict:
426
+ """Retrieve details of a specific group.
427
+
428
+ Args:
429
+ group_id: The unique identifier of the group.
430
+
431
+ Returns:
432
+ dict: JSON response containing group details.
433
+
434
+ Example response;
435
+ {
436
+ 'data': {
437
+ 'attributes': {
438
+ 'displayName': 'Actuary Unit',
439
+ 'groupType': {
440
+ 'code': 'actuary',
441
+ 'name': 'Actuary unit'
442
+ },
443
+ 'id': 'pc:S_I-NOU3hb3FU0qTfu8fd',
444
+ 'loadFactor': 100,
445
+ 'name': 'Actuary Unit',
446
+ 'organization': {
447
+ 'displayName': 'Enigma Fire & Casualty',
448
+ 'id': 'systemTables:1',
449
+ 'type': 'Organization',
450
+ 'uri': '/admin/v1/organizations/systemTables:1'
451
+ },
452
+ 'parent': {
453
+ 'displayName': 'Enigma Fire & Casualty',
454
+ 'id': 'systemTables:1',
455
+ 'type': 'Group',
456
+ 'uri': '/admin/v1/groups/systemTables:1'
457
+ },
458
+ 'securityZone': {
459
+ 'displayName': 'HO UW',
460
+ 'id': 'pc:So-lJXKuecOco_hGZ_8iR'
461
+ },
462
+ 'supervisor': {
463
+ 'displayName': 'Super Visor',
464
+ 'id': 'pc:S1cZ06yduoQadHVOcVCyv',
465
+ 'type': 'User',
466
+ 'uri': '/admin/v1/users/pc:S1cZ06yduoQadHVOcVCyv'
467
+ }
468
+ },
469
+ 'checksum': '0',
470
+ 'links': {...}
471
+ }
472
+ }
473
+
474
+ """
475
+
476
+ request_url = self.config()["adminUrl"] + "/groups/" + str(group_id)
477
+
478
+ return self.do_request(method="GET", url=request_url)
479
+
480
+ # end method definition
481
+
482
+ def get_users(
483
+ self,
484
+ fields: list | None = None,
485
+ filters: list | None = None,
486
+ page_size: int = 25,
487
+ next_page_url: str | None = None,
488
+ ) -> dict:
489
+ """Retrieve a list of Guidewire users.
490
+
491
+ Args:
492
+ fields (list):
493
+ The list of fields in the results. If None, all default
494
+ fields are returned.
495
+ Fields for Guidewire accounts:
496
+ - *all = return all fields
497
+ - *default = return just the default list of fields
498
+ - *summary = return the fields defined for giving a summary
499
+ - *detail = details
500
+ - displayName
501
+ - groupType
502
+ - id
503
+ - loadFactor
504
+ - name
505
+ - organization
506
+ - parent
507
+ - securityZone
508
+ - supervisor
509
+ filters (list):
510
+ List of dictionaries with three keys each:
511
+ - "attribute" - name of the attribute to use for the filter (available attributes see above)
512
+ - "op" - operator:
513
+ * eq - equal
514
+ * ne - not equal
515
+ * lt - less than - also usable for dates (before)
516
+ * gt - greater than - also usable for dates (after)
517
+ * le - less or equal
518
+ * ge - greater or equal
519
+ * in - is in list
520
+ * ni - is NOT in list
521
+ * sw - starts with
522
+ * cn - contains
523
+ - "value": the value to filter for. Either literal or list of values
524
+ page_size (int, optional):
525
+ The maximum number of groups to return.
526
+ next_page_url (str, optional):
527
+ The Guidewire URL to retrieve the next page of Guidewire groups (pagination).
528
+ This is used for the iterator get_groups_iterator() below.
529
+
530
+ Returns:
531
+ dict:
532
+ JSON response containing account data.
533
+
534
+ Example reponse:
535
+ {
536
+ 'count': 10,
537
+ 'data': [
538
+ {
539
+ 'attributes': {
540
+ 'active': True,
541
+ 'displayName': 'Alice Applegate',
542
+ 'externalUser': False,
543
+ 'firstName': 'Alice',
544
+ 'groups': [
545
+ {
546
+ 'displayName': 'Eastern Region Underwriting',
547
+ 'id': 'pc:SDrypgK62o6oS1TxOGcvF',
548
+ 'type': 'Group',
549
+ 'uri': '/admin/v1/groups/pc:SDrypgK62o6oS1TxOGcvF'
550
+ },
551
+ {
552
+ 'displayName': 'Los Angeles Branch UW',
553
+ 'id': 'pc:SJxAbEha2jYpG9Mb5_KAo',
554
+ 'type': 'Group',
555
+ 'uri': '/admin/v1/groups/pc:SJxAbEha2jYpG9Mb5_KAo'
556
+ }
557
+ ],
558
+ 'id': 'pc:Si6MBM-35EAhneDubeFsl',
559
+ 'lastName': 'Applegate',
560
+ 'organization': {
561
+ 'displayName': 'Enigma Fire & Casualty',
562
+ 'id': 'systemTables:1',
563
+ 'type': 'Organization',
564
+ 'uri': '/admin/v1/organizations/systemTables:1'
565
+ },
566
+ 'roles': [
567
+ {
568
+ 'displayName': 'Reinsurance Manager',
569
+ 'id': 'reinsurance_manager',
570
+ 'type': 'Role',
571
+ 'uri': '/admin/v1/roles/reinsurance_manager'
572
+ },
573
+ {
574
+ 'displayName': 'Underwriter',
575
+ 'id': 'underwriter',
576
+ 'type': 'Role',
577
+ 'uri': '/admin/v1/roles/underwriter'
578
+ }
579
+ ],
580
+ 'useOrgAddress': True,
581
+ 'useProducerCodeSecurity': False,
582
+ 'userType': {
583
+ 'code': 'underwriter',
584
+ 'name': 'Underwriter'
585
+ },
586
+ 'username': 'aapplegate',
587
+ 'uwAuthorityProfiles': [
588
+ {
589
+ 'displayName': 'Underwriter 1',
590
+ 'id': 'pc:underwriter1',
591
+ 'type': 'UWAuthorityProfile',
592
+ 'uri': '/admin/v1/uw-authority-profiles/pc:underwriter1'
593
+ }
594
+ ],
595
+ 'vacationStatus': {
596
+ 'code': 'atwork',
597
+ 'name': 'At work'
598
+ },
599
+ 'workPhone': {
600
+ 'displayName': '213-555-8164',
601
+ 'number': '2135558164'
602
+ }
603
+ },
604
+ 'checksum': 'ec4710cd2af59bdc1cd7e15a18707d84',
605
+ 'links': {
606
+ 'self': {'href': '/admin/v1/users/pc:Si6MBM-35EAhneDubeFsl', 'methods': ['delete', 'get', 'patch']}
607
+ }
608
+ },
609
+ ...
610
+ ],
611
+ 'links': {
612
+ 'first': {'href': '/admin/v1/users?fields=%2Adefault&pageSize=20', 'methods': ['get']},
613
+ 'next': {'href': '/admin/v1/users?fields=%2Adefault&pageSize=20&pageOffset=20', 'methods': ['get']},
614
+ 'self': {'href': '/admin/v1/users?fields=%2Adefault&pageSize=20', 'methods': ['get']}
615
+ }
616
+ }
617
+
618
+ """
619
+
620
+ if not next_page_url:
621
+ request_url = self.config()["adminUrl"] + "/users"
622
+
623
+ encoded_query = self.process_parameters(fields=fields, filters=filters, page_size=page_size)
624
+ if encoded_query:
625
+ request_url += "?" + encoded_query
626
+ else:
627
+ request_url = self.config()["restUrl"] + next_page_url
628
+
629
+ return self.do_request(method="GET", url=request_url)
630
+
631
+ # end method definition
632
+
633
+ def get_users_iterator(self, fields: list | None = None, filters: list | None = None, page_size: int = 25) -> iter:
634
+ """Get an iterator object that can be used to traverse all Guidewire users.
635
+
636
+ Returning a generator avoids loading a large number of nodes into memory at once. Instead you
637
+ can iterate over the potential large list of users.
638
+
639
+ Example usage:
640
+ users = guidewire_object.get_users_iterator()
641
+ for user in users:
642
+ logger.info("Traversing Guidewire user -> '%s'...", user.get("attributes", {}).get("displayName"))
643
+
644
+ Args:
645
+ fields (list):
646
+ The list of fields in the results. If None, all default
647
+ fields are returned.
648
+ Fields for Guidewire accounts:
649
+ - *all = return all fields
650
+ - *default = return just the default list of fields
651
+ - *summary = return the fields defined for giving a summary
652
+ - *detail = details
653
+ - active
654
+ - displayName
655
+ - externalUser
656
+ - firstName
657
+ - id
658
+ - lastName
659
+ - organization
660
+ - useOrgAddress
661
+ - useProducerCodeSecurity
662
+ - username
663
+ filters (list):
664
+ List of dictionaries with three keys each:
665
+ - "attribute" - name of the attribute to use for the filter (available attributes see above)
666
+ - "op" - operator:
667
+ * eq - equal
668
+ * ne - not equal
669
+ * lt - less than - also usable for dates (before)
670
+ * gt - greater than - also usable for dates (after)
671
+ * le - less or equal
672
+ * ge - greater or equal
673
+ * in - is in list
674
+ * ni - is NOT in list
675
+ * sw - starts with
676
+ * cn - contains
677
+ - "value": the value to filter for. Either literal or list of values
678
+ page_size (int, optional):
679
+ The maximum number of groups to return.
680
+ next_page_url (str, optional):
681
+ The Guidewire URL to retrieve the next page of Guidewire groups (pagination).
682
+ This is used for the iterator get_groups_iterator() below.
683
+
684
+ Returns:
685
+ iter:
686
+ A generator yielding one Guidewire user per iteration.
687
+ If the REST API fails, returns no value.
688
+
689
+ """
690
+
691
+ next_page_url = None
692
+
693
+ while True:
694
+ response = self.get_users(fields=fields, filters=filters, page_size=page_size, next_page_url=next_page_url)
695
+ if not response or "data" not in response:
696
+ # Don't return None! Plain return is what we need for iterators.
697
+ # Natural Termination: If the generator does not yield, it behaves
698
+ # like an empty iterable when used in a loop or converted to a list:
699
+ return
700
+
701
+ # Yield users one at a time:
702
+ yield from response["data"]
703
+
704
+ # See if we have an additional result page.
705
+ # If not terminate the iterator and return
706
+ # no value.
707
+ next_page_url = response.get("links", {}).get("next", {}).get("href")
708
+ if not next_page_url:
709
+ # Don't return None! Plain return is what we need for iterators.
710
+ # Natural Termination: If the generator does not yield, it behaves
711
+ # like an empty iterable when used in a loop or converted to a list:
712
+ return
713
+
714
+ # end method definition
715
+
716
+ def get_user(self, user_id: str) -> dict:
717
+ """Retrieve details of a specific user.
718
+
719
+ Args:
720
+ user_id:
721
+ The unique identifier of the group.
722
+
723
+ Returns:
724
+ dict:
725
+ JSON response containing group details.
726
+
727
+ Example response;
728
+ {
729
+ 'data': {
730
+ 'attributes': {
731
+ 'active': True,
732
+ 'displayName': 'Alice Applegate',
733
+ 'externalUser': False,
734
+ 'firstName': 'Alice',
735
+ 'groups': [{...}, {...}],
736
+ 'id': 'pc:Si6MBM-35EAhneDubeFsl',
737
+ 'lastName': 'Applegate',
738
+ 'organization': {
739
+ 'displayName': 'Enigma Fire & Casualty',
740
+ 'id': 'systemTables:1',
741
+ 'type': 'Organization',
742
+ 'uri': '/admin/v1/organizations/systemTables:1'
743
+ },
744
+ 'roles': [{...}, {...}],
745
+ 'useOrgAddress': True,
746
+ 'useProducerCodeSecurity': False,
747
+ 'userType': {
748
+ 'code': 'underwriter',
749
+ 'name': 'Underwriter'
750
+ },
751
+ 'username': 'aapplegate',
752
+ 'uwAuthorityProfiles': [{...}],
753
+ 'vacationStatus': {
754
+ 'code': 'atwork',
755
+ 'name': 'At work'
756
+ },
757
+ 'workPhone': {
758
+ 'displayName': '213-555-8164',
759
+ 'number': '2135558164'
760
+ }
761
+ },
762
+ 'checksum': 'ec4710cd2af59bdc1cd7e15a18707d84',
763
+ 'links': {
764
+ 'producer-codes': {
765
+ 'href': '/admin/v1/users/pc:Si6MBM-35EAhneDubeFsl/producer-codes',
766
+ 'methods': [...]
767
+ },
768
+ 'self': {
769
+ 'href': '/admin/v1/users/pc:Si6MBM-35EAhneDubeFsl',
770
+ 'methods': [...]
771
+ }
772
+ }
773
+ }
774
+ }
775
+
776
+ """
777
+
778
+ request_url = self.config()["adminUrl"] + "/users/" + str(user_id)
779
+
780
+ return self.do_request(method="GET", url=request_url)
781
+
782
+ # end method definition
783
+
784
+ def update_user(self, user_id: str, user_data: dict) -> dict:
785
+ """Update an existing user.
786
+
787
+ Args:
788
+ user_id:
789
+ The unique identifier of the user.
790
+ user_data:
791
+ Dictionary containing updated user information.
792
+
793
+ Returns:
794
+ dict:
795
+ Response with updated user details.
796
+
797
+ """
798
+
799
+ request_url = self.config()["adminUrl"] + "/users/" + str(user_id)
800
+
801
+ return self.do_request(method="PUT", url=request_url, data=user_data)
802
+
803
+ # end method definition
804
+
805
+ def get_accounts(
806
+ self,
807
+ fields: list | None = None,
808
+ filters: list | None = None,
809
+ page_size: int = 25,
810
+ next_page_url: str | None = None,
811
+ ) -> dict | None:
172
812
  """Retrieve a list of accounts.
173
813
 
814
+ Args:
815
+ fields (list):
816
+ The list of fields in the results. If None, all default
817
+ fields are returned.
818
+ Fields for Guidewire accounts:
819
+ - *all = return all fields
820
+ - *default = return just the default list of fields
821
+ - *summary = return the fields defined for giving a summary
822
+ - *detail = details
823
+ - accountNumber
824
+ - accountHolder
825
+ - accountStatus
826
+ - businessOperationsDescription
827
+ - createdDate
828
+ - frozen
829
+ - id
830
+ - industryCode
831
+ - organizationType
832
+ - preferredCoverageCurrency
833
+ - preferredSettlementCurrency
834
+ - primaryLanguage
835
+ - primaryLocale
836
+ - primaryLocation
837
+ - producerCodes
838
+ filters (list):
839
+ List of dictionaries with three keys each:
840
+ - "attribute" - name of the attribute to use for the filter (available attributes see above)
841
+ - "op" - operator:
842
+ * eq - equal
843
+ * ne - not equal
844
+ * lt - less than - also usable for dates (before)
845
+ * gt - greater than - also usable for dates (after)
846
+ * le - less or equal
847
+ * ge - greater or equal
848
+ * in - is in list
849
+ * ni - is NOT in list
850
+ * sw - starts with
851
+ * cn - contains
852
+ - "value": the filue to filter for. Either literal or list of values
853
+ page_size (int, optional):
854
+ The maximum number of groups to return.
855
+ next_page_url (str, optional):
856
+ The Guidewire URL to retrieve the next page of Guidewire groups (pagination).
857
+ This is used for the iterator get_groups_iterator() below.
858
+
174
859
  Returns:
175
- dict: JSON response containing account data.
860
+ dict:
861
+ JSON response containing account data. None in case of an error.
862
+
863
+ """
864
+
865
+ if not next_page_url:
866
+ request_url = self.config()["accountUrl"] + "/accounts"
867
+
868
+ encoded_query = self.process_parameters(fields=fields, filters=filters, page_size=page_size)
869
+ if encoded_query:
870
+ request_url += "?" + encoded_query
871
+ else:
872
+ request_url = self.config()["restUrl"] + next_page_url
873
+
874
+ return self.do_request(method="GET", url=request_url)
875
+
876
+ # end method definition
877
+
878
+ def get_accounts_iterator(
879
+ self, fields: list | None = None, filters: list | None = None, page_size: int = 25
880
+ ) -> iter:
881
+ """Get an iterator object that can be used to traverse all Guidewire accounts.
882
+
883
+ Returning a generator avoids loading a large number of nodes into memory at once. Instead you
884
+ can iterate over the potential large list of groups.
885
+
886
+ Example usage:
887
+ accounts = guidewire_object.get_accounts_iterator()
888
+ for account in accounts:
889
+ logger.info("Traversing Guidewire account -> '%s'...", account.get("attributes", {}).get("displayName"))
890
+
891
+ Returns:
892
+ iter:
893
+ A generator yielding one Guidewire account per iteration.
894
+ If the REST API fails, returns no value.
176
895
 
177
896
  """
178
897
 
179
- return self.do_request("GET", "/accounts")
898
+ next_page_url = None
899
+
900
+ while True:
901
+ response = self.get_accounts(
902
+ fields=fields, filters=filters, page_size=page_size, next_page_url=next_page_url
903
+ )
904
+ if not response or "data" not in response:
905
+ # Don't return None! Plain return is what we need for iterators.
906
+ # Natural Termination: If the generator does not yield, it behaves
907
+ # like an empty iterable when used in a loop or converted to a list:
908
+ return
909
+
910
+ # Yield users one at a time:
911
+ yield from response["data"]
912
+
913
+ # See if we have an additional result page.
914
+ # If not terminate the iterator and return
915
+ # no value.
916
+ next_page_url = response.get("links", {}).get("next", {}).get("href")
917
+ if not next_page_url:
918
+ # Don't return None! Plain return is what we need for iterators.
919
+ # Natural Termination: If the generator does not yield, it behaves
920
+ # like an empty iterable when used in a loop or converted to a list:
921
+ return
180
922
 
181
923
  # end method definition
182
924
 
@@ -184,14 +926,18 @@ class Guidewire:
184
926
  """Retrieve details of a specific account.
185
927
 
186
928
  Args:
187
- account_id: The unique identifier of the account.
929
+ account_id:
930
+ The unique identifier of the account.
188
931
 
189
932
  Returns:
190
- dict: JSON response containing account details.
933
+ dict:
934
+ JSON response containing account details.
191
935
 
192
936
  """
193
937
 
194
- return self.do_request("GET", "/accounts/{}".format(account_id))
938
+ request_url = self.config()["accountUrl"] + "/accounts/" + str(account_id)
939
+
940
+ return self.do_request(method="GET", url=request_url)
195
941
 
196
942
  # end method definition
197
943
 
@@ -199,14 +945,18 @@ class Guidewire:
199
945
  """Create a new account.
200
946
 
201
947
  Args:
202
- account_data: Dictionary containing account information.
948
+ account_data:
949
+ Dictionary containing account information.
203
950
 
204
951
  Returns:
205
- dict: JSON response with created account details.
952
+ dict:
953
+ JSON response with created account details.
206
954
 
207
955
  """
208
956
 
209
- return self.do_request("POST", "/accounts", data=account_data)
957
+ request_url = self.config()["accountUrl"] + "/accounts"
958
+
959
+ return self.do_request(method="POST", url=request_url, data=account_data)
210
960
 
211
961
  # end method definition
212
962
 
@@ -214,15 +964,20 @@ class Guidewire:
214
964
  """Update an existing account.
215
965
 
216
966
  Args:
217
- account_id: The unique identifier of the account.
218
- account_data: Dictionary containing updated account information.
967
+ account_id:
968
+ The unique identifier of the account.
969
+ account_data:
970
+ Dictionary containing updated account information.
219
971
 
220
972
  Returns:
221
- dict: JSON response with updated account details.
973
+ dict:
974
+ JSON response with updated account details.
222
975
 
223
976
  """
224
977
 
225
- return self.do_request("PUT", "/accounts/{}".format(account_id), data=account_data)
978
+ request_url = self.config()["accountUrl"] + "/accounts/" + str(account_id)
979
+
980
+ return self.do_request(method="PUT", url=request_url, data=account_data)
226
981
 
227
982
  # end method definition
228
983
 
@@ -237,19 +992,118 @@ class Guidewire:
237
992
 
238
993
  """
239
994
 
240
- return self.do_request("DELETE", "/accounts/{}".format(account_id))
995
+ request_url = self.config()["accountUrl"] + "/accounts/" + str(account_id)
996
+
997
+ return self.do_request(method="DELETE", url=request_url)
241
998
 
242
999
  # end method definition
243
1000
 
244
- def get_claims(self) -> dict:
1001
+ def get_claims(
1002
+ self,
1003
+ fields: list | None = None,
1004
+ filters: list | None = None,
1005
+ page_size: int = 25,
1006
+ next_page_url: str | None = None,
1007
+ ) -> dict | None:
245
1008
  """Retrieve a list of claims.
246
1009
 
1010
+ fields (list):
1011
+ The list of fields in the results. If None, all default
1012
+ fields are returned.
1013
+ Fields for Guidewire accounts:
1014
+ - *all = return all fields
1015
+ - *default = return just the default list of fields
1016
+ - *summary = return the fields defined for giving a summary
1017
+ - *detail = details
1018
+ - displayName
1019
+ - groupType
1020
+ - id
1021
+ - loadFactor
1022
+ - name
1023
+ - organization
1024
+ - parent
1025
+ - securityZone
1026
+ - supervisor
1027
+ filters (list):
1028
+ List of dictionaries with three keys each:
1029
+ - "attribute" - name of the attribute to use for the filter (available attributes see above)
1030
+ - "op" - operator:
1031
+ * eq - equal
1032
+ * ne - not equal
1033
+ * lt - less than - also usable for dates (before)
1034
+ * gt - greater than - also usable for dates (after)
1035
+ * le - less or equal
1036
+ * ge - greater or equal
1037
+ * in - is in list
1038
+ * ni - is NOT in list
1039
+ * sw - starts with
1040
+ * cn - contains
1041
+ - "value": the value to filter for. Either literal or list of values
1042
+ page_size (int, optional):
1043
+ The maximum number of groups to return.
1044
+ next_page_url (str, optional):
1045
+ The Guidewire URL to retrieve the next page of Guidewire groups (pagination).
1046
+ This is used for the iterator get_groups_iterator() below.
1047
+
247
1048
  Returns:
248
- dict: JSON response containing claim data.
1049
+ dict | None:
1050
+ JSON response containing claim data.
249
1051
 
250
1052
  """
251
1053
 
252
- return self.do_request("GET", "/claims")
1054
+ if not next_page_url:
1055
+ request_url = self.config()["claimUrl"] + "/claim-infos"
1056
+
1057
+ encoded_query = self.process_parameters(fields=fields, filters=filters, page_size=page_size)
1058
+ if encoded_query:
1059
+ request_url += "?" + encoded_query
1060
+ else:
1061
+ request_url = self.config()["restUrl"] + next_page_url
1062
+
1063
+ return self.do_request(method="GET", url=request_url)
1064
+
1065
+ # end method definition
1066
+
1067
+ def get_claims_iterator(self, fields: list | None = None, filters: list | None = None, page_size: int = 25) -> iter:
1068
+ """Get an iterator object that can be used to traverse all Guidewire claims.
1069
+
1070
+ Returning a generator avoids loading a large number of nodes into memory at once. Instead you
1071
+ can iterate over the potential large list of groups.
1072
+
1073
+ Example usage:
1074
+ claims = guidewire_object.get_claims_iterator()
1075
+ for claim in claims:
1076
+ logger.info("Traversing Guidewire claim -> '%s'...", claim.get("attributes", {}).get("displayName"))
1077
+
1078
+ Returns:
1079
+ iter:
1080
+ A generator yielding one Guidewire claim per iteration.
1081
+ If the REST API fails, returns no value.
1082
+
1083
+ """
1084
+
1085
+ next_page_url = None
1086
+
1087
+ while True:
1088
+ response = self.get_claims(fields=fields, filters=filters, page_size=page_size, next_page_url=next_page_url)
1089
+ if not response or "data" not in response:
1090
+ # Don't return None! Plain return is what we need for iterators.
1091
+ # Natural Termination: If the generator does not yield, it behaves
1092
+ # like an empty iterable when used in a loop or converted to a list:
1093
+ return
1094
+
1095
+ # Yield users one at a time:
1096
+ yield from response["data"]
1097
+
1098
+ # See if we have an additional result page.
1099
+ # If not terminate the iterator and return
1100
+ # no value.
1101
+ next_page_url = response.get("links", {}).get("next", {}).get("href")
1102
+ if not next_page_url:
1103
+ # Don't return None! Plain return is what we need for iterators.
1104
+ # Natural Termination: If the generator does not yield, it behaves
1105
+ # like an empty iterable when used in a loop or converted to a list:
1106
+ return
253
1107
 
254
1108
  # end method definition
255
1109
 
@@ -257,14 +1111,18 @@ class Guidewire:
257
1111
  """Retrieve details of a specific claim.
258
1112
 
259
1113
  Args:
260
- claim_id: The unique identifier of the claim.
1114
+ claim_id:
1115
+ The unique identifier of the claim.
261
1116
 
262
1117
  Returns:
263
- dict: JSON response containing claim details.
1118
+ dict:
1119
+ JSON response containing claim details.
264
1120
 
265
1121
  """
266
1122
 
267
- return self.do_request("GET", "/claims/{}".format(claim_id))
1123
+ request_url = self.config()["claimUrl"] + "/claims/" + str(claim_id)
1124
+
1125
+ return self.do_request(method="GET", url=request_url)
268
1126
 
269
1127
  # end method definition
270
1128
 
@@ -281,7 +1139,9 @@ class Guidewire:
281
1139
 
282
1140
  """
283
1141
 
284
- return self.do_request("POST", "/claims", data=claim_data)
1142
+ request_url = self.config()["claimUrl"] + "/claims"
1143
+
1144
+ return self.do_request(method="POST", url=request_url, data=claim_data)
285
1145
 
286
1146
  # end method definition
287
1147
 
@@ -300,7 +1160,9 @@ class Guidewire:
300
1160
 
301
1161
  """
302
1162
 
303
- return self.do_request("PUT", "/claims/{}".format(claim_id), data=claim_data)
1163
+ request_url = self.config()["claimUrl"] + "/claims/" + str(claim_id)
1164
+
1165
+ return self.do_request(method="PUT", url=request_url, data=claim_data)
304
1166
 
305
1167
  # end method definition
306
1168
 
@@ -317,6 +1179,8 @@ class Guidewire:
317
1179
 
318
1180
  """
319
1181
 
320
- return self.do_request("DELETE", "/claims/{}".format(claim_id))
1182
+ request_url = self.config()["claimUrl"] + "/claims/" + str(claim_id)
1183
+
1184
+ return self.do_request(method="DELETE", url=request_url)
321
1185
 
322
1186
  # end method definition