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.
Files changed (321) hide show
  1. wbcore/cache/decorators.py +5 -3
  2. wbcore/cache/registry.py +14 -7
  3. wbcore/configs/__init__.py +1 -0
  4. wbcore/configs/configs.py +5 -0
  5. wbcore/configs/decorators.py +1 -1
  6. wbcore/configurations/configurations/apps.py +3 -2
  7. wbcore/configurations/configurations/authentication.py +1 -1
  8. wbcore/configurations/configurations/base.py +1 -1
  9. wbcore/configurations/configurations/cache.py +1 -1
  10. wbcore/configurations/configurations/i18nl10n.py +2 -1
  11. wbcore/configurations/configurations/maintenance.py +1 -1
  12. wbcore/configurations/configurations/media.py +1 -1
  13. wbcore/configurations/configurations/middleware.py +1 -1
  14. wbcore/configurations/configurations/rest_framework.py +1 -1
  15. wbcore/configurations/configurations/static.py +3 -3
  16. wbcore/configurations/configurations/wbcore.py +1 -1
  17. wbcore/content_type/serializers.py +13 -5
  18. wbcore/content_type/utils.py +3 -3
  19. wbcore/content_type/viewsets.py +2 -2
  20. wbcore/contrib/agenda/filters/calendar_item.py +5 -4
  21. wbcore/contrib/agenda/locale/de/LC_MESSAGES/django.po +145 -52
  22. wbcore/contrib/agenda/locale/de/LC_MESSAGES/django.po.translated +236 -0
  23. wbcore/contrib/agenda/locale/en/LC_MESSAGES/django.po +200 -0
  24. wbcore/contrib/agenda/locale/fr/LC_MESSAGES/django.po +201 -0
  25. wbcore/contrib/agenda/viewsets/calendar_items.py +7 -7
  26. wbcore/contrib/agenda/viewsets/menu/calendar_items.py +0 -6
  27. wbcore/contrib/ai/exceptions.py +5 -5
  28. wbcore/contrib/ai/llm/config.py +76 -27
  29. wbcore/contrib/ai/llm/mixins.py +5 -8
  30. wbcore/contrib/ai/llm/utils.py +50 -26
  31. wbcore/contrib/authentication/admin.py +2 -2
  32. wbcore/contrib/authentication/factories/__init__.py +8 -1
  33. wbcore/contrib/authentication/factories/users.py +19 -0
  34. wbcore/contrib/authentication/filters.py +1 -2
  35. wbcore/contrib/authentication/locale/de/LC_MESSAGES/django.po +209 -187
  36. wbcore/contrib/authentication/locale/de/LC_MESSAGES/django.po.translated +634 -0
  37. wbcore/contrib/authentication/locale/en/LC_MESSAGES/django.po +590 -0
  38. wbcore/contrib/authentication/locale/fr/LC_MESSAGES/django.po +592 -0
  39. wbcore/contrib/authentication/models/users.py +3 -3
  40. wbcore/contrib/authentication/models/users_activities.py +1 -1
  41. wbcore/contrib/authentication/serializers/users.py +2 -2
  42. wbcore/contrib/authentication/tests/test_tokens.py +3 -3
  43. wbcore/contrib/authentication/tests/test_users.py +0 -1
  44. wbcore/contrib/authentication/urls.py +0 -4
  45. wbcore/contrib/authentication/viewsets/endpoints/user_activities.py +2 -11
  46. wbcore/contrib/authentication/viewsets/endpoints/users.py +0 -3
  47. wbcore/contrib/authentication/viewsets/user_activities.py +2 -1
  48. wbcore/contrib/authentication/viewsets/users.py +6 -4
  49. wbcore/contrib/color/models.py +2 -1
  50. wbcore/contrib/currency/factories.py +1 -1
  51. wbcore/contrib/currency/import_export/backends/fixerio/currency_fx_rates.py +3 -1
  52. wbcore/contrib/currency/models.py +30 -8
  53. wbcore/contrib/currency/serializers.py +5 -1
  54. wbcore/contrib/currency/tests/test_serializers.py +7 -3
  55. wbcore/contrib/currency/tests/test_viewsets.py +1 -1
  56. wbcore/contrib/currency/viewsets/currency.py +2 -2
  57. wbcore/contrib/currency/viewsets/endpoints/currency_fx_rates.py +0 -9
  58. wbcore/contrib/dataloader/tests/test/dataloaders/protocols.py +1 -2
  59. wbcore/contrib/dataloader/utils.py +2 -2
  60. wbcore/contrib/directory/factories/__init__.py +1 -1
  61. wbcore/contrib/directory/factories/entries.py +2 -1
  62. wbcore/contrib/directory/filters/entries.py +9 -0
  63. wbcore/contrib/directory/locale/de/LC_MESSAGES/django.po +728 -714
  64. wbcore/contrib/directory/locale/de/LC_MESSAGES/django.po.translated +1779 -0
  65. wbcore/contrib/directory/locale/en/LC_MESSAGES/django.po +1652 -0
  66. wbcore/contrib/directory/locale/fr/LC_MESSAGES/django.po +1654 -0
  67. wbcore/contrib/directory/migrations/0011_person_description_person_i18n.py +24 -0
  68. wbcore/contrib/directory/migrations/0012_alter_person_managers.py +20 -0
  69. wbcore/contrib/directory/migrations/0013_alter_clientmanagerrelationship_options.py +17 -0
  70. wbcore/contrib/directory/models/contacts.py +2 -2
  71. wbcore/contrib/directory/models/entries.py +31 -5
  72. wbcore/contrib/directory/models/relationships.py +31 -35
  73. wbcore/contrib/directory/permissions.py +6 -0
  74. wbcore/contrib/directory/serializers/companies.py +16 -8
  75. wbcore/contrib/directory/serializers/contacts.py +8 -8
  76. wbcore/contrib/directory/serializers/entries.py +26 -15
  77. wbcore/contrib/directory/serializers/entry_representations.py +4 -2
  78. wbcore/contrib/directory/serializers/persons.py +12 -10
  79. wbcore/contrib/directory/serializers/relationships.py +2 -2
  80. wbcore/contrib/directory/tests/conftest.py +2 -0
  81. wbcore/contrib/directory/tests/disable_signals.py +11 -1
  82. wbcore/contrib/directory/tests/signals.py +2 -2
  83. wbcore/contrib/directory/tests/test_models.py +88 -66
  84. wbcore/contrib/directory/tests/test_serializers.py +1 -1
  85. wbcore/contrib/directory/tests/test_viewsets.py +8 -8
  86. wbcore/contrib/directory/viewsets/buttons/__init__.py +1 -1
  87. wbcore/contrib/directory/viewsets/buttons/relationships.py +32 -0
  88. wbcore/contrib/directory/viewsets/contacts.py +6 -6
  89. wbcore/contrib/directory/viewsets/display/__init__.py +1 -1
  90. wbcore/contrib/directory/viewsets/display/contacts.py +1 -14
  91. wbcore/contrib/directory/viewsets/display/entries.py +68 -38
  92. wbcore/contrib/directory/viewsets/display/relationships.py +26 -50
  93. wbcore/contrib/directory/viewsets/endpoints/relationships.py +1 -26
  94. wbcore/contrib/directory/viewsets/entries.py +8 -6
  95. wbcore/contrib/directory/viewsets/previews/entries.py +3 -3
  96. wbcore/contrib/directory/viewsets/relationships.py +16 -2
  97. wbcore/contrib/directory/viewsets/titles/relationships.py +2 -3
  98. wbcore/contrib/documents/filters.py +0 -2
  99. wbcore/contrib/documents/locale/de/LC_MESSAGES/django.po +103 -94
  100. wbcore/contrib/documents/locale/de/LC_MESSAGES/django.po.translated +285 -0
  101. wbcore/contrib/documents/locale/en/LC_MESSAGES/django.po +271 -0
  102. wbcore/contrib/documents/locale/fr/LC_MESSAGES/django.po +270 -0
  103. wbcore/contrib/documents/tests/test_models.py +32 -28
  104. wbcore/contrib/documents/viewsets/endpoints/shareable_links.py +2 -21
  105. wbcore/contrib/dynamic_preferences/types.py +108 -0
  106. wbcore/contrib/dynamic_preferences/viewsets.py +27 -0
  107. wbcore/contrib/example_app/filters/event.py +3 -1
  108. wbcore/contrib/example_app/filters/match.py +1 -1
  109. wbcore/contrib/example_app/models.py +91 -22
  110. wbcore/contrib/example_app/serializers/person_team.py +4 -4
  111. wbcore/contrib/example_app/templates/example_app/embedded_view.html +19 -0
  112. wbcore/contrib/example_app/tests/e2e/test_teams.py +1 -1
  113. wbcore/contrib/example_app/tests/test_models/test_match.py +17 -7
  114. wbcore/contrib/example_app/urls.py +2 -0
  115. wbcore/contrib/example_app/views.py +7 -0
  116. wbcore/contrib/example_app/viewsets/displays/team.py +23 -4
  117. wbcore/contrib/example_app/viewsets/menu/menus.py +1 -1
  118. wbcore/contrib/example_app/viewsets/menus.py +1 -1
  119. wbcore/contrib/geography/tests/conftest.py +14 -0
  120. wbcore/contrib/geography/tests/test_models.py +23 -8
  121. wbcore/contrib/geography/tests/test_viewsets.py +96 -2
  122. wbcore/contrib/guardian/tests/test_model_mixins.py +3 -4
  123. wbcore/contrib/guardian/tests/test_tasks.py +9 -9
  124. wbcore/contrib/guardian/tests/test_viewsets.py +2 -2
  125. wbcore/contrib/guardian/viewsets/configs/__init__.py +1 -1
  126. wbcore/contrib/guardian/viewsets/configs/buttons.py +9 -0
  127. wbcore/contrib/guardian/viewsets/configs/endpoints.py +7 -0
  128. wbcore/contrib/guardian/viewsets/viewsets.py +2 -0
  129. wbcore/contrib/i18n/__init__.py +2 -0
  130. wbcore/contrib/i18n/buttons.py +33 -0
  131. wbcore/contrib/i18n/serializers/__init__.py +0 -0
  132. wbcore/contrib/i18n/serializers/fields.py +20 -0
  133. wbcore/contrib/i18n/serializers/mixins.py +13 -0
  134. wbcore/contrib/i18n/tests/conftest.py +11 -0
  135. wbcore/contrib/i18n/tests/test_viewsets.py +67 -0
  136. wbcore/contrib/i18n/translation.py +140 -0
  137. wbcore/contrib/i18n/viewsets.py +36 -0
  138. wbcore/contrib/icons/backends/default.py +1 -0
  139. wbcore/contrib/icons/backends/material.py +1 -0
  140. wbcore/contrib/icons/icons.py +5 -8
  141. wbcore/contrib/io/admin.py +1 -0
  142. wbcore/contrib/io/backends/mail.py +3 -2
  143. wbcore/contrib/io/backends/utils.py +14 -17
  144. wbcore/contrib/io/exceptions.py +8 -0
  145. wbcore/contrib/io/factories.py +1 -1
  146. wbcore/contrib/io/import_export/backends/mail.py +1 -0
  147. wbcore/contrib/io/import_export/backends/sftp.py +29 -20
  148. wbcore/contrib/io/import_export/backends/stream.py +2 -2
  149. wbcore/contrib/io/import_export/parsers/__init__.py +0 -0
  150. wbcore/contrib/io/import_export/parsers/base_csv.py +36 -0
  151. wbcore/contrib/io/import_export/parsers/resources.py +50 -0
  152. wbcore/contrib/io/imports.py +33 -25
  153. wbcore/contrib/io/locale/de/LC_MESSAGES/django.po +114 -22
  154. wbcore/contrib/io/locale/de/LC_MESSAGES/django.po.translated +103 -0
  155. wbcore/contrib/io/locale/en/LC_MESSAGES/django.po +138 -0
  156. wbcore/contrib/io/locale/fr/LC_MESSAGES/django.po +138 -0
  157. wbcore/contrib/io/migrations/0008_importsource_resource_kwargs.py +18 -0
  158. wbcore/contrib/io/models.py +65 -45
  159. wbcore/contrib/io/resources.py +0 -6
  160. wbcore/contrib/io/serializers.py +2 -2
  161. wbcore/contrib/io/signals.py +4 -0
  162. wbcore/contrib/io/tests/test_backends.py +19 -13
  163. wbcore/contrib/io/tests/test_exports.py +1 -1
  164. wbcore/contrib/io/tests/test_imports.py +1 -1
  165. wbcore/contrib/io/tests/test_models.py +47 -14
  166. wbcore/contrib/io/tests/test_viewsets.py +271 -0
  167. wbcore/contrib/io/viewset_mixins.py +41 -54
  168. wbcore/contrib/notifications/admin.py +1 -0
  169. wbcore/contrib/notifications/apps.py +2 -1
  170. wbcore/contrib/notifications/backends/abstract_backend.py +2 -4
  171. wbcore/contrib/notifications/backends/firebase/backends.py +5 -2
  172. wbcore/contrib/notifications/dispatch.py +18 -7
  173. wbcore/contrib/notifications/factories/notification_types.py +1 -0
  174. wbcore/contrib/notifications/locale/de/LC_MESSAGES/django.po +25 -19
  175. wbcore/contrib/notifications/locale/de/LC_MESSAGES/django.po.translated +63 -0
  176. wbcore/contrib/notifications/locale/en/LC_MESSAGES/django.po +61 -0
  177. wbcore/contrib/notifications/locale/fr/LC_MESSAGES/django.po +62 -0
  178. wbcore/contrib/notifications/migrations/0008_notificationtype_is_lock.py +18 -0
  179. wbcore/contrib/notifications/migrations/0009_alter_notificationtypesetting_options_and_more.py +32 -0
  180. wbcore/contrib/notifications/models/notification_types.py +67 -24
  181. wbcore/contrib/notifications/serializers/notification_types.py +16 -1
  182. wbcore/contrib/notifications/tests/test_models/test_tokens.py +8 -0
  183. wbcore/contrib/notifications/tests/test_serializers/test_notification_types.py +5 -0
  184. wbcore/contrib/notifications/tests/test_viewsets/test_notification_types.py +3 -5
  185. wbcore/contrib/notifications/utils.py +3 -2
  186. wbcore/contrib/notifications/viewsets/configs/notification_types.py +28 -6
  187. wbcore/contrib/notifications/viewsets/menus.py +1 -1
  188. wbcore/contrib/notifications/viewsets/notification_types.py +12 -2
  189. wbcore/contrib/pandas/fields.py +38 -10
  190. wbcore/contrib/pandas/filters.py +4 -1
  191. wbcore/contrib/pandas/filterset.py +8 -7
  192. wbcore/contrib/pandas/tests/test_fields/test_number_fields.py +2 -7
  193. wbcore/contrib/pandas/utils.py +1 -1
  194. wbcore/contrib/pandas/views.py +14 -13
  195. wbcore/contrib/tags/models/tags.py +4 -1
  196. wbcore/contrib/workflow/factories/display.py +2 -2
  197. wbcore/contrib/workflow/factories/transition.py +16 -15
  198. wbcore/contrib/workflow/locale/de/LC_MESSAGES/django.po +457 -566
  199. wbcore/contrib/workflow/locale/de/LC_MESSAGES/django.po.translated +1326 -0
  200. wbcore/contrib/workflow/locale/en/LC_MESSAGES/django.po +1102 -0
  201. wbcore/contrib/workflow/locale/fr/LC_MESSAGES/django.po +1114 -0
  202. wbcore/contrib/workflow/models/data.py +7 -4
  203. wbcore/contrib/workflow/models/process.py +2 -2
  204. wbcore/contrib/workflow/models/step.py +57 -15
  205. wbcore/contrib/workflow/serializers/data.py +8 -8
  206. wbcore/contrib/workflow/serializers/process.py +3 -2
  207. wbcore/contrib/workflow/tests/conftest.py +224 -0
  208. wbcore/contrib/workflow/tests/test_dispatch.py +82 -77
  209. wbcore/contrib/workflow/tests/test_displays.py +10 -88
  210. wbcore/contrib/workflow/tests/test_filters.py +57 -40
  211. wbcore/contrib/workflow/tests/test_models/step/test_decision_step.py +71 -68
  212. wbcore/contrib/workflow/tests/test_models/step/test_email_step.py +78 -38
  213. wbcore/contrib/workflow/tests/test_models/step/test_finish_step.py +152 -90
  214. wbcore/contrib/workflow/tests/test_models/step/test_join_step.py +100 -110
  215. wbcore/contrib/workflow/tests/test_models/step/test_step.py +168 -33
  216. wbcore/contrib/workflow/tests/test_models/test_condition.py +1 -1
  217. wbcore/contrib/workflow/tests/test_models/test_workflow.py +3 -3
  218. wbcore/contrib/workflow/tests/test_serializers.py +172 -150
  219. wbcore/contrib/workflow/tests/test_viewsets.py +264 -323
  220. wbcore/contrib/workflow/tests/test_workflow_assignees.py +215 -205
  221. wbcore/contrib/workflow/viewsets/process.py +4 -1
  222. wbcore/contrib/workflow/workflows/assignees.py +12 -7
  223. wbcore/dynamic_preferences_registry.py +102 -0
  224. wbcore/enums.py +2 -51
  225. wbcore/filters/fields/choices.py +4 -6
  226. wbcore/filters/fields/content_type.py +15 -4
  227. wbcore/filters/fields/datetime.py +50 -25
  228. wbcore/filters/fields/models.py +18 -9
  229. wbcore/filters/fields/numbers.py +9 -8
  230. wbcore/filters/filterset.py +27 -6
  231. wbcore/filters/mixins.py +41 -42
  232. wbcore/forms.py +6 -6
  233. wbcore/fsm/markdown_extensions.py +1 -1
  234. wbcore/fsm/mixins.py +20 -6
  235. wbcore/locale/de/LC_MESSAGES/django.po +982 -397
  236. wbcore/locale/de/LC_MESSAGES/django.po.translated +1580 -0
  237. wbcore/locale/en/LC_MESSAGES/django.po +1234 -0
  238. wbcore/locale/fr/LC_MESSAGES/django.po +1235 -0
  239. wbcore/markdown/models.py +8 -5
  240. wbcore/markdown/views.py +1 -1
  241. wbcore/menus/menus.py +2 -2
  242. wbcore/metadata/configs/buttons/bases.py +10 -7
  243. wbcore/metadata/configs/buttons/buttons.py +2 -1
  244. wbcore/metadata/configs/buttons/enums.py +50 -0
  245. wbcore/metadata/configs/buttons/view_config.py +13 -46
  246. wbcore/metadata/configs/display/display.py +2 -2
  247. wbcore/metadata/configs/display/formatting.py +6 -9
  248. wbcore/metadata/configs/display/instance_display/display.py +5 -2
  249. wbcore/metadata/configs/display/instance_display/pages.py +1 -1
  250. wbcore/metadata/configs/display/instance_display/shortcuts.py +1 -1
  251. wbcore/metadata/configs/display/list_display.py +54 -40
  252. wbcore/metadata/configs/display/models.py +6 -0
  253. wbcore/metadata/configs/display/view_config.py +11 -9
  254. wbcore/metadata/configs/endpoints.py +11 -4
  255. wbcore/metadata/configs/fields.py +6 -1
  256. wbcore/metadata/configs/filter_fields.py +12 -13
  257. wbcore/metadata/configs/identifiers.py +3 -1
  258. wbcore/metadata/tests/test_buttons.py +13 -16
  259. wbcore/models/fields.py +2 -2
  260. wbcore/pagination.py +1 -2
  261. wbcore/permissions/permissions.py +2 -2
  262. wbcore/permissions/utils.py +2 -2
  263. wbcore/release_notes/display.py +2 -8
  264. wbcore/release_notes/serializers.py +2 -9
  265. wbcore/release_notes/viewsets.py +8 -2
  266. wbcore/reversion/viewsets/titles.py +4 -3
  267. wbcore/serializers/__init__.py +2 -0
  268. wbcore/serializers/fields/__init__.py +2 -1
  269. wbcore/serializers/fields/boolean.py +1 -1
  270. wbcore/serializers/fields/choice.py +28 -4
  271. wbcore/serializers/fields/datetime.py +45 -36
  272. wbcore/serializers/fields/fields.py +1 -1
  273. wbcore/serializers/fields/fsm.py +1 -1
  274. wbcore/serializers/fields/list.py +2 -5
  275. wbcore/serializers/fields/mixins.py +24 -11
  276. wbcore/serializers/fields/number.py +6 -23
  277. wbcore/serializers/fields/other.py +2 -10
  278. wbcore/serializers/fields/related.py +4 -6
  279. wbcore/serializers/fields/text.py +1 -1
  280. wbcore/serializers/fields/types.py +2 -0
  281. wbcore/serializers/serializers.py +12 -3
  282. wbcore/signals/__init__.py +1 -0
  283. wbcore/signals/clone.py +4 -0
  284. wbcore/signals/models.py +2 -6
  285. wbcore/tasks.py +2 -2
  286. wbcore/templates/wbcore/email_base_template.html +3 -3
  287. wbcore/test/e2e_helpers_methods/e2e_checks.py +10 -4
  288. wbcore/test/e2e_helpers_methods/e2e_helper_methods.py +4 -2
  289. wbcore/test/mixins.py +52 -102
  290. wbcore/test/tests.py +6 -9
  291. wbcore/test/utils.py +3 -4
  292. wbcore/tests/e2e/test_e2e.py +2 -2
  293. wbcore/tests/test_cache/test_decorators.py +4 -7
  294. wbcore/tests/test_configs.py +2 -5
  295. wbcore/tests/test_enums.py +2 -1
  296. wbcore/tests/test_fields/test_choice_fields.py +9 -1
  297. wbcore/tests/test_fields/test_number_fields.py +7 -15
  298. wbcore/tests/test_fields/test_other_fields.py +1 -2
  299. wbcore/tests/test_filters/test_mixins.py +35 -35
  300. wbcore/tests/test_list_display.py +0 -2
  301. wbcore/tests/test_models/test_mixins.py +1 -1
  302. wbcore/tests/test_utils/test_date.py +1 -1
  303. wbcore/tests/test_utils/test_date_builder.py +25 -1
  304. wbcore/tests/test_utils/test_primary.py +1 -1
  305. wbcore/urls.py +4 -0
  306. wbcore/utils/date.py +18 -2
  307. wbcore/utils/figures.py +2 -2
  308. wbcore/utils/models.py +21 -4
  309. wbcore/utils/reportlab.py +7 -0
  310. wbcore/utils/rrules.py +3 -1
  311. wbcore/utils/string_loader.py +1 -1
  312. wbcore/utils/strings.py +3 -3
  313. wbcore/utils/views.py +8 -3
  314. wbcore/viewsets/mixins.py +9 -4
  315. {wbcore-1.46.0.dist-info → wbcore-1.58.2.dist-info}/METADATA +9 -5
  316. {wbcore-1.46.0.dist-info → wbcore-1.58.2.dist-info}/RECORD +317 -271
  317. wbcore/contrib/geography/tests/test_serializers.py +0 -7
  318. wbcore/contrib/geography/tests/tests.py +0 -13
  319. wbcore/contrib/io/tests/tests.py +0 -19
  320. wbcore/contrib/workflow/tests/tests.py +0 -25
  321. {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
- def get_list_endpoint(self, **kwargs):
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
- def get_list_endpoint(self, **kwargs):
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") for start, end in zip(dff.date, dff.latest_refresh)
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
- try:
70
+ with suppress(User.DoesNotExist):
70
71
  user = User.objects.get(email=request.data["email"])
71
- user.reset_password(request)
72
- except Exception:
73
- pass
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",
@@ -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, key=lambda subject: sum((s - q) ** 2 for s, q in zip(_hex2rgb(subject), color_rgb))
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(f'{self.ENDPOINT}/{_date.strftime("%Y-%m-%d")}?', params=params, headers=self.HEADERS)
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
- symbol = f"({self.symbol})" if self.symbol else ""
26
- return f"{self.key} {symbol}"
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 = models.Manager()
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
- return Decimal(1.0)
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 "{{key}} ({{symbol}})"
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", "title", "key", "symbol", "_detail")
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, expected_data):
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
- expected_data["_detail"] = detail
51
- assert serializer.data == expected_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("title") == euro.title
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 = ordering_fields = ["-symbol"]
23
- search_fields = ("symbol", "key")
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
- )
@@ -2,5 +2,4 @@ from typing import Iterator, Protocol
2
2
 
3
3
 
4
4
  class EntityTestDataProtocol(Protocol):
5
- def data(self, n: int) -> Iterator[int]:
6
- ...
5
+ def data(self, n: int) -> Iterator[int]: ...
@@ -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))
@@ -18,7 +18,7 @@ from .entries import (
18
18
  EntryFactory,
19
19
  PersonFactory,
20
20
  PersonWithEmployerFactory,
21
- Random_ClientFactory,
21
+ RandomClientFactory,
22
22
  SpecializationFactory,
23
23
  UnemployedPersonFactory,
24
24
  PersonSignatureFactory,
@@ -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 Random_ClientFactory(ClientFactory):
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,