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,8 +1,9 @@
1
1
  import pytest
2
+ from pytest_mock import MockerFixture
2
3
  from rest_framework.test import APIRequestFactory
3
4
 
4
- from wbcore.contrib.authentication.factories import GroupFactory, UserFactory
5
- from wbcore.contrib.workflow.models import ProcessStep, Step
5
+ from wbcore.contrib.authentication.models import Group, User
6
+ from wbcore.contrib.workflow.models import ProcessStep, Step, Transition, UserStep
6
7
  from wbcore.contrib.workflow.serializers import (
7
8
  AssignedProcessStepSerializer,
8
9
  ProcessStepModelSerializer,
@@ -10,169 +11,190 @@ from wbcore.contrib.workflow.serializers import (
10
11
  from wbcore.test.utils import get_or_create_superuser
11
12
 
12
13
 
13
- @pytest.mark.django_db
14
- class TestProcessStep:
15
- api_factory = APIRequestFactory()
14
+ @pytest.fixture
15
+ def process_step(mocker: MockerFixture):
16
+ mocked_process_step = mocker.MagicMock(spec=ProcessStep)
17
+ mocked_process_step.pk = 1
18
+ mocked_process_step.state = ProcessStep.StepState.ACTIVE
19
+ return mocked_process_step
16
20
 
17
- def test_next_process_step_buttons_superuser(self, transition_factory, process_step_factory, user_step_factory):
18
- step = user_step_factory()
19
- transition1 = transition_factory(
20
- from_step=step,
21
- )
22
- transition2 = transition_factory(
23
- from_step=step,
24
- )
25
- transition_factory(to_step=step)
26
- transition_factory()
27
- process_step = process_step_factory(step=step, state=ProcessStep.StepState.ACTIVE)
28
- request = self.api_factory.get("")
29
- request.user = get_or_create_superuser()
30
- serializer = ProcessStepModelSerializer(process_step, context={"request": request})
31
- assert serializer.data
32
- transition_labels = {x["label"] for x in serializer.data["_buttons"]}
33
- assert transition_labels == {transition1.name, transition2.name}
34
21
 
35
- def test_next_process_step_buttons_assignee(self, transition_factory, process_step_factory, user_step_factory):
36
- step = user_step_factory()
37
- transition = transition_factory(
38
- from_step=step,
39
- )
40
- user = UserFactory()
41
- process_step = process_step_factory(assignee=user, step=step, state=ProcessStep.StepState.ACTIVE)
42
- request = self.api_factory.get("")
43
- request.user = user
44
- serializer = ProcessStepModelSerializer(process_step, context={"request": request})
45
- assert serializer.data
46
- assert serializer.data["_buttons"][0]["label"] == transition.name
47
-
48
- def test_next_process_step_buttons_group(self, transition_factory, process_step_factory, user_step_factory):
49
- step = user_step_factory(assignee_method=None)
50
- transition = transition_factory(
51
- from_step=step,
52
- )
53
- group = GroupFactory()
54
- user = UserFactory(groups=[group])
55
- process_step = process_step_factory(group=group, step=step, state=ProcessStep.StepState.ACTIVE)
56
- request = self.api_factory.get("")
57
- request.user = user
58
- serializer = ProcessStepModelSerializer(process_step, context={"request": request})
59
- assert serializer.data
60
- assert serializer.data["_buttons"][0]["label"] == transition.name
61
-
62
- @pytest.mark.parametrize(
63
- "state",
64
- [
65
- ProcessStep.StepState.CANCELED,
66
- ProcessStep.StepState.FAILED,
67
- ProcessStep.StepState.FINISHED,
68
- ProcessStep.StepState.WAITING,
69
- ],
70
- )
71
- def test_next_process_step_buttons_not_active(
72
- self, state, transition_factory, process_step_factory, user_step_factory
73
- ):
74
- step = user_step_factory()
75
- transition_factory(
76
- from_step=step,
22
+ class TestProcessStep:
23
+ @pytest.fixture
24
+ def transitions(self, mocker: MockerFixture):
25
+ transition_1 = mocker.MagicMock(spec=Transition)
26
+ transition_1.pk = 101
27
+ transition_1.name = "Transition One"
28
+ transition_1.icon = "icon_1"
29
+
30
+ transition_2 = mocker.MagicMock(spec=Transition)
31
+ transition_2.pk = 102
32
+ transition_2.name = "Transition Two"
33
+ transition_2.icon = "icon_2"
34
+
35
+ return (transition_1, transition_2)
36
+
37
+ @pytest.fixture
38
+ def casted_step(self, mocker: MockerFixture):
39
+ mocked_casted_step = mocker.MagicMock(spec=Step, assignee_method=False)
40
+ return mocked_casted_step
41
+
42
+ @pytest.fixture
43
+ def user_step(self, mocker: MockerFixture, casted_step, transitions):
44
+ mocked_user_step = mocker.MagicMock(spec=UserStep)
45
+ mocked_user_step.step_type = Step.StepType.USERSTEP
46
+ mocked_user_step.get_casted_step.return_value = casted_step
47
+ mocked_user_step.get_all_valid_outgoing_transitions.return_value = [*transitions]
48
+ return mocked_user_step
49
+
50
+ @pytest.fixture(autouse=True)
51
+ def mocked_patch_path(self, mocker: MockerFixture):
52
+ mocker.patch(
53
+ "wbcore.contrib.workflow.models.workflow",
54
+ return_value="/dummy-url/",
77
55
  )
78
- process_step = process_step_factory(step=step, state=state)
79
- request = self.api_factory.get("")
80
- request.user = get_or_create_superuser()
81
- serializer = ProcessStepModelSerializer(process_step, context={"request": request})
82
- assert serializer.data
83
- assert serializer.data["_buttons"] == []
84
-
85
- @pytest.mark.parametrize(
86
- "step_type",
87
- [
88
- Step.StepType.DECISIONSTEP,
89
- Step.StepType.EMAILSTEP,
90
- Step.StepType.FINISHSTEP,
91
- Step.StepType.JOINSTEP,
92
- Step.StepType.SCRIPTSTEP,
93
- Step.StepType.SPLITSTEP,
94
- ],
95
- )
96
- def test_next_process_step_buttons_not_user_step(
97
- self, step_type, transition_factory, process_step_factory, step_factory
98
- ):
99
- step = step_factory(step_type=step_type)
100
- transition_factory(
101
- from_step=step,
56
+ mocker.patch(
57
+ "wbcore.contrib.workflow.dispatch.ContentType.objects.get_for_model",
58
+ return_value="content_type",
102
59
  )
103
- process_step = process_step_factory(step=step, state=ProcessStep.StepState.ACTIVE)
104
- request = self.api_factory.get("")
105
- request.user = get_or_create_superuser()
106
- serializer = ProcessStepModelSerializer(process_step, context={"request": request})
107
- assert serializer.data
108
- assert serializer.data["_buttons"] == []
109
60
 
110
- def test_next_process_step_buttons_not_assigned(self, transition_factory, process_step_factory, user_step_factory):
111
- step = user_step_factory()
112
- transition_factory(
113
- from_step=step,
114
- )
115
- process_step = process_step_factory(step=step, state=ProcessStep.StepState.ACTIVE)
116
- request = self.api_factory.get("")
117
- request.user = UserFactory()
118
- serializer = ProcessStepModelSerializer(process_step, context={"request": request})
119
- assert serializer.data
120
- assert serializer.data["_buttons"] == []
121
-
122
- def test_next_process_step_buttons_assigned_group_with_method(
123
- self, transition_factory, process_step_factory, user_step_factory
61
+ @pytest.mark.parametrize("user", ["super_user", "user", "group"])
62
+ def test_next_process_step_buttons(self, mocker: MockerFixture, user, process_step, user_step):
63
+ """
64
+ This test verifies that the method next_process_step_buttons returns buttons when:
65
+ - "super_user": The user is a superuser.
66
+ - "user": The user is the assignee of the process step.
67
+ - "group": The user belongs to the group assigned to the process step.
68
+ """
69
+ # Arrange
70
+ mocked_process_step = process_step
71
+ mocked_process_step.step = user_step
72
+
73
+ request_user = mocker.MagicMock(spec=User, is_superuser=(user == "super_user"))
74
+ if user == "user":
75
+ mocked_process_step.assignee = request_user
76
+ elif user == "group":
77
+ mocked_group = mocker.MagicMock(spec=Group)
78
+ mocked_group.user_set.all.return_value = [request_user]
79
+ mocked_process_step.group = mocked_group
80
+ request = mocker.MagicMock(user=request_user)
81
+
82
+ # Act
83
+ serializer = ProcessStepModelSerializer(mocked_process_step, context={"request": request})
84
+ data = serializer.data
85
+ button_labels = {button["label"] for button in data["_buttons"]}
86
+
87
+ # Assert
88
+ assert len(data["_buttons"]) == 2
89
+ assert button_labels == {"Transition One", "Transition Two"}
90
+
91
+ @pytest.mark.parametrize("reason", ["finished_state", "not_user_step"])
92
+ def test_no_transition_buttons_when_step_is_not_eligible(
93
+ self, mocker: MockerFixture, reason, process_step, user_step
124
94
  ):
125
- step = user_step_factory()
126
- transition_factory(
127
- from_step=step,
128
- )
129
- group = GroupFactory()
130
- user = UserFactory(groups=[group])
131
- process_step = process_step_factory(group=group, step=step, state=ProcessStep.StepState.ACTIVE)
132
- request = self.api_factory.get("")
133
- request.user = user
134
- serializer = ProcessStepModelSerializer(process_step, context={"request": request})
135
- assert serializer.data
136
- assert serializer.data["_buttons"] == []
95
+ """
96
+ Test that no transition buttons appear if:
97
+ - The process step is in a non-active state, OR
98
+ - The step is not a UserStep type.
99
+ """
100
+ # Arrange
101
+ mocked_process_step = process_step
102
+ if reason == "inactive_state":
103
+ mocked_process_step.state = ProcessStep.StepState.FINISHED
104
+ else:
105
+ user_step.step_type = Step.StepType.SPLITSTEP
106
+
107
+ super_user = mocker.MagicMock(spec=User, is_superuser=True)
108
+ request = mocker.MagicMock(user=super_user)
109
+ # Act
110
+ serializer = ProcessStepModelSerializer(mocked_process_step, context={"request": request})
111
+ data = serializer.data
112
+
113
+ # Assert
114
+ assert len(data["_buttons"]) == 0
115
+
116
+ def test_next_process_step_buttons_not_assigned(self, mocker: MockerFixture, process_step, user_step, casted_step):
117
+ """
118
+ No buttons when there is a assignee_method
119
+ """
120
+ # Arrange
121
+ request_user = mocker.MagicMock(spec=User, is_superuser=False)
122
+ request = mocker.MagicMock(user=request_user)
123
+
124
+ mocked_group = mocker.MagicMock(spec=Group)
125
+ mocked_group.user_set.all.return_value = [request_user]
126
+
127
+ mocked_casted_step = casted_step
128
+ mocked_casted_step.assignee_method = True
129
+
130
+ mocked_user_step = user_step
131
+ mocked_user_step.get_casted_step.return_value = casted_step
132
+
133
+ mocked_process_step = process_step
134
+ mocked_process_step.step = mocked_user_step
135
+ mocked_process_step.group = mocked_group
136
+
137
+ # Act
138
+ serializer = ProcessStepModelSerializer(mocked_process_step, context={"request": request})
139
+ data = serializer.data
140
+ # Assert
141
+ assert len(data["_buttons"]) == 0
137
142
 
138
143
  def test_next_process_step_buttons_no_transitions(
139
- self, transition_factory, process_step_factory, user_step_factory
144
+ self, mocker: MockerFixture, process_step, user_step, casted_step
140
145
  ):
141
- step = user_step_factory()
142
- transition_factory()
143
- transition_factory(to_step=step)
144
- transition_factory()
145
- process_step = process_step_factory(step=step, state=ProcessStep.StepState.ACTIVE)
146
- request = self.api_factory.get("")
147
- request.user = get_or_create_superuser()
148
- serializer = ProcessStepModelSerializer(process_step, context={"request": request})
149
- assert serializer.data
150
- assert serializer.data["_buttons"] == []
146
+ """
147
+ No transitions no buttons
148
+ """
149
+ # Arrange
150
+ request_user = mocker.MagicMock(spec=User, is_superuser=True)
151
+ request = mocker.MagicMock(user=request_user)
151
152
 
153
+ mocked_user_step = user_step
154
+ mocked_user_step.get_all_valid_outgoing_transitions.return_value = []
152
155
 
153
- @pytest.mark.django_db
154
- class TestAssignedProcessStep:
155
- api_factory = APIRequestFactory()
156
+ mocked_process_step = process_step
157
+ mocked_process_step.step = user_step
156
158
 
157
- def test_get_instance_endpoint_no_request(self, process_step_factory):
158
- process_step = process_step_factory()
159
- serializer = AssignedProcessStepSerializer(process_step)
160
- assert serializer.data
161
- assert serializer.data["instance_endpoint"] == ""
159
+ # Act
160
+ serializer = ProcessStepModelSerializer(mocked_process_step, context={"request": request})
161
+ data = serializer.data
162
+ # Assert
163
+ assert len(data["_buttons"]) == 0
162
164
 
163
- def test_get_instance_endpoint_no_attached_instance(self, process_step_factory):
164
- process_step = process_step_factory(process__instance=None, process__instance_id=None)
165
- request = self.api_factory.get("")
166
- request.user = get_or_create_superuser()
167
- serializer = AssignedProcessStepSerializer(process_step, context={"request": request})
165
+
166
+ class TestAssignedProcessStep:
167
+ @pytest.fixture
168
+ def process_step_with_assignee(self, mocker: MockerFixture, process_step):
169
+ mocked_step = mocker.MagicMock(spec=Step)
170
+ mocked_step.id = 42
171
+ mocked_user = mocker.MagicMock(spec=User)
172
+ mocked_user.id = 3
173
+ process_step.step = mocked_step
174
+ process_step.assignee = mocked_user
175
+ return process_step
176
+
177
+ def test_get_instance_endpoint_no_request(self, mocker: MockerFixture, process_step_with_assignee):
178
+ serializer = AssignedProcessStepSerializer(process_step_with_assignee)
168
179
  assert serializer.data
169
- assert "processstep" in serializer.data["instance_endpoint"]
180
+ assert serializer.data["instance_endpoint"] == ""
170
181
 
171
- def test_get_instance_endpoint_attached_instance(self, process_step_factory):
172
- process_step = process_step_factory()
173
- request = self.api_factory.get("")
182
+ @pytest.mark.django_db
183
+ @pytest.mark.with_db
184
+ @pytest.mark.parametrize("with_instance", [True, False])
185
+ def test_get_instance_endpoint_no_attached_instance(self, process_step_factory, with_instance):
186
+ api_factory = APIRequestFactory()
187
+ process_step = (
188
+ process_step_factory()
189
+ if with_instance
190
+ else process_step_factory(process__instance=None, process__instance_id=None)
191
+ )
192
+ request = api_factory.get("")
174
193
  request.user = get_or_create_superuser()
175
194
  serializer = AssignedProcessStepSerializer(process_step, context={"request": request})
176
195
  assert serializer.data
177
- assert "processstep" not in serializer.data["instance_endpoint"]
178
- assert "person" in serializer.data["instance_endpoint"]
196
+ if with_instance:
197
+ assert "processstep" not in serializer.data["instance_endpoint"]
198
+ assert "person" in serializer.data["instance_endpoint"]
199
+ else:
200
+ assert "processstep" in serializer.data["instance_endpoint"]