amsdal_crm 0.2.0__tar.gz → 0.2.2__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 (73) hide show
  1. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/PKG-INFO +1 -1
  2. amsdal_crm-0.2.2/amsdal_crm/__about__.py +1 -0
  3. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/migrations/0000_initial.py +121 -0
  4. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/models/entity.py +20 -0
  5. amsdal_crm-0.2.0/amsdal_crm/__about__.py +0 -1
  6. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/.amsdal/.environment +0 -0
  7. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/.amsdal-cli +0 -0
  8. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/.github/workflows/ci.yml +0 -0
  9. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/.github/workflows/release.yml +0 -0
  10. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/.github/workflows/tag_check.yml +0 -0
  11. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/.gitignore +0 -0
  12. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/CLAUDE.md +0 -0
  13. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/README.md +0 -0
  14. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/RELEASE.md +0 -0
  15. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/Third-Party Materials - AMSDAL Dependencies - License Notices.md +0 -0
  16. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/__init__.py +0 -0
  17. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/app.py +0 -0
  18. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/constants.py +0 -0
  19. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/errors.py +0 -0
  20. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/fixtures/__init__.py +0 -0
  21. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/fixtures/permissions.py +0 -0
  22. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/fixtures/pipelines.py +0 -0
  23. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/lifecycle/__init__.py +0 -0
  24. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/lifecycle/consumer.py +0 -0
  25. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/models/__init__.py +0 -0
  26. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/models/activity.py +0 -0
  27. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/models/attachment.py +0 -0
  28. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/models/custom_field_definition.py +0 -0
  29. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/models/deal.py +0 -0
  30. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/models/pipeline.py +0 -0
  31. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/models/stage.py +0 -0
  32. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/models/workflow_rule.py +0 -0
  33. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/services/__init__.py +0 -0
  34. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/services/activity_service.py +0 -0
  35. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/services/custom_field_service.py +0 -0
  36. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/services/deal_service.py +0 -0
  37. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/services/email_service.py +0 -0
  38. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/services/workflow_service.py +0 -0
  39. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/amsdal_crm/settings.py +0 -0
  40. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/config.yml +0 -0
  41. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/license_check.py +0 -0
  42. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/pyproject.toml +0 -0
  43. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/scripts/release.sh +0 -0
  44. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/scripts/tag_check.sh +0 -0
  45. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/conftest.py +0 -0
  46. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/integration/__init__.py +0 -0
  47. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/integration/conftest.py +0 -0
  48. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/integration/services/__init__.py +0 -0
  49. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/integration/services/test_deal_service.py +0 -0
  50. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/integration/services/test_email_service.py +0 -0
  51. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/integration/services/test_workflow_service.py +0 -0
  52. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/unit/__init__.py +0 -0
  53. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/unit/conftest.py +0 -0
  54. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/unit/lifecycle/__init__.py +0 -0
  55. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/unit/lifecycle/test_consumer.py +0 -0
  56. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/unit/models/__init__.py +0 -0
  57. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/unit/models/test_activity.py +0 -0
  58. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/unit/models/test_deal.py +0 -0
  59. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/unit/models/test_entity.py +0 -0
  60. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/unit/models/test_pipeline.py +0 -0
  61. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/unit/models/test_remaining.py +0 -0
  62. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/unit/models/test_stage.py +0 -0
  63. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/unit/services/__init__.py +0 -0
  64. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/unit/services/test_activity_service.py +0 -0
  65. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/unit/services/test_custom_field_service.py +0 -0
  66. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/unit/services/test_deal_service.py +0 -0
  67. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/unit/services/test_email_service.py +0 -0
  68. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/unit/services/test_workflow_service.py +0 -0
  69. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/unit/test_app.py +0 -0
  70. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/unit/test_constants.py +0 -0
  71. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/unit/test_errors.py +0 -0
  72. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/tests/unit/test_settings.py +0 -0
  73. {amsdal_crm-0.2.0 → amsdal_crm-0.2.2}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: amsdal_crm
3
- Version: 0.2.0
3
+ Version: 0.2.2
4
4
  Summary: amsdal-crm plugin for AMSDAL Framework
5
5
  Requires-Python: >=3.11
6
6
  Requires-Dist: aiohttp==3.12.15
@@ -0,0 +1 @@
1
+ __version__ = '0.2.2'
@@ -92,6 +92,32 @@ class Migration(migrations.Migration):
92
92
  "description": "Entity (Person/Organization/Trust) model.\n\nRepresents a company or organization in the CRM system.\nOwned by individual users with permission controls.",
93
93
  },
94
94
  ),
95
+ migrations.CreateClass(
96
+ module_type=ModuleType.CONTRIB,
97
+ class_name="EntityAddress",
98
+ new_schema={
99
+ "title": "EntityAddress",
100
+ "properties": {
101
+ "created_at": {"type": "datetime", "title": "Created At", "format": "date-time"},
102
+ "updated_at": {"type": "datetime", "title": "Updated At", "format": "date-time"},
103
+ "line1": {"type": "string", "title": "Address Line 1"},
104
+ "line2": {"type": "string", "title": "Address Line 2"},
105
+ "city": {"type": "string", "title": "City"},
106
+ "region": {"type": "string", "title": "Region/State"},
107
+ "postal_code": {"type": "string", "title": "Postal Code"},
108
+ "country": {"type": "string", "title": "Country"},
109
+ "is_primary": {"type": "boolean", "default": False, "title": "Is Primary"},
110
+ "custom_fields": {"type": "anything", "title": "Custom Fields"},
111
+ },
112
+ "custom_code": 'async def apre_create(self) -> None:\n """Async hook called before creating account."""\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = await CustomFieldService.avalidate_custom_fields(\'EntityAddress\', self.custom_fields)\n await super().apre_create()\n\nasync def apre_update(self) -> None:\n """Async hook called before updating account."""\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = await CustomFieldService.avalidate_custom_fields(\'EntityAddress\', self.custom_fields)\n await super().apre_update()\n\ndef pre_create(self) -> None:\n """Hook called before creating account."""\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = CustomFieldService.validate_custom_fields(\'EntityAddress\', self.custom_fields)\n super().pre_create()\n\ndef pre_update(self) -> None:\n """Hook called before updating account."""\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = CustomFieldService.validate_custom_fields(\'EntityAddress\', self.custom_fields)\n super().pre_update()',
113
+ "storage_metadata": {
114
+ "table_name": "EntityAddress",
115
+ "db_fields": {},
116
+ "primary_key": ["partition_key"],
117
+ "foreign_keys": {},
118
+ },
119
+ },
120
+ ),
95
121
  migrations.CreateClass(
96
122
  module_type=ModuleType.CONTRIB,
97
123
  class_name="Pipeline",
@@ -338,6 +364,101 @@ class Migration(migrations.Migration):
338
364
  "description": "Task activity with priority and status.",
339
365
  },
340
366
  ),
