wbcore 1.46.0__py2.py3-none-any.whl → 1.58.2__py2.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.
- wbcore/cache/decorators.py +5 -3
- wbcore/cache/registry.py +14 -7
- wbcore/configs/__init__.py +1 -0
- wbcore/configs/configs.py +5 -0
- wbcore/configs/decorators.py +1 -1
- wbcore/configurations/configurations/apps.py +3 -2
- wbcore/configurations/configurations/authentication.py +1 -1
- wbcore/configurations/configurations/base.py +1 -1
- wbcore/configurations/configurations/cache.py +1 -1
- wbcore/configurations/configurations/i18nl10n.py +2 -1
- wbcore/configurations/configurations/maintenance.py +1 -1
- wbcore/configurations/configurations/media.py +1 -1
- wbcore/configurations/configurations/middleware.py +1 -1
- wbcore/configurations/configurations/rest_framework.py +1 -1
- wbcore/configurations/configurations/static.py +3 -3
- wbcore/configurations/configurations/wbcore.py +1 -1
- wbcore/content_type/serializers.py +13 -5
- wbcore/content_type/utils.py +3 -3
- wbcore/content_type/viewsets.py +2 -2
- wbcore/contrib/agenda/filters/calendar_item.py +5 -4
- wbcore/contrib/agenda/locale/de/LC_MESSAGES/django.po +145 -52
- wbcore/contrib/agenda/locale/de/LC_MESSAGES/django.po.translated +236 -0
- wbcore/contrib/agenda/locale/en/LC_MESSAGES/django.po +200 -0
- wbcore/contrib/agenda/locale/fr/LC_MESSAGES/django.po +201 -0
- wbcore/contrib/agenda/viewsets/calendar_items.py +7 -7
- wbcore/contrib/agenda/viewsets/menu/calendar_items.py +0 -6
- wbcore/contrib/ai/exceptions.py +5 -5
- wbcore/contrib/ai/llm/config.py +76 -27
- wbcore/contrib/ai/llm/mixins.py +5 -8
- wbcore/contrib/ai/llm/utils.py +50 -26
- wbcore/contrib/authentication/admin.py +2 -2
- wbcore/contrib/authentication/factories/__init__.py +8 -1
- wbcore/contrib/authentication/factories/users.py +19 -0
- wbcore/contrib/authentication/filters.py +1 -2
- wbcore/contrib/authentication/locale/de/LC_MESSAGES/django.po +209 -187
- wbcore/contrib/authentication/locale/de/LC_MESSAGES/django.po.translated +634 -0
- wbcore/contrib/authentication/locale/en/LC_MESSAGES/django.po +590 -0
- wbcore/contrib/authentication/locale/fr/LC_MESSAGES/django.po +592 -0
- wbcore/contrib/authentication/models/users.py +3 -3
- wbcore/contrib/authentication/models/users_activities.py +1 -1
- wbcore/contrib/authentication/serializers/users.py +2 -2
- wbcore/contrib/authentication/tests/test_tokens.py +3 -3
- wbcore/contrib/authentication/tests/test_users.py +0 -1
- wbcore/contrib/authentication/urls.py +0 -4
- wbcore/contrib/authentication/viewsets/endpoints/user_activities.py +2 -11
- wbcore/contrib/authentication/viewsets/endpoints/users.py +0 -3
- wbcore/contrib/authentication/viewsets/user_activities.py +2 -1
- wbcore/contrib/authentication/viewsets/users.py +6 -4
- wbcore/contrib/color/models.py +2 -1
- wbcore/contrib/currency/factories.py +1 -1
- wbcore/contrib/currency/import_export/backends/fixerio/currency_fx_rates.py +3 -1
- wbcore/contrib/currency/models.py +30 -8
- wbcore/contrib/currency/serializers.py +5 -1
- wbcore/contrib/currency/tests/test_serializers.py +7 -3
- wbcore/contrib/currency/tests/test_viewsets.py +1 -1
- wbcore/contrib/currency/viewsets/currency.py +2 -2
- wbcore/contrib/currency/viewsets/endpoints/currency_fx_rates.py +0 -9
- wbcore/contrib/dataloader/tests/test/dataloaders/protocols.py +1 -2
- wbcore/contrib/dataloader/utils.py +2 -2
- wbcore/contrib/directory/factories/__init__.py +1 -1
- wbcore/contrib/directory/factories/entries.py +2 -1
- wbcore/contrib/directory/filters/entries.py +9 -0
- wbcore/contrib/directory/locale/de/LC_MESSAGES/django.po +728 -714
- wbcore/contrib/directory/locale/de/LC_MESSAGES/django.po.translated +1779 -0
- wbcore/contrib/directory/locale/en/LC_MESSAGES/django.po +1652 -0
- wbcore/contrib/directory/locale/fr/LC_MESSAGES/django.po +1654 -0
- wbcore/contrib/directory/migrations/0011_person_description_person_i18n.py +24 -0
- wbcore/contrib/directory/migrations/0012_alter_person_managers.py +20 -0
- wbcore/contrib/directory/migrations/0013_alter_clientmanagerrelationship_options.py +17 -0
- wbcore/contrib/directory/models/contacts.py +2 -2
- wbcore/contrib/directory/models/entries.py +31 -5
- wbcore/contrib/directory/models/relationships.py +31 -35
- wbcore/contrib/directory/permissions.py +6 -0
- wbcore/contrib/directory/serializers/companies.py +16 -8
- wbcore/contrib/directory/serializers/contacts.py +8 -8
- wbcore/contrib/directory/serializers/entries.py +26 -15
- wbcore/contrib/directory/serializers/entry_representations.py +4 -2
- wbcore/contrib/directory/serializers/persons.py +12 -10
- wbcore/contrib/directory/serializers/relationships.py +2 -2
- wbcore/contrib/directory/tests/conftest.py +2 -0
- wbcore/contrib/directory/tests/disable_signals.py +11 -1
- wbcore/contrib/directory/tests/signals.py +2 -2
- wbcore/contrib/directory/tests/test_models.py +88 -66
- wbcore/contrib/directory/tests/test_serializers.py +1 -1
- wbcore/contrib/directory/tests/test_viewsets.py +8 -8
- wbcore/contrib/directory/viewsets/buttons/__init__.py +1 -1
- wbcore/contrib/directory/viewsets/buttons/relationships.py +32 -0
- wbcore/contrib/directory/viewsets/contacts.py +6 -6
- wbcore/contrib/directory/viewsets/display/__init__.py +1 -1
- wbcore/contrib/directory/viewsets/display/contacts.py +1 -14
- wbcore/contrib/directory/viewsets/display/entries.py +68 -38
- wbcore/contrib/directory/viewsets/display/relationships.py +26 -50
- wbcore/contrib/directory/viewsets/endpoints/relationships.py +1 -26
- wbcore/contrib/directory/viewsets/entries.py +8 -6
- wbcore/contrib/directory/viewsets/previews/entries.py +3 -3
- wbcore/contrib/directory/viewsets/relationships.py +16 -2
- wbcore/contrib/directory/viewsets/titles/relationships.py +2 -3
- wbcore/contrib/documents/filters.py +0 -2
- wbcore/contrib/documents/locale/de/LC_MESSAGES/django.po +103 -94
- wbcore/contrib/documents/locale/de/LC_MESSAGES/django.po.translated +285 -0
- wbcore/contrib/documents/locale/en/LC_MESSAGES/django.po +271 -0
- wbcore/contrib/documents/locale/fr/LC_MESSAGES/django.po +270 -0
- wbcore/contrib/documents/tests/test_models.py +32 -28
- wbcore/contrib/documents/viewsets/endpoints/shareable_links.py +2 -21
- wbcore/contrib/dynamic_preferences/types.py +108 -0
- wbcore/contrib/dynamic_preferences/viewsets.py +27 -0
- wbcore/contrib/example_app/filters/event.py +3 -1
- wbcore/contrib/example_app/filters/match.py +1 -1
- wbcore/contrib/example_app/models.py +91 -22
- wbcore/contrib/example_app/serializers/person_team.py +4 -4
- wbcore/contrib/example_app/templates/example_app/embedded_view.html +19 -0
- wbcore/contrib/example_app/tests/e2e/test_teams.py +1 -1
- wbcore/contrib/example_app/tests/test_models/test_match.py +17 -7
- wbcore/contrib/example_app/urls.py +2 -0
- wbcore/contrib/example_app/views.py +7 -0
- wbcore/contrib/example_app/viewsets/displays/team.py +23 -4
- wbcore/contrib/example_app/viewsets/menu/menus.py +1 -1
- wbcore/contrib/example_app/viewsets/menus.py +1 -1
- wbcore/contrib/geography/tests/conftest.py +14 -0
- wbcore/contrib/geography/tests/test_models.py +23 -8
- wbcore/contrib/geography/tests/test_viewsets.py +96 -2
- wbcore/contrib/guardian/tests/test_model_mixins.py +3 -4
- wbcore/contrib/guardian/tests/test_tasks.py +9 -9
- wbcore/contrib/guardian/tests/test_viewsets.py +2 -2
- wbcore/contrib/guardian/viewsets/configs/__init__.py +1 -1
- wbcore/contrib/guardian/viewsets/configs/buttons.py +9 -0
- wbcore/contrib/guardian/viewsets/configs/endpoints.py +7 -0
- wbcore/contrib/guardian/viewsets/viewsets.py +2 -0
- wbcore/contrib/i18n/__init__.py +2 -0
- wbcore/contrib/i18n/buttons.py +33 -0
- wbcore/contrib/i18n/serializers/__init__.py +0 -0
- wbcore/contrib/i18n/serializers/fields.py +20 -0
- wbcore/contrib/i18n/serializers/mixins.py +13 -0
- wbcore/contrib/i18n/tests/conftest.py +11 -0
- wbcore/contrib/i18n/tests/test_viewsets.py +67 -0
- wbcore/contrib/i18n/translation.py +140 -0
- wbcore/contrib/i18n/viewsets.py +36 -0
- wbcore/contrib/icons/backends/default.py +1 -0
- wbcore/contrib/icons/backends/material.py +1 -0
- wbcore/contrib/icons/icons.py +5 -8
- wbcore/contrib/io/admin.py +1 -0
- wbcore/contrib/io/backends/mail.py +3 -2
- wbcore/contrib/io/backends/utils.py +14 -17
- wbcore/contrib/io/exceptions.py +8 -0
- wbcore/contrib/io/factories.py +1 -1
- wbcore/contrib/io/import_export/backends/mail.py +1 -0
- wbcore/contrib/io/import_export/backends/sftp.py +29 -20
- wbcore/contrib/io/import_export/backends/stream.py +2 -2
- wbcore/contrib/io/import_export/parsers/__init__.py +0 -0
- wbcore/contrib/io/import_export/parsers/base_csv.py +36 -0
- wbcore/contrib/io/import_export/parsers/resources.py +50 -0
- wbcore/contrib/io/imports.py +33 -25
- wbcore/contrib/io/locale/de/LC_MESSAGES/django.po +114 -22
- wbcore/contrib/io/locale/de/LC_MESSAGES/django.po.translated +103 -0
- wbcore/contrib/io/locale/en/LC_MESSAGES/django.po +138 -0
- wbcore/contrib/io/locale/fr/LC_MESSAGES/django.po +138 -0
- wbcore/contrib/io/migrations/0008_importsource_resource_kwargs.py +18 -0
- wbcore/contrib/io/models.py +65 -45
- wbcore/contrib/io/resources.py +0 -6
- wbcore/contrib/io/serializers.py +2 -2
- wbcore/contrib/io/signals.py +4 -0
- wbcore/contrib/io/tests/test_backends.py +19 -13
- wbcore/contrib/io/tests/test_exports.py +1 -1
- wbcore/contrib/io/tests/test_imports.py +1 -1
- wbcore/contrib/io/tests/test_models.py +47 -14
- wbcore/contrib/io/tests/test_viewsets.py +271 -0
- wbcore/contrib/io/viewset_mixins.py +41 -54
- wbcore/contrib/notifications/admin.py +1 -0
- wbcore/contrib/notifications/apps.py +2 -1
- wbcore/contrib/notifications/backends/abstract_backend.py +2 -4
- wbcore/contrib/notifications/backends/firebase/backends.py +5 -2
- wbcore/contrib/notifications/dispatch.py +18 -7
- wbcore/contrib/notifications/factories/notification_types.py +1 -0
- wbcore/contrib/notifications/locale/de/LC_MESSAGES/django.po +25 -19
- wbcore/contrib/notifications/locale/de/LC_MESSAGES/django.po.translated +63 -0
- wbcore/contrib/notifications/locale/en/LC_MESSAGES/django.po +61 -0
- wbcore/contrib/notifications/locale/fr/LC_MESSAGES/django.po +62 -0
- wbcore/contrib/notifications/migrations/0008_notificationtype_is_lock.py +18 -0
- wbcore/contrib/notifications/migrations/0009_alter_notificationtypesetting_options_and_more.py +32 -0
- wbcore/contrib/notifications/models/notification_types.py +67 -24
- wbcore/contrib/notifications/serializers/notification_types.py +16 -1
- wbcore/contrib/notifications/tests/test_models/test_tokens.py +8 -0
- wbcore/contrib/notifications/tests/test_serializers/test_notification_types.py +5 -0
- wbcore/contrib/notifications/tests/test_viewsets/test_notification_types.py +3 -5
- wbcore/contrib/notifications/utils.py +3 -2
- wbcore/contrib/notifications/viewsets/configs/notification_types.py +28 -6
- wbcore/contrib/notifications/viewsets/menus.py +1 -1
- wbcore/contrib/notifications/viewsets/notification_types.py +12 -2
- wbcore/contrib/pandas/fields.py +38 -10
- wbcore/contrib/pandas/filters.py +4 -1
- wbcore/contrib/pandas/filterset.py +8 -7
- wbcore/contrib/pandas/tests/test_fields/test_number_fields.py +2 -7
- wbcore/contrib/pandas/utils.py +1 -1
- wbcore/contrib/pandas/views.py +14 -13
- wbcore/contrib/tags/models/tags.py +4 -1
- wbcore/contrib/workflow/factories/display.py +2 -2
- wbcore/contrib/workflow/factories/transition.py +16 -15
- wbcore/contrib/workflow/locale/de/LC_MESSAGES/django.po +457 -566
- wbcore/contrib/workflow/locale/de/LC_MESSAGES/django.po.translated +1326 -0
- wbcore/contrib/workflow/locale/en/LC_MESSAGES/django.po +1102 -0
- wbcore/contrib/workflow/locale/fr/LC_MESSAGES/django.po +1114 -0
- wbcore/contrib/workflow/models/data.py +7 -4
- wbcore/contrib/workflow/models/process.py +2 -2
- wbcore/contrib/workflow/models/step.py +57 -15
- wbcore/contrib/workflow/serializers/data.py +8 -8
- wbcore/contrib/workflow/serializers/process.py +3 -2
- wbcore/contrib/workflow/tests/conftest.py +224 -0
- wbcore/contrib/workflow/tests/test_dispatch.py +82 -77
- wbcore/contrib/workflow/tests/test_displays.py +10 -88
- wbcore/contrib/workflow/tests/test_filters.py +57 -40
- wbcore/contrib/workflow/tests/test_models/step/test_decision_step.py +71 -68
- wbcore/contrib/workflow/tests/test_models/step/test_email_step.py +78 -38
- wbcore/contrib/workflow/tests/test_models/step/test_finish_step.py +152 -90
- wbcore/contrib/workflow/tests/test_models/step/test_join_step.py +100 -110
- wbcore/contrib/workflow/tests/test_models/step/test_step.py +168 -33
- wbcore/contrib/workflow/tests/test_models/test_condition.py +1 -1
- wbcore/contrib/workflow/tests/test_models/test_workflow.py +3 -3
- wbcore/contrib/workflow/tests/test_serializers.py +172 -150
- wbcore/contrib/workflow/tests/test_viewsets.py +264 -323
- wbcore/contrib/workflow/tests/test_workflow_assignees.py +215 -205
- wbcore/contrib/workflow/viewsets/process.py +4 -1
- wbcore/contrib/workflow/workflows/assignees.py +12 -7
- wbcore/dynamic_preferences_registry.py +102 -0
- wbcore/enums.py +2 -51
- wbcore/filters/fields/choices.py +4 -6
- wbcore/filters/fields/content_type.py +15 -4
- wbcore/filters/fields/datetime.py +50 -25
- wbcore/filters/fields/models.py +18 -9
- wbcore/filters/fields/numbers.py +9 -8
- wbcore/filters/filterset.py +27 -6
- wbcore/filters/mixins.py +41 -42
- wbcore/forms.py +6 -6
- wbcore/fsm/markdown_extensions.py +1 -1
- wbcore/fsm/mixins.py +20 -6
- wbcore/locale/de/LC_MESSAGES/django.po +982 -397
- wbcore/locale/de/LC_MESSAGES/django.po.translated +1580 -0
- wbcore/locale/en/LC_MESSAGES/django.po +1234 -0
- wbcore/locale/fr/LC_MESSAGES/django.po +1235 -0
- wbcore/markdown/models.py +8 -5
- wbcore/markdown/views.py +1 -1
- wbcore/menus/menus.py +2 -2
- wbcore/metadata/configs/buttons/bases.py +10 -7
- wbcore/metadata/configs/buttons/buttons.py +2 -1
- wbcore/metadata/configs/buttons/enums.py +50 -0
- wbcore/metadata/configs/buttons/view_config.py +13 -46
- wbcore/metadata/configs/display/display.py +2 -2
- wbcore/metadata/configs/display/formatting.py +6 -9
- wbcore/metadata/configs/display/instance_display/display.py +5 -2
- wbcore/metadata/configs/display/instance_display/pages.py +1 -1
- wbcore/metadata/configs/display/instance_display/shortcuts.py +1 -1
- wbcore/metadata/configs/display/list_display.py +54 -40
- wbcore/metadata/configs/display/models.py +6 -0
- wbcore/metadata/configs/display/view_config.py +11 -9
- wbcore/metadata/configs/endpoints.py +11 -4
- wbcore/metadata/configs/fields.py +6 -1
- wbcore/metadata/configs/filter_fields.py +12 -13
- wbcore/metadata/configs/identifiers.py +3 -1
- wbcore/metadata/tests/test_buttons.py +13 -16
- wbcore/models/fields.py +2 -2
- wbcore/pagination.py +1 -2
- wbcore/permissions/permissions.py +2 -2
- wbcore/permissions/utils.py +2 -2
- wbcore/release_notes/display.py +2 -8
- wbcore/release_notes/serializers.py +2 -9
- wbcore/release_notes/viewsets.py +8 -2
- wbcore/reversion/viewsets/titles.py +4 -3
- wbcore/serializers/__init__.py +2 -0
- wbcore/serializers/fields/__init__.py +2 -1
- wbcore/serializers/fields/boolean.py +1 -1
- wbcore/serializers/fields/choice.py +28 -4
- wbcore/serializers/fields/datetime.py +45 -36
- wbcore/serializers/fields/fields.py +1 -1
- wbcore/serializers/fields/fsm.py +1 -1
- wbcore/serializers/fields/list.py +2 -5
- wbcore/serializers/fields/mixins.py +24 -11
- wbcore/serializers/fields/number.py +6 -23
- wbcore/serializers/fields/other.py +2 -10
- wbcore/serializers/fields/related.py +4 -6
- wbcore/serializers/fields/text.py +1 -1
- wbcore/serializers/fields/types.py +2 -0
- wbcore/serializers/serializers.py +12 -3
- wbcore/signals/__init__.py +1 -0
- wbcore/signals/clone.py +4 -0
- wbcore/signals/models.py +2 -6
- wbcore/tasks.py +2 -2
- wbcore/templates/wbcore/email_base_template.html +3 -3
- wbcore/test/e2e_helpers_methods/e2e_checks.py +10 -4
- wbcore/test/e2e_helpers_methods/e2e_helper_methods.py +4 -2
- wbcore/test/mixins.py +52 -102
- wbcore/test/tests.py +6 -9
- wbcore/test/utils.py +3 -4
- wbcore/tests/e2e/test_e2e.py +2 -2
- wbcore/tests/test_cache/test_decorators.py +4 -7
- wbcore/tests/test_configs.py +2 -5
- wbcore/tests/test_enums.py +2 -1
- wbcore/tests/test_fields/test_choice_fields.py +9 -1
- wbcore/tests/test_fields/test_number_fields.py +7 -15
- wbcore/tests/test_fields/test_other_fields.py +1 -2
- wbcore/tests/test_filters/test_mixins.py +35 -35
- wbcore/tests/test_list_display.py +0 -2
- wbcore/tests/test_models/test_mixins.py +1 -1
- wbcore/tests/test_utils/test_date.py +1 -1
- wbcore/tests/test_utils/test_date_builder.py +25 -1
- wbcore/tests/test_utils/test_primary.py +1 -1
- wbcore/urls.py +4 -0
- wbcore/utils/date.py +18 -2
- wbcore/utils/figures.py +2 -2
- wbcore/utils/models.py +21 -4
- wbcore/utils/reportlab.py +7 -0
- wbcore/utils/rrules.py +3 -1
- wbcore/utils/string_loader.py +1 -1
- wbcore/utils/strings.py +3 -3
- wbcore/utils/views.py +8 -3
- wbcore/viewsets/mixins.py +9 -4
- {wbcore-1.46.0.dist-info → wbcore-1.58.2.dist-info}/METADATA +9 -5
- {wbcore-1.46.0.dist-info → wbcore-1.58.2.dist-info}/RECORD +317 -271
- wbcore/contrib/geography/tests/test_serializers.py +0 -7
- wbcore/contrib/geography/tests/tests.py +0 -13
- wbcore/contrib/io/tests/tests.py +0 -19
- wbcore/contrib/workflow/tests/tests.py +0 -25
- {wbcore-1.46.0.dist-info → wbcore-1.58.2.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Generated by Django 5.0.12 on 2025-02-28 10:21
|
|
2
|
+
|
|
3
|
+
import modeltrans.fields
|
|
4
|
+
from django.db import migrations, models
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
|
|
9
|
+
dependencies = [
|
|
10
|
+
('directory', '0010_remove_addresscontact_city'),
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
operations = [
|
|
14
|
+
migrations.AddField(
|
|
15
|
+
model_name='person',
|
|
16
|
+
name='description',
|
|
17
|
+
field=models.TextField(blank=True, default=''),
|
|
18
|
+
),
|
|
19
|
+
migrations.AddField(
|
|
20
|
+
model_name='person',
|
|
21
|
+
name='i18n',
|
|
22
|
+
field=modeltrans.fields.TranslationField(fields=['description'], required_languages=(), virtual_fields=True),
|
|
23
|
+
),
|
|
24
|
+
]
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Generated by Django 5.0.13 on 2025-03-10 14:40
|
|
2
|
+
|
|
3
|
+
import django.db.models.manager
|
|
4
|
+
from django.db import migrations
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
|
|
9
|
+
dependencies = [
|
|
10
|
+
('directory', '0011_person_description_person_i18n'),
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
operations = [
|
|
14
|
+
migrations.AlterModelManagers(
|
|
15
|
+
name='person',
|
|
16
|
+
managers=[
|
|
17
|
+
('all_objects', django.db.models.manager.Manager()),
|
|
18
|
+
],
|
|
19
|
+
),
|
|
20
|
+
]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Generated by Django 5.0.14 on 2025-05-05 09:13
|
|
2
|
+
|
|
3
|
+
from django.db import migrations
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('directory', '0012_alter_person_managers'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AlterModelOptions(
|
|
14
|
+
name='clientmanagerrelationship',
|
|
15
|
+
options={'permissions': (('administrate_clientmanagerrelationship', 'Can administrate Client Manager Relationship'),), 'verbose_name': 'Client Manager Relationship', 'verbose_name_plural': 'Client Manager Relationships'},
|
|
16
|
+
),
|
|
17
|
+
]
|
|
@@ -40,7 +40,7 @@ class BankingContact(PrimaryMixin, WBModel):
|
|
|
40
40
|
@classmethod
|
|
41
41
|
def get_color_map(cls):
|
|
42
42
|
colors = [WBColor.RED_LIGHT.value, WBColor.YELLOW_LIGHT.value, WBColor.GREEN_LIGHT.value]
|
|
43
|
-
return [choice for choice in zip(cls, colors)]
|
|
43
|
+
return [choice for choice in zip(cls, colors, strict=False)]
|
|
44
44
|
|
|
45
45
|
status = FSMField(
|
|
46
46
|
default=Status.DRAFT,
|
|
@@ -227,7 +227,7 @@ class BankingContact(PrimaryMixin, WBModel):
|
|
|
227
227
|
|
|
228
228
|
notification_types = [
|
|
229
229
|
create_notification_type(
|
|
230
|
-
code="directory.
|
|
230
|
+
code="directory.banking_contact.approval",
|
|
231
231
|
title="Banking Contact Notification",
|
|
232
232
|
help_text="Sends out a notification when you want need to approve a change in bank details",
|
|
233
233
|
)
|
|
@@ -17,15 +17,18 @@ from django.utils import timezone
|
|
|
17
17
|
from django.utils.functional import cached_property
|
|
18
18
|
from django.utils.translation import gettext_lazy as _
|
|
19
19
|
from dynamic_preferences.registries import global_preferences_registry
|
|
20
|
+
from modeltrans.fields import TranslationField
|
|
20
21
|
from slugify import slugify
|
|
21
22
|
|
|
22
23
|
from wbcore.contrib.agenda.models import CalendarItem
|
|
23
24
|
from wbcore.contrib.authentication.models import User
|
|
25
|
+
from wbcore.contrib.currency.models import Currency
|
|
24
26
|
from wbcore.contrib.directory.models.contacts import (
|
|
25
27
|
AddressContact,
|
|
26
28
|
BankingContact,
|
|
27
29
|
ContactLocationChoices,
|
|
28
30
|
EmailContact,
|
|
31
|
+
SocialMediaContact,
|
|
29
32
|
TelephoneContact,
|
|
30
33
|
WebsiteContact,
|
|
31
34
|
)
|
|
@@ -244,10 +247,6 @@ class EntryDefaultQueryset(models.QuerySet):
|
|
|
244
247
|
EmailContact.objects.filter(primary=True, entry__id=OuterRef("pk")).values("address")[:1],
|
|
245
248
|
output_field=CharField(),
|
|
246
249
|
),
|
|
247
|
-
secondary_email=Subquery(
|
|
248
|
-
EmailContact.objects.filter(primary=False, entry__id=OuterRef("pk")).values("address")[:1],
|
|
249
|
-
output_field=CharField(),
|
|
250
|
-
),
|
|
251
250
|
primary_telephone=Subquery(
|
|
252
251
|
TelephoneContact.objects.filter(primary=True, entry__id=OuterRef("pk")).values("number")[:1],
|
|
253
252
|
output_field=CharField(),
|
|
@@ -262,6 +261,14 @@ class EntryDefaultQueryset(models.QuerySet):
|
|
|
262
261
|
.values("primary_address")[:1],
|
|
263
262
|
output_field=CharField(),
|
|
264
263
|
),
|
|
264
|
+
primary_website=Subquery(
|
|
265
|
+
WebsiteContact.objects.filter(primary=True, entry__id=OuterRef("pk")).values("url")[:1],
|
|
266
|
+
output_field=CharField(),
|
|
267
|
+
),
|
|
268
|
+
primary_social=Subquery(
|
|
269
|
+
SocialMediaContact.objects.filter(primary=True, entry__id=OuterRef("pk")).values("url")[:1],
|
|
270
|
+
output_field=CharField(),
|
|
271
|
+
),
|
|
265
272
|
last_event=Subquery(
|
|
266
273
|
CalendarItem.objects.filter(
|
|
267
274
|
period__endswith__lte=timezone.now(),
|
|
@@ -271,6 +278,15 @@ class EntryDefaultQueryset(models.QuerySet):
|
|
|
271
278
|
.order_by("-period__startswith")
|
|
272
279
|
.values("title")[:1]
|
|
273
280
|
),
|
|
281
|
+
last_event_period_endswith=Subquery(
|
|
282
|
+
CalendarItem.objects.filter(
|
|
283
|
+
period__endswith__lte=timezone.now(),
|
|
284
|
+
visibility=CalendarItem.Visibility.PUBLIC,
|
|
285
|
+
entities=OuterRef("pk"),
|
|
286
|
+
)
|
|
287
|
+
.order_by("-period__startswith")
|
|
288
|
+
.values("period__endswith")[:1]
|
|
289
|
+
),
|
|
274
290
|
cities=ArrayAgg("addresses__geography_city", filter=Q(addresses__geography_city__isnull=False)),
|
|
275
291
|
)
|
|
276
292
|
return qs
|
|
@@ -398,6 +414,14 @@ class Entry(ComplexToStringMixin, DeleteToDisableMixin, WBModel):
|
|
|
398
414
|
if additional_field_key in self.additional_fields:
|
|
399
415
|
del self.additional_fields[additional_field_key]
|
|
400
416
|
|
|
417
|
+
def get_banking_contact(self, currency: Currency) -> BankingContact | None:
|
|
418
|
+
bank_accounts = self.banking.all()
|
|
419
|
+
if bank_accounts.filter(currency=currency).exists():
|
|
420
|
+
bank_accounts = bank_accounts.filter(currency=currency)
|
|
421
|
+
if bank_accounts.filter(primary=True).exists():
|
|
422
|
+
bank_accounts = bank_accounts.filter(primary=True)
|
|
423
|
+
return bank_accounts.first()
|
|
424
|
+
|
|
401
425
|
@classmethod
|
|
402
426
|
def get_endpoint_basename(cls):
|
|
403
427
|
return "wbcore:directory:entry"
|
|
@@ -540,6 +564,8 @@ class Person(Entry):
|
|
|
540
564
|
blank=True,
|
|
541
565
|
verbose_name=_("Specializations"),
|
|
542
566
|
)
|
|
567
|
+
description = models.TextField(default="", blank=True)
|
|
568
|
+
i18n = TranslationField(fields=["description"])
|
|
543
569
|
|
|
544
570
|
objects = DefaultPersonManager()
|
|
545
571
|
registered_users = RegisteredPersonManager()
|
|
@@ -583,7 +609,7 @@ class Person(Entry):
|
|
|
583
609
|
"/".join(self.employers.all().values_list("name", flat=True)) if self.employers.exists() else ""
|
|
584
610
|
)
|
|
585
611
|
if employers_repr:
|
|
586
|
-
return f
|
|
612
|
+
return f"{self.first_name} {self.last_name}{(' (%s)' % employers_repr)}"
|
|
587
613
|
except ValueError:
|
|
588
614
|
pass
|
|
589
615
|
return f"{self.first_name} {self.last_name}"
|
|
@@ -148,6 +148,22 @@ class ClientManagerRelationship(ComplexToStringMixin, PrimaryMixin, WBModel):
|
|
|
148
148
|
APPROVED = "APPROVED", _("Approved")
|
|
149
149
|
REMOVED = "REMOVED", _("Removed")
|
|
150
150
|
|
|
151
|
+
@property
|
|
152
|
+
def can_update_primary_field(self):
|
|
153
|
+
return super().can_update_primary_field and self.status in [
|
|
154
|
+
ClientManagerRelationship.Status.APPROVED,
|
|
155
|
+
ClientManagerRelationship.Status.PENDINGREMOVE,
|
|
156
|
+
]
|
|
157
|
+
|
|
158
|
+
def get_related_queryset(self):
|
|
159
|
+
return ClientManagerRelationship.objects.filter(
|
|
160
|
+
client=self.client,
|
|
161
|
+
status__in=[
|
|
162
|
+
ClientManagerRelationship.Status.APPROVED,
|
|
163
|
+
ClientManagerRelationship.Status.PENDINGREMOVE,
|
|
164
|
+
],
|
|
165
|
+
)
|
|
166
|
+
|
|
151
167
|
PRIMARY_ATTR_FIELDS = ["client"]
|
|
152
168
|
|
|
153
169
|
relationship_manager = models.ForeignKey(
|
|
@@ -156,10 +172,6 @@ class ClientManagerRelationship(ComplexToStringMixin, PrimaryMixin, WBModel):
|
|
|
156
172
|
verbose_name=_("Relationship Manager"),
|
|
157
173
|
related_name="manager_of",
|
|
158
174
|
)
|
|
159
|
-
primary = models.BooleanField(
|
|
160
|
-
verbose_name=_("Primary"),
|
|
161
|
-
default=False,
|
|
162
|
-
)
|
|
163
175
|
client = models.ForeignKey(
|
|
164
176
|
on_delete=models.CASCADE,
|
|
165
177
|
to="directory.Entry",
|
|
@@ -194,7 +206,7 @@ class ClientManagerRelationship(ComplexToStringMixin, PrimaryMixin, WBModel):
|
|
|
194
206
|
field=status,
|
|
195
207
|
source=[Status.DRAFT],
|
|
196
208
|
target=Status.APPROVED,
|
|
197
|
-
permission=lambda instance, user: user.has_perm("directory.
|
|
209
|
+
permission=lambda instance, user: user.has_perm("directory.administrate_clientmanagerrelationship"),
|
|
198
210
|
custom={
|
|
199
211
|
"_transition_button": ActionButton(
|
|
200
212
|
method=RequestType.PATCH,
|
|
@@ -209,13 +221,13 @@ class ClientManagerRelationship(ComplexToStringMixin, PrimaryMixin, WBModel):
|
|
|
209
221
|
},
|
|
210
222
|
)
|
|
211
223
|
def mngapprove(self, by=None, description=None, **kwargs):
|
|
212
|
-
|
|
224
|
+
pass
|
|
213
225
|
|
|
214
226
|
@transition(
|
|
215
227
|
field=status,
|
|
216
228
|
source=[Status.PENDINGADD],
|
|
217
229
|
target=Status.DRAFT,
|
|
218
|
-
permission=lambda instance, user: user.has_perm("directory.
|
|
230
|
+
permission=lambda instance, user: user.has_perm("directory.administrate_clientmanagerrelationship"),
|
|
219
231
|
custom={
|
|
220
232
|
"_transition_button": ActionButton(
|
|
221
233
|
method=RequestType.PATCH,
|
|
@@ -236,7 +248,7 @@ class ClientManagerRelationship(ComplexToStringMixin, PrimaryMixin, WBModel):
|
|
|
236
248
|
field=status,
|
|
237
249
|
source=[Status.PENDINGADD],
|
|
238
250
|
target=Status.APPROVED,
|
|
239
|
-
permission=lambda instance, user: user.has_perm("directory.
|
|
251
|
+
permission=lambda instance, user: user.has_perm("directory.administrate_clientmanagerrelationship"),
|
|
240
252
|
custom={
|
|
241
253
|
"_transition_button": ActionButton(
|
|
242
254
|
method=RequestType.PATCH,
|
|
@@ -251,13 +263,13 @@ class ClientManagerRelationship(ComplexToStringMixin, PrimaryMixin, WBModel):
|
|
|
251
263
|
},
|
|
252
264
|
)
|
|
253
265
|
def approve(self, by=None, description=None, **kwargs):
|
|
254
|
-
|
|
266
|
+
pass
|
|
255
267
|
|
|
256
268
|
@transition(
|
|
257
269
|
field=status,
|
|
258
270
|
source=[Status.PENDINGREMOVE],
|
|
259
271
|
target=Status.APPROVED,
|
|
260
|
-
permission=lambda instance, user: user.has_perm("directory.
|
|
272
|
+
permission=lambda instance, user: user.has_perm("directory.administrate_clientmanagerrelationship"),
|
|
261
273
|
custom={
|
|
262
274
|
"_transition_button": ActionButton(
|
|
263
275
|
method=RequestType.PATCH,
|
|
@@ -278,7 +290,7 @@ class ClientManagerRelationship(ComplexToStringMixin, PrimaryMixin, WBModel):
|
|
|
278
290
|
field=status,
|
|
279
291
|
source=[Status.PENDINGREMOVE],
|
|
280
292
|
target=Status.REMOVED,
|
|
281
|
-
permission=lambda instance, user: user.has_perm("directory.
|
|
293
|
+
permission=lambda instance, user: user.has_perm("directory.administrate_clientmanagerrelationship"),
|
|
282
294
|
custom={
|
|
283
295
|
"_transition_button": ActionButton(
|
|
284
296
|
method=RequestType.PATCH,
|
|
@@ -295,8 +307,8 @@ class ClientManagerRelationship(ComplexToStringMixin, PrimaryMixin, WBModel):
|
|
|
295
307
|
def approveremoval(self, by=None, description=None, **kwargs):
|
|
296
308
|
pass
|
|
297
309
|
|
|
298
|
-
def is_not_primary(
|
|
299
|
-
return not
|
|
310
|
+
def is_not_primary(self):
|
|
311
|
+
return not self.primary
|
|
300
312
|
|
|
301
313
|
@transition(
|
|
302
314
|
field=status,
|
|
@@ -319,10 +331,10 @@ class ClientManagerRelationship(ComplexToStringMixin, PrimaryMixin, WBModel):
|
|
|
319
331
|
def makeprimary(self, by=None, description=None, **kwargs):
|
|
320
332
|
self.primary = True
|
|
321
333
|
|
|
322
|
-
def last_primary(
|
|
323
|
-
return not
|
|
324
|
-
ClientManagerRelationship.objects.exclude(id=
|
|
325
|
-
.filter(status=ClientManagerRelationship.Status.APPROVED, client=
|
|
334
|
+
def last_primary(self):
|
|
335
|
+
return not self.primary and (
|
|
336
|
+
ClientManagerRelationship.objects.exclude(id=self.id)
|
|
337
|
+
.filter(status=ClientManagerRelationship.Status.APPROVED, client=self.client, primary=True)
|
|
326
338
|
.exists()
|
|
327
339
|
)
|
|
328
340
|
|
|
@@ -373,24 +385,6 @@ class ClientManagerRelationship(ComplexToStringMixin, PrimaryMixin, WBModel):
|
|
|
373
385
|
def delete(self, **kwargs):
|
|
374
386
|
super().delete(no_deletion=False) # For this model we actually want to delete the object
|
|
375
387
|
|
|
376
|
-
def get_related_queryset(self):
|
|
377
|
-
return (
|
|
378
|
-
super().get_related_queryset().filter(status=self.Status.APPROVED)
|
|
379
|
-
) # only one approved relationship can be primary
|
|
380
|
-
|
|
381
|
-
def _handle_primary_status(self):
|
|
382
|
-
if (
|
|
383
|
-
self.primary is True
|
|
384
|
-
and ClientManagerRelationship.objects.filter(client=self.client, primary=True).exists()
|
|
385
|
-
):
|
|
386
|
-
ClientManagerRelationship.objects.filter(client=self.client, primary=True).update(primary=False)
|
|
387
|
-
|
|
388
|
-
if (
|
|
389
|
-
self.primary is False
|
|
390
|
-
and not ClientManagerRelationship.objects.filter(client=self.client, primary=True).exists()
|
|
391
|
-
):
|
|
392
|
-
self.primary = True
|
|
393
|
-
|
|
394
388
|
class Meta:
|
|
395
389
|
verbose_name = _("Client Manager Relationship")
|
|
396
390
|
verbose_name_plural = _("Client Manager Relationships")
|
|
@@ -402,6 +396,7 @@ class ClientManagerRelationship(ComplexToStringMixin, PrimaryMixin, WBModel):
|
|
|
402
396
|
help_text="Sends you a notification when there is a Relationship manager change to approve.",
|
|
403
397
|
)
|
|
404
398
|
]
|
|
399
|
+
permissions = (("administrate_clientmanagerrelationship", "Can administrate Client Manager Relationship"),)
|
|
405
400
|
|
|
406
401
|
@classmethod
|
|
407
402
|
def get_representation_endpoint(cls):
|
|
@@ -560,6 +555,7 @@ class EmployerEmployeeRelationship(PrimaryMixin):
|
|
|
560
555
|
def get_representation_value_key(cls):
|
|
561
556
|
return "id"
|
|
562
557
|
|
|
558
|
+
@classmethod
|
|
563
559
|
def representation_label_key(cls):
|
|
564
560
|
return "{{position_name}}"
|
|
565
561
|
|
|
@@ -26,10 +26,8 @@ class CompanyModelSerializer(EntryModelSerializer):
|
|
|
26
26
|
many=True,
|
|
27
27
|
)
|
|
28
28
|
_employees = PersonRepresentationSerializer(source="employees", many=True)
|
|
29
|
-
is_primary_employer = wb_serializers.BooleanField(
|
|
30
|
-
tier = wb_serializers.CharField(
|
|
31
|
-
help_text=settings.DEFAULT_TIERING_HELP_TEXT, required=False, read_only=True, label=_("Tier")
|
|
32
|
-
)
|
|
29
|
+
is_primary_employer = wb_serializers.BooleanField(read_only=True)
|
|
30
|
+
tier = wb_serializers.CharField(help_text=settings.DEFAULT_TIERING_HELP_TEXT, label=_("Tier"), required=False)
|
|
33
31
|
_type = CompanyTypeRepresentationSerializer(source="type")
|
|
34
32
|
|
|
35
33
|
@wb_serializers.register_resource()
|
|
@@ -63,6 +61,8 @@ class CompanyModelSerializer(EntryModelSerializer):
|
|
|
63
61
|
"primary_email",
|
|
64
62
|
"primary_manager_repr",
|
|
65
63
|
"primary_telephone",
|
|
64
|
+
"primary_website",
|
|
65
|
+
"primary_social",
|
|
66
66
|
"profile_image",
|
|
67
67
|
"salutation",
|
|
68
68
|
"signature",
|
|
@@ -77,7 +77,7 @@ class CompanyModelSerializer(EntryModelSerializer):
|
|
|
77
77
|
|
|
78
78
|
class CompanyModelListSerializer(CompanyModelSerializer):
|
|
79
79
|
eer_id = wb_serializers.CharField(default="", required=False, read_only=True)
|
|
80
|
-
is_primary_employer = wb_serializers.BooleanField(
|
|
80
|
+
is_primary_employer = wb_serializers.BooleanField(read_only=True)
|
|
81
81
|
|
|
82
82
|
@wb_serializers.register_resource()
|
|
83
83
|
def delete(self, instance, request, user):
|
|
@@ -127,8 +127,14 @@ class CompanyModelListSerializer(CompanyModelSerializer):
|
|
|
127
127
|
"_customer_status",
|
|
128
128
|
"eer_id",
|
|
129
129
|
"is_primary_employer",
|
|
130
|
+
"primary_address",
|
|
131
|
+
"primary_email",
|
|
130
132
|
"primary_manager_repr",
|
|
133
|
+
"primary_telephone",
|
|
134
|
+
"primary_website",
|
|
135
|
+
"primary_social",
|
|
131
136
|
"last_event",
|
|
137
|
+
"last_event_period_endswith",
|
|
132
138
|
"tier",
|
|
133
139
|
"type",
|
|
134
140
|
"_type",
|
|
@@ -137,10 +143,12 @@ class CompanyModelListSerializer(CompanyModelSerializer):
|
|
|
137
143
|
|
|
138
144
|
|
|
139
145
|
class BankModelSerializer(wb_serializers.ModelSerializer):
|
|
140
|
-
primary_address = wb_serializers.CharField(
|
|
141
|
-
|
|
146
|
+
primary_address = wb_serializers.CharField(
|
|
147
|
+
allow_null=True, label=_("Primary Address"), read_only=True, required=False
|
|
148
|
+
)
|
|
149
|
+
primary_email = wb_serializers.CharField(allow_null=True, label=_("Primary Email"), required=False, read_only=True)
|
|
142
150
|
primary_telephone = wb_serializers.TelephoneField(
|
|
143
|
-
allow_null=True,
|
|
151
|
+
allow_null=True, label=_("Primary Telephone"), read_only=True, required=False
|
|
144
152
|
)
|
|
145
153
|
_relationship_managers = PersonRepresentationSerializer(many=True, source="relationship_managers")
|
|
146
154
|
|
|
@@ -126,8 +126,8 @@ class EmailContactSerializer(wb_serializers.ModelSerializer):
|
|
|
126
126
|
if address:
|
|
127
127
|
try:
|
|
128
128
|
validate_email(address)
|
|
129
|
-
except ValidationError:
|
|
130
|
-
raise serializers.ValidationError({"address": _("Invalid e-mail address")})
|
|
129
|
+
except ValidationError as e:
|
|
130
|
+
raise serializers.ValidationError({"address": _("Invalid e-mail address")}) from e
|
|
131
131
|
return data
|
|
132
132
|
|
|
133
133
|
class Meta:
|
|
@@ -261,8 +261,8 @@ class TelephoneContactSerializer(wb_serializers.ModelSerializer):
|
|
|
261
261
|
data["number"] = formatted_number
|
|
262
262
|
else:
|
|
263
263
|
raise serializers.ValidationError({"number": _("Invalid phone number format")})
|
|
264
|
-
except Exception:
|
|
265
|
-
raise serializers.ValidationError({"number": _("Invalid phone number format")})
|
|
264
|
+
except Exception as e:
|
|
265
|
+
raise serializers.ValidationError({"number": _("Invalid phone number format")}) from e
|
|
266
266
|
|
|
267
267
|
if entry and formatting_successful:
|
|
268
268
|
telephone_contact = TelephoneContact.objects.filter(number=formatted_number, entry=entry)
|
|
@@ -310,7 +310,7 @@ class BankingContactSerializer(wb_serializers.ModelSerializer):
|
|
|
310
310
|
iban_formatted = iban.formatted
|
|
311
311
|
data["iban"] = iban_formatted
|
|
312
312
|
except ValueError as e:
|
|
313
|
-
raise serializers.ValidationError({"iban": e})
|
|
313
|
+
raise serializers.ValidationError({"iban": e}) from e
|
|
314
314
|
|
|
315
315
|
if entry and iban_formatted:
|
|
316
316
|
banking_contact = BankingContact.objects.filter(iban=iban_formatted, entry=entry)
|
|
@@ -325,7 +325,7 @@ class BankingContactSerializer(wb_serializers.ModelSerializer):
|
|
|
325
325
|
try:
|
|
326
326
|
BIC(swift_bic_repr)
|
|
327
327
|
except ValueError as e:
|
|
328
|
-
raise serializers.ValidationError({"swift_bic": e})
|
|
328
|
+
raise serializers.ValidationError({"swift_bic": e}) from e
|
|
329
329
|
return data
|
|
330
330
|
|
|
331
331
|
class Meta:
|
|
@@ -364,8 +364,8 @@ class SocialMediaContactSerializer(wb_serializers.ModelSerializer):
|
|
|
364
364
|
url = data.get("url", self.instance.url if self.instance else "")
|
|
365
365
|
try:
|
|
366
366
|
URLValidator()(url)
|
|
367
|
-
except ValidationError:
|
|
368
|
-
raise serializers.ValidationError({"url": _("The URL you provided seems to be wrong.")})
|
|
367
|
+
except ValidationError as e:
|
|
368
|
+
raise serializers.ValidationError({"url": _("The URL you provided seems to be wrong.")}) from e
|
|
369
369
|
|
|
370
370
|
if self.instance and (
|
|
371
371
|
((data_entry := data.get("entry")) != self.instance.entry)
|
|
@@ -166,6 +166,7 @@ class SpecializationRepresentationSerializer(wb_serializers.RepresentationSerial
|
|
|
166
166
|
|
|
167
167
|
class EntryModelSerializer(wb_serializers.ModelSerializer):
|
|
168
168
|
last_event = wb_serializers.CharField(read_only=True)
|
|
169
|
+
last_event_period_endswith = wb_serializers.DateTimeField(read_only=True)
|
|
169
170
|
activity_heat = wb_serializers.RangeSelectField(
|
|
170
171
|
color="rgb(220,20,60)", label=_("Activity Heat"), read_only=True, required=False
|
|
171
172
|
)
|
|
@@ -180,7 +181,7 @@ class EntryModelSerializer(wb_serializers.ModelSerializer):
|
|
|
180
181
|
read_only=True,
|
|
181
182
|
required=False,
|
|
182
183
|
)
|
|
183
|
-
is_primary_employer = wb_serializers.BooleanField(
|
|
184
|
+
is_primary_employer = wb_serializers.BooleanField(read_only=True)
|
|
184
185
|
position_in_company = wb_serializers.CharField(
|
|
185
186
|
allow_null=True,
|
|
186
187
|
default="",
|
|
@@ -191,19 +192,26 @@ class EntryModelSerializer(wb_serializers.ModelSerializer):
|
|
|
191
192
|
read_only=True,
|
|
192
193
|
required=False,
|
|
193
194
|
)
|
|
194
|
-
primary_address = wb_serializers.CharField(
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
195
|
+
primary_address = wb_serializers.CharField(
|
|
196
|
+
allow_null=True, read_only=True, required=False, label=_("Primary Address")
|
|
197
|
+
)
|
|
198
|
+
primary_email = wb_serializers.CharField(
|
|
199
|
+
allow_null=True, required=False, read_only=False, label=_("Primary Email")
|
|
200
|
+
)
|
|
201
|
+
primary_manager_repr = wb_serializers.CharField(
|
|
202
|
+
allow_null=True, read_only=True, required=False, label=_("Primary Manager")
|
|
203
|
+
)
|
|
204
|
+
primary_telephone = wb_serializers.TelephoneField(
|
|
205
|
+
allow_null=True,
|
|
206
|
+
required=False,
|
|
207
|
+
label=_("Primary Telephone"),
|
|
208
|
+
)
|
|
209
|
+
primary_website = wb_serializers.URLField(allow_null=True, required=False, label=_("Primary Website"))
|
|
210
|
+
primary_social = wb_serializers.URLField(allow_null=True, required=False, label=_("Primary Social"))
|
|
198
211
|
profile_image = wb_serializers.ImageField(allow_null=True, required=False, label=_("Profile Image"))
|
|
199
212
|
_relationship_managers = PersonRepresentationSerializer(many=True, source="relationship_managers")
|
|
200
213
|
_social_media = SocialMediaContactRepresentationSerializer(many=True, read_only=True, source="social_media")
|
|
201
|
-
primary_manager = wb_serializers.PrimaryKeyRelatedField(
|
|
202
|
-
queryset=lambda: Person.objects.filter_only_internal(),
|
|
203
|
-
default=wb_serializers.CurrentUserDefault("profile"),
|
|
204
|
-
label=_("Primary Manager"),
|
|
205
|
-
required=False,
|
|
206
|
-
)
|
|
214
|
+
primary_manager = wb_serializers.PrimaryKeyRelatedField(label=_("Primary Manager"), required=False, read_only=True)
|
|
207
215
|
_primary_manager = InternalUserProfileRepresentationSerializer(source="primary_manager")
|
|
208
216
|
|
|
209
217
|
@wb_serializers.register_resource()
|
|
@@ -251,8 +259,8 @@ class EntryModelSerializer(wb_serializers.ModelSerializer):
|
|
|
251
259
|
if primary_email := data.get("primary_email", None):
|
|
252
260
|
try:
|
|
253
261
|
validate_email(primary_email)
|
|
254
|
-
except ValidationError:
|
|
255
|
-
raise ValidationError({"primary_email": "Invalid e-mail address"})
|
|
262
|
+
except ValidationError as e:
|
|
263
|
+
raise ValidationError({"primary_email": "Invalid e-mail address"}) from e
|
|
256
264
|
|
|
257
265
|
if primary_telephone := data.get("primary_telephone", None):
|
|
258
266
|
try:
|
|
@@ -264,8 +272,8 @@ class EntryModelSerializer(wb_serializers.ModelSerializer):
|
|
|
264
272
|
data["primary_telephone"] = formatted_number
|
|
265
273
|
else:
|
|
266
274
|
raise ValidationError({"primary_telephone": gettext("Invalid phone number format")})
|
|
267
|
-
except Exception:
|
|
268
|
-
raise ValidationError({"primary_telephone": gettext("Invalid phone number format")})
|
|
275
|
+
except Exception as e:
|
|
276
|
+
raise ValidationError({"primary_telephone": gettext("Invalid phone number format")}) from e
|
|
269
277
|
return super().validate(data)
|
|
270
278
|
|
|
271
279
|
def update(self, instance, validated_data):
|
|
@@ -316,6 +324,7 @@ class EntryModelSerializer(wb_serializers.ModelSerializer):
|
|
|
316
324
|
|
|
317
325
|
fields = (
|
|
318
326
|
"last_event",
|
|
327
|
+
"last_event_period_endswith",
|
|
319
328
|
"id",
|
|
320
329
|
"computed_str",
|
|
321
330
|
"activity_heat",
|
|
@@ -331,6 +340,8 @@ class EntryModelSerializer(wb_serializers.ModelSerializer):
|
|
|
331
340
|
"primary_email",
|
|
332
341
|
"primary_manager_repr",
|
|
333
342
|
"primary_telephone",
|
|
343
|
+
"primary_website",
|
|
344
|
+
"primary_social",
|
|
334
345
|
"profile_image",
|
|
335
346
|
"relationship_managers",
|
|
336
347
|
"_relationship_managers",
|
|
@@ -9,8 +9,10 @@ from ..models import Entry
|
|
|
9
9
|
class EntryRepresentationSerializer(wb_serializers.RepresentationSerializer):
|
|
10
10
|
_detail = wb_serializers.SerializerMethodField()
|
|
11
11
|
_detail_preview = wb_serializers.HyperlinkField(reverse_name="wbcore:directory:entry-detail")
|
|
12
|
-
primary_email = wb_serializers.CharField(
|
|
13
|
-
primary_telephone = wb_serializers.TelephoneField(
|
|
12
|
+
primary_email = wb_serializers.CharField(read_only=True, required=False, label=_("Primary Email"), allow_null=True)
|
|
13
|
+
primary_telephone = wb_serializers.TelephoneField(
|
|
14
|
+
read_only=True, required=False, label=_("Primary Telephone"), allow_null=True
|
|
15
|
+
)
|
|
14
16
|
|
|
15
17
|
def get__detail(self, obj):
|
|
16
18
|
if obj.is_company:
|
|
@@ -3,6 +3,7 @@ from rest_framework.reverse import reverse
|
|
|
3
3
|
|
|
4
4
|
from wbcore import serializers as wb_serializers
|
|
5
5
|
from wbcore.contrib.color.enums import WBColor
|
|
6
|
+
from wbcore.contrib.i18n.serializers.mixins import ModelTranslateSerializerMixin
|
|
6
7
|
|
|
7
8
|
from ..models import Company, EmployerEmployeeRelationship, Person, Position
|
|
8
9
|
from .entries import (
|
|
@@ -13,14 +14,11 @@ from .entries import (
|
|
|
13
14
|
from .relationships import PositionRepresentationSerializer
|
|
14
15
|
|
|
15
16
|
|
|
16
|
-
class PersonModelSerializer(EntryModelSerializer):
|
|
17
|
-
activites_count = wb_serializers.IntegerField(default=0, read_only=True)
|
|
18
|
-
|
|
17
|
+
class PersonModelSerializer(ModelTranslateSerializerMixin, EntryModelSerializer):
|
|
19
18
|
primary_employer_repr = wb_serializers.CharField(read_only=True, required=False, label=_("Primary Employer"))
|
|
20
19
|
has_user_account = wb_serializers.CharField(read_only=True, label=_("User Account"))
|
|
21
20
|
name = wb_serializers.CharField(read_only=True)
|
|
22
21
|
last_connection = wb_serializers.DateTimeField(read_only=True, default=None, label=_("Last Connection"))
|
|
23
|
-
secondary_email = wb_serializers.CharField(default="", label=_("Secondary Email"), allow_null=True, read_only=True)
|
|
24
22
|
personality_profile_red = wb_serializers.RangeSelectField(
|
|
25
23
|
color=WBColor.RED_LIGHT.value, required=False, label=_("Personality Profile Red")
|
|
26
24
|
)
|
|
@@ -31,7 +29,7 @@ class PersonModelSerializer(EntryModelSerializer):
|
|
|
31
29
|
color=WBColor.BLUE_LIGHT.value, required=False, label=_("Personality Profile Blue")
|
|
32
30
|
)
|
|
33
31
|
_specializations = SpecializationRepresentationSerializer(source="specializations", many=True)
|
|
34
|
-
tier = wb_serializers.CharField(
|
|
32
|
+
tier = wb_serializers.CharField(help_text=_("Tier of the primary employer"), label=_("Tier"), required=False)
|
|
35
33
|
|
|
36
34
|
def get_user_account_email(self, obj):
|
|
37
35
|
if hasattr(obj, "user_account"):
|
|
@@ -81,7 +79,6 @@ class PersonModelSerializer(EntryModelSerializer):
|
|
|
81
79
|
"name",
|
|
82
80
|
"computed_str",
|
|
83
81
|
"active_employee",
|
|
84
|
-
"activites_count",
|
|
85
82
|
"activity_heat",
|
|
86
83
|
"addresses",
|
|
87
84
|
"cities",
|
|
@@ -103,14 +100,17 @@ class PersonModelSerializer(EntryModelSerializer):
|
|
|
103
100
|
"primary_manager_repr",
|
|
104
101
|
"primary_employer_repr",
|
|
105
102
|
"primary_telephone",
|
|
103
|
+
"primary_website",
|
|
104
|
+
"primary_social",
|
|
106
105
|
"profile_image",
|
|
107
106
|
"salutation",
|
|
108
|
-
"secondary_email",
|
|
109
107
|
"specializations",
|
|
110
108
|
"_specializations",
|
|
111
109
|
"tier",
|
|
112
110
|
"_additional_resources",
|
|
113
111
|
"initials",
|
|
112
|
+
"description",
|
|
113
|
+
"_i18n",
|
|
114
114
|
)
|
|
115
115
|
|
|
116
116
|
|
|
@@ -201,12 +201,14 @@ class PersonModelListSerializer(PersonModelSerializer):
|
|
|
201
201
|
"_cities",
|
|
202
202
|
"customer_status",
|
|
203
203
|
"primary_employer_repr",
|
|
204
|
+
"primary_address",
|
|
205
|
+
"primary_email",
|
|
204
206
|
"primary_manager_repr",
|
|
207
|
+
"primary_website",
|
|
208
|
+
"primary_social",
|
|
209
|
+
"primary_telephone",
|
|
205
210
|
"last_event",
|
|
206
211
|
"position_in_company",
|
|
207
|
-
"primary_email",
|
|
208
|
-
"primary_telephone",
|
|
209
|
-
"primary_telephone",
|
|
210
212
|
"tier",
|
|
211
213
|
"_additional_resources",
|
|
212
214
|
)
|
|
@@ -131,8 +131,8 @@ class RelationshipModelSerializer(serializers.ModelSerializer):
|
|
|
131
131
|
data["from_entry_id"] = self.instance.from_entry.id
|
|
132
132
|
else:
|
|
133
133
|
data["from_entry_id"] = self.context["view"].kwargs["entry_id"]
|
|
134
|
-
except KeyError:
|
|
135
|
-
raise ValidationError(_("From entry has to be set."))
|
|
134
|
+
except KeyError as e:
|
|
135
|
+
raise ValidationError(_("From entry has to be set.")) from e
|
|
136
136
|
from_entry = data.get("from_entry", getattr(self.instance, "from_entry", None))
|
|
137
137
|
to_entry = data.get("to_entry", getattr(self.instance, "to_entry", None))
|
|
138
138
|
|
|
@@ -5,6 +5,7 @@ from django.db.models.signals import pre_migrate
|
|
|
5
5
|
from pytest_factoryboy import register
|
|
6
6
|
from wbcore.contrib.authentication.factories import InternalUserFactory, UserFactory
|
|
7
7
|
from wbcore.contrib.geography.tests.signals import app_pre_migration
|
|
8
|
+
from wbcore.contrib.currency.factories import CurrencyFactory
|
|
8
9
|
from wbcore.tests.conftest import *
|
|
9
10
|
|
|
10
11
|
from ..factories import (
|
|
@@ -45,6 +46,7 @@ register(RelationshipFactory)
|
|
|
45
46
|
register(RelationshipTypeFactory)
|
|
46
47
|
register(CustomerStatusFactory)
|
|
47
48
|
register(CompanyTypeFactory)
|
|
49
|
+
register(CurrencyFactory)
|
|
48
50
|
|
|
49
51
|
|
|
50
52
|
@pytest.fixture(autouse=True, scope="session")
|