constec 0.5.3__tar.gz → 0.6.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. {constec-0.5.3 → constec-0.6.0}/PKG-INFO +1 -1
  2. constec-0.6.0/constec/db/migrations/0008_refactor_creator_fields.py +173 -0
  3. {constec-0.5.3 → constec-0.6.0}/constec/db/models/__init__.py +1 -2
  4. {constec-0.5.3 → constec-0.6.0}/constec/db/models/automation.py +75 -99
  5. {constec-0.5.3 → constec-0.6.0}/constec.egg-info/PKG-INFO +1 -1
  6. {constec-0.5.3 → constec-0.6.0}/constec.egg-info/SOURCES.txt +1 -0
  7. {constec-0.5.3 → constec-0.6.0}/pyproject.toml +1 -1
  8. {constec-0.5.3 → constec-0.6.0}/LICENSE +0 -0
  9. {constec-0.5.3 → constec-0.6.0}/README.md +0 -0
  10. {constec-0.5.3 → constec-0.6.0}/constec/db/__init__.py +0 -0
  11. {constec-0.5.3 → constec-0.6.0}/constec/db/apps.py +0 -0
  12. {constec-0.5.3 → constec-0.6.0}/constec/db/migrations/0001_initial.py +0 -0
  13. {constec-0.5.3 → constec-0.6.0}/constec/db/migrations/0002_module_level.py +0 -0
  14. {constec-0.5.3 → constec-0.6.0}/constec/db/migrations/0003_remove_module_level.py +0 -0
  15. {constec-0.5.3 → constec-0.6.0}/constec/db/migrations/0004_rename_entities_company_cuit_idx_entities_company_e2c50f_idx_and_more.py +0 -0
  16. {constec-0.5.3 → constec-0.6.0}/constec/db/migrations/0005_event.py +0 -0
  17. {constec-0.5.3 → constec-0.6.0}/constec/db/migrations/0006_automation_trigger_action_executionlog_notificationtemplate.py +0 -0
  18. {constec-0.5.3 → constec-0.6.0}/constec/db/migrations/0007_add_organization_to_automations.py +0 -0
  19. {constec-0.5.3 → constec-0.6.0}/constec/db/migrations/__init__.py +0 -0
  20. {constec-0.5.3 → constec-0.6.0}/constec/db/models/base.py +0 -0
  21. {constec-0.5.3 → constec-0.6.0}/constec/db/models/company.py +0 -0
  22. {constec-0.5.3 → constec-0.6.0}/constec/db/models/contact.py +0 -0
  23. {constec-0.5.3 → constec-0.6.0}/constec/db/models/erp.py +0 -0
  24. {constec-0.5.3 → constec-0.6.0}/constec/db/models/erp_entity.py +0 -0
  25. {constec-0.5.3 → constec-0.6.0}/constec/db/models/flow.py +0 -0
  26. {constec-0.5.3 → constec-0.6.0}/constec/db/models/group.py +0 -0
  27. {constec-0.5.3 → constec-0.6.0}/constec/db/models/module.py +0 -0
  28. {constec-0.5.3 → constec-0.6.0}/constec/db/models/organization.py +0 -0
  29. {constec-0.5.3 → constec-0.6.0}/constec/db/models/person.py +0 -0
  30. {constec-0.5.3 → constec-0.6.0}/constec/db/models/session.py +0 -0
  31. {constec-0.5.3 → constec-0.6.0}/constec/db/models/tag.py +0 -0
  32. {constec-0.5.3 → constec-0.6.0}/constec/db/models/user.py +0 -0
  33. {constec-0.5.3 → constec-0.6.0}/constec/py.typed +0 -0
  34. {constec-0.5.3 → constec-0.6.0}/constec/services/__init__.py +0 -0
  35. {constec-0.5.3 → constec-0.6.0}/constec/services/encryption.py +0 -0
  36. {constec-0.5.3 → constec-0.6.0}/constec/shared/__init__.py +0 -0
  37. {constec-0.5.3 → constec-0.6.0}/constec/shared/exceptions.py +0 -0
  38. {constec-0.5.3 → constec-0.6.0}/constec/utils/__init__.py +0 -0
  39. {constec-0.5.3 → constec-0.6.0}/constec/utils/cuit.py +0 -0
  40. {constec-0.5.3 → constec-0.6.0}/constec/utils/password.py +0 -0
  41. {constec-0.5.3 → constec-0.6.0}/constec.egg-info/dependency_links.txt +0 -0
  42. {constec-0.5.3 → constec-0.6.0}/constec.egg-info/requires.txt +0 -0
  43. {constec-0.5.3 → constec-0.6.0}/constec.egg-info/top_level.txt +0 -0
  44. {constec-0.5.3 → constec-0.6.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: constec
3
- Version: 0.5.3
3
+ Version: 0.6.0
4
4
  Summary: Base library for the Constec ecosystem - shared utilities, models, and namespace foundation
5
5
  License: MIT
6
6
  Project-URL: Homepage, https://github.com/TpmyCT/constec-python
@@ -0,0 +1,173 @@
1
+ # Generated manually - Refactor creator fields to support User and OrganizationUser
2
+
3
+ from django.db import migrations, models
4
+ import django.db.models.deletion
5
+
6
+
7
+ def migrate_creator_data(apps, schema_editor):
8
+ """Migrate existing created_by data to created_by_user."""
9
+ Automation = apps.get_model('constec_db', 'Automation')
10
+ NotificationTemplate = apps.get_model('constec_db', 'NotificationTemplate')
11
+
12
+ # Migrate Automation creators
13
+ for automation in Automation.objects.all():
14
+ if automation.created_by:
15
+ automation.created_by_user = automation.created_by
16
+ automation.save(update_fields=['created_by_user'])
17
+
18
+ # Migrate NotificationTemplate creators
19
+ for template in NotificationTemplate.objects.all():
20
+ if template.created_by:
21
+ template.created_by_user = template.created_by
22
+ template.save(update_fields=['created_by_user'])
23
+
24
+
25
+ class Migration(migrations.Migration):
26
+
27
+ dependencies = [
28
+ ('constec_db', '0007_add_organization_to_automations'),
29
+ ]
30
+
31
+ operations = [
32
+ # 1. Add new creator fields to Automation (nullable temporarily for data migration)
33
+ migrations.AddField(
34
+ model_name='automation',
35
+ name='created_by_user',
36
+ field=models.ForeignKey(
37
+ blank=True,
38
+ help_text='User creator (company-level)',
39
+ null=True,
40
+ on_delete=django.db.models.deletion.CASCADE,
41
+ related_name='created_automations',
42
+ to='constec_db.user'
43
+ ),
44
+ ),
45
+ migrations.AddField(
46
+ model_name='automation',
47
+ name='created_by_org_user',
48
+ field=models.ForeignKey(
49
+ blank=True,
50
+ help_text='OrganizationUser creator (org-level)',
51
+ null=True,
52
+ on_delete=django.db.models.deletion.CASCADE,
53
+ related_name='created_automations',
54
+ to='constec_db.organizationuser'
55
+ ),
56
+ ),
57
+
58
+ # 2. Add new creator fields to NotificationTemplate (nullable temporarily for data migration)
59
+ migrations.AddField(
60
+ model_name='notificationtemplate',
61
+ name='created_by_user',
62
+ field=models.ForeignKey(
63
+ blank=True,
64
+ help_text='User creator (company-level)',
65
+ null=True,
66
+ on_delete=django.db.models.deletion.CASCADE,
67
+ related_name='created_templates',
68
+ to='constec_db.user'
69
+ ),
70
+ ),
71
+ migrations.AddField(
72
+ model_name='notificationtemplate',
73
+ name='created_by_org_user',
74
+ field=models.ForeignKey(
75
+ blank=True,
76
+ help_text='OrganizationUser creator (org-level)',
77
+ null=True,
78
+ on_delete=django.db.models.deletion.CASCADE,
79
+ related_name='created_templates',
80
+ to='constec_db.organizationuser'
81
+ ),
82
+ ),
83
+
84
+ # 3. Add triggered_by_org_user to ExecutionLog
85
+ migrations.AddField(
86
+ model_name='executionlog',
87
+ name='triggered_by_org_user',
88
+ field=models.ForeignKey(
89
+ blank=True,
90
+ help_text='OrganizationUser who triggered execution (org-level)',
91
+ null=True,
92
+ on_delete=django.db.models.deletion.SET_NULL,
93
+ related_name='triggered_executions',
94
+ to='constec_db.organizationuser'
95
+ ),
96
+ ),
97
+
98
+ # 4. Update existing triggered_by_user field help text
99
+ migrations.AlterField(
100
+ model_name='executionlog',
101
+ name='triggered_by_user',
102
+ field=models.ForeignKey(
103
+ blank=True,
104
+ help_text='User who triggered execution (company-level)',
105
+ null=True,
106
+ on_delete=django.db.models.deletion.SET_NULL,
107
+ related_name='triggered_executions',
108
+ to='constec_db.user'
109
+ ),
110
+ ),
111
+
112
+ # 5. Migrate data from old created_by to new created_by_user
113
+ migrations.RunPython(migrate_creator_data, reverse_code=migrations.RunPython.noop),
114
+
115
+ # 6. Remove old created_by fields
116
+ migrations.RemoveField(
117
+ model_name='automation',
118
+ name='created_by',
119
+ ),
120
+ migrations.RemoveField(
121
+ model_name='notificationtemplate',
122
+ name='created_by',
123
+ ),
124
+
125
+ # 7. Add constraints for Automation
126
+ migrations.AddConstraint(
127
+ model_name='automation',
128
+ constraint=models.CheckConstraint(
129
+ check=models.Q(
130
+ ('created_by_user__isnull', False),
131
+ ('created_by_org_user__isnull', True)
132
+ ) | models.Q(
133
+ ('created_by_user__isnull', True),
134
+ ('created_by_org_user__isnull', False)
135
+ ),
136
+ name='automation_single_creator'
137
+ ),
138
+ ),
139
+ migrations.AddConstraint(
140
+ model_name='automation',
141
+ constraint=models.CheckConstraint(
142
+ check=models.Q(('created_by_user__isnull', False)) | models.Q(('created_by_org_user__isnull', False)),
143
+ name='automation_requires_creator'
144
+ ),
145
+ ),
146
+
147
+ # 8. Add constraints for NotificationTemplate
148
+ migrations.AddConstraint(
149
+ model_name='notificationtemplate',
150
+ constraint=models.CheckConstraint(
151
+ check=models.Q(
152
+ ('created_by_user__isnull', False),
153
+ ('created_by_org_user__isnull', True)
154
+ ) | models.Q(
155
+ ('created_by_user__isnull', True),
156
+ ('created_by_org_user__isnull', False)
157
+ ),
158
+ name='template_single_creator'
159
+ ),
160
+ ),
161
+ migrations.AddConstraint(
162
+ model_name='notificationtemplate',
163
+ constraint=models.CheckConstraint(
164
+ check=models.Q(('created_by_user__isnull', False)) | models.Q(('created_by_org_user__isnull', False)),
165
+ name='template_requires_creator'
166
+ ),
167
+ ),
168
+
169
+ # 9. Delete deprecated Event model
170
+ migrations.DeleteModel(
171
+ name='Event',
172
+ ),
173
+ ]
@@ -42,7 +42,7 @@ from .flow import FlowTemplate, Flow
42
42
  from .session import Session, Message
43
43
 
44
44
  # Automations models (automations schema)
45
- from .automation import Event, Automation, Trigger, Action, ExecutionLog, NotificationTemplate
45
+ from .automation import Automation, Trigger, Action, ExecutionLog, NotificationTemplate
46
46
 
47
47
 
48
48
  __all__ = [
@@ -93,7 +93,6 @@ __all__ = [
93
93
  'Session',
94
94
  'Message',
95
95
  # Automations (automations schema)
96
- 'Event',
97
96
  'Automation',
98
97
  'Trigger',
99
98
  'Action',
@@ -6,7 +6,7 @@ from django.db.models import Q
6
6
  from django.core.exceptions import ValidationError
7
7
  from .base import UUIDModel
8
8
  from .company import Company
9
- from .organization import Organization
9
+ from .organization import Organization, OrganizationUser
10
10
  from .user import User
11
11
 
12
12
 
@@ -53,10 +53,23 @@ class Automation(UUIDModel):
53
53
  db_index=True,
54
54
  help_text="Organization para automations compartidas (opcional si se define company)"
55
55
  )
56
- created_by = models.ForeignKey(
56
+
57
+ # Creator - only ONE of these should be filled (XOR)
58
+ created_by_user = models.ForeignKey(
57
59
  User,
58
60
  on_delete=models.CASCADE,
59
- related_name='created_automations'
61
+ null=True,
62
+ blank=True,
63
+ related_name='created_automations',
64
+ help_text="User creator (company-level)"
65
+ )
66
+ created_by_org_user = models.ForeignKey(
67
+ OrganizationUser,
68
+ on_delete=models.CASCADE,
69
+ null=True,
70
+ blank=True,
71
+ related_name='created_automations',
72
+ help_text="OrganizationUser creator (org-level)"
60
73
  )
61
74
 
62
75
  # Info básica
@@ -107,12 +120,26 @@ class Automation(UUIDModel):
107
120
  models.CheckConstraint(
108
121
  check=Q(company__isnull=False) | Q(organization__isnull=False),
109
122
  name='automation_requires_company_or_organization'
110
- )
123
+ ),
124
+ models.CheckConstraint(
125
+ check=Q(created_by_user__isnull=False) | Q(created_by_org_user__isnull=False),
126
+ name='automation_requires_creator'
127
+ ),
128
+ models.CheckConstraint(
129
+ check=Q(created_by_user__isnull=False, created_by_org_user__isnull=True) |
130
+ Q(created_by_user__isnull=True, created_by_org_user__isnull=False),
131
+ name='automation_single_creator'
132
+ ),
111
133
  ]
112
134
 
113
135
  def __str__(self):
114
136
  return f"{self.name} ({self.status})"
115
137
 
138
+ @property
139
+ def creator(self):
140
+ """Helper to access creator regardless of type."""
141
+ return self.created_by_user or self.created_by_org_user
142
+
116
143
 
117
144
  class Trigger(UUIDModel):
118
145
  """
@@ -294,7 +321,16 @@ class ExecutionLog(UUIDModel):
294
321
  on_delete=models.SET_NULL,
295
322
  null=True,
296
323
  blank=True,
297
- related_name='triggered_executions'
324
+ related_name='triggered_executions',
325
+ help_text="User who triggered execution (company-level)"
326
+ )
327
+ triggered_by_org_user = models.ForeignKey(
328
+ OrganizationUser,
329
+ on_delete=models.SET_NULL,
330
+ null=True,
331
+ blank=True,
332
+ related_name='triggered_executions',
333
+ help_text="OrganizationUser who triggered execution (org-level)"
298
334
  )
299
335
 
300
336
  # Estado
@@ -341,6 +377,11 @@ class ExecutionLog(UUIDModel):
341
377
  def __str__(self):
342
378
  return f"{self.automation.name} - {self.status} ({self.started_at})"
343
379
 
380
+ @property
381
+ def trigger_user(self):
382
+ """Helper to access trigger user regardless of type."""
383
+ return self.triggered_by_user or self.triggered_by_org_user
384
+
344
385
 
345
386
  class NotificationTemplate(UUIDModel):
346
387
  """
@@ -374,10 +415,23 @@ class NotificationTemplate(UUIDModel):
374
415
  db_index=True,
375
416
  help_text="Organization para templates compartidos (opcional si se define company)"
376
417
  )
377
- created_by = models.ForeignKey(
418
+
419
+ # Creator - only ONE of these should be filled (XOR)
420
+ created_by_user = models.ForeignKey(
378
421
  User,
379
422
  on_delete=models.CASCADE,
380
- related_name='created_templates'
423
+ null=True,
424
+ blank=True,
425
+ related_name='created_templates',
426
+ help_text="User creator (company-level)"
427
+ )
428
+ created_by_org_user = models.ForeignKey(
429
+ OrganizationUser,
430
+ on_delete=models.CASCADE,
431
+ null=True,
432
+ blank=True,
433
+ related_name='created_templates',
434
+ help_text="OrganizationUser creator (org-level)"
381
435
  )
382
436
 
383
437
  # Info básica
@@ -413,100 +467,22 @@ class NotificationTemplate(UUIDModel):
413
467
  models.CheckConstraint(
414
468
  check=Q(company__isnull=False) | Q(organization__isnull=False),
415
469
  name='template_requires_company_or_organization'
416
- )
470
+ ),
471
+ models.CheckConstraint(
472
+ check=Q(created_by_user__isnull=False) | Q(created_by_org_user__isnull=False),
473
+ name='template_requires_creator'
474
+ ),
475
+ models.CheckConstraint(
476
+ check=Q(created_by_user__isnull=False, created_by_org_user__isnull=True) |
477
+ Q(created_by_user__isnull=True, created_by_org_user__isnull=False),
478
+ name='template_single_creator'
479
+ ),
417
480
  ]
