amsdal_crm 0.1.2__tar.gz → 0.1.4__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.
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/PKG-INFO +1 -1
- amsdal_crm-0.1.4/amsdal_crm/__about__.py +1 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/lifecycle/consumer.py +40 -6
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/models/account.py +3 -3
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/models/contact.py +3 -3
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/models/deal.py +2 -2
- amsdal_crm-0.1.2/amsdal_crm/__about__.py +0 -1
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/.amsdal/.environment +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/.amsdal-cli +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/.github/workflows/ci.yml +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/.github/workflows/release.yml +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/.github/workflows/tag_check.yml +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/.gitignore +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/CLAUDE.md +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/README.md +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/RELEASE.md +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/Third-Party Materials - AMSDAL Dependencies - License Notices.md +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/__init__.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/app.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/constants.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/errors.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/fixtures/__init__.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/fixtures/permissions.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/fixtures/pipelines.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/lifecycle/__init__.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/migrations/0000_initial.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/models/__init__.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/models/activity.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/models/attachment.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/models/custom_field_definition.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/models/pipeline.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/models/stage.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/models/workflow_rule.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/services/__init__.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/services/activity_service.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/services/custom_field_service.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/services/deal_service.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/services/email_service.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/services/workflow_service.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/amsdal_crm/settings.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/config.yml +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/license_check.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/pyproject.toml +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/scripts/release.sh +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/scripts/tag_check.sh +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/conftest.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/integration/__init__.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/integration/conftest.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/integration/services/__init__.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/integration/services/test_deal_service.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/integration/services/test_email_service.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/integration/services/test_workflow_service.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/unit/__init__.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/unit/conftest.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/unit/lifecycle/__init__.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/unit/lifecycle/test_consumer.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/unit/models/__init__.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/unit/models/test_account.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/unit/models/test_activity.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/unit/models/test_contact.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/unit/models/test_deal.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/unit/models/test_pipeline.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/unit/models/test_remaining.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/unit/models/test_stage.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/unit/services/__init__.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/unit/services/test_activity_service.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/unit/services/test_custom_field_service.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/unit/services/test_deal_service.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/unit/services/test_email_service.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/unit/services/test_workflow_service.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/unit/test_app.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/unit/test_constants.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/unit/test_errors.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/tests/unit/test_settings.py +0 -0
- {amsdal_crm-0.1.2 → amsdal_crm-0.1.4}/uv.lock +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '0.1.4'
|
|
@@ -50,7 +50,7 @@ class DealWonNotificationConsumer(LifecycleConsumer):
|
|
|
50
50
|
pass
|
|
51
51
|
|
|
52
52
|
|
|
53
|
-
def _custom_field_def_to_control(field_def: Any) -> dict[str, Any]:
|
|
53
|
+
def _custom_field_def_to_control(field_def: Any, values: dict[str, Any]) -> dict[str, Any]:
|
|
54
54
|
"""Convert a CustomFieldDefinition to a frontend control config.
|
|
55
55
|
|
|
56
56
|
Args:
|
|
@@ -82,6 +82,9 @@ def _custom_field_def_to_control(field_def: Any) -> dict[str, Any]:
|
|
|
82
82
|
if field_def.choices:
|
|
83
83
|
control['options'] = [{'label': choice, 'value': choice} for choice in field_def.choices]
|
|
84
84
|
|
|
85
|
+
if values and field_def.field_name in values:
|
|
86
|
+
control['value'] = values[field_def.field_name]
|
|
87
|
+
|
|
85
88
|
return control
|
|
86
89
|
|
|
87
90
|
|
|
@@ -98,9 +101,6 @@ def _add_custom_fields_to_control(control: dict[str, Any], custom_field_controls
|
|
|
98
101
|
if 'controls' not in control:
|
|
99
102
|
control['controls'] = []
|
|
100
103
|
|
|
101
|
-
if 'control' in control:
|
|
102
|
-
control.pop('control', None)
|
|
103
|
-
|
|
104
104
|
# Find the custom_fields control and update it, or append custom fields at the end
|
|
105
105
|
custom_fields_control = None
|
|
106
106
|
for ctrl in control.get('controls', []):
|
|
@@ -112,6 +112,8 @@ def _add_custom_fields_to_control(control: dict[str, Any], custom_field_controls
|
|
|
112
112
|
# Update the custom_fields control to be a group with nested controls
|
|
113
113
|
custom_fields_control['type'] = 'group'
|
|
114
114
|
custom_fields_control['controls'] = custom_field_controls
|
|
115
|
+
if 'control' in custom_fields_control:
|
|
116
|
+
custom_fields_control.pop('control', None)
|
|
115
117
|
else:
|
|
116
118
|
# Add custom fields as a new group at the end
|
|
117
119
|
control['controls'].append(
|
|
@@ -124,6 +126,30 @@ def _add_custom_fields_to_control(control: dict[str, Any], custom_field_controls
|
|
|
124
126
|
)
|
|
125
127
|
|
|
126
128
|
|
|
129
|
+
def get_values_from_response(response: dict[str, Any] | list[dict[str, Any]]) -> dict[str, Any]:
|
|
130
|
+
"""
|
|
131
|
+
Extracts values from a response dictionary or list of dictionaries.
|
|
132
|
+
|
|
133
|
+
This function processes a response to extract the relevant values. It checks if the response
|
|
134
|
+
is a dictionary containing a 'rows' key and processes the rows to find the appropriate values.
|
|
135
|
+
If the response is not in the expected format, it returns an empty dictionary.
|
|
136
|
+
|
|
137
|
+
Args:
|
|
138
|
+
response (dict[str, Any] | list[dict[str, Any]]): The response to extract values from.
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
dict[str, Any]: A dictionary containing the extracted values.
|
|
142
|
+
"""
|
|
143
|
+
if not isinstance(response, dict) or 'rows' not in response or not response['rows']:
|
|
144
|
+
return {}
|
|
145
|
+
|
|
146
|
+
for row in response['rows']:
|
|
147
|
+
if '_metadata' in row and row['_metadata'].get('next_version') is None:
|
|
148
|
+
return row
|
|
149
|
+
|
|
150
|
+
return response['rows'][0]
|
|
151
|
+
|
|
152
|
+
|
|
127
153
|
class CustomAttributesFrontendConfigConsumer(LifecycleConsumer):
|
|
128
154
|
"""Consumer that propagates custom attributes into frontend config.
|
|
129
155
|
|
|
@@ -152,6 +178,8 @@ class CustomAttributesFrontendConfigConsumer(LifecycleConsumer):
|
|
|
152
178
|
if not isinstance(response, dict) or 'control' not in response:
|
|
153
179
|
return
|
|
154
180
|
|
|
181
|
+
values = get_values_from_response(response)
|
|
182
|
+
|
|
155
183
|
custom_field_defs = list(
|
|
156
184
|
CustomFieldDefinition.objects.filter(
|
|
157
185
|
entity_type=class_name,
|
|
@@ -166,7 +194,9 @@ class CustomAttributesFrontendConfigConsumer(LifecycleConsumer):
|
|
|
166
194
|
# Sort by display_order
|
|
167
195
|
custom_field_defs.sort(key=lambda x: x.display_order)
|
|
168
196
|
|
|
169
|
-
custom_field_controls = [
|
|
197
|
+
custom_field_controls = [
|
|
198
|
+
_custom_field_def_to_control(field_def, values=values) for field_def in custom_field_defs
|
|
199
|
+
]
|
|
170
200
|
|
|
171
201
|
_add_custom_fields_to_control(response['control'], custom_field_controls)
|
|
172
202
|
|
|
@@ -191,6 +221,8 @@ class CustomAttributesFrontendConfigConsumer(LifecycleConsumer):
|
|
|
191
221
|
if not isinstance(response, dict) or 'control' not in response:
|
|
192
222
|
return
|
|
193
223
|
|
|
224
|
+
values = get_values_from_response(response)
|
|
225
|
+
|
|
194
226
|
custom_field_defs = list(
|
|
195
227
|
await CustomFieldDefinition.objects.filter(
|
|
196
228
|
entity_type=class_name,
|
|
@@ -205,7 +237,9 @@ class CustomAttributesFrontendConfigConsumer(LifecycleConsumer):
|
|
|
205
237
|
# Sort by display_order
|
|
206
238
|
custom_field_defs.sort(key=lambda x: x.display_order)
|
|
207
239
|
|
|
208
|
-
custom_field_controls = [
|
|
240
|
+
custom_field_controls = [
|
|
241
|
+
_custom_field_def_to_control(field_def, values=values) for field_def in custom_field_defs
|
|
242
|
+
]
|
|
209
243
|
|
|
210
244
|
_add_custom_fields_to_control(response['control'], custom_field_controls)
|
|
211
245
|
|
|
@@ -89,7 +89,7 @@ class Account(TimestampMixin, Model):
|
|
|
89
89
|
if self.custom_fields:
|
|
90
90
|
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
91
91
|
|
|
92
|
-
self.custom_fields = CustomFieldService.
|
|
92
|
+
self.custom_fields = await CustomFieldService.avalidate_custom_fields('Account', self.custom_fields)
|
|
93
93
|
await super().apre_create()
|
|
94
94
|
|
|
95
95
|
def pre_update(self) -> None:
|
|
@@ -109,7 +109,7 @@ class Account(TimestampMixin, Model):
|
|
|
109
109
|
if self.custom_fields:
|
|
110
110
|
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
111
111
|
|
|
112
|
-
self.custom_fields = CustomFieldService.
|
|
112
|
+
self.custom_fields = await CustomFieldService.avalidate_custom_fields('Account', self.custom_fields)
|
|
113
113
|
|
|
114
114
|
# Call parent to handle timestamps
|
|
115
115
|
await super().apre_update()
|
|
@@ -124,4 +124,4 @@ class Account(TimestampMixin, Model):
|
|
|
124
124
|
"""Async hook called after updating account."""
|
|
125
125
|
from amsdal_crm.services.workflow_service import WorkflowService
|
|
126
126
|
|
|
127
|
-
WorkflowService.
|
|
127
|
+
await WorkflowService.aexecute_rules('Account', 'update', self)
|
|
@@ -89,7 +89,7 @@ class Contact(TimestampMixin, Model):
|
|
|
89
89
|
if self.custom_fields:
|
|
90
90
|
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
91
91
|
|
|
92
|
-
self.custom_fields = CustomFieldService.
|
|
92
|
+
self.custom_fields = await CustomFieldService.avalidate_custom_fields('Contact', self.custom_fields)
|
|
93
93
|
await super().apre_create()
|
|
94
94
|
|
|
95
95
|
def pre_update(self) -> None:
|
|
@@ -109,7 +109,7 @@ class Contact(TimestampMixin, Model):
|
|
|
109
109
|
if self.custom_fields:
|
|
110
110
|
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
111
111
|
|
|
112
|
-
self.custom_fields = CustomFieldService.
|
|
112
|
+
self.custom_fields = await CustomFieldService.avalidate_custom_fields('Contact', self.custom_fields)
|
|
113
113
|
|
|
114
114
|
# Call parent to handle timestamps
|
|
115
115
|
await super().apre_update()
|
|
@@ -124,7 +124,7 @@ class Contact(TimestampMixin, Model):
|
|
|
124
124
|
"""Async hook called after updating contact."""
|
|
125
125
|
from amsdal_crm.services.workflow_service import WorkflowService
|
|
126
126
|
|
|
127
|
-
WorkflowService.
|
|
127
|
+
await WorkflowService.aexecute_rules('Contact', 'update', self)
|
|
128
128
|
|
|
129
129
|
|
|
130
130
|
from amsdal_crm.models.account import Account
|
|
@@ -99,7 +99,7 @@ class Deal(TimestampMixin, Model):
|
|
|
99
99
|
if self.custom_fields:
|
|
100
100
|
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
101
101
|
|
|
102
|
-
self.custom_fields = CustomFieldService.
|
|
102
|
+
self.custom_fields = await CustomFieldService.avalidate_custom_fields('Deal', self.custom_fields)
|
|
103
103
|
await super().apre_create()
|
|
104
104
|
|
|
105
105
|
def pre_update(self) -> None:
|
|
@@ -137,7 +137,7 @@ class Deal(TimestampMixin, Model):
|
|
|
137
137
|
if self.custom_fields:
|
|
138
138
|
from amsdal_crm.services.custom_field_service import CustomFieldService
|
|
139
139
|
|
|
140
|
-
self.custom_fields = CustomFieldService.
|
|
140
|
+
self.custom_fields = await CustomFieldService.avalidate_custom_fields('Deal', self.custom_fields)
|
|
141
141
|
|
|
142
142
|
# Load stage if it's a reference and sync closed status
|
|
143
143
|
from amsdal_models.classes.helpers.reference_loader import ReferenceLoader
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = '0.1.2'
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|