amsdal_crm 0.1.7__tar.gz → 0.1.9__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 (75) hide show
  1. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/PKG-INFO +1 -1
  2. amsdal_crm-0.1.9/amsdal_crm/__about__.py +1 -0
  3. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/migrations/0000_initial.py +1 -1
  4. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/models/deal.py +7 -2
  5. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/models/stage.py +8 -0
  6. amsdal_crm-0.1.7/amsdal_crm/__about__.py +0 -1
  7. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/.amsdal/.environment +0 -0
  8. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/.amsdal-cli +0 -0
  9. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/.github/workflows/ci.yml +0 -0
  10. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/.github/workflows/release.yml +0 -0
  11. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/.github/workflows/tag_check.yml +0 -0
  12. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/.gitignore +0 -0
  13. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/CLAUDE.md +0 -0
  14. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/README.md +0 -0
  15. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/RELEASE.md +0 -0
  16. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/Third-Party Materials - AMSDAL Dependencies - License Notices.md +0 -0
  17. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/__init__.py +0 -0
  18. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/app.py +0 -0
  19. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/constants.py +0 -0
  20. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/errors.py +0 -0
  21. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/fixtures/__init__.py +0 -0
  22. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/fixtures/permissions.py +0 -0
  23. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/fixtures/pipelines.py +0 -0
  24. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/lifecycle/__init__.py +0 -0
  25. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/lifecycle/consumer.py +0 -0
  26. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/models/__init__.py +0 -0
  27. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/models/account.py +0 -0
  28. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/models/activity.py +0 -0
  29. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/models/attachment.py +0 -0
  30. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/models/contact.py +0 -0
  31. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/models/custom_field_definition.py +0 -0
  32. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/models/pipeline.py +0 -0
  33. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/models/workflow_rule.py +0 -0
  34. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/services/__init__.py +0 -0
  35. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/services/activity_service.py +0 -0
  36. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/services/custom_field_service.py +0 -0
  37. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/services/deal_service.py +0 -0
  38. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/services/email_service.py +0 -0
  39. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/services/workflow_service.py +0 -0
  40. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/amsdal_crm/settings.py +0 -0
  41. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/config.yml +0 -0
  42. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/license_check.py +0 -0
  43. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/pyproject.toml +0 -0
  44. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/scripts/release.sh +0 -0
  45. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/scripts/tag_check.sh +0 -0
  46. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/conftest.py +0 -0
  47. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/integration/__init__.py +0 -0
  48. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/integration/conftest.py +0 -0
  49. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/integration/services/__init__.py +0 -0
  50. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/integration/services/test_deal_service.py +0 -0
  51. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/integration/services/test_email_service.py +0 -0
  52. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/integration/services/test_workflow_service.py +0 -0
  53. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/unit/__init__.py +0 -0
  54. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/unit/conftest.py +0 -0
  55. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/unit/lifecycle/__init__.py +0 -0
  56. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/unit/lifecycle/test_consumer.py +0 -0
  57. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/unit/models/__init__.py +0 -0
  58. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/unit/models/test_account.py +0 -0
  59. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/unit/models/test_activity.py +0 -0
  60. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/unit/models/test_contact.py +0 -0
  61. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/unit/models/test_deal.py +0 -0
  62. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/unit/models/test_pipeline.py +0 -0
  63. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/unit/models/test_remaining.py +0 -0
  64. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/unit/models/test_stage.py +0 -0
  65. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/unit/services/__init__.py +0 -0
  66. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/unit/services/test_activity_service.py +0 -0
  67. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/unit/services/test_custom_field_service.py +0 -0
  68. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/unit/services/test_deal_service.py +0 -0
  69. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/unit/services/test_email_service.py +0 -0
  70. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/unit/services/test_workflow_service.py +0 -0
  71. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/unit/test_app.py +0 -0
  72. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/unit/test_constants.py +0 -0
  73. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/unit/test_errors.py +0 -0
  74. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/tests/unit/test_settings.py +0 -0
  75. {amsdal_crm-0.1.7 → amsdal_crm-0.1.9}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: amsdal_crm
3
- Version: 0.1.7
3
+ Version: 0.1.9
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.1.9'
@@ -469,7 +469,7 @@ class Migration(migrations.Migration):
469
469
  "is_won": {"type": "boolean", "default": False, "title": "Is Won"},
470
470
  "custom_fields": {"type": "anything", "title": "Custom Fields"},
471
471
  },
472
- "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 apost_update(self) -> None:\n """Async hook called after updating deal."""\n from amsdal_crm.services.workflow_service import WorkflowService\n WorkflowService.execute_rules(\'Deal\', \'update\', self)\n\nasync def apre_create(self) -> None:\n """Async hook called before creating deal."""\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = await CustomFieldService.avalidate_custom_fields(\'Deal\', self.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 if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = await CustomFieldService.avalidate_custom_fields(\'Deal\', self.custom_fields)\n from amsdal_models.classes.helpers.reference_loader import ReferenceLoader\n stage = await ReferenceLoader(self.stage).aload_reference() if isinstance(self.stage, Reference) else self.stage\n self.is_closed = stage.is_closed_won or stage.is_closed_lost\n self.is_won = stage.is_closed_won\n if self.is_closed and (not self.closed_date):\n self.closed_date = _dt.datetime.now(_dt.UTC)\n await super().apre_update()\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.owner_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 """Hook called before creating deal."""\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = CustomFieldService.validate_custom_fields(\'Deal\', self.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 if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = CustomFieldService.validate_custom_fields(\'Deal\', self.custom_fields)\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 self.is_closed = stage.is_closed_won or stage.is_closed_lost\n self.is_won = stage.is_closed_won\n if self.is_closed and (not self.closed_date):\n self.closed_date = _dt.datetime.now(_dt.UTC)\n super().pre_update()',
472
+ "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 apost_update(self) -> None:\n """Async hook called after updating deal."""\n from amsdal_crm.services.workflow_service import WorkflowService\n WorkflowService.execute_rules(\'Deal\', \'update\', self)\n\nasync def apre_create(self) -> None:\n """Async hook called before creating deal."""\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = await CustomFieldService.avalidate_custom_fields(\'Deal\', self.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 if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = await CustomFieldService.avalidate_custom_fields(\'Deal\', self.custom_fields)\n stage = await self.stage\n self.is_closed = stage.is_closed_won or stage.is_closed_lost\n self.is_won = stage.is_closed_won\n if self.is_closed and (not self.closed_date):\n self.closed_date = _dt.datetime.now(_dt.UTC)\n await super().apre_update()\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.owner_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 """Hook called before creating deal."""\n if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = CustomFieldService.validate_custom_fields(\'Deal\', self.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 if self.custom_fields:\n from amsdal_crm.services.custom_field_service import CustomFieldService\n self.custom_fields = CustomFieldService.validate_custom_fields(\'Deal\', self.custom_fields)\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 self.is_closed = stage.is_closed_won or stage.is_closed_lost\n self.is_won = stage.is_closed_won\n if self.is_closed and (not self.closed_date):\n self.closed_date = _dt.datetime.now(_dt.UTC)\n super().pre_update()',
473
473
  "storage_metadata": {
474
474
  "table_name": "Deal",
475
475
  "db_fields": {
@@ -9,11 +9,17 @@ from amsdal.contrib.auth.models.user import User
9
9
  from amsdal.models.mixins import TimestampMixin
10
10
  from amsdal_models.classes.data_models.indexes import IndexInfo
11
11
  from amsdal_models.classes.model import Model
12
+ from amsdal_models.managers.model_manager import Manager
12
13
  from amsdal_utils.models.data_models.reference import Reference
13
14
  from amsdal_utils.models.enums import ModuleType
14
15
  from pydantic.fields import Field
15
16
 
16
17
 
18
+ class DealManager(Manager):
19
+ def get_queryset(self) -> 'DealManager':
20
+ return super().get_queryset().select_related('stage')
21
+
22
+
17
23
  class Deal(TimestampMixin, Model):
18
24
  """Deal (Sales Opportunity) model.
19
25
 
@@ -140,9 +146,8 @@ class Deal(TimestampMixin, Model):
140
146
  self.custom_fields = await CustomFieldService.avalidate_custom_fields('Deal', self.custom_fields)
141
147
 
142
148
  # Load stage if it's a reference and sync closed status
143
- from amsdal_models.classes.helpers.reference_loader import ReferenceLoader
144
149
 
145
- stage = await ReferenceLoader(self.stage).aload_reference() if isinstance(self.stage, Reference) else self.stage
150
+ stage = await self.stage
146
151
  self.is_closed = stage.is_closed_won or stage.is_closed_lost
147
152
  self.is_won = stage.is_closed_won
148
153
 
@@ -4,11 +4,17 @@ from typing import ClassVar
4
4
 
5
5
  from amsdal_models.classes.data_models.indexes import IndexInfo
6
6
  from amsdal_models.classes.model import Model
7
+ from amsdal_models.managers.model_manager import Manager
7
8
  from amsdal_utils.models.enums import ModuleType
8
9
  from pydantic import ConfigDict
9
10
  from pydantic.fields import Field
10
11
 
11
12
 
13
+ class StageManager(Manager):
14
+ def get_queryset(self) -> 'StageManager':
15
+ return super().get_queryset().select_related('pipeline')
16
+
17
+
12
18
  class Stage(Model):
13
19
  """Pipeline stage model.
14
20
 
@@ -18,6 +24,8 @@ class Stage(Model):
18
24
 
19
25
  model_config: ClassVar[ConfigDict] = ConfigDict(arbitrary_types_allowed=True)
20
26
 
27
+ objects = StageManager()
28
+
21
29
  __module_type__: ClassVar[ModuleType] = ModuleType.CONTRIB
22
30
  __indexes__: ClassVar[list[IndexInfo]] = [
23
31
  IndexInfo(name='idx_stage_order', field='order'),
@@ -1 +0,0 @@
1
- __version__ = '0.1.7'
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