amsdal_crm 0.2.2__py3-none-any.whl → 0.2.4__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.
- amsdal_crm/__about__.py +1 -1
- amsdal_crm/migrations/0000_initial.py +12 -12
- amsdal_crm/models/common.py +45 -0
- amsdal_crm/models/deal.py +4 -35
- amsdal_crm/models/entity.py +7 -223
- {amsdal_crm-0.2.2.dist-info → amsdal_crm-0.2.4.dist-info}/METADATA +1 -1
- {amsdal_crm-0.2.2.dist-info → amsdal_crm-0.2.4.dist-info}/RECORD +8 -7
- {amsdal_crm-0.2.2.dist-info → amsdal_crm-0.2.4.dist-info}/WHEEL +0 -0
amsdal_crm/__about__.py
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = '0.2.
|
|
1
|
+
__version__ = '0.2.4'
|
|
@@ -65,6 +65,7 @@ class Migration(migrations.Migration):
|
|
|
65
65
|
"properties": {
|
|
66
66
|
"created_at": {"type": "datetime", "title": "Created At", "format": "date-time"},
|
|
67
67
|
"updated_at": {"type": "datetime", "title": "Updated At", "format": "date-time"},
|
|
68
|
+
"custom_fields": {"type": "anything", "title": "Custom Fields"},
|
|
68
69
|
"name": {"type": "string", "title": "Entity Name"},
|
|
69
70
|
"legal_name": {"type": "string", "title": "Legal Name"},
|
|
70
71
|
"status": {
|
|
@@ -75,10 +76,9 @@ class Migration(migrations.Migration):
|
|
|
75
76
|
"enum": ["Active", "Inactive"],
|
|
76
77
|
},
|
|
77
78
|
"note": {"type": "string", "title": "Note"},
|
|
78
|
-
"custom_fields": {"type": "anything", "title": "Custom Fields"},
|
|
79
79
|
"assigned_to": {"type": "User", "title": "Assigned To"},
|
|
80
80
|
},
|
|
81
|
-
"custom_code": 'from amsdal.contrib.auth.models.user import User\n\n\n@property\ndef display_name(self) -> str:\n """Return display name for the account."""\n return self.name\n\nasync def
|
|
81
|
+
"custom_code": 'from amsdal.contrib.auth.models.user import User\n\n\n@classmethod\ndef custom_fields_cell_template(cls) -> str:\n return \'JsonTemplate\'\n\n@property\ndef display_name(self) -> str:\n """Return display name for the account."""\n return self.name\n\nasync def _avalidate_custom_fields(self) -> None:\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = await CustomFieldService.avalidate_custom_fields(self.__class__.__name__, self.custom_fields)\n\nasync def apost_update(self) -> None:\n """Async hook called after updating account."""\n from amsdal_crm.services.workflow_service import WorkflowService\n await WorkflowService.aexecute_rules(\'Entity\', \'update\', self)\n\nasync def apre_create(self) -> None:\n await self._avalidate_custom_fields()\n await super().apre_create()\n\nasync def apre_update(self) -> None:\n await self._avalidate_custom_fields()\n await super().apre_update()\n\ndef _validate_custom_fields(self) -> None:\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = CustomFieldService.validate_custom_fields(self.__class__.__name__, self.custom_fields)\n\ndef has_object_permission(self, user: \'User\', action: str) -> bool:\n """Check if user has permission to perform action on this account.\n\n Args:\n user: The user attempting the action\n action: The action being attempted (read, create, update, delete)\n\n Returns:\n True if user has permission, False otherwise\n """\n if self.assigned_to and self.assigned_to.email == user.email:\n return True\n if user.permissions:\n for permission in user.permissions:\n if permission.model == \'*\' and permission.action in (\'*\', action):\n return True\n if permission.model == \'Entity\' and permission.action in (\'*\', action):\n return True\n return False\n\ndef post_update(self) -> None:\n """Hook called after updating account."""\n from amsdal_crm.services.workflow_service import WorkflowService\n WorkflowService.execute_rules(\'Entity\', \'update\', self)\n\ndef pre_create(self) -> None:\n self._validate_custom_fields()\n super().pre_create()\n\ndef pre_update(self) -> None:\n self._validate_custom_fields()\n super().pre_update()',
|
|
82
82
|
"storage_metadata": {
|
|
83
83
|
"table_name": "Entity",
|
|
84
84
|
"db_fields": {"assigned_to": ["assigned_to_partition_key"]},
|
|
@@ -100,6 +100,7 @@ class Migration(migrations.Migration):
|
|
|
100
100
|
"properties": {
|
|
101
101
|
"created_at": {"type": "datetime", "title": "Created At", "format": "date-time"},
|
|
102
102
|
"updated_at": {"type": "datetime", "title": "Updated At", "format": "date-time"},
|
|
103
|
+
"custom_fields": {"type": "anything", "title": "Custom Fields"},
|
|
103
104
|
"line1": {"type": "string", "title": "Address Line 1"},
|
|
104
105
|
"line2": {"type": "string", "title": "Address Line 2"},
|
|
105
106
|
"city": {"type": "string", "title": "City"},
|
|
@@ -107,9 +108,8 @@ class Migration(migrations.Migration):
|
|
|
107
108
|
"postal_code": {"type": "string", "title": "Postal Code"},
|
|
108
109
|
"country": {"type": "string", "title": "Country"},
|
|
109
110
|
"is_primary": {"type": "boolean", "default": False, "title": "Is Primary"},
|
|
110
|
-
"custom_fields": {"type": "anything", "title": "Custom Fields"},
|
|
111
111
|
},
|
|
112
|
-
"custom_code":
|
|
112
|
+
"custom_code": "@classmethod\ndef custom_fields_cell_template(cls) -> str:\n return 'JsonTemplate'\n\nasync def _avalidate_custom_fields(self) -> None:\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = await CustomFieldService.avalidate_custom_fields(self.__class__.__name__, self.custom_fields)\n\nasync def apre_create(self) -> None:\n await self._avalidate_custom_fields()\n await super().apre_create()\n\nasync def apre_update(self) -> None:\n await self._avalidate_custom_fields()\n await super().apre_update()\n\ndef _validate_custom_fields(self) -> None:\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = CustomFieldService.validate_custom_fields(self.__class__.__name__, self.custom_fields)\n\ndef pre_create(self) -> None:\n self._validate_custom_fields()\n super().pre_create()\n\ndef pre_update(self) -> None:\n self._validate_custom_fields()\n super().pre_update()",
|
|
113
113
|
"storage_metadata": {
|
|
114
114
|
"table_name": "EntityAddress",
|
|
115
115
|
"db_fields": {},
|
|
@@ -373,17 +373,17 @@ class Migration(migrations.Migration):
|
|
|
373
373
|
"properties": {
|
|
374
374
|
"created_at": {"type": "datetime", "title": "Created At", "format": "date-time"},
|
|
375
375
|
"updated_at": {"type": "datetime", "title": "Updated At", "format": "date-time"},
|
|
376
|
+
"custom_fields": {"type": "anything", "title": "Custom Fields"},
|
|
376
377
|
"value": {"type": "string", "title": "Contact Point Value"},
|
|
377
378
|
"is_primary": {"type": "boolean", "default": False, "title": "Is Primary"},
|
|
378
379
|
"can_contact": {"type": "boolean", "default": True, "title": "Can Contact"},
|
|
379
|
-
"custom_fields": {"type": "anything", "title": "Custom Fields"},
|
|
380
380
|
"entity": {
|
|
381
381
|
"type": "Entity",
|
|
382
382
|
"title": "Entity",
|
|
383
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
384
|
},
|
|
385
385
|
},
|
|
386
|
-
"custom_code":
|
|
386
|
+
"custom_code": "@classmethod\ndef custom_fields_cell_template(cls) -> str:\n return 'JsonTemplate'\n\nasync def _avalidate_custom_fields(self) -> None:\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = await CustomFieldService.avalidate_custom_fields(self.__class__.__name__, self.custom_fields)\n\nasync def apre_create(self) -> None:\n await self._avalidate_custom_fields()\n await super().apre_create()\n\nasync def apre_update(self) -> None:\n await self._avalidate_custom_fields()\n await super().apre_update()\n\ndef _validate_custom_fields(self) -> None:\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = CustomFieldService.validate_custom_fields(self.__class__.__name__, self.custom_fields)\n\ndef pre_create(self) -> None:\n self._validate_custom_fields()\n super().pre_create()\n\ndef pre_update(self) -> None:\n self._validate_custom_fields()\n super().pre_update()",
|
|
387
387
|
"storage_metadata": {
|
|
388
388
|
"table_name": "EntityContactPoint",
|
|
389
389
|
"db_fields": {"entity": ["entity_partition_key"]},
|
|
@@ -401,17 +401,17 @@ class Migration(migrations.Migration):
|
|
|
401
401
|
"properties": {
|
|
402
402
|
"created_at": {"type": "datetime", "title": "Created At", "format": "date-time"},
|
|
403
403
|
"updated_at": {"type": "datetime", "title": "Updated At", "format": "date-time"},
|
|
404
|
+
"custom_fields": {"type": "anything", "title": "Custom Fields"},
|
|
404
405
|
"value": {"type": "string", "title": "Identifier Value"},
|
|
405
406
|
"country": {"type": "string", "title": "Country"},
|
|
406
407
|
"is_primary": {"type": "boolean", "default": False, "title": "Is Primary"},
|
|
407
|
-
"custom_fields": {"type": "anything", "title": "Custom Fields"},
|
|
408
408
|
"entity": {
|
|
409
409
|
"type": "Entity",
|
|
410
410
|
"title": "Entity",
|
|
411
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
412
|
},
|
|
413
413
|
},
|
|
414
|
-
"custom_code":
|
|
414
|
+
"custom_code": "@classmethod\ndef custom_fields_cell_template(cls) -> str:\n return 'JsonTemplate'\n\nasync def _avalidate_custom_fields(self) -> None:\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = await CustomFieldService.avalidate_custom_fields(self.__class__.__name__, self.custom_fields)\n\nasync def apre_create(self) -> None:\n await self._avalidate_custom_fields()\n await super().apre_create()\n\nasync def apre_update(self) -> None:\n await self._avalidate_custom_fields()\n await super().apre_update()\n\ndef _validate_custom_fields(self) -> None:\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = CustomFieldService.validate_custom_fields(self.__class__.__name__, self.custom_fields)\n\ndef pre_create(self) -> None:\n self._validate_custom_fields()\n super().pre_create()\n\ndef pre_update(self) -> None:\n self._validate_custom_fields()\n super().pre_update()",
|
|
415
415
|
"storage_metadata": {
|
|
416
416
|
"table_name": "EntityIdentifier",
|
|
417
417
|
"db_fields": {"entity": ["entity_partition_key"]},
|
|
@@ -429,10 +429,10 @@ class Migration(migrations.Migration):
|
|
|
429
429
|
"properties": {
|
|
430
430
|
"created_at": {"type": "datetime", "title": "Created At", "format": "date-time"},
|
|
431
431
|
"updated_at": {"type": "datetime", "title": "Updated At", "format": "date-time"},
|
|
432
|
+
"custom_fields": {"type": "anything", "title": "Custom Fields"},
|
|
432
433
|
"start_date": {"type": "string", "title": "Start Date"},
|
|
433
434
|
"end_date": {"type": "string", "title": "End Date"},
|
|
434
435
|
"relationship_group_name": {"type": "string", "title": "Relationship Group Name"},
|
|
435
|
-
"custom_fields": {"type": "anything", "title": "Custom Fields"},
|
|
436
436
|
"from_entity": {
|
|
437
437
|
"type": "Entity",
|
|
438
438
|
"title": "From Entity",
|
|
@@ -444,7 +444,7 @@ class Migration(migrations.Migration):
|
|
|
444
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
445
|
},
|
|
446
446
|
},
|
|
447
|
-
"custom_code":
|
|
447
|
+
"custom_code": "@classmethod\ndef custom_fields_cell_template(cls) -> str:\n return 'JsonTemplate'\n\nasync def _avalidate_custom_fields(self) -> None:\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = await CustomFieldService.avalidate_custom_fields(self.__class__.__name__, self.custom_fields)\n\nasync def apre_create(self) -> None:\n await self._avalidate_custom_fields()\n await super().apre_create()\n\nasync def apre_update(self) -> None:\n await self._avalidate_custom_fields()\n await super().apre_update()\n\ndef _validate_custom_fields(self) -> None:\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = CustomFieldService.validate_custom_fields(self.__class__.__name__, self.custom_fields)\n\ndef pre_create(self) -> None:\n self._validate_custom_fields()\n super().pre_create()\n\ndef pre_update(self) -> None:\n self._validate_custom_fields()\n super().pre_update()",
|
|
448
448
|
"storage_metadata": {
|
|
449
449
|
"table_name": "EntityRelationship",
|
|
450
450
|
"db_fields": {
|
|
@@ -513,6 +513,7 @@ class Migration(migrations.Migration):
|
|
|
513
513
|
"properties": {
|
|
514
514
|
"created_at": {"type": "datetime", "title": "Created At", "format": "date-time"},
|
|
515
515
|
"updated_at": {"type": "datetime", "title": "Updated At", "format": "date-time"},
|
|
516
|
+
"custom_fields": {"type": "anything", "title": "Custom Fields"},
|
|
516
517
|
"name": {"type": "string", "title": "Deal Name"},
|
|
517
518
|
"amount": {"type": "number", "title": "Amount"},
|
|
518
519
|
"currency": {"type": "string", "default": "USD", "title": "Currency"},
|
|
@@ -539,10 +540,9 @@ class Migration(migrations.Migration):
|
|
|
539
540
|
"title": "Status",
|
|
540
541
|
"enum": ["open", "closed_won", "closed_lost"],
|
|
541
542
|
},
|
|
542
|
-
"custom_fields": {"type": "anything", "title": "Custom Fields"},
|
|
543
543
|
"assigned_to": {"type": "User", "title": "Assigned To"},
|
|
544
544
|
},
|
|
545
|
-
"custom_code": "import datetime as _dt\n\nfrom amsdal.contrib.auth.models.user import User\nfrom amsdal_utils.models.data_models.reference import Reference\n\n\n@property\ndef display_name(self) -> str:\n \"\"\"Return display name for the deal.\"\"\"\n return self.name\n\n@property\ndef stage_name(self) -> str:\n \"\"\"Returns stage name for display.\"\"\"\n if hasattr(self.stage, 'name'):\n return self.stage.name\n return str(self.stage)\n\nasync def
|
|
545
|
+
"custom_code": "import datetime as _dt\n\nfrom amsdal.contrib.auth.models.user import User\nfrom amsdal_utils.models.data_models.reference import Reference\n\n\n@classmethod\ndef custom_fields_cell_template(cls) -> str:\n return 'JsonTemplate'\n\n@property\ndef display_name(self) -> str:\n \"\"\"Return display name for the deal.\"\"\"\n return self.name\n\n@property\ndef stage_name(self) -> str:\n \"\"\"Returns stage name for display.\"\"\"\n if hasattr(self.stage, 'name'):\n return self.stage.name\n return str(self.stage)\n\nasync def _avalidate_custom_fields(self) -> None:\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = await CustomFieldService.avalidate_custom_fields(self.__class__.__name__, self.custom_fields)\n\nasync def apost_update(self) -> None:\n \"\"\"Async hook called after updating deal.\"\"\"\n from amsdal_crm.services.workflow_service import WorkflowService\n await WorkflowService.aexecute_rules('Deal', 'update', self)\n\nasync def apre_create(self) -> None:\n await self._avalidate_custom_fields()\n await super().apre_create()\n\nasync def apre_update(self) -> None:\n \"\"\"Async hook called before updating deal.\n\n Automatically syncs is_closed and is_won status with stage,\n and sets closed_date when deal is closed.\n \"\"\"\n stage = await self.stage\n if stage.status == 'open':\n self.status = 'open'\n if stage.status == 'closed_won':\n self.status = 'closed_won'\n if stage.status == 'closed_lost':\n self.status = 'closed_lost'\n if self.status in ('closed_won', 'closed_lost') and (not self.closed_date):\n self.closed_date = _dt.datetime.now(_dt.UTC)\n await super().apre_update()\n\ndef _validate_custom_fields(self) -> None:\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = CustomFieldService.validate_custom_fields(self.__class__.__name__, self.custom_fields)\n\ndef has_object_permission(self, user: 'User', action: str) -> bool:\n \"\"\"Check if user has permission to perform action on this deal.\n\n Args:\n user: The user attempting the action\n action: The action being attempted (read, create, update, delete)\n\n Returns:\n True if user has permission, False otherwise\n \"\"\"\n if self.assigned_to and self.assigned_to.email == user.email:\n return True\n if user.permissions:\n for permission in user.permissions:\n if permission.model == '*' and permission.action in ('*', action):\n return True\n if permission.model == 'Deal' and permission.action in ('*', action):\n return True\n return False\n\ndef post_update(self) -> None:\n \"\"\"Hook called after updating deal.\"\"\"\n from amsdal_crm.services.workflow_service import WorkflowService\n WorkflowService.execute_rules('Deal', 'update', self)\n\ndef pre_create(self) -> None:\n self._validate_custom_fields()\n super().pre_create()\n\ndef pre_update(self) -> None:\n \"\"\"Hook called before updating deal.\n\n Automatically syncs is_closed and is_won status with stage,\n and sets closed_date when deal is closed.\n \"\"\"\n from amsdal_models.classes.helpers.reference_loader import ReferenceLoader\n stage = ReferenceLoader(self.stage).load_reference() if isinstance(self.stage, Reference) else self.stage\n if stage.status == 'open':\n self.status = 'open'\n if stage.status == 'closed_won':\n self.status = 'closed_won'\n if stage.status == 'closed_lost':\n self.status = 'closed_lost'\n if self.status in ('closed_won', 'closed_lost') and (not self.closed_date):\n self.closed_date = _dt.datetime.now(_dt.UTC)\n super().pre_update()",
|
|
546
546
|
"storage_metadata": {
|
|
547
547
|
"table_name": "Deal",
|
|
548
548
|
"db_fields": {
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from pydantic.fields import Field
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class CustomFieldsMixin:
|
|
7
|
+
custom_fields: dict[str, Any] | None = Field(default=None, title='Custom Fields')
|
|
8
|
+
|
|
9
|
+
@classmethod
|
|
10
|
+
def custom_fields_cell_template(cls) -> str:
|
|
11
|
+
return 'JsonTemplate'
|
|
12
|
+
|
|
13
|
+
def pre_create(self) -> None:
|
|
14
|
+
self._validate_custom_fields()
|
|
15
|
+
super().pre_create()
|
|
16
|
+
|
|
17
|
+
async def apre_create(self) -> None:
|
|
18
|
+
await self._avalidate_custom_fields()
|
|
19
|
+
await super().apre_create()
|
|
20
|
+
|
|
21
|
+
def pre_update(self) -> None:
|
|
22
|
+
self._validate_custom_fields()
|
|
23
|
+
super().pre_update()
|
|
24
|
+
|
|
25
|
+
async def apre_update(self) -> None:
|
|
26
|
+
await self._avalidate_custom_fields()
|
|
27
|
+
await super().apre_update()
|
|
28
|
+
|
|
29
|
+
def _validate_custom_fields(self) -> None:
|
|
30
|
+
if self.custom_fields:
|
|
31
|
+
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
32
|
+
|
|
33
|
+
self.custom_fields = CustomFieldService.validate_custom_fields(
|
|
34
|
+
self.__class__.__name__,
|
|
35
|
+
self.custom_fields,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
async def _avalidate_custom_fields(self) -> None:
|
|
39
|
+
if self.custom_fields:
|
|
40
|
+
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
41
|
+
|
|
42
|
+
self.custom_fields = await CustomFieldService.avalidate_custom_fields(
|
|
43
|
+
self.__class__.__name__,
|
|
44
|
+
self.custom_fields,
|
|
45
|
+
)
|
amsdal_crm/models/deal.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"""Deal Model."""
|
|
2
2
|
|
|
3
3
|
import datetime as _dt
|
|
4
|
-
from typing import Any
|
|
5
4
|
from typing import ClassVar
|
|
6
5
|
from typing import Literal
|
|
7
6
|
|
|
@@ -14,13 +13,15 @@ from amsdal_utils.models.data_models.reference import Reference
|
|
|
14
13
|
from amsdal_utils.models.enums import ModuleType
|
|
15
14
|
from pydantic.fields import Field
|
|
16
15
|
|
|
16
|
+
from amsdal_crm.models.common import CustomFieldsMixin
|
|
17
|
+
|
|
17
18
|
|
|
18
19
|
class DealManager(Manager):
|
|
19
20
|
def get_queryset(self) -> 'DealManager':
|
|
20
21
|
return super().get_queryset().select_related('stage')
|
|
21
22
|
|
|
22
23
|
|
|
23
|
-
class Deal(TimestampMixin, Model):
|
|
24
|
+
class Deal(CustomFieldsMixin, TimestampMixin, Model):
|
|
24
25
|
"""Deal (Sales Opportunity) model.
|
|
25
26
|
|
|
26
27
|
Represents a sales opportunity linked to an account and contact,
|
|
@@ -50,9 +51,6 @@ class Deal(TimestampMixin, Model):
|
|
|
50
51
|
# Status tracking
|
|
51
52
|
status: Literal['open', 'closed_won', 'closed_lost'] = Field(default='open', title='Status')
|
|
52
53
|
|
|
53
|
-
# Custom fields (JSON)
|
|
54
|
-
custom_fields: dict[str, Any] | None = Field(default=None, title='Custom Fields')
|
|
55
|
-
|
|
56
54
|
@property
|
|
57
55
|
def display_name(self) -> str:
|
|
58
56
|
"""Return display name for the deal."""
|
|
@@ -90,34 +88,12 @@ class Deal(TimestampMixin, Model):
|
|
|
90
88
|
|
|
91
89
|
return False
|
|
92
90
|
|
|
93
|
-
def pre_create(self) -> None:
|
|
94
|
-
"""Hook called before creating deal."""
|
|
95
|
-
if self.custom_fields:
|
|
96
|
-
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
97
|
-
|
|
98
|
-
self.custom_fields = CustomFieldService.validate_custom_fields('Deal', self.custom_fields)
|
|
99
|
-
super().pre_create()
|
|
100
|
-
|
|
101
|
-
async def apre_create(self) -> None:
|
|
102
|
-
"""Async hook called before creating deal."""
|
|
103
|
-
if self.custom_fields:
|
|
104
|
-
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
105
|
-
|
|
106
|
-
self.custom_fields = await CustomFieldService.avalidate_custom_fields('Deal', self.custom_fields)
|
|
107
|
-
await super().apre_create()
|
|
108
|
-
|
|
109
91
|
def pre_update(self) -> None:
|
|
110
92
|
"""Hook called before updating deal.
|
|
111
93
|
|
|
112
94
|
Automatically syncs is_closed and is_won status with stage,
|
|
113
95
|
and sets closed_date when deal is closed.
|
|
114
96
|
"""
|
|
115
|
-
# Validate custom fields first
|
|
116
|
-
if self.custom_fields:
|
|
117
|
-
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
118
|
-
|
|
119
|
-
self.custom_fields = CustomFieldService.validate_custom_fields('Deal', self.custom_fields)
|
|
120
|
-
|
|
121
97
|
# Load stage if it's a reference and sync closed status
|
|
122
98
|
from amsdal_models.classes.helpers.reference_loader import ReferenceLoader
|
|
123
99
|
|
|
@@ -142,14 +118,7 @@ class Deal(TimestampMixin, Model):
|
|
|
142
118
|
|
|
143
119
|
Automatically syncs is_closed and is_won status with stage,
|
|
144
120
|
and sets closed_date when deal is closed.
|
|
145
|
-
"""
|
|
146
|
-
# Validate custom fields first
|
|
147
|
-
if self.custom_fields:
|
|
148
|
-
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
149
|
-
|
|
150
|
-
self.custom_fields = await CustomFieldService.avalidate_custom_fields('Deal', self.custom_fields)
|
|
151
|
-
|
|
152
|
-
# Load stage if it's a reference and sync closed status
|
|
121
|
+
""" # Load stage if it's a reference and sync closed status
|
|
153
122
|
|
|
154
123
|
stage = await self.stage
|
|
155
124
|
if stage.status == 'open':
|
amsdal_crm/models/entity.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
"""Account Model."""
|
|
2
2
|
|
|
3
|
-
from typing import Any
|
|
4
3
|
from typing import ClassVar
|
|
5
4
|
from typing import Literal
|
|
6
5
|
|
|
@@ -12,8 +11,10 @@ from amsdal_models.classes.model import Model
|
|
|
12
11
|
from amsdal_utils.models.enums import ModuleType
|
|
13
12
|
from pydantic.fields import Field
|
|
14
13
|
|
|
14
|
+
from amsdal_crm.models.common import CustomFieldsMixin
|
|
15
15
|
|
|
16
|
-
|
|
16
|
+
|
|
17
|
+
class Entity(CustomFieldsMixin, TimestampMixin, Model):
|
|
17
18
|
"""Entity (Person/Organization/Trust) model.
|
|
18
19
|
|
|
19
20
|
Represents a company or organization in the CRM system.
|
|
@@ -34,9 +35,6 @@ class Entity(TimestampMixin, Model):
|
|
|
34
35
|
|
|
35
36
|
assigned_to: User | None = Field(default=None, title='Assigned To')
|
|
36
37
|
|
|
37
|
-
# Custom fields (JSON)
|
|
38
|
-
custom_fields: dict[str, Any] | None = Field(default=None, title='Custom Fields')
|
|
39
|
-
|
|
40
38
|
@property
|
|
41
39
|
def display_name(self) -> str:
|
|
42
40
|
"""Return display name for the account."""
|
|
@@ -65,44 +63,6 @@ class Entity(TimestampMixin, Model):
|
|
|
65
63
|
|
|
66
64
|
return False
|
|
67
65
|
|
|
68
|
-
def pre_create(self) -> None:
|
|
69
|
-
"""Hook called before creating account."""
|
|
70
|
-
if self.custom_fields:
|
|
71
|
-
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
72
|
-
|
|
73
|
-
self.custom_fields = CustomFieldService.validate_custom_fields('Entity', self.custom_fields)
|
|
74
|
-
super().pre_create()
|
|
75
|
-
|
|
76
|
-
async def apre_create(self) -> None:
|
|
77
|
-
"""Async hook called before creating account."""
|
|
78
|
-
if self.custom_fields:
|
|
79
|
-
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
80
|
-
|
|
81
|
-
self.custom_fields = await CustomFieldService.avalidate_custom_fields('Entity', self.custom_fields)
|
|
82
|
-
await super().apre_create()
|
|
83
|
-
|
|
84
|
-
def pre_update(self) -> None:
|
|
85
|
-
"""Hook called before updating account."""
|
|
86
|
-
# Validate custom fields first
|
|
87
|
-
if self.custom_fields:
|
|
88
|
-
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
89
|
-
|
|
90
|
-
self.custom_fields = CustomFieldService.validate_custom_fields('Entity', self.custom_fields)
|
|
91
|
-
|
|
92
|
-
# Call parent to handle timestamps
|
|
93
|
-
super().pre_update()
|
|
94
|
-
|
|
95
|
-
async def apre_update(self) -> None:
|
|
96
|
-
"""Async hook called before updating account."""
|
|
97
|
-
# Validate custom fields first
|
|
98
|
-
if self.custom_fields:
|
|
99
|
-
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
100
|
-
|
|
101
|
-
self.custom_fields = await CustomFieldService.avalidate_custom_fields('Entity', self.custom_fields)
|
|
102
|
-
|
|
103
|
-
# Call parent to handle timestamps
|
|
104
|
-
await super().apre_update()
|
|
105
|
-
|
|
106
66
|
def post_update(self) -> None:
|
|
107
67
|
"""Hook called after updating account."""
|
|
108
68
|
from amsdal_crm.services.workflow_service import WorkflowService
|
|
@@ -116,7 +76,7 @@ class Entity(TimestampMixin, Model):
|
|
|
116
76
|
await WorkflowService.aexecute_rules('Entity', 'update', self)
|
|
117
77
|
|
|
118
78
|
|
|
119
|
-
class EntityRelationship(TimestampMixin, Model):
|
|
79
|
+
class EntityRelationship(CustomFieldsMixin, TimestampMixin, Model):
|
|
120
80
|
__module_type__: ClassVar[ModuleType] = ModuleType.CONTRIB
|
|
121
81
|
|
|
122
82
|
from_entity: Entity = Field(title='From Entity')
|
|
@@ -125,53 +85,8 @@ class EntityRelationship(TimestampMixin, Model):
|
|
|
125
85
|
end_date: str | None = Field(default=None, title='End Date')
|
|
126
86
|
relationship_group_name: str | None = Field(default=None, title='Relationship Group Name')
|
|
127
87
|
|
|
128
|
-
# Custom fields (JSON)
|
|
129
|
-
custom_fields: dict[str, Any] | None = Field(default=None, title='Custom Fields')
|
|
130
|
-
|
|
131
|
-
def pre_create(self) -> None:
|
|
132
|
-
"""Hook called before creating account."""
|
|
133
|
-
if self.custom_fields:
|
|
134
|
-
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
135
|
-
|
|
136
|
-
self.custom_fields = CustomFieldService.validate_custom_fields('EntityRelationship', self.custom_fields)
|
|
137
|
-
super().pre_create()
|
|
138
88
|
|
|
139
|
-
|
|
140
|
-
"""Async hook called before creating account."""
|
|
141
|
-
if self.custom_fields:
|
|
142
|
-
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
143
|
-
|
|
144
|
-
self.custom_fields = await CustomFieldService.avalidate_custom_fields(
|
|
145
|
-
'EntityRelationship', self.custom_fields
|
|
146
|
-
)
|
|
147
|
-
await super().apre_create()
|
|
148
|
-
|
|
149
|
-
def pre_update(self) -> None:
|
|
150
|
-
"""Hook called before updating account."""
|
|
151
|
-
# Validate custom fields first
|
|
152
|
-
if self.custom_fields:
|
|
153
|
-
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
154
|
-
|
|
155
|
-
self.custom_fields = CustomFieldService.validate_custom_fields('EntityRelationship', self.custom_fields)
|
|
156
|
-
|
|
157
|
-
# Call parent to handle timestamps
|
|
158
|
-
super().pre_update()
|
|
159
|
-
|
|
160
|
-
async def apre_update(self) -> None:
|
|
161
|
-
"""Async hook called before updating account."""
|
|
162
|
-
# Validate custom fields first
|
|
163
|
-
if self.custom_fields:
|
|
164
|
-
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
165
|
-
|
|
166
|
-
self.custom_fields = await CustomFieldService.avalidate_custom_fields(
|
|
167
|
-
'EntityRelationship', self.custom_fields
|
|
168
|
-
)
|
|
169
|
-
|
|
170
|
-
# Call parent to handle timestamps
|
|
171
|
-
await super().apre_update()
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
class EntityIdentifier(TimestampMixin, Model):
|
|
89
|
+
class EntityIdentifier(CustomFieldsMixin, TimestampMixin, Model):
|
|
175
90
|
__module_type__: ClassVar[ModuleType] = ModuleType.CONTRIB
|
|
176
91
|
|
|
177
92
|
entity: Entity = Field(title='Entity')
|
|
@@ -181,53 +96,8 @@ class EntityIdentifier(TimestampMixin, Model):
|
|
|
181
96
|
# TODO: validate one per entity
|
|
182
97
|
is_primary: bool = Field(default=False, title='Is Primary')
|
|
183
98
|
|
|
184
|
-
# Custom fields (JSON)
|
|
185
|
-
custom_fields: dict[str, Any] | None = Field(default=None, title='Custom Fields')
|
|
186
|
-
|
|
187
|
-
def pre_create(self) -> None:
|
|
188
|
-
"""Hook called before creating account."""
|
|
189
|
-
if self.custom_fields:
|
|
190
|
-
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
191
|
-
|
|
192
|
-
self.custom_fields = CustomFieldService.validate_custom_fields('EntityIdentifier', self.custom_fields)
|
|
193
|
-
super().pre_create()
|
|
194
|
-
|
|
195
|
-
async def apre_create(self) -> None:
|
|
196
|
-
"""Async hook called before creating account."""
|
|
197
|
-
if self.custom_fields:
|
|
198
|
-
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
199
|
-
|
|
200
|
-
self.custom_fields = await CustomFieldService.avalidate_custom_fields(
|
|
201
|
-
'EntityIdentifier', self.custom_fields
|
|
202
|
-
)
|
|
203
|
-
await super().apre_create()
|
|
204
|
-
|
|
205
|
-
def pre_update(self) -> None:
|
|
206
|
-
"""Hook called before updating account."""
|
|
207
|
-
# Validate custom fields first
|
|
208
|
-
if self.custom_fields:
|
|
209
|
-
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
210
99
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
# Call parent to handle timestamps
|
|
214
|
-
super().pre_update()
|
|
215
|
-
|
|
216
|
-
async def apre_update(self) -> None:
|
|
217
|
-
"""Async hook called before updating account."""
|
|
218
|
-
# Validate custom fields first
|
|
219
|
-
if self.custom_fields:
|
|
220
|
-
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
221
|
-
|
|
222
|
-
self.custom_fields = await CustomFieldService.avalidate_custom_fields(
|
|
223
|
-
'EntityIdentifier', self.custom_fields
|
|
224
|
-
)
|
|
225
|
-
|
|
226
|
-
# Call parent to handle timestamps
|
|
227
|
-
await super().apre_update()
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
class EntityContactPoint(TimestampMixin, Model):
|
|
100
|
+
class EntityContactPoint(CustomFieldsMixin, TimestampMixin, Model):
|
|
231
101
|
__module_type__: ClassVar[ModuleType] = ModuleType.CONTRIB
|
|
232
102
|
|
|
233
103
|
entity: Entity = Field(title='Entity')
|
|
@@ -237,53 +107,8 @@ class EntityContactPoint(TimestampMixin, Model):
|
|
|
237
107
|
is_primary: bool = Field(default=False, title='Is Primary')
|
|
238
108
|
can_contact: bool = Field(default=True, title='Can Contact')
|
|
239
109
|
|
|
240
|
-
# Custom fields (JSON)
|
|
241
|
-
custom_fields: dict[str, Any] | None = Field(default=None, title='Custom Fields')
|
|
242
|
-
|
|
243
|
-
def pre_create(self) -> None:
|
|
244
|
-
"""Hook called before creating account."""
|
|
245
|
-
if self.custom_fields:
|
|
246
|
-
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
247
|
-
|
|
248
|
-
self.custom_fields = CustomFieldService.validate_custom_fields('EntityContactPoint', self.custom_fields)
|
|
249
|
-
super().pre_create()
|
|
250
|
-
|
|
251
|
-
async def apre_create(self) -> None:
|
|
252
|
-
"""Async hook called before creating account."""
|
|
253
|
-
if self.custom_fields:
|
|
254
|
-
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
255
|
-
|
|
256
|
-
self.custom_fields = await CustomFieldService.avalidate_custom_fields(
|
|
257
|
-
'EntityContactPoint', self.custom_fields
|
|
258
|
-
)
|
|
259
|
-
await super().apre_create()
|
|
260
|
-
|
|
261
|
-
def pre_update(self) -> None:
|
|
262
|
-
"""Hook called before updating account."""
|
|
263
|
-
# Validate custom fields first
|
|
264
|
-
if self.custom_fields:
|
|
265
|
-
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
266
|
-
|
|
267
|
-
self.custom_fields = CustomFieldService.validate_custom_fields('EntityContactPoint', self.custom_fields)
|
|
268
|
-
|
|
269
|
-
# Call parent to handle timestamps
|
|
270
|
-
super().pre_update()
|
|
271
|
-
|
|
272
|
-
async def apre_update(self) -> None:
|
|
273
|
-
"""Async hook called before updating account."""
|
|
274
|
-
# Validate custom fields first
|
|
275
|
-
if self.custom_fields:
|
|
276
|
-
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
277
110
|
|
|
278
|
-
|
|
279
|
-
'EntityContactPoint', self.custom_fields
|
|
280
|
-
)
|
|
281
|
-
|
|
282
|
-
# Call parent to handle timestamps
|
|
283
|
-
await super().apre_update()
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
class EntityAddress(TimestampMixin, Model):
|
|
111
|
+
class EntityAddress(CustomFieldsMixin, TimestampMixin, Model):
|
|
287
112
|
__module_type__: ClassVar[ModuleType] = ModuleType.CONTRIB
|
|
288
113
|
|
|
289
114
|
line1: str | None = Field(title='Address Line 1')
|
|
@@ -295,44 +120,3 @@ class EntityAddress(TimestampMixin, Model):
|
|
|
295
120
|
|
|
296
121
|
# TODO: validate one per entity
|
|
297
122
|
is_primary: bool = Field(default=False, title='Is Primary')
|
|
298
|
-
|
|
299
|
-
# Custom fields (JSON)
|
|
300
|
-
custom_fields: dict[str, Any] | None = Field(default=None, title='Custom Fields')
|
|
301
|
-
|
|
302
|
-
def pre_create(self) -> None:
|
|
303
|
-
"""Hook called before creating account."""
|
|
304
|
-
if self.custom_fields:
|
|
305
|
-
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
306
|
-
|
|
307
|
-
self.custom_fields = CustomFieldService.validate_custom_fields('EntityAddress', self.custom_fields)
|
|
308
|
-
super().pre_create()
|
|
309
|
-
|
|
310
|
-
async def apre_create(self) -> None:
|
|
311
|
-
"""Async hook called before creating account."""
|
|
312
|
-
if self.custom_fields:
|
|
313
|
-
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
314
|
-
|
|
315
|
-
self.custom_fields = await CustomFieldService.avalidate_custom_fields('EntityAddress', self.custom_fields)
|
|
316
|
-
await super().apre_create()
|
|
317
|
-
|
|
318
|
-
def pre_update(self) -> None:
|
|
319
|
-
"""Hook called before updating account."""
|
|
320
|
-
# Validate custom fields first
|
|
321
|
-
if self.custom_fields:
|
|
322
|
-
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
323
|
-
|
|
324
|
-
self.custom_fields = CustomFieldService.validate_custom_fields('EntityAddress', self.custom_fields)
|
|
325
|
-
|
|
326
|
-
# Call parent to handle timestamps
|
|
327
|
-
super().pre_update()
|
|
328
|
-
|
|
329
|
-
async def apre_update(self) -> None:
|
|
330
|
-
"""Async hook called before updating account."""
|
|
331
|
-
# Validate custom fields first
|
|
332
|
-
if self.custom_fields:
|
|
333
|
-
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
334
|
-
|
|
335
|
-
self.custom_fields = await CustomFieldService.avalidate_custom_fields('EntityAddress', self.custom_fields)
|
|
336
|
-
|
|
337
|
-
# Call parent to handle timestamps
|
|
338
|
-
await super().apre_update()
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
amsdal_crm/Third-Party Materials - AMSDAL Dependencies - License Notices.md,sha256=ML7PqsHrTMNNZn8E_rA-LzDCAafMSxMcrmSg8YOi-wo,113896
|
|
2
|
-
amsdal_crm/__about__.py,sha256=
|
|
2
|
+
amsdal_crm/__about__.py,sha256=N5-p8dQB8uwuCMpS1ADLf_E6rvWovtRRp3vY9Cq2gw4,22
|
|
3
3
|
amsdal_crm/__init__.py,sha256=b4wxJYesA5Ctk1IrAvlw64i_0EU3SiK1Tw6sUYakd18,303
|
|
4
4
|
amsdal_crm/app.py,sha256=JLvueh_2KURQLDWMQlq4Z6gAFsqBDTRf6pK095ehp14,1373
|
|
5
5
|
amsdal_crm/constants.py,sha256=5Ga7q9zEKcQZnAoKv_SE_7w8WxvhPFkM9gY9NruOEaA,347
|
|
@@ -10,13 +10,14 @@ amsdal_crm/fixtures/permissions.py,sha256=TQEY_zX60GSudSZqmonaYqWCaod6oBsQw1NQPu
|
|
|
10
10
|
amsdal_crm/fixtures/pipelines.py,sha256=ZCLmgrA700Sl7Oy7l4IQ8FbIbC1378OkcJTrZe5701o,2064
|
|
11
11
|
amsdal_crm/lifecycle/__init__.py,sha256=B8nw19lEIr7U15Lnu6jh7yzZwF9LWWh4-p3X63sAicQ,31
|
|
12
12
|
amsdal_crm/lifecycle/consumer.py,sha256=owS9kXKPs3Lzy7RiN_jI6hHEO6c90Tf-DT6aNqQ3uj4,8893
|
|
13
|
-
amsdal_crm/migrations/0000_initial.py,sha256=
|
|
13
|
+
amsdal_crm/migrations/0000_initial.py,sha256=Jf7iw4wOzwM9DIFfNGZoaaB_AsmUnRz8OB8iy7skUqM,62079
|
|
14
14
|
amsdal_crm/models/__init__.py,sha256=3c-gqBkw2PXg4rp_wH2EN6viRu7Ff926Etn_BkQa5RU,18
|
|
15
15
|
amsdal_crm/models/activity.py,sha256=Hwy_Z_zhk96yopTcm4vU4-SZbPg152r7N9er96Jkdho,4732
|
|
16
16
|
amsdal_crm/models/attachment.py,sha256=B-6IuPrF6-VDnsFz_Q4UCh09YcFMs4o4zyT4VpvLe3U,1513
|
|
17
|
+
amsdal_crm/models/common.py,sha256=cKArZNNO7hsXrd9s4GF36nqZbsLkVldHovcCH5cJ-aM,1398
|
|
17
18
|
amsdal_crm/models/custom_field_definition.py,sha256=0IIWcetZ0vXT8lPRGahyt7phoNKuCq2MQO6C8wEGk4Q,1749
|
|
18
|
-
amsdal_crm/models/deal.py,sha256=
|
|
19
|
-
amsdal_crm/models/entity.py,sha256=
|
|
19
|
+
amsdal_crm/models/deal.py,sha256=dwO3NFL-l_2tgWXEKtouuUF40VV5f_bqN_NcW7Mhr38,5300
|
|
20
|
+
amsdal_crm/models/entity.py,sha256=Xtwu6IiGU3DRw-55zcGrFtt_k4Eit0KhOkLC9kn-QqE,4642
|
|
20
21
|
amsdal_crm/models/pipeline.py,sha256=DXJh5MbCCRctEHhDfxef5RxFWSKN0D4v6UK75q5ssL8,925
|
|
21
22
|
amsdal_crm/models/stage.py,sha256=57rhfA4Oib8DKjDifWQe3EFxh-Auww3_PgOPfj4-L0E,1666
|
|
22
23
|
amsdal_crm/models/workflow_rule.py,sha256=g-vAdJHKyA1PsiB3vPhd474Uvq94USHz35W1c5XyrAQ,1535
|
|
@@ -26,6 +27,6 @@ amsdal_crm/services/custom_field_service.py,sha256=r2dr2gijTbi9r56XV64bSArx0jTGw
|
|
|
26
27
|
amsdal_crm/services/deal_service.py,sha256=PTxCQy6YqMyrtL4sRhyCU09V6OemrmZ405sQk-eBUlA,4803
|
|
27
28
|
amsdal_crm/services/email_service.py,sha256=L9o-WaOET0tjo9g-zzC8GGCtfDZVheziHM_ob10jO2M,3518
|
|
28
29
|
amsdal_crm/services/workflow_service.py,sha256=7m_vbk9FL_FCy9KS9LM4ueztO9ZsLwbvubdo9NA345g,7020
|
|
29
|
-
amsdal_crm-0.2.
|
|
30
|
-
amsdal_crm-0.2.
|
|
31
|
-
amsdal_crm-0.2.
|
|
30
|
+
amsdal_crm-0.2.4.dist-info/METADATA,sha256=OR346BRRjyP-Od4wg4T4b8q5-A0luscGgU0u8G2j2bU,1596
|
|
31
|
+
amsdal_crm-0.2.4.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
32
|
+
amsdal_crm-0.2.4.dist-info/RECORD,,
|
|
File without changes
|