418
481
 
419
482
  def __str__(self):
420
483
  return f"{self.channel}: {self.name}"
421
484
 
422
-
423
- class Event(UUIDModel):
424
- """
425
- Evento programado con soporte para múltiples tipos y recurrencia flexible.
426
-
427
- Tipos soportados:
428
- - notification: Notificaciones programadas
429
- - automation: Automatizaciones programadas (acciones HTTP, workflows, etc.)
430
- """
431
-
432
- EVENT_TYPE_CHOICES = [
433
- ('notification', 'Notification'),
434
- ('automation', 'Automation'),
435
- ]
436
-
437
- STATUS_CHOICES = [
438
- ('active', 'Active'), # Activo y programado
439
- ('paused', 'Paused'), # Pausado temporalmente
440
- ('completed', 'Completed'), # Completado (para puntuales)
441
- ('failed', 'Failed'), # Falló la última ejecución
442
- ('cancelled', 'Cancelled'), # Cancelado permanentemente
443
- ]
444
-
445
- RECURRENCE_TYPE_CHOICES = [
446
- ('punctual', 'Punctual'), # Una o más veces en fechas específicas
447
- ('periodic', 'Periodic'), # Recurrente
448
- ]
449
-
450
- # FKs
451
- company = models.ForeignKey(Company, on_delete=models.CASCADE, db_index=True)
452
-
453
- # Tipo de evento
454
- event_type = models.CharField(max_length=50, choices=EVENT_TYPE_CHOICES)
455
-
456
- # Info básica
457
- title = models.CharField(max_length=255)
458
- description = models.TextField(blank=True)
459
- status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='active')
460
-
461
- # Recurrencia
462
- recurrence_type = models.CharField(
463
- max_length=20,
464
- choices=RECURRENCE_TYPE_CHOICES,
465
- help_text="Tipo de recurrencia: puntual (fechas específicas) o periódico"
466
- )
467
- recurrence_config = models.JSONField(
468
- help_text="Configuración de recurrencia en formato JSON"
469
- )
470
-
471
- # Configuración específica del tipo de evento
472
- config = models.JSONField(
473
- default=dict,
474
- help_text="Configuración específica según event_type (mensaje, URL, etc.)"
475
- )
476
-
477
- # Control de ejecución
478
- next_execution_at = models.DateTimeField(
479
- null=True,
480
- blank=True,
481
- db_index=True,
482
- help_text="Próxima fecha/hora de ejecución calculada"
483
- )
484
- last_executed_at = models.DateTimeField(
485
- null=True,
486
- blank=True,
487
- help_text="Última vez que se ejecutó"
488
- )
489
- execution_count = models.IntegerField(
490
- default=0,
491
- help_text="Cantidad de veces que se ha ejecutado"
492
- )
493
-
494
- # Auditoría
495
- created_by = models.ForeignKey(
496
- User,
497
- on_delete=models.CASCADE,
498
- related_name='created_events'
499
- )
500
-
501
- class Meta:
502
- db_table = '"automations"."events"'
503
- app_label = 'constec_db'
504
- indexes = [
505
- models.Index(fields=['company', 'event_type']),
506
- models.Index(fields=['status', 'next_execution_at']),
507
- models.Index(fields=['recurrence_type']),
508
- ]
509
- ordering = ['next_execution_at']
510
-
511
- def __str__(self):
512
- return f"{self.event_type}: {self.title}"
485
+ @property
486
+ def creator(self):
487
+ """Helper to access creator regardless of type."""
488
+ return self.created_by_user or self.created_by_org_user
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: constec
3
- Version: 0.5.3
3
+ Version: 0.6.0
4
4
  Summary: Base library for the Constec ecosystem - shared utilities, models, and namespace foundation
5
5
  License: MIT
6
6
  Project-URL: Homepage, https://github.com/TpmyCT/constec-python
@@ -16,6 +16,7 @@ constec/db/migrations/0004_rename_entities_company_cuit_idx_entities_company_e2c
16
16
  constec/db/migrations/0005_event.py
17
17
  constec/db/migrations/0006_automation_trigger_action_executionlog_notificationtemplate.py
18
18
  constec/db/migrations/0007_add_organization_to_automations.py
19
+ constec/db/migrations/0008_refactor_creator_fields.py
19
20
  constec/db/migrations/__init__.py
20
21
  constec/db/models/__init__.py
21
22
  constec/db/models/automation.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "constec"
7
- version = "0.5.3"
7
+ version = "0.6.0"
8
8
  description = "Base library for the Constec ecosystem - shared utilities, models, and namespace foundation"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes