tallyfy 1.0.16__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.
Files changed (52) hide show
  1. tallyfy/__init__.py +27 -0
  2. tallyfy/__pycache__/__init__.cpython-310.pyc +0 -0
  3. tallyfy/__pycache__/core.cpython-310.pyc +0 -0
  4. tallyfy/__pycache__/form_fields_management.cpython-310.pyc +0 -0
  5. tallyfy/__pycache__/models.cpython-310.pyc +0 -0
  6. tallyfy/__pycache__/task_management.cpython-310.pyc +0 -0
  7. tallyfy/__pycache__/template_management.cpython-310.pyc +0 -0
  8. tallyfy/__pycache__/user_management.cpython-310.pyc +0 -0
  9. tallyfy/core.py +361 -0
  10. tallyfy/form_fields_management/__init__.py +70 -0
  11. tallyfy/form_fields_management/__pycache__/__init__.cpython-310.pyc +0 -0
  12. tallyfy/form_fields_management/__pycache__/base.cpython-310.pyc +0 -0
  13. tallyfy/form_fields_management/__pycache__/crud_operations.cpython-310.pyc +0 -0
  14. tallyfy/form_fields_management/__pycache__/options_management.cpython-310.pyc +0 -0
  15. tallyfy/form_fields_management/__pycache__/suggestions.cpython-310.pyc +0 -0
  16. tallyfy/form_fields_management/base.py +109 -0
  17. tallyfy/form_fields_management/crud_operations.py +234 -0
  18. tallyfy/form_fields_management/options_management.py +222 -0
  19. tallyfy/form_fields_management/suggestions.py +411 -0
  20. tallyfy/models.py +1464 -0
  21. tallyfy/organization_management/__init__.py +26 -0
  22. tallyfy/organization_management/base.py +76 -0
  23. tallyfy/organization_management/retrieval.py +39 -0
  24. tallyfy/task_management/__init__.py +81 -0
  25. tallyfy/task_management/__pycache__/__init__.cpython-310.pyc +0 -0
  26. tallyfy/task_management/__pycache__/base.cpython-310.pyc +0 -0
  27. tallyfy/task_management/__pycache__/creation.cpython-310.pyc +0 -0
  28. tallyfy/task_management/__pycache__/retrieval.cpython-310.pyc +0 -0
  29. tallyfy/task_management/__pycache__/search.cpython-310.pyc +0 -0
  30. tallyfy/task_management/base.py +125 -0
  31. tallyfy/task_management/creation.py +221 -0
  32. tallyfy/task_management/retrieval.py +252 -0
  33. tallyfy/task_management/search.py +198 -0
  34. tallyfy/template_management/__init__.py +85 -0
  35. tallyfy/template_management/analysis.py +1099 -0
  36. tallyfy/template_management/automation.py +469 -0
  37. tallyfy/template_management/base.py +56 -0
  38. tallyfy/template_management/basic_operations.py +479 -0
  39. tallyfy/template_management/health_assessment.py +793 -0
  40. tallyfy/user_management/__init__.py +70 -0
  41. tallyfy/user_management/__pycache__/__init__.cpython-310.pyc +0 -0
  42. tallyfy/user_management/__pycache__/base.cpython-310.pyc +0 -0
  43. tallyfy/user_management/__pycache__/invitation.cpython-310.pyc +0 -0
  44. tallyfy/user_management/__pycache__/retrieval.cpython-310.pyc +0 -0
  45. tallyfy/user_management/base.py +146 -0
  46. tallyfy/user_management/invitation.py +286 -0
  47. tallyfy/user_management/retrieval.py +381 -0
  48. tallyfy-1.0.16.dist-info/METADATA +742 -0
  49. tallyfy-1.0.16.dist-info/RECORD +52 -0
  50. tallyfy-1.0.16.dist-info/WHEEL +5 -0
  51. tallyfy-1.0.16.dist-info/licenses/LICENSE +21 -0
  52. tallyfy-1.0.16.dist-info/top_level.txt +1 -0
tallyfy/models.py ADDED
@@ -0,0 +1,1464 @@
1
+ """
2
+ Data models for Tallyfy API responses
3
+ """
4
+
5
+ from typing import Dict, Any, Optional, List
6
+ from dataclasses import dataclass
7
+
8
+
9
+ class TallyfyError(Exception):
10
+ """Custom exception for Tallyfy API errors"""
11
+
12
+ def __init__(self, message: str, status_code: Optional[int] = None, response_data: Optional[Any] = None):
13
+ super().__init__(message)
14
+ self.status_code = status_code
15
+ self.response_data = response_data
16
+
17
+
18
+ @dataclass
19
+ class Country:
20
+ """Country data model"""
21
+ id: int
22
+ name: str
23
+ phone_code: str
24
+ iso2: str
25
+
26
+ @classmethod
27
+ def from_dict(cls, data: Dict[str, Any]) -> 'Country':
28
+ """Create Country instance from dictionary"""
29
+ return cls(
30
+ id=data.get('id', 0),
31
+ name=data.get('name', ''),
32
+ phone_code=data.get('phone_code', ''),
33
+ iso2=data.get('iso2', '')
34
+ )
35
+
36
+
37
+ @dataclass
38
+ class User:
39
+ """User data model"""
40
+ id: int
41
+ email: str
42
+ username: str
43
+ first_name: str
44
+ last_name: str
45
+ full_name: str
46
+ profile_pic: Optional[str] = None
47
+ locale: Optional[str] = None
48
+ active: bool = True
49
+ is_suspended: bool = False
50
+ created_at: Optional[str] = None
51
+ last_updated: Optional[str] = None
52
+ last_login_at: Optional[str] = None
53
+ activated_at: Optional[str] = None
54
+ support_user: bool = False
55
+ country: Optional[Country] = None
56
+ phone: Optional[str] = None
57
+ job_title: Optional[str] = None
58
+ job_description: Optional[str] = None
59
+ team: Optional[str] = None
60
+ timezone: Optional[str] = None
61
+ UTC_offset: Optional[str] = None
62
+ last_accessed_at: Optional[str] = None
63
+ approved_at: Optional[str] = None
64
+ invited_by: Optional[int] = None
65
+ disabled_at: Optional[str] = None
66
+ disabled_by: Optional[int] = None
67
+ reactivated_at: Optional[str] = None
68
+ reactivated_by: Optional[int] = None
69
+ status: Optional[str] = None
70
+ date_format: Optional[str] = None
71
+ last_known_ip: Optional[str] = None
72
+ last_known_country: Optional[str] = None
73
+ role: Optional[str] = None
74
+
75
+ @classmethod
76
+ def from_dict(cls, data: Dict[str, Any]) -> 'User':
77
+ """Create User instance from dictionary"""
78
+ country_data = data.get('country')
79
+ country = Country.from_dict(country_data) if country_data else None
80
+
81
+ return cls(
82
+ id=data.get('id', 0),
83
+ email=data.get('email', ''),
84
+ username=data.get('username', ''),
85
+ first_name=data.get('first_name', ''),
86
+ last_name=data.get('last_name', ''),
87
+ full_name=data.get('full_name', ''),
88
+ profile_pic=data.get('profile_pic'),
89
+ locale=data.get('locale'),
90
+ active=data.get('active', True),
91
+ is_suspended=data.get('is_suspended', False),
92
+ created_at=data.get('created_at'),
93
+ last_updated=data.get('last_updated'),
94
+ last_login_at=data.get('last_login_at'),
95
+ activated_at=data.get('activated_at'),
96
+ support_user=data.get('support_user', False),
97
+ country=country,
98
+ phone=data.get('phone'),
99
+ job_title=data.get('job_title'),
100
+ job_description=data.get('job_description'),
101
+ team=data.get('team'),
102
+ timezone=data.get('timezone'),
103
+ UTC_offset=data.get('UTC_offset'),
104
+ last_accessed_at=data.get('last_accessed_at'),
105
+ approved_at=data.get('approved_at'),
106
+ invited_by=data.get('invited_by'),
107
+ disabled_at=data.get('disabled_at'),
108
+ disabled_by=data.get('disabled_by'),
109
+ reactivated_at=data.get('reactivated_at'),
110
+ reactivated_by=data.get('reactivated_by'),
111
+ status=data.get('status'),
112
+ date_format=data.get('date_format'),
113
+ last_known_ip=data.get('last_known_ip'),
114
+ last_known_country=data.get('last_known_country'),
115
+ role=data.get('role')
116
+ )
117
+
118
+
119
+ @dataclass
120
+ class GuestDetails:
121
+ """Guest details data model"""
122
+ first_name: Optional[str] = None
123
+ last_name: Optional[str] = None
124
+ status: Optional[str] = None
125
+ phone_1: Optional[str] = None
126
+ phone_2: Optional[str] = None
127
+ image_url: Optional[str] = None
128
+ contact_url: Optional[str] = None
129
+ company_url: Optional[str] = None
130
+ opportunity_url: Optional[str] = None
131
+ company_name: Optional[str] = None
132
+ opportunity_name: Optional[str] = None
133
+ external_sync_source: Optional[str] = None
134
+ external_date_creation: Optional[str] = None
135
+ timezone: Optional[str] = None
136
+ reactivated_at: Optional[str] = None
137
+ reactivated_by: Optional[int] = None
138
+ disabled_on: Optional[str] = None
139
+ disabled_by: Optional[int] = None
140
+
141
+ @classmethod
142
+ def from_dict(cls, data: Dict[str, Any]) -> 'GuestDetails':
143
+ """Create GuestDetails instance from dictionary"""
144
+ return cls(
145
+ first_name=data.get('first_name'),
146
+ last_name=data.get('last_name'),
147
+ status=data.get('status'),
148
+ phone_1=data.get('phone_1'),
149
+ phone_2=data.get('phone_2'),
150
+ image_url=data.get('image_url'),
151
+ contact_url=data.get('contact_url'),
152
+ company_url=data.get('company_url'),
153
+ opportunity_url=data.get('opportunity_url'),
154
+ company_name=data.get('company_name'),
155
+ opportunity_name=data.get('opportunity_name'),
156
+ external_sync_source=data.get('external_sync_source'),
157
+ external_date_creation=data.get('external_date_creation'),
158
+ timezone=data.get('timezone'),
159
+ reactivated_at=data.get('reactivated_at'),
160
+ reactivated_by=data.get('reactivated_by'),
161
+ disabled_on=data.get('disabled_on'),
162
+ disabled_by=data.get('disabled_by')
163
+ )
164
+
165
+
166
+ @dataclass
167
+ class Guest:
168
+ """Guest data model"""
169
+ email: str
170
+ last_accessed_at: Optional[str] = None
171
+ last_known_ip: Optional[str] = None
172
+ last_known_country: Optional[str] = None
173
+ details: Optional[GuestDetails] = None
174
+
175
+ @classmethod
176
+ def from_dict(cls, data: Dict[str, Any]) -> 'Guest':
177
+ """Create Guest instance from dictionary"""
178
+ details_data = data.get('details')
179
+ details = GuestDetails.from_dict(details_data) if details_data else None
180
+
181
+ return cls(
182
+ email=data.get('email', ''),
183
+ last_accessed_at=data.get('last_accessed_at'),
184
+ last_known_ip=data.get('last_known_ip'),
185
+ last_known_country=data.get('last_known_country'),
186
+ details=details
187
+ )
188
+
189
+
190
+ @dataclass
191
+ class TaskOwners:
192
+ """Task owners data model"""
193
+ users: List[int] = None
194
+ guests: List[str] = None
195
+ groups: List[int] = None
196
+ task_urls: List[str] = None
197
+
198
+ def __post_init__(self):
199
+ """Initialize empty lists if None"""
200
+ if self.users is None:
201
+ self.users = []
202
+ if self.guests is None:
203
+ self.guests = []
204
+ if self.groups is None:
205
+ self.groups = []
206
+ if self.task_urls is None:
207
+ self.task_urls = []
208
+
209
+ @classmethod
210
+ def from_dict(cls, data: Dict[str, Any]) -> 'TaskOwners':
211
+ """Create TaskOwners instance from dictionary"""
212
+ return cls(
213
+ users=data.get('users', []),
214
+ guests=data.get('guests', []),
215
+ groups=data.get('groups', []),
216
+ task_urls=data.get('taskUrls', [])
217
+ )
218
+
219
+
220
+
221
+
222
+
223
+ @dataclass
224
+ class RunProgress:
225
+ """Run progress data model"""
226
+ complete: int = 0
227
+ total: int = 0
228
+ percent: float = 0.0
229
+
230
+ @classmethod
231
+ def from_dict(cls, data: Dict[str, Any]) -> 'RunProgress':
232
+ """Create RunProgress instance from dictionary"""
233
+ return cls(
234
+ complete=data.get('complete', 0),
235
+ total=data.get('total', 0),
236
+ percent=data.get('percent', 0.0)
237
+ )
238
+
239
+
240
+ @dataclass
241
+ class Run:
242
+ """Run (Process) data model"""
243
+ id: str
244
+ increment_id: int
245
+ checklist_id: str
246
+ checklist_title: str
247
+ assign_someone_else: bool
248
+ name: str
249
+ summary: Optional[str] = None
250
+ status: str = "active"
251
+ progress: Optional[RunProgress] = None
252
+ whole_progress: Optional[RunProgress] = None
253
+ started_by: Optional[int] = None
254
+ prerun: Optional[Dict[str, Any]] = None
255
+ prerun_completed_at: Optional[str] = None
256
+ prerun_completed_by: Optional[int] = None
257
+ prerun_length: Optional[int] = None
258
+ starred: bool = False
259
+ created_at: Optional[str] = None
260
+ due_date: Optional[str] = None
261
+ owner_id: Optional[int] = None
262
+ started_at: Optional[str] = None
263
+ last_updated: Optional[str] = None
264
+ completed_at: Optional[str] = None
265
+ late_tasks: Optional[int] = None
266
+ archived_at: Optional[str] = None
267
+ due_date_passed: bool = False
268
+ collaborators: List[int] = None
269
+ due_soon: bool = False
270
+ max_task_deadline: Optional[str] = None
271
+
272
+ def __post_init__(self):
273
+ """Initialize empty lists if None"""
274
+ if self.collaborators is None:
275
+ self.collaborators = []
276
+
277
+ @classmethod
278
+ def from_dict(cls, data: Dict[str, Any]) -> 'Run':
279
+ """Create Run instance from dictionary"""
280
+ progress_data = data.get('progress')
281
+ progress = RunProgress.from_dict(progress_data) if progress_data else None
282
+
283
+ whole_progress_data = data.get('whole_progress')
284
+ whole_progress = RunProgress.from_dict(whole_progress_data) if whole_progress_data else None
285
+
286
+ return cls(
287
+ id=data.get('id', ''),
288
+ increment_id=data.get('increment_id', 0),
289
+ checklist_id=data.get('checklist_id', ''),
290
+ checklist_title=data.get('checklist_title', ''),
291
+ assign_someone_else=data.get('assign_someone_else', False),
292
+ name=data.get('name', ''),
293
+ summary=data.get('summary'),
294
+ status=data.get('status', 'active'),
295
+ progress=progress,
296
+ whole_progress=whole_progress,
297
+ started_by=data.get('started_by'),
298
+ prerun=data.get('prerun'),
299
+ prerun_completed_at=data.get('prerun_completed_at'),
300
+ prerun_completed_by=data.get('prerun_completed_by'),
301
+ prerun_length=data.get('prerun_length'),
302
+ starred=data.get('starred', False),
303
+ created_at=data.get('created_at'),
304
+ due_date=data.get('due_date'),
305
+ owner_id=data.get('owner_id'),
306
+ started_at=data.get('started_at'),
307
+ last_updated=data.get('last_updated'),
308
+ completed_at=data.get('completed_at'),
309
+ late_tasks=data.get('late_tasks'),
310
+ archived_at=data.get('archived_at'),
311
+ due_date_passed=data.get('due_date_passed', False),
312
+ collaborators=data.get('collaborators', []),
313
+ due_soon=data.get('due_soon', False),
314
+ max_task_deadline=data.get('max_task_deadline')
315
+ )
316
+
317
+
318
+ @dataclass
319
+ class Folder:
320
+ """Folder data model for search results"""
321
+ id: str
322
+ parent: Optional[str]
323
+ name: str
324
+
325
+ @classmethod
326
+ def from_dict(cls, data: Dict[str, Any]) -> 'Folder':
327
+ """Create Folder instance from dictionary"""
328
+ return cls(
329
+ id=data.get('id', ''),
330
+ parent=data.get('parent'),
331
+ name=data.get('name', '')
332
+ )
333
+
334
+
335
+ @dataclass
336
+ class Tag:
337
+ """Tag data model for industry and topic tags"""
338
+ id: str
339
+ title: str
340
+ type: str
341
+ color: str
342
+ created_at: Optional[str] = None
343
+ deleted_at: Optional[str] = None
344
+
345
+ @classmethod
346
+ def from_dict(cls, data: Dict[str, Any]) -> 'Tag':
347
+ """Create Tag instance from dictionary"""
348
+ return cls(
349
+ id=data.get('id', ''),
350
+ title=data.get('title', ''),
351
+ type=data.get('type', ''),
352
+ color=data.get('color', ''),
353
+ created_at=data.get('created_at'),
354
+ deleted_at=data.get('deleted_at')
355
+ )
356
+
357
+
358
+ @dataclass
359
+ class PrerunField:
360
+ """Prerun field data model"""
361
+ id: str
362
+ checklist_id: str
363
+ alias: str
364
+ field_type: str
365
+ guidance: Optional[str] = None
366
+ position: int = 1
367
+ required: bool = True
368
+ use_wysiwyg_editor: bool = True
369
+ collect_time: bool = True
370
+ options: List[Dict[str, Any]] = None
371
+ field_validation: List[str] = None
372
+ created_at: Optional[str] = None
373
+ last_updated: Optional[str] = None
374
+
375
+ def __post_init__(self):
376
+ """Initialize empty lists if None"""
377
+ if self.options is None:
378
+ self.options = []
379
+ if self.field_validation is None:
380
+ self.field_validation = []
381
+
382
+ @classmethod
383
+ def from_dict(cls, data: Dict[str, Any]) -> 'PrerunField':
384
+ """Create PrerunField instance from dictionary"""
385
+ return cls(
386
+ id=data.get('id', ''),
387
+ checklist_id=data.get('checklist_id', ''),
388
+ alias=data.get('alias', ''),
389
+ field_type=data.get('field_type', 'text'),
390
+ guidance=data.get('guidance'),
391
+ position=data.get('position', 1),
392
+ required=data.get('required', True),
393
+ use_wysiwyg_editor=data.get('use_wysiwyg_editor', True),
394
+ collect_time=data.get('collect_time', True),
395
+ options=data.get('options', []),
396
+ field_validation=data.get('field_validation', []),
397
+ created_at=data.get('created_at'),
398
+ last_updated=data.get('last_updated')
399
+ )
400
+
401
+
402
+ @dataclass
403
+ class AutomationCondition:
404
+ """Automation condition data model"""
405
+ id: str
406
+ conditionable_id: str
407
+ conditionable_type: str
408
+ operation: str
409
+ statement: str
410
+ logic: str
411
+ position: int
412
+ column_contains_name: Optional[str] = None
413
+
414
+ @classmethod
415
+ def from_dict(cls, data: Dict[str, Any]) -> 'AutomationCondition':
416
+ """Create AutomationCondition instance from dictionary"""
417
+ return cls(
418
+ id=data.get('id', ''),
419
+ conditionable_id=data.get('conditionable_id', ''),
420
+ conditionable_type=data.get('conditionable_type', ''),
421
+ operation=data.get('operation', ''),
422
+ statement=data.get('statement', ''),
423
+ logic=data.get('logic', ''),
424
+ position=data.get('position', 0),
425
+ column_contains_name=data.get('column_contains_name')
426
+ )
427
+
428
+
429
+ @dataclass
430
+ class AutomationDeadline:
431
+ """Automation deadline data model"""
432
+ value: int
433
+ unit: str
434
+
435
+ @classmethod
436
+ def from_dict(cls, data: Dict[str, Any]) -> 'AutomationDeadline':
437
+ """Create AutomationDeadline instance from dictionary"""
438
+ return cls(
439
+ value=data.get('value', 0),
440
+ unit=data.get('unit', 'days')
441
+ )
442
+
443
+
444
+ @dataclass
445
+ class AutomationAssignees:
446
+ """Automation assignees data model"""
447
+ users: List[int] = None
448
+ guests: List[str] = None
449
+ groups: List[str] = None
450
+
451
+ def __post_init__(self):
452
+ """Initialize empty lists if None"""
453
+ if self.users is None:
454
+ self.users = []
455
+ if self.guests is None:
456
+ self.guests = []
457
+ if self.groups is None:
458
+ self.groups = []
459
+
460
+ @classmethod
461
+ def from_dict(cls, data: Dict[str, Any]) -> 'AutomationAssignees':
462
+ """Create AutomationAssignees instance from dictionary"""
463
+ return cls(
464
+ users=data.get('users', []),
465
+ guests=data.get('guests', []),
466
+ groups=data.get('groups', [])
467
+ )
468
+
469
+
470
+ @dataclass
471
+ class AutomationAction:
472
+ """Automation action data model"""
473
+ id: str
474
+ action_type: str
475
+ action_verb: str
476
+ target_step_id: Optional[str] = None
477
+ position: int = 0
478
+ actionable_id: Optional[str] = None
479
+ actionable_type: Optional[str] = None
480
+ deadline: Optional[AutomationDeadline] = None
481
+ assignees: Optional[AutomationAssignees] = None
482
+
483
+ @classmethod
484
+ def from_dict(cls, data: Dict[str, Any]) -> 'AutomationAction':
485
+ """Create AutomationAction instance from dictionary"""
486
+ deadline_data = data.get('deadline')
487
+ deadline = AutomationDeadline.from_dict(deadline_data) if deadline_data else None
488
+
489
+ assignees_data = data.get('assignees')
490
+ assignees = AutomationAssignees.from_dict(assignees_data) if assignees_data else None
491
+
492
+ return cls(
493
+ id=data.get('id', ''),
494
+ action_type=data.get('action_type', ''),
495
+ action_verb=data.get('action_verb', ''),
496
+ target_step_id=data.get('target_step_id'),
497
+ position=data.get('position', 0),
498
+ actionable_id=data.get('actionable_id'),
499
+ actionable_type=data.get('actionable_type'),
500
+ deadline=deadline,
501
+ assignees=assignees
502
+ )
503
+
504
+
505
+ @dataclass
506
+ class AutomatedAction:
507
+ """Automated action data model"""
508
+ id: str
509
+ automated_alias: str
510
+ conditions: List[AutomationCondition] = None
511
+ then_actions: List[AutomationAction] = None
512
+ created_at: Optional[str] = None
513
+ last_updated: Optional[str] = None
514
+ archived_at: Optional[str] = None
515
+
516
+ def __post_init__(self):
517
+ """Initialize empty lists if None"""
518
+ if self.conditions is None:
519
+ self.conditions = []
520
+ if self.then_actions is None:
521
+ self.then_actions = []
522
+
523
+ @classmethod
524
+ def from_dict(cls, data: Dict[str, Any]) -> 'AutomatedAction':
525
+ """Create AutomatedAction instance from dictionary"""
526
+ conditions_data = data.get('conditions', [])
527
+ conditions = [AutomationCondition.from_dict(cond_data) for cond_data in conditions_data] if conditions_data else []
528
+
529
+ actions_data = data.get('then_actions', [])
530
+ then_actions = [AutomationAction.from_dict(action_data) for action_data in actions_data] if actions_data else []
531
+
532
+ return cls(
533
+ id=data.get('id', ''),
534
+ automated_alias=data.get('automated_alias', ''),
535
+ conditions=conditions,
536
+ then_actions=then_actions,
537
+ created_at=data.get('created_at'),
538
+ last_updated=data.get('last_updated'),
539
+ archived_at=data.get('archived_at')
540
+ )
541
+
542
+
543
+ @dataclass
544
+ class StepStartDate:
545
+ """Step start date data model"""
546
+ value: int = 0
547
+ unit: str = "days"
548
+
549
+ @classmethod
550
+ def from_dict(cls, data: Dict[str, Any]) -> 'StepStartDate':
551
+ """Create StepStartDate instance from dictionary"""
552
+ return cls(
553
+ value=data.get('value', 0),
554
+ unit=data.get('unit', 'days')
555
+ )
556
+
557
+
558
+ @dataclass
559
+ class StepDeadline:
560
+ """Step deadline data model"""
561
+ value: int = 0
562
+ unit: str = "days"
563
+ option: str = "from"
564
+ step: str = "start_run"
565
+
566
+ @classmethod
567
+ def from_dict(cls, data: Dict[str, Any]) -> 'StepDeadline':
568
+ """Create StepDeadline instance from dictionary"""
569
+ return cls(
570
+ value=data.get('value', 0),
571
+ unit=data.get('unit', 'days'),
572
+ option=data.get('option', 'from'),
573
+ step=data.get('step', 'start_run')
574
+ )
575
+
576
+
577
+ @dataclass
578
+ class StepBpToLaunch:
579
+ """Step blueprint to launch data model"""
580
+ id: Optional[str] = None
581
+ default_name_format: Optional[str] = None
582
+ tasks_within_process: bool = True
583
+
584
+ @classmethod
585
+ def from_dict(cls, data: Dict[str, Any]) -> 'StepBpToLaunch':
586
+ """Create StepBpToLaunch instance from dictionary"""
587
+ return cls(
588
+ id=data.get('id'),
589
+ default_name_format=data.get('default_name_format'),
590
+ tasks_within_process=data.get('tasks_within_process', True)
591
+ )
592
+
593
+
594
+ @dataclass
595
+ class Capture:
596
+ """Capture (form field) data model"""
597
+ id: str
598
+ step_id: str
599
+ field_type: str
600
+ label: str
601
+ guidance: Optional[str] = None
602
+ position: int = 1
603
+ required: bool = True
604
+ options: List[Dict[str, Any]] = None
605
+ columns: List[Dict[str, Any]] = None
606
+ default_value_enabled: bool = False
607
+ default_value: Optional[str] = None
608
+ created_at: Optional[str] = None
609
+ last_updated: Optional[str] = None
610
+
611
+ def __post_init__(self):
612
+ """Initialize empty lists if None"""
613
+ if self.options is None:
614
+ self.options = []
615
+ if self.columns is None:
616
+ self.columns = []
617
+
618
+ @classmethod
619
+ def from_dict(cls, data: Dict[str, Any]) -> 'Capture':
620
+ """Create Capture instance from dictionary"""
621
+ return cls(
622
+ id=data.get('id', ''),
623
+ step_id=data.get('step_id', ''),
624
+ field_type=data.get('field_type', 'text'),
625
+ label=data.get('label', ''),
626
+ guidance=data.get('guidance'),
627
+ position=data.get('position', 1),
628
+ required=data.get('required', True),
629
+ options=data.get('options', []),
630
+ columns=data.get('columns', []),
631
+ default_value_enabled=data.get('default_value_enabled', False),
632
+ default_value=data.get('default_value'),
633
+ created_at=data.get('created_at'),
634
+ last_updated=data.get('last_updated')
635
+ )
636
+
637
+
638
+ @dataclass
639
+ class Step:
640
+ """Step data model"""
641
+ id: str
642
+ checklist_id: str
643
+ title: str
644
+ alias: Optional[str] = None
645
+ summary: Optional[str] = None
646
+ step_type: Optional[str] = None
647
+ position: int = 1
648
+ allow_guest_owners: bool = False
649
+ max_assignable: int = 1
650
+ skip_start_process: bool = False
651
+ can_complete_only_assignees: bool = False
652
+ everyone_must_complete: bool = False
653
+ webhook: Optional[str] = None
654
+ start_date: Optional[StepStartDate] = None
655
+ is_soft_start_date: bool = False
656
+ deadline: Optional[StepDeadline] = None
657
+ bp_to_launch: Optional[StepBpToLaunch] = None
658
+ assignees: List[int] = None
659
+ guests: List[str] = None
660
+ groups: List[str] = None
661
+ captures: List[Capture] = None
662
+ prevent_guest_comment: bool = False
663
+ roles: List[str] = None
664
+ role_changes_every_time: bool = False
665
+ created_at: Optional[str] = None
666
+ last_updated: Optional[str] = None
667
+ archived_at: Optional[str] = None
668
+
669
+ def __post_init__(self):
670
+ """Initialize empty lists if None"""
671
+ if self.assignees is None:
672
+ self.assignees = []
673
+ if self.guests is None:
674
+ self.guests = []
675
+ if self.groups is None:
676
+ self.groups = []
677
+ if self.captures is None:
678
+ self.captures = []
679
+ if self.roles is None:
680
+ self.roles = []
681
+
682
+ @classmethod
683
+ def from_dict(cls, data: Dict[str, Any]) -> 'Step':
684
+ """Create Step instance from dictionary"""
685
+ start_date_data = data.get('start_date')
686
+ start_date = StepStartDate.from_dict(start_date_data) if start_date_data else None
687
+
688
+ deadline_data = data.get('deadline')
689
+ deadline = StepDeadline.from_dict(deadline_data) if deadline_data else None
690
+
691
+ bp_to_launch_data = data.get('bp_to_launch')
692
+ bp_to_launch = StepBpToLaunch.from_dict(bp_to_launch_data) if bp_to_launch_data else None
693
+
694
+ captures_data = data.get('captures', [])
695
+ captures = [Capture.from_dict(capture_data) for capture_data in captures_data] if captures_data else []
696
+
697
+ return cls(
698
+ id=data.get('id', ''),
699
+ checklist_id=data.get('checklist_id', ''),
700
+ title=data.get('title', ''),
701
+ alias=data.get('alias'),
702
+ summary=data.get('summary'),
703
+ step_type=data.get('step_type'),
704
+ position=data.get('position', 1),
705
+ allow_guest_owners=data.get('allow_guest_owners', False),
706
+ max_assignable=data.get('max_assignable', 1),
707
+ skip_start_process=data.get('skip_start_process', False),
708
+ can_complete_only_assignees=data.get('can_complete_only_assignees', False),
709
+ everyone_must_complete=data.get('everyone_must_complete', False),
710
+ webhook=data.get('webhook'),
711
+ start_date=start_date,
712
+ is_soft_start_date=data.get('is_soft_start_date', False),
713
+ deadline=deadline,
714
+ bp_to_launch=bp_to_launch,
715
+ assignees=data.get('assignees', []),
716
+ guests=data.get('guests', []),
717
+ groups=data.get('groups', []),
718
+ captures=captures,
719
+ prevent_guest_comment=data.get('prevent_guest_comment', False),
720
+ roles=data.get('roles', []),
721
+ role_changes_every_time=data.get('role_changes_every_time', False),
722
+ created_at=data.get('created_at'),
723
+ last_updated=data.get('last_updated'),
724
+ archived_at=data.get('archived_at')
725
+ )
726
+
727
+
728
+ @dataclass
729
+ class Task:
730
+ """Task data model"""
731
+ id: str
732
+ increment_id: int
733
+ title: str
734
+ original_title: str
735
+ allow_guest_owners: bool
736
+ run_id: Optional[str] = None
737
+ checklist_id: Optional[str] = None
738
+ linked_step_id: Optional[str] = None
739
+ step_id: Optional[str] = None
740
+ alias: Optional[str] = None
741
+ taskdata: Optional[Dict[str, Any]] = None
742
+ owners: Optional[TaskOwners] = None
743
+ step: Optional[Step] = None
744
+ run: Optional[Run] = None
745
+ is_completable: bool = True
746
+ status: str = "not-started"
747
+ status_label: str = "not-started"
748
+ task_type: str = "task"
749
+ is_approved: Optional[bool] = None
750
+ position: int = 0
751
+ started_at: Optional[str] = None
752
+ deadline: Optional[str] = None
753
+ created_at: Optional[str] = None
754
+ last_updated: Optional[str] = None
755
+ archived_at: Optional[str] = None
756
+ completed_at: Optional[str] = None
757
+ starter_id: Optional[int] = None
758
+ completer_id: Optional[int] = None
759
+ is_oneoff_task: bool = False
760
+ everyone_must_complete: bool = False
761
+ completion_progress: Optional[float] = None
762
+ has_deadline_dependent_child_tasks: bool = False
763
+ can_complete_only_assignees: bool = False
764
+ max_assignable: int = 0
765
+ webhook: Optional[str] = None
766
+ prevent_guest_comment: bool = False
767
+ stage_id: Optional[str] = None
768
+ problem: bool = False
769
+ blueprint_position: Optional[int] = None
770
+ is_soft_start_date: bool = False
771
+ send_chromeless: Optional[bool] = None
772
+ run_status: Optional[str] = None
773
+ completer_guest: Optional[str] = None
774
+
775
+ @classmethod
776
+ def from_dict(cls, data: Dict[str, Any]) -> 'Task':
777
+ """Create Task instance from dictionary"""
778
+ owners_data = data.get('owners')
779
+ owners = TaskOwners.from_dict(owners_data) if owners_data else None
780
+
781
+ try:
782
+ step_data = data.get('step')['data']
783
+ step = Step.from_dict(step_data) if step_data else None
784
+ except:
785
+ step = None
786
+
787
+ try:
788
+ run_data = data.get('run')['data']
789
+ run = Run.from_dict(run_data) if run_data else None
790
+ except:
791
+ run = None
792
+
793
+ return cls(
794
+ id=data.get('id', ''),
795
+ increment_id=data.get('increment_id', 0),
796
+ title=data.get('title', ''),
797
+ original_title=data.get('original_title', ''),
798
+ allow_guest_owners=data.get('allow_guest_owners', False),
799
+ run_id=data.get('run_id'),
800
+ checklist_id=data.get('checklist_id'),
801
+ linked_step_id=data.get('linked_step_id'),
802
+ step_id=data.get('step_id'),
803
+ alias=data.get('alias'),
804
+ taskdata=data.get('taskdata', {}),
805
+ owners=owners,
806
+ step=step,
807
+ run=run,
808
+ is_completable=data.get('is_completable', True),
809
+ status=data.get('status', 'not-started'),
810
+ status_label=data.get('status_label', 'not-started'),
811
+ task_type=data.get('task_type', 'task'),
812
+ is_approved=data.get('is_approved'),
813
+ position=data.get('position', 0),
814
+ started_at=data.get('started_at'),
815
+ deadline=data.get('deadline'),
816
+ created_at=data.get('created_at'),
817
+ last_updated=data.get('last_updated'),
818
+ archived_at=data.get('archived_at'),
819
+ completed_at=data.get('completed_at'),
820
+ starter_id=data.get('starter_id'),
821
+ completer_id=data.get('completer_id'),
822
+ is_oneoff_task=data.get('is_oneoff_task', False),
823
+ everyone_must_complete=data.get('everyone_must_complete', False),
824
+ completion_progress=data.get('completion_progress'),
825
+ has_deadline_dependent_child_tasks=data.get('has_deadline_dependent_child_tasks', False),
826
+ can_complete_only_assignees=data.get('can_complete_only_assignees', False),
827
+ max_assignable=data.get('max_assignable', 0),
828
+ webhook=data.get('webhook'),
829
+ prevent_guest_comment=data.get('prevent_guest_comment', False),
830
+ stage_id=data.get('stage_id'),
831
+ problem=data.get('problem', False),
832
+ blueprint_position=data.get('blueprint_position'),
833
+ is_soft_start_date=data.get('is_soft_start_date', False),
834
+ send_chromeless=data.get('send_chromeless'),
835
+ run_status=data.get('run_status'),
836
+ completer_guest=data.get('completer_guest')
837
+ )
838
+
839
+ @dataclass
840
+ class Template:
841
+ """Template data model"""
842
+ id: str
843
+ title: str
844
+ summary: Optional[str] = None
845
+ starred: bool = True
846
+ webhook: Optional[str] = None
847
+ explanation_video: Optional[str] = None
848
+ guidance: Optional[str] = None
849
+ icon: Optional[str] = None
850
+ alias: Optional[str] = None
851
+ prerun: List[PrerunField] = None
852
+ automated_actions: List[AutomatedAction] = None
853
+ steps: List[Step] = None
854
+ created_by: Optional[int] = None
855
+ owner_id: Optional[int] = None
856
+ started_processes: int = 0
857
+ kickoff_title: Optional[str] = None
858
+ kickoff_description: Optional[str] = None
859
+ created_at: Optional[str] = None
860
+ last_updated: Optional[str] = None
861
+ archived_at: Optional[str] = None
862
+ is_public: bool = True
863
+ is_featured: bool = True
864
+ users: List[int] = None
865
+ groups: List[str] = None
866
+ public_cover: Optional[str] = None
867
+ industry_tags: List[Tag] = None
868
+ topic_tags: List[Tag] = None
869
+ type: Optional[str] = None
870
+ default_process_name_format: Optional[str] = None
871
+ is_public_kickoff: bool = True
872
+ dual_version_enabled: bool = True
873
+ is_published_state: bool = True
874
+ auto_naming: bool = True
875
+ last_updated_by: Optional[str] = None
876
+ linked_tasks: List[Task] = None
877
+ folderize_process: bool = True
878
+ tag_process: bool = True
879
+ allow_launcher_change_name: bool = True
880
+ is_pinned: bool = True
881
+ ko_form_blueprint_id: Optional[str] = None
882
+ default_folder: Optional[str] = None
883
+ folder_changeable_by_launcher: bool = True
884
+ kickoff_sharing_user_id: Optional[int] = None
885
+
886
+ def __post_init__(self):
887
+ """Initialize empty lists if None"""
888
+ if self.prerun is None:
889
+ self.prerun = []
890
+ if self.automated_actions is None:
891
+ self.automated_actions = []
892
+ if self.users is None:
893
+ self.users = []
894
+ if self.groups is None:
895
+ self.groups = []
896
+ if self.industry_tags is None:
897
+ self.industry_tags = []
898
+ if self.topic_tags is None:
899
+ self.topic_tags = []
900
+ if self.linked_tasks is None:
901
+ self.linked_tasks = []
902
+ if self.steps is None:
903
+ self.steps = []
904
+
905
+ @classmethod
906
+ def from_dict(cls, data: Dict[str, Any]) -> 'Template':
907
+ """Create Template instance from dictionary"""
908
+ prerun_data = data.get('prerun', [])
909
+ prerun = [PrerunField.from_dict(field_data) for field_data in prerun_data] if prerun_data else []
910
+
911
+ automated_actions_data = data.get('automated_actions', [])
912
+ automated_actions = [AutomatedAction.from_dict(action_data) for action_data in automated_actions_data] if automated_actions_data else []
913
+
914
+ steps_data = data.get('steps', [])
915
+ steps = [Step.from_dict(step_data) for step_data in
916
+ steps_data['data']] if steps_data else []
917
+
918
+ industry_tags_data = data.get('industry_tags', [])
919
+ industry_tags = [Tag.from_dict(tag_data) for tag_data in industry_tags_data] if industry_tags_data else []
920
+
921
+ topic_tags_data = data.get('topic_tags', [])
922
+ topic_tags = [Tag.from_dict(tag_data) for tag_data in topic_tags_data] if topic_tags_data else []
923
+
924
+ linked_tasks_data = data.get('linked_tasks', [])
925
+ linked_tasks = [Task.from_dict(task_data) for task_data in linked_tasks_data] if linked_tasks_data else []
926
+
927
+ return cls(
928
+ id=data.get('id', ''),
929
+ title=data.get('title', ''),
930
+ summary=data.get('summary'),
931
+ starred=data.get('starred', True),
932
+ webhook=data.get('webhook'),
933
+ explanation_video=data.get('explanation_video'),
934
+ guidance=data.get('guidance'),
935
+ icon=data.get('icon'),
936
+ alias=data.get('alias'),
937
+ prerun=prerun,
938
+ automated_actions=automated_actions,
939
+ steps=steps,
940
+ created_by=data.get('created_by'),
941
+ owner_id=data.get('owner_id'),
942
+ started_processes=data.get('started_processes', 0),
943
+ kickoff_title=data.get('kickoff_title'),
944
+ kickoff_description=data.get('kickoff_description'),
945
+ created_at=data.get('created_at'),
946
+ last_updated=data.get('last_updated'),
947
+ archived_at=data.get('archived_at'),
948
+ is_public=data.get('is_public', True),
949
+ is_featured=data.get('is_featured', True),
950
+ users=data.get('users', []),
951
+ groups=data.get('groups', []),
952
+ public_cover=data.get('public_cover'),
953
+ industry_tags=industry_tags,
954
+ topic_tags=topic_tags,
955
+ type=data.get('type'),
956
+ default_process_name_format=data.get('default_process_name_format'),
957
+ is_public_kickoff=data.get('is_public_kickoff', True),
958
+ dual_version_enabled=data.get('dual_version_enabled', True),
959
+ is_published_state=data.get('is_published_state', True),
960
+ auto_naming=data.get('auto_naming', True),
961
+ last_updated_by=data.get('last_updated_by'),
962
+ linked_tasks=linked_tasks,
963
+ folderize_process=data.get('folderize_process', True),
964
+ tag_process=data.get('tag_process', True),
965
+ allow_launcher_change_name=data.get('allow_launcher_change_name', True),
966
+ is_pinned=data.get('is_pinned', True),
967
+ ko_form_blueprint_id=data.get('ko_form_blueprint_id'),
968
+ default_folder=data.get('default_folder'),
969
+ folder_changeable_by_launcher=data.get('folder_changeable_by_launcher', True),
970
+ kickoff_sharing_user_id=data.get('kickoff_sharing_user_id')
971
+ )
972
+
973
+
974
+
975
+ @dataclass
976
+ class SearchResult:
977
+ """Search result data model for templates, processes, and tasks"""
978
+ id: str
979
+ increment_id: int
980
+ search_type: str
981
+
982
+ # Common fields
983
+ name: Optional[str] = None
984
+ title: Optional[str] = None
985
+ status: Optional[str] = None
986
+ type: Optional[str] = None
987
+
988
+ # Template-specific fields
989
+ steps_count: Optional[int] = None
990
+ icon: Optional[str] = None
991
+ is_public: Optional[bool] = None
992
+ is_featured: Optional[bool] = None
993
+ organization_id: Optional[str] = None
994
+ folders: Optional[List[Folder]] = None
995
+
996
+ # Process-specific fields
997
+ due_date_passed: Optional[bool] = None
998
+ due_soon: Optional[bool] = None
999
+
1000
+ # Task-specific fields
1001
+ status_label: Optional[str] = None
1002
+ position: Optional[int] = None
1003
+ deadline: Optional[str] = None
1004
+ created_at: Optional[str] = None
1005
+ starter_id: Optional[int] = None
1006
+ is_oneoff_task: Optional[bool] = None
1007
+ owners: Optional[TaskOwners] = None
1008
+
1009
+ def __post_init__(self):
1010
+ """Initialize empty lists if None"""
1011
+ if self.folders is None:
1012
+ self.folders = []
1013
+
1014
+ @classmethod
1015
+ def from_dict(cls, data: Dict[str, Any], search_type: str) -> 'SearchResult':
1016
+ """Create SearchResult instance from dictionary"""
1017
+ folders_data = data.get('folders', [])
1018
+ folders = [Folder.from_dict(folder_data) for folder_data in folders_data] if folders_data else []
1019
+
1020
+ owners_data = data.get('owners')
1021
+ owners = TaskOwners.from_dict(owners_data) if owners_data else None
1022
+
1023
+ return cls(
1024
+ id=data.get('id', ''),
1025
+ increment_id=data.get('increment_id', 0),
1026
+ search_type=search_type,
1027
+ name=data.get('name'),
1028
+ title=data.get('title'),
1029
+ status=data.get('status'),
1030
+ type=data.get('type'),
1031
+ steps_count=data.get('steps_count'),
1032
+ icon=data.get('icon'),
1033
+ is_public=data.get('is_public'),
1034
+ is_featured=data.get('is_featured'),
1035
+ organization_id=data.get('organization_id'),
1036
+ folders=folders,
1037
+ due_date_passed=data.get('due_date_passed'),
1038
+ due_soon=data.get('due_soon'),
1039
+ status_label=data.get('status_label'),
1040
+ position=data.get('position'),
1041
+ deadline=data.get('deadline'),
1042
+ created_at=data.get('created_at'),
1043
+ starter_id=data.get('starter_id'),
1044
+ is_oneoff_task=data.get('is_oneoff_task'),
1045
+ owners=owners
1046
+ )
1047
+
1048
+
1049
+ @dataclass
1050
+ class PaginationLinks:
1051
+ """Pagination links data model"""
1052
+ next: Optional[str] = None
1053
+ prev: Optional[str] = None
1054
+
1055
+ @classmethod
1056
+ def from_dict(cls, data: Dict[str, Any]) -> 'PaginationLinks':
1057
+ """Create PaginationLinks instance from dictionary"""
1058
+ return cls(
1059
+ next=data.get('next'),
1060
+ prev=data.get('prev')
1061
+ )
1062
+
1063
+
1064
+ @dataclass
1065
+ class PaginationMeta:
1066
+ """Pagination metadata model"""
1067
+ total: int
1068
+ count: int
1069
+ per_page: int
1070
+ current_page: int
1071
+ total_pages: int
1072
+ links: Optional[PaginationLinks] = None
1073
+
1074
+ @classmethod
1075
+ def from_dict(cls, data: Dict[str, Any]) -> 'PaginationMeta':
1076
+ """Create PaginationMeta instance from dictionary"""
1077
+ links_data = data.get('links', {})
1078
+ links = PaginationLinks.from_dict(links_data) if links_data else None
1079
+
1080
+ return cls(
1081
+ total=data.get('total', 0),
1082
+ count=data.get('count', 0),
1083
+ per_page=data.get('per_page', 0),
1084
+ current_page=data.get('current_page', 1),
1085
+ total_pages=data.get('total_pages', 0),
1086
+ links=links
1087
+ )
1088
+
1089
+
1090
+ @dataclass
1091
+ class OrganizationWorkingDays:
1092
+ """Organization working days configuration"""
1093
+ Monday: Optional[Dict[str, Any]] = None
1094
+ Tuesday: Optional[Dict[str, Any]] = None
1095
+ Wednesday: Optional[Dict[str, Any]] = None
1096
+ Thursday: Optional[Dict[str, Any]] = None
1097
+ Friday: Optional[Dict[str, Any]] = None
1098
+ Saturday: Optional[Dict[str, Any]] = None
1099
+ Sunday: Optional[Dict[str, Any]] = None
1100
+
1101
+ @classmethod
1102
+ def from_dict(cls, data: Dict[str, Any]) -> 'OrganizationWorkingDays':
1103
+ """Create OrganizationWorkingDays instance from dictionary"""
1104
+ return cls(
1105
+ Monday=data.get('Monday'),
1106
+ Tuesday=data.get('Tuesday'),
1107
+ Wednesday=data.get('Wednesday'),
1108
+ Thursday=data.get('Thursday'),
1109
+ Friday=data.get('Friday'),
1110
+ Saturday=data.get('Saturday'),
1111
+ Sunday=data.get('Sunday')
1112
+ )
1113
+
1114
+
1115
+ @dataclass
1116
+ class OrganizationDefaultDeadline:
1117
+ """Organization default deadline configuration"""
1118
+ type: str = "days"
1119
+ value: int = 5
1120
+
1121
+ @classmethod
1122
+ def from_dict(cls, data: Dict[str, Any]) -> 'OrganizationDefaultDeadline':
1123
+ """Create OrganizationDefaultDeadline instance from dictionary"""
1124
+ return cls(
1125
+ type=data.get('type', 'days'),
1126
+ value=data.get('value', 5)
1127
+ )
1128
+
1129
+
1130
+ @dataclass
1131
+ class OrganizationAutoArchive:
1132
+ """Organization auto archive configuration"""
1133
+ unit: str = "weeks"
1134
+ value: int = 52
1135
+
1136
+ @classmethod
1137
+ def from_dict(cls, data: Dict[str, Any]) -> 'OrganizationAutoArchive':
1138
+ """Create OrganizationAutoArchive instance from dictionary"""
1139
+ return cls(
1140
+ unit=data.get('unit', 'weeks'),
1141
+ value=data.get('value', 52)
1142
+ )
1143
+
1144
+
1145
+ @dataclass
1146
+ class Organization:
1147
+ """Organization data model"""
1148
+ id: str
1149
+ name: str
1150
+ industry: Optional[str] = None
1151
+ description: Optional[str] = None
1152
+ address1: Optional[str] = None
1153
+ address2: Optional[str] = None
1154
+ created_on: Optional[str] = None
1155
+ last_updated: Optional[str] = None
1156
+ live_support_enabled: int = 0
1157
+ org_logo: Optional[str] = None
1158
+ settings: Optional[str] = None
1159
+ country: Optional[str] = None
1160
+ state: Optional[str] = None
1161
+ city: Optional[str] = None
1162
+ zipcode: Optional[str] = None
1163
+ users_count: int = 0
1164
+ payment_state: Optional[str] = None
1165
+ team_size: Optional[List[int]] = None
1166
+ signup_survey: Optional[str] = None
1167
+ in_trial: bool = False
1168
+ analytics_enabled: bool = True
1169
+ limit_trial_features: bool = False
1170
+ real_time_billing: bool = True
1171
+ saml_enabled: bool = False
1172
+ saml_login_url: Optional[str] = None
1173
+ sso_default_role: Optional[str] = None
1174
+ preferred_trial_plan: Optional[str] = None
1175
+ google_analytics_id: Optional[str] = None
1176
+ mixpanel_token: Optional[str] = None
1177
+ plan_code: Optional[str] = None
1178
+ auto_join_signups: bool = False
1179
+ home_bg: Optional[str] = None
1180
+ guest_onboarding_snippet: Optional[str] = None
1181
+ maximum_group_assignment_limit: int = 0
1182
+ allow_user_invite: bool = True
1183
+ allow_manage_groups: bool = True
1184
+ working_days: Optional[OrganizationWorkingDays] = None
1185
+ deadline_setting: Optional[str] = None
1186
+ wyiwyg: bool = True
1187
+ cadence_days: Optional[List[str]] = None
1188
+ guest_cadence_days: Optional[List[str]] = None
1189
+ timezone: Optional[str] = None
1190
+ default_deadline: Optional[OrganizationDefaultDeadline] = None
1191
+ auto_archive: bool = False
1192
+ auto_complete_tasks: bool = True
1193
+ auto_complete_task_months: int = 18
1194
+ light_role_error_snippet: Optional[str] = None
1195
+ azure_cognitive_service: Optional[str] = None
1196
+ global_css: Optional[str] = None
1197
+ error_404_template: Optional[str] = None
1198
+ enable_custom_404_error: bool = False
1199
+ enable_custom_smtp: bool = False
1200
+ onboarding_template_id: Optional[str] = None
1201
+ enable_onboarding_template: bool = True
1202
+ disable_min_members_billing: bool = False
1203
+ enable_light_users_billing: bool = False
1204
+ webhook_date_field_format: str = "yyyy-MM-ddTHH:mm:ssZ"
1205
+ purpose: Optional[str] = None
1206
+ process_today: Optional[str] = None
1207
+ restrict_blueprint_permissions: bool = False
1208
+ auto_archive_processes_after: Optional[OrganizationAutoArchive] = None
1209
+ use_generative_ai: bool = True
1210
+ homepage_snippet: Optional[str] = None
1211
+ onboarding_snippet: Optional[str] = None
1212
+ disabled_on: Optional[str] = None
1213
+ last_accessed: Optional[str] = None
1214
+ user_role: Optional[str] = None
1215
+
1216
+ def __post_init__(self):
1217
+ """Initialize empty lists if None"""
1218
+ if self.team_size is None:
1219
+ self.team_size = []
1220
+ if self.cadence_days is None:
1221
+ self.cadence_days = []
1222
+ if self.guest_cadence_days is None:
1223
+ self.guest_cadence_days = []
1224
+
1225
+ @classmethod
1226
+ def from_dict(cls, data: Dict[str, Any]) -> 'Organization':
1227
+ """Create Organization instance from dictionary"""
1228
+ working_days_data = data.get('working_days')
1229
+ working_days = OrganizationWorkingDays.from_dict(working_days_data) if working_days_data else None
1230
+
1231
+ default_deadline_data = data.get('default_deadline')
1232
+ default_deadline = OrganizationDefaultDeadline.from_dict(default_deadline_data) if default_deadline_data else None
1233
+
1234
+ auto_archive_processes_after_data = data.get('auto_archive_processes_after')
1235
+ auto_archive_processes_after = OrganizationAutoArchive.from_dict(auto_archive_processes_after_data) if auto_archive_processes_after_data else None
1236
+
1237
+ return cls(
1238
+ id=data.get('id', ''),
1239
+ name=data.get('name', ''),
1240
+ industry=data.get('industry'),
1241
+ description=data.get('description'),
1242
+ address1=data.get('address1'),
1243
+ address2=data.get('address2'),
1244
+ created_on=data.get('created_on'),
1245
+ last_updated=data.get('last_updated'),
1246
+ live_support_enabled=data.get('live_support_enabled', 0),
1247
+ org_logo=data.get('org_logo'),
1248
+ settings=data.get('settings'),
1249
+ country=data.get('country'),
1250
+ state=data.get('state'),
1251
+ city=data.get('city'),
1252
+ zipcode=data.get('zipcode'),
1253
+ users_count=data.get('users_count', 0),
1254
+ payment_state=data.get('payment_state'),
1255
+ team_size=data.get('team_size', []),
1256
+ signup_survey=data.get('signup_survey'),
1257
+ in_trial=data.get('in_trial', False),
1258
+ analytics_enabled=data.get('analytics_enabled', True),
1259
+ limit_trial_features=data.get('limit_trial_features', False),
1260
+ real_time_billing=data.get('real_time_billing', True),
1261
+ saml_enabled=data.get('saml_enabled', False),
1262
+ saml_login_url=data.get('saml_login_url'),
1263
+ sso_default_role=data.get('sso_default_role'),
1264
+ preferred_trial_plan=data.get('preferred_trial_plan'),
1265
+ google_analytics_id=data.get('google_analytics_id'),
1266
+ mixpanel_token=data.get('mixpanel_token'),
1267
+ plan_code=data.get('plan_code'),
1268
+ auto_join_signups=data.get('auto_join_signups', False),
1269
+ home_bg=data.get('home_bg'),
1270
+ guest_onboarding_snippet=data.get('guest_onboarding_snippet'),
1271
+ maximum_group_assignment_limit=data.get('maximum_group_assignment_limit', 0),
1272
+ allow_user_invite=data.get('allow_user_invite', True),
1273
+ allow_manage_groups=data.get('allow_manage_groups', True),
1274
+ working_days=working_days,
1275
+ deadline_setting=data.get('deadline_setting'),
1276
+ wyiwyg=data.get('wyiwyg', True),
1277
+ cadence_days=data.get('cadence_days', []),
1278
+ guest_cadence_days=data.get('guest_cadence_days', []),
1279
+ timezone=data.get('timezone'),
1280
+ default_deadline=default_deadline,
1281
+ auto_archive=data.get('auto_archive', False),
1282
+ auto_complete_tasks=data.get('auto_complete_tasks', True),
1283
+ auto_complete_task_months=data.get('auto_complete_task_months', 18),
1284
+ light_role_error_snippet=data.get('light_role_error_snippet'),
1285
+ azure_cognitive_service=data.get('azure_cognitive_service'),
1286
+ global_css=data.get('global_css'),
1287
+ error_404_template=data.get('error_404_template'),
1288
+ enable_custom_404_error=data.get('enable_custom_404_error', False),
1289
+ enable_custom_smtp=data.get('enable_custom_smtp', False),
1290
+ onboarding_template_id=data.get('onboarding_template_id'),
1291
+ enable_onboarding_template=data.get('enable_onboarding_template', True),
1292
+ disable_min_members_billing=data.get('disable_min_members_billing', False),
1293
+ enable_light_users_billing=data.get('enable_light_users_billing', False),
1294
+ webhook_date_field_format=data.get('webhook_date_field_format', 'yyyy-MM-ddTHH:mm:ssZ'),
1295
+ purpose=data.get('purpose'),
1296
+ process_today=data.get('process_today'),
1297
+ restrict_blueprint_permissions=data.get('restrict_blueprint_permissions', False),
1298
+ auto_archive_processes_after=auto_archive_processes_after,
1299
+ use_generative_ai=data.get('use_generative_ai', True),
1300
+ homepage_snippet=data.get('homepage_snippet'),
1301
+ onboarding_snippet=data.get('onboarding_snippet'),
1302
+ disabled_on=data.get('disabled_on'),
1303
+ last_accessed=data.get('last_accessed'),
1304
+ user_role=data.get('user_role')
1305
+ )
1306
+
1307
+
1308
+ @dataclass
1309
+ class OrganizationsList:
1310
+ """Organizations list response with pagination"""
1311
+ data: List[Organization]
1312
+ meta: PaginationMeta
1313
+
1314
+ @classmethod
1315
+ def from_dict(cls, data: Dict[str, Any]) -> 'OrganizationsList':
1316
+ """Create OrganizationsList instance from dictionary"""
1317
+ organizations_data = data.get('data', [])
1318
+ organizations = [Organization.from_dict(org_data) for org_data in organizations_data]
1319
+
1320
+ meta_data = data.get('meta', {})
1321
+ pagination_meta = meta_data.get('pagination', {})
1322
+ meta = PaginationMeta.from_dict(pagination_meta)
1323
+
1324
+ return cls(
1325
+ data=organizations,
1326
+ meta=meta
1327
+ )
1328
+
1329
+
1330
+ @dataclass
1331
+ class TemplatesList:
1332
+ """Templates list response with pagination"""
1333
+ data: List[Template]
1334
+ meta: PaginationMeta
1335
+
1336
+ @classmethod
1337
+ def from_dict(cls, data: Dict[str, Any]) -> 'TemplatesList':
1338
+ """Create TemplatesList instance from dictionary"""
1339
+ templates_data = data.get('data', [])
1340
+ templates = [Template.from_dict(template_data) for template_data in templates_data]
1341
+
1342
+ meta_data = data.get('meta', {})
1343
+ pagination_meta = meta_data.get('pagination', {})
1344
+ meta = PaginationMeta.from_dict(pagination_meta)
1345
+
1346
+ return cls(
1347
+ data=templates,
1348
+ meta=meta
1349
+ )
1350
+
1351
+
1352
+ @dataclass
1353
+ class UsersList:
1354
+ """Users list response with pagination"""
1355
+ data: List[User]
1356
+ meta: PaginationMeta
1357
+
1358
+ @classmethod
1359
+ def from_dict(cls, data: Dict[str, Any]) -> 'UsersList':
1360
+ """Create UsersList instance from dictionary"""
1361
+ users_data = data.get('data', [])
1362
+ users = [User.from_dict(user_data) for user_data in users_data]
1363
+
1364
+ meta_data = data.get('meta', {})
1365
+ pagination_meta = meta_data.get('pagination', {})
1366
+ meta = PaginationMeta.from_dict(pagination_meta)
1367
+
1368
+ return cls(
1369
+ data=users,
1370
+ meta=meta
1371
+ )
1372
+
1373
+
1374
+ @dataclass
1375
+ class GuestsList:
1376
+ """Guests list response with pagination"""
1377
+ data: List[Guest]
1378
+ meta: PaginationMeta
1379
+
1380
+ @classmethod
1381
+ def from_dict(cls, data: Dict[str, Any]) -> 'GuestsList':
1382
+ """Create GuestsList instance from dictionary"""
1383
+ guests_data = data.get('data', [])
1384
+ guests = [Guest.from_dict(guest_data) for guest_data in guests_data]
1385
+
1386
+ meta_data = data.get('meta', {})
1387
+ pagination_meta = meta_data.get('pagination', {})
1388
+ meta = PaginationMeta.from_dict(pagination_meta)
1389
+
1390
+ return cls(
1391
+ data=guests,
1392
+ meta=meta
1393
+ )
1394
+
1395
+
1396
+ @dataclass
1397
+ class TasksList:
1398
+ """Tasks list response with pagination"""
1399
+ data: List[Task]
1400
+ meta: PaginationMeta
1401
+
1402
+ @classmethod
1403
+ def from_dict(cls, data: Dict[str, Any]) -> 'TasksList':
1404
+ """Create TasksList instance from dictionary"""
1405
+ tasks_data = data.get('data', [])
1406
+ tasks = [Task.from_dict(task_data) for task_data in tasks_data]
1407
+
1408
+ meta_data = data.get('meta', {})
1409
+ pagination_meta = meta_data.get('pagination', {})
1410
+ meta = PaginationMeta.from_dict(pagination_meta)
1411
+
1412
+ return cls(
1413
+ data=tasks,
1414
+ meta=meta
1415
+ )
1416
+
1417
+
1418
+ @dataclass
1419
+ class RunsList:
1420
+ """Runs (Processes) list response with pagination"""
1421
+ data: List[Run]
1422
+ meta: PaginationMeta
1423
+
1424
+ @classmethod
1425
+ def from_dict(cls, data: Dict[str, Any]) -> 'RunsList':
1426
+ """Create RunsList instance from dictionary"""
1427
+ runs_data = data.get('data', [])
1428
+ runs = [Run.from_dict(run_data) for run_data in runs_data]
1429
+
1430
+ meta_data = data.get('meta', {})
1431
+ pagination_meta = meta_data.get('pagination', {})
1432
+ meta = PaginationMeta.from_dict(pagination_meta)
1433
+
1434
+ return cls(
1435
+ data=runs,
1436
+ meta=meta
1437
+ )
1438
+
1439
+
1440
+ @dataclass
1441
+ class SearchResultsList:
1442
+ """Search results list response with pagination"""
1443
+ data: List[SearchResult]
1444
+ meta: PaginationMeta
1445
+ search_type: str
1446
+
1447
+ @classmethod
1448
+ def from_dict(cls, data: Dict[str, Any], search_type: str) -> 'SearchResultsList':
1449
+ """Create SearchResultsList instance from dictionary"""
1450
+ # Search response has results nested under the search type key
1451
+ type_data = data.get(search_type, {})
1452
+ results_data = type_data.get('data', [])
1453
+ results = [SearchResult.from_dict(result_data, search_type) for result_data in results_data]
1454
+
1455
+ # Get pagination from the nested type data
1456
+ meta_data = type_data.get('meta', {})
1457
+ pagination_meta = meta_data.get('pagination', {})
1458
+ meta = PaginationMeta.from_dict(pagination_meta)
1459
+
1460
+ return cls(
1461
+ data=results,
1462
+ meta=meta,
1463
+ search_type=search_type
1464
+ )