367
+ migrations.CreateClass(
368
+ module_type=ModuleType.CONTRIB,
369
+ class_name="EntityContactPoint",
370
+ new_schema={
371
+ "title": "EntityContactPoint",
372
+ "required": ["value", "entity"],
373
+ "properties": {
374
+ "created_at": {"type": "datetime", "title": "Created At", "format": "date-time"},
375
+ "updated_at": {"type": "datetime", "title": "Updated At", "format": "date-time"},
376
+ "value": {"type": "string", "title": "Contact Point Value"},
377
+ "is_primary": {"type": "boolean", "default": False, "title": "Is Primary"},
378
+ "can_contact": {"type": "boolean", "default": True, "title": "Can Contact"},
379
+ "custom_fields": {"type": "anything", "title": "Custom Fields"},
380
+ "entity": {
381
+ "type": "Entity",
382
+ "title": "Entity",
383
+ "description": "Entity (Person/Organization/Trust) model.\n\nRepresents a company or organization in the CRM system.\nOwned by individual users with permission controls.",
384
+ },
385
+ },
386
+ "custom_code": 'async def apre_create(self) -> None:\n """Async hook called before creating account."""\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = await CustomFieldService.avalidate_custom_fields(\'EntityContactPoint\', self.custom_fields)\n await super().apre_create()\n\nasync def apre_update(self) -> None:\n """Async hook called before updating account."""\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = await CustomFieldService.avalidate_custom_fields(\'EntityContactPoint\', self.custom_fields)\n await super().apre_update()\n\ndef pre_create(self) -> None:\n """Hook called before creating account."""\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = CustomFieldService.validate_custom_fields(\'EntityContactPoint\', self.custom_fields)\n super().pre_create()\n\ndef pre_update(self) -> None:\n """Hook called before updating account."""\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = CustomFieldService.validate_custom_fields(\'EntityContactPoint\', self.custom_fields)\n super().pre_update()',
387
+ "storage_metadata": {
388
+ "table_name": "EntityContactPoint",
389
+ "db_fields": {"entity": ["entity_partition_key"]},
390
+ "primary_key": ["partition_key"],
391
+ "foreign_keys": {"entity": [{"entity_partition_key": "string"}, "Entity", ["partition_key"]]},
392
+ },
393
+ },
394
+ ),
395
+ migrations.CreateClass(
396
+ module_type=ModuleType.CONTRIB,
397
+ class_name="EntityIdentifier",
398
+ new_schema={
399
+ "title": "EntityIdentifier",
400
+ "required": ["value", "entity"],
401
+ "properties": {
402
+ "created_at": {"type": "datetime", "title": "Created At", "format": "date-time"},
403
+ "updated_at": {"type": "datetime", "title": "Updated At", "format": "date-time"},
404
+ "value": {"type": "string", "title": "Identifier Value"},
405
+ "country": {"type": "string", "title": "Country"},
406
+ "is_primary": {"type": "boolean", "default": False, "title": "Is Primary"},
407
+ "custom_fields": {"type": "anything", "title": "Custom Fields"},
408
+ "entity": {
409
+ "type": "Entity",
410
+ "title": "Entity",
411
+ "description": "Entity (Person/Organization/Trust) model.\n\nRepresents a company or organization in the CRM system.\nOwned by individual users with permission controls.",
412
+ },
413
+ },
414
+ "custom_code": 'async def apre_create(self) -> None:\n """Async hook called before creating account."""\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = await CustomFieldService.avalidate_custom_fields(\'EntityIdentifier\', self.custom_fields)\n await super().apre_create()\n\nasync def apre_update(self) -> None:\n """Async hook called before updating account."""\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = await CustomFieldService.avalidate_custom_fields(\'EntityIdentifier\', self.custom_fields)\n await super().apre_update()\n\ndef pre_create(self) -> None:\n """Hook called before creating account."""\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = CustomFieldService.validate_custom_fields(\'EntityIdentifier\', self.custom_fields)\n super().pre_create()\n\ndef pre_update(self) -> None:\n """Hook called before updating account."""\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = CustomFieldService.validate_custom_fields(\'EntityIdentifier\', self.custom_fields)\n super().pre_update()',
415
+ "storage_metadata": {
416
+ "table_name": "EntityIdentifier",
417
+ "db_fields": {"entity": ["entity_partition_key"]},
418
+ "primary_key": ["partition_key"],
419
+ "foreign_keys": {"entity": [{"entity_partition_key": "string"}, "Entity", ["partition_key"]]},
420
+ },
421
+ },
422
+ ),
423
+ migrations.CreateClass(
424
+ module_type=ModuleType.CONTRIB,
425
+ class_name="EntityRelationship",
426
+ new_schema={
427
+ "title": "EntityRelationship",
428
+ "required": ["from_entity", "to_entity"],
429
+ "properties": {
430
+ "created_at": {"type": "datetime", "title": "Created At", "format": "date-time"},
431
+ "updated_at": {"type": "datetime", "title": "Updated At", "format": "date-time"},
432
+ "start_date": {"type": "string", "title": "Start Date"},
433
+ "end_date": {"type": "string", "title": "End Date"},
434
+ "relationship_group_name": {"type": "string", "title": "Relationship Group Name"},
435
+ "custom_fields": {"type": "anything", "title": "Custom Fields"},
436
+ "from_entity": {
437
+ "type": "Entity",
438
+ "title": "From Entity",
439
+ "description": "Entity (Person/Organization/Trust) model.\n\nRepresents a company or organization in the CRM system.\nOwned by individual users with permission controls.",
440
+ },
441
+ "to_entity": {
442
+ "type": "Entity",
443
+ "title": "To Entity",
444
+ "description": "Entity (Person/Organization/Trust) model.\n\nRepresents a company or organization in the CRM system.\nOwned by individual users with permission controls.",
445
+ },
446
+ },
447
+ "custom_code": 'async def apre_create(self) -> None:\n """Async hook called before creating account."""\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = await CustomFieldService.avalidate_custom_fields(\'EntityRelationship\', self.custom_fields)\n await super().apre_create()\n\nasync def apre_update(self) -> None:\n """Async hook called before updating account."""\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = await CustomFieldService.avalidate_custom_fields(\'EntityRelationship\', self.custom_fields)\n await super().apre_update()\n\ndef pre_create(self) -> None:\n """Hook called before creating account."""\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = CustomFieldService.validate_custom_fields(\'EntityRelationship\', self.custom_fields)\n super().pre_create()\n\ndef pre_update(self) -> None:\n """Hook called before updating account."""\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = CustomFieldService.validate_custom_fields(\'EntityRelationship\', self.custom_fields)\n super().pre_update()',
448
+ "storage_metadata": {
449
+ "table_name": "EntityRelationship",
450
+ "db_fields": {
451
+ "from_entity": ["from_entity_partition_key"],
452
+ "to_entity": ["to_entity_partition_key"],
453
+ },
454
+ "primary_key": ["partition_key"],
455
+ "foreign_keys": {
456
+ "from_entity": [{"from_entity_partition_key": "string"}, "Entity", ["partition_key"]],
457
+ "to_entity": [{"to_entity_partition_key": "string"}, "Entity", ["partition_key"]],
458
+ },
459
+ },
460
+ },
461
+ ),
341
462
  migrations.CreateClass(
342
463
  module_type=ModuleType.CONTRIB,
343
464
  class_name="Stage",
@@ -117,12 +117,17 @@ class Entity(TimestampMixin, Model):
117
117
 
118
118
 
119
119
  class EntityRelationship(TimestampMixin, Model):
120
+ __module_type__: ClassVar[ModuleType] = ModuleType.CONTRIB
121
+
120
122
  from_entity: Entity = Field(title='From Entity')
121
123
  to_entity: Entity = Field(title='To Entity')
122
124
  start_date: str | None = Field(default=None, title='Start Date')
123
125
  end_date: str | None = Field(default=None, title='End Date')
124
126
  relationship_group_name: str | None = Field(default=None, title='Relationship Group Name')
125
127
 
128
+ # Custom fields (JSON)
129
+ custom_fields: dict[str, Any] | None = Field(default=None, title='Custom Fields')
130
+
126
131
  def pre_create(self) -> None:
127
132
  """Hook called before creating account."""
128
133
  if self.custom_fields:
@@ -167,6 +172,8 @@ class EntityRelationship(TimestampMixin, Model):
167
172
 
168
173
 
169
174
  class EntityIdentifier(TimestampMixin, Model):
175
+ __module_type__: ClassVar[ModuleType] = ModuleType.CONTRIB
176
+
170
177
  entity: Entity = Field(title='Entity')
171
178
  value: str = Field(title='Identifier Value')
172
179
  country: str | None = Field(default=None, title='Country')
@@ -174,6 +181,9 @@ class EntityIdentifier(TimestampMixin, Model):
174
181
  # TODO: validate one per entity
175
182
  is_primary: bool = Field(default=False, title='Is Primary')
176
183
 
184
+ # Custom fields (JSON)
185
+ custom_fields: dict[str, Any] | None = Field(default=None, title='Custom Fields')
186
+
177
187
  def pre_create(self) -> None:
178
188
  """Hook called before creating account."""
179
189
  if self.custom_fields:
@@ -218,6 +228,8 @@ class EntityIdentifier(TimestampMixin, Model):
218
228
 
219
229
 
220
230
  class EntityContactPoint(TimestampMixin, Model):
231
+ __module_type__: ClassVar[ModuleType] = ModuleType.CONTRIB
232
+
221
233
  entity: Entity = Field(title='Entity')
222
234
  value: str = Field(title='Contact Point Value')
223
235
 
@@ -225,6 +237,9 @@ class EntityContactPoint(TimestampMixin, Model):
225
237
  is_primary: bool = Field(default=False, title='Is Primary')
226
238
  can_contact: bool = Field(default=True, title='Can Contact')
227
239
 
240
+ # Custom fields (JSON)
241
+ custom_fields: dict[str, Any] | None = Field(default=None, title='Custom Fields')
242
+
228
243
  def pre_create(self) -> None:
229
244
  """Hook called before creating account."""
230
245
  if self.custom_fields:
@@ -269,6 +284,8 @@ class EntityContactPoint(TimestampMixin, Model):
269
284
 
270
285
 
271
286
  class EntityAddress(TimestampMixin, Model):
287
+ __module_type__: ClassVar[ModuleType] = ModuleType.CONTRIB
288
+
272
289
  line1: str | None = Field(title='Address Line 1')
273
290
  line2: str | None = Field(default=None, title='Address Line 2')
274
291
  city: str | None = Field(title='City')
@@ -279,6 +296,9 @@ class EntityAddress(TimestampMixin, Model):
279
296
  # TODO: validate one per entity
280
297
  is_primary: bool = Field(default=False, title='Is Primary')
281
298
 
299
+ # Custom fields (JSON)
300
+ custom_fields: dict[str, Any] | None = Field(default=None, title='Custom Fields')
301
+
282
302
  def pre_create(self) -> None:
283
303
  """Hook called before creating account."""
284
304
  if self.custom_fields:
@@ -1 +0,0 @@
1
- __version__ = '0.2.0'
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes