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
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
from rest_framework.reverse import reverse
|
|
2
|
-
|
|
3
1
|
from wbcore.metadata.configs.endpoints import EndpointViewConfig
|
|
4
2
|
|
|
5
3
|
|
|
@@ -7,17 +5,10 @@ class UserActivityModelEndpointConfig(EndpointViewConfig):
|
|
|
7
5
|
def get_endpoint(self, **kwargs):
|
|
8
6
|
return None
|
|
9
7
|
|
|
10
|
-
def get_list_endpoint(self, **kwargs):
|
|
11
|
-
return reverse("wbcore:authentication:useractivity-list", args=[], request=self.request)
|
|
12
|
-
|
|
13
8
|
|
|
14
9
|
class UserActivityUserModelEndpointConfig(UserActivityModelEndpointConfig):
|
|
15
|
-
|
|
16
|
-
return reverse(
|
|
17
|
-
"wbcore:authentication:user-useractivity-list", args=[self.view.kwargs["user_id"]], request=self.request
|
|
18
|
-
)
|
|
10
|
+
pass
|
|
19
11
|
|
|
20
12
|
|
|
21
13
|
class UserActivityTableEndpointConfig(UserActivityModelEndpointConfig):
|
|
22
|
-
|
|
23
|
-
return reverse("wbcore:authentication:useractivitytable-list", args=[], request=self.request)
|
|
14
|
+
pass
|
|
@@ -14,8 +14,5 @@ class UserProfileModelEndpointConfig(EndpointViewConfig):
|
|
|
14
14
|
def get_endpoint(self, **kwargs):
|
|
15
15
|
return None
|
|
16
16
|
|
|
17
|
-
def get_list_endpoint(self, **kwargs):
|
|
18
|
-
return reverse("wbcore:authentication:userprofile-list", args=[], request=self.request)
|
|
19
|
-
|
|
20
17
|
def get_instance_endpoint(self, **kwargs):
|
|
21
18
|
return reverse("wbcore:authentication:userprofile-list", args=[], request=self.request)
|
|
@@ -157,7 +157,8 @@ class UserActivityChart(viewsets.ChartViewSet):
|
|
|
157
157
|
cum_times = pd.Series(
|
|
158
158
|
dt
|
|
159
159
|
for group in [
|
|
160
|
-
pd.date_range(start, end, freq="Min")
|
|
160
|
+
pd.date_range(start, end, freq="Min")
|
|
161
|
+
for start, end in zip(dff.date, dff.latest_refresh, strict=False)
|
|
161
162
|
]
|
|
162
163
|
for dt in group
|
|
163
164
|
).value_counts()
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
from contextlib import suppress
|
|
2
3
|
|
|
3
4
|
from django.conf import settings
|
|
4
5
|
from django.contrib.auth.models import Group, Permission
|
|
@@ -66,11 +67,12 @@ logger = logging.getLogger()
|
|
|
66
67
|
@permission_classes([AllowAny])
|
|
67
68
|
@authentication_classes([])
|
|
68
69
|
def reset_password_email(request):
|
|
69
|
-
|
|
70
|
+
with suppress(User.DoesNotExist):
|
|
70
71
|
user = User.objects.get(email=request.data["email"])
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
try:
|
|
73
|
+
user.reset_password(request)
|
|
74
|
+
except Exception as e:
|
|
75
|
+
logger.error(f"While user {user} try to reset password, we encounter the error {e}")
|
|
74
76
|
return Response(
|
|
75
77
|
{
|
|
76
78
|
"status": "ok",
|
wbcore/contrib/color/models.py
CHANGED
|
@@ -39,7 +39,8 @@ class ColorGradient(models.Model):
|
|
|
39
39
|
if color:
|
|
40
40
|
color_rgb = _hex2rgb(color)
|
|
41
41
|
nearest_color = min(
|
|
42
|
-
self.colors,
|
|
42
|
+
self.colors,
|
|
43
|
+
key=lambda subject: sum((s - q) ** 2 for s, q in zip(_hex2rgb(subject), color_rgb, strict=False)),
|
|
43
44
|
)
|
|
44
45
|
|
|
45
46
|
index = self.colors.index(nearest_color)
|
|
@@ -6,7 +6,7 @@ import yaml
|
|
|
6
6
|
from .models import Currency, CurrencyFXRates
|
|
7
7
|
|
|
8
8
|
with open(pathlib.Path(__file__).parent.joinpath("fixtures").joinpath("currency.yaml"), "r") as yaml_file:
|
|
9
|
-
currency_dict = yaml.load(yaml_file, Loader=yaml.CLoader)
|
|
9
|
+
currency_dict = yaml.load(yaml_file, Loader=yaml.CLoader) # noqa: S506
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
class CurrencyFactory(factory.django.DjangoModelFactory):
|
|
@@ -55,7 +55,9 @@ class DataBackend(AbstractDataBackend):
|
|
|
55
55
|
params["symbols"] = ",".join(obj_external_ids)
|
|
56
56
|
res = []
|
|
57
57
|
for _date in pd.date_range(start, execution_date, freq="B"):
|
|
58
|
-
r = requests.get(
|
|
58
|
+
r = requests.get(
|
|
59
|
+
f'{self.ENDPOINT}/{_date.strftime("%Y-%m-%d")}?', params=params, headers=self.HEADERS, timeout=10
|
|
60
|
+
)
|
|
59
61
|
if r.status_code == requests.codes.ok:
|
|
60
62
|
res_json = r.json()
|
|
61
63
|
if res_json and res_json["success"]:
|
|
@@ -4,7 +4,9 @@ from datetime import date as date_lib
|
|
|
4
4
|
from decimal import Decimal
|
|
5
5
|
|
|
6
6
|
from django.db import models
|
|
7
|
-
from django.db.models import Expression, ExpressionWrapper, Subquery
|
|
7
|
+
from django.db.models import Case, CharField, Expression, ExpressionWrapper, F, Q, Subquery, Value, When
|
|
8
|
+
from django.db.models.functions import Concat
|
|
9
|
+
from persisting_theory import QuerySet
|
|
8
10
|
|
|
9
11
|
from wbcore.contrib.io.mixins import ImportMixin
|
|
10
12
|
from wbcore.models import WBModel
|
|
@@ -13,6 +15,21 @@ from wbcore.utils.models import LabelKeyMixin
|
|
|
13
15
|
from .import_export.handlers import CurrencyFXRatesImportHandler, CurrencyImportHandler
|
|
14
16
|
|
|
15
17
|
|
|
18
|
+
class CurrencyDefaultManager(models.Manager):
|
|
19
|
+
def get_queryset(self) -> QuerySet:
|
|
20
|
+
return (
|
|
21
|
+
super()
|
|
22
|
+
.get_queryset()
|
|
23
|
+
.annotate(
|
|
24
|
+
name_repr=Case(
|
|
25
|
+
When(Q(symbol="") | Q(symbol__isnull=True), then=F("title")),
|
|
26
|
+
default=Concat(F("title"), Value(" ("), F("symbol"), Value(")")),
|
|
27
|
+
output_field=CharField(),
|
|
28
|
+
)
|
|
29
|
+
)
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
16
33
|
class Currency(ImportMixin, LabelKeyMixin, WBModel):
|
|
17
34
|
import_export_handler_class = CurrencyImportHandler
|
|
18
35
|
|
|
@@ -21,18 +38,19 @@ class Currency(ImportMixin, LabelKeyMixin, WBModel):
|
|
|
21
38
|
verbose_name_plural = "Currencies"
|
|
22
39
|
ordering = ("title",)
|
|
23
40
|
|
|
24
|
-
def __str__(self):
|
|
25
|
-
|
|
26
|
-
|
|
41
|
+
def __str__(self) -> str:
|
|
42
|
+
if self.symbol:
|
|
43
|
+
return f"{self.title} ({self.symbol})"
|
|
44
|
+
return self.title
|
|
27
45
|
|
|
28
|
-
def __repr__(self):
|
|
46
|
+
def __repr__(self) -> str:
|
|
29
47
|
return self.key
|
|
30
48
|
|
|
31
49
|
title = models.CharField(max_length=255)
|
|
32
50
|
symbol = models.CharField(max_length=10, blank=True, null=True)
|
|
33
51
|
key = models.CharField(max_length=3, unique=True)
|
|
34
52
|
|
|
35
|
-
objects =
|
|
53
|
+
objects = CurrencyDefaultManager()
|
|
36
54
|
|
|
37
55
|
LABEL_KEY = "{{key}} ({{symbol}})"
|
|
38
56
|
|
|
@@ -46,6 +64,8 @@ class Currency(ImportMixin, LabelKeyMixin, WBModel):
|
|
|
46
64
|
Returns:
|
|
47
65
|
float -- The fx rate value with the new base currency
|
|
48
66
|
"""
|
|
67
|
+
if self == other_currency:
|
|
68
|
+
return Decimal(1.0)
|
|
49
69
|
try:
|
|
50
70
|
if exact_lookup:
|
|
51
71
|
base = CurrencyFXRates.objects.get(date=valuation_date, currency=self)
|
|
@@ -63,7 +83,9 @@ class Currency(ImportMixin, LabelKeyMixin, WBModel):
|
|
|
63
83
|
raise CurrencyFXRates.DoesNotExist
|
|
64
84
|
return (1 / base.value) * other.value
|
|
65
85
|
except CurrencyFXRates.DoesNotExist:
|
|
66
|
-
|
|
86
|
+
if exact_lookup:
|
|
87
|
+
return self.convert(valuation_date, other_currency, exact_lookup=False)
|
|
88
|
+
raise CurrencyFXRates.DoesNotExist from None
|
|
67
89
|
|
|
68
90
|
@classmethod
|
|
69
91
|
def get_endpoint_basename(cls) -> str:
|
|
@@ -79,7 +101,7 @@ class Currency(ImportMixin, LabelKeyMixin, WBModel):
|
|
|
79
101
|
|
|
80
102
|
@classmethod
|
|
81
103
|
def get_representation_label_key(cls) -> str:
|
|
82
|
-
return "{{
|
|
104
|
+
return "{{name_repr}}"
|
|
83
105
|
|
|
84
106
|
|
|
85
107
|
class CurrencyFXRates(ImportMixin, models.Model):
|
|
@@ -8,11 +8,15 @@ from .models import Currency, CurrencyFXRates
|
|
|
8
8
|
class CurrencyRepresentationSerializer(wb_serializers.RepresentationSerializer):
|
|
9
9
|
"""Representation Serializer for Currencies"""
|
|
10
10
|
|
|
11
|
+
name_repr = wb_serializers.SerializerMethodField(read_only=True)
|
|
11
12
|
_detail = wb_serializers.HyperlinkField(reverse_name="wbcore:currency:currency-detail")
|
|
12
13
|
|
|
14
|
+
def get_name_repr(self, obj):
|
|
15
|
+
return str(obj)
|
|
16
|
+
|
|
13
17
|
class Meta:
|
|
14
18
|
model = Currency
|
|
15
|
-
fields = ("id", "
|
|
19
|
+
fields = ("id", "name_repr", "key", "_detail")
|
|
16
20
|
|
|
17
21
|
|
|
18
22
|
class CurrencyModelSerializer(wb_serializers.ModelSerializer):
|
|
@@ -30,6 +30,10 @@ class TestSerializers:
|
|
|
30
30
|
mocker.patch.object(currency_fx_rate, "currency_id", currency.id)
|
|
31
31
|
return currency_fx_rate
|
|
32
32
|
|
|
33
|
+
@pytest.fixture
|
|
34
|
+
def expected_representation_data(self, currency):
|
|
35
|
+
return {"id": currency.id, "name_repr": f"{currency.title} ({currency.symbol})", "key": currency.key}
|
|
36
|
+
|
|
33
37
|
@pytest.fixture
|
|
34
38
|
def expected_data(self, currency):
|
|
35
39
|
return {"id": currency.id, "title": currency.title, "key": currency.key, "symbol": currency.symbol}
|
|
@@ -43,12 +47,12 @@ class TestSerializers:
|
|
|
43
47
|
"currency": currency_fx_rate.currency_id,
|
|
44
48
|
}
|
|
45
49
|
|
|
46
|
-
def test_currency_representation_serializer(self, mocker: MockerFixture, currency,
|
|
50
|
+
def test_currency_representation_serializer(self, mocker: MockerFixture, currency, expected_representation_data):
|
|
47
51
|
detail = f"/wbcore/currency/currency/{currency.id}/"
|
|
48
52
|
mocker.patch("wbcore.serializers.fields.fields.HyperlinkField", return_value=detail)
|
|
49
53
|
serializer = CurrencyRepresentationSerializer(instance=currency)
|
|
50
|
-
|
|
51
|
-
assert serializer.data ==
|
|
54
|
+
expected_representation_data["_detail"] = detail
|
|
55
|
+
assert serializer.data == expected_representation_data
|
|
52
56
|
|
|
53
57
|
def test_currency_model_serializer(self, mocker: MockerFixture, currency, expected_data):
|
|
54
58
|
mocker.patch(
|
|
@@ -50,7 +50,7 @@ class TestCurrencyRepresentationViewSets:
|
|
|
50
50
|
assert response.status_code == status.HTTP_200_OK
|
|
51
51
|
assert instance.get("id") == euro.id
|
|
52
52
|
assert instance.get("key") == euro.key
|
|
53
|
-
assert instance.get("
|
|
53
|
+
assert instance.get("name_repr") == f"{euro.title} ({euro.symbol})"
|
|
54
54
|
|
|
55
55
|
|
|
56
56
|
@pytest.mark.viewset_tests
|
|
@@ -19,8 +19,8 @@ class CurrencyRepresentationViewSet(viewsets.RepresentationViewSet):
|
|
|
19
19
|
serializer_class = CurrencyRepresentationSerializer
|
|
20
20
|
filter_backends = (filters.OrderingFilter, filters.SearchFilter)
|
|
21
21
|
|
|
22
|
-
ordering =
|
|
23
|
-
search_fields = ("
|
|
22
|
+
ordering = ["name_repr"]
|
|
23
|
+
search_fields = ("name_repr", "key")
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
class CurrencyModelViewSet(viewsets.ModelViewSet):
|
|
@@ -1,15 +1,6 @@
|
|
|
1
|
-
from rest_framework.reverse import reverse
|
|
2
|
-
|
|
3
1
|
from wbcore.metadata.configs.endpoints import EndpointViewConfig
|
|
4
2
|
|
|
5
3
|
|
|
6
4
|
class CurrencyFXRatesCurrencyEndpointConfig(EndpointViewConfig):
|
|
7
5
|
def get_endpoint(self, **kwargs):
|
|
8
6
|
return None
|
|
9
|
-
|
|
10
|
-
def get_list_endpoint(self, **kwargs):
|
|
11
|
-
return reverse(
|
|
12
|
-
"wbcore:currency:currency-currencyfxrates-list",
|
|
13
|
-
args=[self.view.kwargs["currency_id"]],
|
|
14
|
-
request=self.request,
|
|
15
|
-
)
|
|
@@ -12,9 +12,9 @@ def dictfetchall[T](cursor: "CursorWrapper", dict_type: type[T] = dict) -> Itera
|
|
|
12
12
|
columns = get_columns(cursor)
|
|
13
13
|
for row in cursor.fetchall():
|
|
14
14
|
# The spec for TypedDict is not compliant with the sepc for dict
|
|
15
|
-
yield dict_type(zip(columns, row)) # type: ignore
|
|
15
|
+
yield dict_type(zip(columns, row, strict=False)) # type: ignore
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
def dictfetchone(cursor: "CursorWrapper") -> dict:
|
|
19
19
|
columns = get_columns(cursor)
|
|
20
|
-
return dict(zip(columns, cursor.fetchone() or []))
|
|
20
|
+
return dict(zip(columns, cursor.fetchone() or [], strict=False))
|
|
@@ -114,6 +114,7 @@ class PersonFactory(EntryFactory):
|
|
|
114
114
|
first_name = factory.Faker("first_name")
|
|
115
115
|
last_name = factory.Faker("last_name")
|
|
116
116
|
birthday = factory.Faker("date_object")
|
|
117
|
+
description = factory.Faker("text")
|
|
117
118
|
personality_profile_red = random.randint(1, 5)
|
|
118
119
|
personality_profile_green = random.randint(1, 5)
|
|
119
120
|
personality_profile_blue = random.randint(1, 5)
|
|
@@ -157,7 +158,7 @@ class ClientFactory(PersonFactory):
|
|
|
157
158
|
self.clients.add(person)
|
|
158
159
|
|
|
159
160
|
|
|
160
|
-
class
|
|
161
|
+
class RandomClientFactory(ClientFactory):
|
|
161
162
|
@factory.post_generation
|
|
162
163
|
def clients(self, create, extracted, **kwargs):
|
|
163
164
|
self.clients.add(PersonFactory())
|
|
@@ -30,6 +30,15 @@ class EntryFilter(wb_filters.FilterSet):
|
|
|
30
30
|
help_text=_("Filter by activities in a date range"),
|
|
31
31
|
method="filter_last_event",
|
|
32
32
|
)
|
|
33
|
+
last_event_period_endswith = wb_filters.DateTimeFilter(
|
|
34
|
+
label=_("Last Event Period End date"), field_name="last_event_period_endswith", lookup_expr="exact"
|
|
35
|
+
)
|
|
36
|
+
last_event_period_endswith__gte = wb_filters.DateTimeFilter(
|
|
37
|
+
label=_("Last Event Period End date"), field_name="last_event_period_endswith", lookup_expr="gte"
|
|
38
|
+
)
|
|
39
|
+
last_event_period_endswith__lte = wb_filters.DateTimeFilter(
|
|
40
|
+
label=_("Last Event Period End date"), field_name="last_event_period_endswith", lookup_expr="lte"
|
|
41
|
+
)
|
|
33
42
|
|
|
34
43
|
activity_heat = wb_filters.MultipleLookupFilter(
|
|
35
44
|
field_class=wb_filters.RangeSelectFilter,
|