wbcrm 2.2.1__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.

Potentially problematic release.


This version of wbcrm might be problematic. Click here for more details.

Files changed (155) hide show
  1. wbcrm/__init__.py +1 -0
  2. wbcrm/admin/__init__.py +4 -0
  3. wbcrm/admin/accounts.py +59 -0
  4. wbcrm/admin/activities.py +101 -0
  5. wbcrm/admin/groups.py +7 -0
  6. wbcrm/admin/products.py +8 -0
  7. wbcrm/apps.py +5 -0
  8. wbcrm/configurations/__init__.py +1 -0
  9. wbcrm/configurations/base.py +16 -0
  10. wbcrm/dynamic_preferences_registry.py +38 -0
  11. wbcrm/factories/__init__.py +14 -0
  12. wbcrm/factories/accounts.py +56 -0
  13. wbcrm/factories/activities.py +125 -0
  14. wbcrm/factories/groups.py +23 -0
  15. wbcrm/factories/products.py +10 -0
  16. wbcrm/filters/__init__.py +10 -0
  17. wbcrm/filters/accounts.py +67 -0
  18. wbcrm/filters/activities.py +181 -0
  19. wbcrm/filters/groups.py +20 -0
  20. wbcrm/filters/products.py +37 -0
  21. wbcrm/filters/signals.py +94 -0
  22. wbcrm/migrations/0001_initial_squashed_squashed_0032_productcompanyrelationship_alter_product_prospects_and_more.py +3948 -0
  23. wbcrm/migrations/0002_alter_activity_repeat_choice.py +32 -0
  24. wbcrm/migrations/0003_remove_activity_external_id_and_more.py +63 -0
  25. wbcrm/migrations/0004_alter_activity_status.py +28 -0
  26. wbcrm/migrations/0005_account_accountrole_accountroletype_and_more.py +182 -0
  27. wbcrm/migrations/0006_alter_activity_location.py +17 -0
  28. wbcrm/migrations/0007_alter_account_status.py +23 -0
  29. wbcrm/migrations/0008_alter_activity_options.py +16 -0
  30. wbcrm/migrations/0009_alter_account_is_public.py +19 -0
  31. wbcrm/migrations/0010_alter_account_reference_id.py +17 -0
  32. wbcrm/migrations/0011_activity_summary.py +22 -0
  33. wbcrm/migrations/0012_alter_activity_summary.py +17 -0
  34. wbcrm/migrations/0013_account_action_plan_account_relationship_status_and_more.py +34 -0
  35. wbcrm/migrations/0014_alter_account_relationship_status.py +24 -0
  36. wbcrm/migrations/0015_alter_activity_type.py +23 -0
  37. wbcrm/migrations/0016_auto_20241205_1015.py +106 -0
  38. wbcrm/migrations/__init__.py +0 -0
  39. wbcrm/models/__init__.py +4 -0
  40. wbcrm/models/accounts.py +637 -0
  41. wbcrm/models/activities.py +1335 -0
  42. wbcrm/models/groups.py +118 -0
  43. wbcrm/models/products.py +83 -0
  44. wbcrm/models/recurrence.py +279 -0
  45. wbcrm/preferences.py +14 -0
  46. wbcrm/serializers/__init__.py +23 -0
  47. wbcrm/serializers/accounts.py +126 -0
  48. wbcrm/serializers/activities.py +526 -0
  49. wbcrm/serializers/groups.py +30 -0
  50. wbcrm/serializers/products.py +57 -0
  51. wbcrm/serializers/recurrence.py +90 -0
  52. wbcrm/serializers/signals.py +70 -0
  53. wbcrm/synchronization/__init__.py +0 -0
  54. wbcrm/synchronization/activity/__init__.py +0 -0
  55. wbcrm/synchronization/activity/admin.py +72 -0
  56. wbcrm/synchronization/activity/backend.py +207 -0
  57. wbcrm/synchronization/activity/backends/__init__.py +0 -0
  58. wbcrm/synchronization/activity/backends/google/__init__.py +2 -0
  59. wbcrm/synchronization/activity/backends/google/google_calendar_backend.py +399 -0
  60. wbcrm/synchronization/activity/backends/google/request_utils/__init__.py +16 -0
  61. wbcrm/synchronization/activity/backends/google/tasks.py +21 -0
  62. wbcrm/synchronization/activity/backends/google/tests/__init__.py +0 -0
  63. wbcrm/synchronization/activity/backends/google/tests/conftest.py +1 -0
  64. wbcrm/synchronization/activity/backends/google/tests/test_data.py +81 -0
  65. wbcrm/synchronization/activity/backends/google/tests/test_google_backend.py +319 -0
  66. wbcrm/synchronization/activity/backends/google/tests/test_utils.py +274 -0
  67. wbcrm/synchronization/activity/backends/google/typing_informations.py +139 -0
  68. wbcrm/synchronization/activity/backends/google/utils.py +216 -0
  69. wbcrm/synchronization/activity/backends/outlook/__init__.py +0 -0
  70. wbcrm/synchronization/activity/backends/outlook/backend.py +576 -0
  71. wbcrm/synchronization/activity/backends/outlook/msgraph.py +438 -0
  72. wbcrm/synchronization/activity/backends/outlook/parser.py +423 -0
  73. wbcrm/synchronization/activity/backends/outlook/tests/__init__.py +0 -0
  74. wbcrm/synchronization/activity/backends/outlook/tests/conftest.py +1 -0
  75. wbcrm/synchronization/activity/backends/outlook/tests/fixtures.py +606 -0
  76. wbcrm/synchronization/activity/backends/outlook/tests/test_admin.py +117 -0
  77. wbcrm/synchronization/activity/backends/outlook/tests/test_backend.py +269 -0
  78. wbcrm/synchronization/activity/backends/outlook/tests/test_controller.py +237 -0
  79. wbcrm/synchronization/activity/backends/outlook/tests/test_parser.py +173 -0
  80. wbcrm/synchronization/activity/controller.py +545 -0
  81. wbcrm/synchronization/activity/dynamic_preferences_registry.py +107 -0
  82. wbcrm/synchronization/activity/preferences.py +21 -0
  83. wbcrm/synchronization/activity/shortcuts.py +9 -0
  84. wbcrm/synchronization/activity/signals.py +28 -0
  85. wbcrm/synchronization/activity/tasks.py +21 -0
  86. wbcrm/synchronization/activity/urls.py +6 -0
  87. wbcrm/synchronization/activity/utils.py +46 -0
  88. wbcrm/synchronization/activity/views.py +37 -0
  89. wbcrm/synchronization/admin.py +1 -0
  90. wbcrm/synchronization/apps.py +15 -0
  91. wbcrm/synchronization/dynamic_preferences_registry.py +1 -0
  92. wbcrm/synchronization/management.py +36 -0
  93. wbcrm/synchronization/tasks.py +1 -0
  94. wbcrm/synchronization/urls.py +5 -0
  95. wbcrm/tasks.py +312 -0
  96. wbcrm/tests/__init__.py +0 -0
  97. wbcrm/tests/accounts/__init__.py +0 -0
  98. wbcrm/tests/accounts/test_models.py +380 -0
  99. wbcrm/tests/accounts/test_viewsets.py +87 -0
  100. wbcrm/tests/conftest.py +76 -0
  101. wbcrm/tests/disable_signals.py +52 -0
  102. wbcrm/tests/e2e/__init__.py +1 -0
  103. wbcrm/tests/e2e/e2e_wbcrm_utility.py +82 -0
  104. wbcrm/tests/e2e/test_e2e.py +369 -0
  105. wbcrm/tests/test_assignee_methods.py +39 -0
  106. wbcrm/tests/test_chartviewsets.py +111 -0
  107. wbcrm/tests/test_dto.py +63 -0
  108. wbcrm/tests/test_filters.py +51 -0
  109. wbcrm/tests/test_models.py +216 -0
  110. wbcrm/tests/test_recurrence.py +291 -0
  111. wbcrm/tests/test_report.py +20 -0
  112. wbcrm/tests/test_serializers.py +170 -0
  113. wbcrm/tests/test_tasks.py +94 -0
  114. wbcrm/tests/test_viewsets.py +967 -0
  115. wbcrm/tests/tests.py +120 -0
  116. wbcrm/typings.py +107 -0
  117. wbcrm/urls.py +67 -0
  118. wbcrm/viewsets/__init__.py +22 -0
  119. wbcrm/viewsets/accounts.py +121 -0
  120. wbcrm/viewsets/activities.py +315 -0
  121. wbcrm/viewsets/buttons/__init__.py +7 -0
  122. wbcrm/viewsets/buttons/accounts.py +27 -0
  123. wbcrm/viewsets/buttons/activities.py +68 -0
  124. wbcrm/viewsets/buttons/signals.py +17 -0
  125. wbcrm/viewsets/display/__init__.py +12 -0
  126. wbcrm/viewsets/display/accounts.py +110 -0
  127. wbcrm/viewsets/display/activities.py +443 -0
  128. wbcrm/viewsets/display/groups.py +22 -0
  129. wbcrm/viewsets/display/products.py +105 -0
  130. wbcrm/viewsets/endpoints/__init__.py +8 -0
  131. wbcrm/viewsets/endpoints/accounts.py +32 -0
  132. wbcrm/viewsets/endpoints/activities.py +30 -0
  133. wbcrm/viewsets/endpoints/groups.py +7 -0
  134. wbcrm/viewsets/endpoints/products.py +9 -0
  135. wbcrm/viewsets/groups.py +37 -0
  136. wbcrm/viewsets/menu/__init__.py +8 -0
  137. wbcrm/viewsets/menu/accounts.py +18 -0
  138. wbcrm/viewsets/menu/activities.py +61 -0
  139. wbcrm/viewsets/menu/groups.py +16 -0
  140. wbcrm/viewsets/menu/products.py +20 -0
  141. wbcrm/viewsets/mixins.py +34 -0
  142. wbcrm/viewsets/previews/__init__.py +1 -0
  143. wbcrm/viewsets/previews/activities.py +10 -0
  144. wbcrm/viewsets/products.py +56 -0
  145. wbcrm/viewsets/recurrence.py +26 -0
  146. wbcrm/viewsets/titles/__init__.py +13 -0
  147. wbcrm/viewsets/titles/accounts.py +22 -0
  148. wbcrm/viewsets/titles/activities.py +61 -0
  149. wbcrm/viewsets/titles/products.py +13 -0
  150. wbcrm/viewsets/titles/utils.py +46 -0
  151. wbcrm/workflows/__init__.py +1 -0
  152. wbcrm/workflows/assignee_methods.py +25 -0
  153. wbcrm-2.2.1.dist-info/METADATA +11 -0
  154. wbcrm-2.2.1.dist-info/RECORD +155 -0
  155. wbcrm-2.2.1.dist-info/WHEEL +5 -0
@@ -0,0 +1,37 @@
1
+ from rest_framework.decorators import action
2
+ from wbcore import viewsets
3
+ from wbcore.metadata.configs.display.instance_display.shortcuts import (
4
+ create_simple_display,
5
+ )
6
+ from wbcore.viewsets import RepresentationViewSet
7
+ from wbcrm.filters import GroupFilter
8
+ from wbcrm.models import Group
9
+ from wbcrm.serializers import GroupModelSerializer, GroupRepresentationSerializer
10
+ from wbcrm.viewsets.display import GroupModelDisplay
11
+ from wbcrm.viewsets.endpoints import GroupEndpointConfig
12
+
13
+
14
+ class GroupRepresentationViewSet(RepresentationViewSet):
15
+ queryset = Group.objects.all()
16
+ search_fields = ("title",)
17
+ serializer_class = GroupRepresentationSerializer
18
+
19
+
20
+ class GroupModelViewSet(viewsets.ModelViewSet):
21
+ LIST_DOCUMENTATION = "wbcrm/markdown/documentation/group.md"
22
+ IDENTIFIER = "wbcrm:group"
23
+ ordering = ("title",)
24
+ ordering_fields = ("title", "members")
25
+ search_fields = ("title",)
26
+ filterset_class = GroupFilter
27
+ queryset = Group.objects.all().prefetch_related("members")
28
+ serializer_class = GroupModelSerializer
29
+ display_config_class = GroupModelDisplay
30
+ endpoint_config_class = GroupEndpointConfig
31
+
32
+ @action(methods=["GET"], detail=True)
33
+ def pre_change(self, request, pk=None):
34
+ return viewsets.PreAction(
35
+ message="Do you really want to change this?",
36
+ instance_display=create_simple_display([["title"]]),
37
+ ).to_response()
@@ -0,0 +1,8 @@
1
+ from .accounts import ACCOUNT_MENUITEM
2
+ from .activities import (
3
+ ACTIVITY_MENUTITEM,
4
+ ACTIVITYCHART_MENUITEM,
5
+ ACTIVITYTYPE_MENUITEM,
6
+ )
7
+ from .groups import GROUPS_MENUITEM
8
+ from .products import PRODUCT_MENUITEM
@@ -0,0 +1,18 @@
1
+ from wbcore.menus import ItemPermission, MenuItem
2
+ from wbcore.permissions.shortcuts import is_internal_user
3
+
4
+ ACCOUNT_MENUITEM = MenuItem(
5
+ label="Accounts",
6
+ endpoint="wbcrm:account-list",
7
+ endpoint_get_parameters={"parent__isnull": True},
8
+ permission=ItemPermission(
9
+ method=lambda request: is_internal_user(request.user), permissions=["wbcrm.view_account"]
10
+ ),
11
+ add=MenuItem(
12
+ label="Create Account",
13
+ endpoint="wbcrm:account-list",
14
+ permission=ItemPermission(
15
+ method=lambda request: is_internal_user(request.user), permissions=["wbcrm.add_account"]
16
+ ),
17
+ ),
18
+ )
@@ -0,0 +1,61 @@
1
+ from datetime import timedelta
2
+
3
+ from django.utils import timezone
4
+ from django.utils.translation import gettext as _
5
+ from wbcore.menus import ItemPermission, MenuItem
6
+ from wbcore.permissions.shortcuts import is_internal_user
7
+
8
+
9
+ def default_activity_create_get_params(request) -> dict:
10
+ return {"participants": request.user.profile.id}
11
+
12
+
13
+ def default_activitychart_get_params(request) -> dict:
14
+ current_last_week_date_start = timezone.now().date() - timedelta(days=7)
15
+ current_next_week_date_end = timezone.now().date() + timedelta(days=7)
16
+
17
+ return {"period": f"{current_last_week_date_start:%Y-%m-%d},{current_next_week_date_end:%Y-%m-%d}"}
18
+
19
+
20
+ ACTIVITYTYPE_MENUITEM = MenuItem(
21
+ label=_("Activity Types"),
22
+ endpoint="wbcrm:activitytype-list",
23
+ permission=ItemPermission(
24
+ method=lambda request: is_internal_user(request.user),
25
+ permissions=["wbcrm.view_activitytype"],
26
+ ),
27
+ add=MenuItem(
28
+ label=_("Create Activity Type"),
29
+ endpoint="wbcrm:activitytype-list",
30
+ permission=ItemPermission(
31
+ method=lambda request: is_internal_user(request.user),
32
+ permissions=["wbcrm.add_activitytype"],
33
+ ),
34
+ ),
35
+ )
36
+
37
+
38
+ ACTIVITY_MENUTITEM = MenuItem(
39
+ label=_("Activities"),
40
+ endpoint="wbcrm:activity-list",
41
+ permission=ItemPermission(
42
+ method=lambda request: is_internal_user(request.user), permissions=["wbcrm.view_activity"]
43
+ ),
44
+ # endpoint_get_parameters={"only_recent": True}, # TODO confirm that this can actually be commented out
45
+ add=MenuItem(
46
+ label=_("Create Activity"),
47
+ endpoint="wbcrm:activity-list",
48
+ permission=ItemPermission(
49
+ method=lambda request: is_internal_user(request.user), permissions=["wbcrm.add_activity"]
50
+ ),
51
+ endpoint_get_parameters=default_activity_create_get_params,
52
+ ),
53
+ )
54
+ ACTIVITYCHART_MENUITEM = MenuItem(
55
+ label=_("Activity Chart"),
56
+ endpoint="wbcrm:activitychart-list",
57
+ permission=ItemPermission(
58
+ method=lambda request: is_internal_user(request.user), permissions=["wbcrm.view_activity"]
59
+ ),
60
+ endpoint_get_parameters=default_activitychart_get_params,
61
+ )
@@ -0,0 +1,16 @@
1
+ from django.utils.translation import gettext as _
2
+ from wbcore.menus import ItemPermission, MenuItem
3
+ from wbcore.permissions.shortcuts import is_internal_user
4
+
5
+ GROUPS_MENUITEM = MenuItem(
6
+ label=_("Groups"),
7
+ endpoint="wbcrm:group-list",
8
+ permission=ItemPermission(method=lambda request: is_internal_user(request.user), permissions=["wbcrm.view_group"]),
9
+ add=MenuItem(
10
+ label=_("Create Groups"),
11
+ endpoint="wbcrm:group-list",
12
+ permission=ItemPermission(
13
+ method=lambda request: is_internal_user(request.user), permissions=["wbcrm.add_group"]
14
+ ),
15
+ ),
16
+ )
@@ -0,0 +1,20 @@
1
+ from django.utils.translation import gettext as _
2
+ from wbcore.menus import ItemPermission, MenuItem
3
+ from wbcore.permissions.shortcuts import is_internal_user
4
+
5
+ PRODUCT_MENUITEM = MenuItem(
6
+ label=_("Products"),
7
+ endpoint="wbcrm:product-list",
8
+ permission=ItemPermission(
9
+ method=lambda request: is_internal_user(request.user),
10
+ permissions=["wbcrm.view_product"],
11
+ ),
12
+ add=MenuItem(
13
+ label=_("Create Product"),
14
+ endpoint="wbcrm:product-list",
15
+ permission=ItemPermission(
16
+ method=lambda request: is_internal_user(request.user),
17
+ permissions=["wbcrm.add_product"],
18
+ ),
19
+ ),
20
+ )
@@ -0,0 +1,34 @@
1
+ from datetime import date
2
+
3
+ from django.utils.functional import cached_property
4
+ from wbcrm.models.accounts import Account, AccountRole
5
+
6
+
7
+ class AccountPermissionMixin:
8
+ queryset = Account.objects.all()
9
+
10
+ @cached_property
11
+ def validity_date(self) -> date:
12
+ if validity_date_repr := self.request.GET.get("validity_date"):
13
+ return date.strftime(validity_date_repr, "%Y-%m-%d")
14
+ return date.today()
15
+
16
+ def get_queryset(self, *args, **kwargs):
17
+ return (
18
+ super().get_queryset(*args, **kwargs).filter_for_user(self.request.user, validity_date=self.validity_date)
19
+ )
20
+
21
+
22
+ class AccountRolePermissionMixin:
23
+ queryset = AccountRole.objects.all()
24
+
25
+ @cached_property
26
+ def validity_date(self) -> date:
27
+ if validity_date_repr := self.request.GET.get("validity_date"):
28
+ return date.strftime(validity_date_repr, "%Y-%m-%d")
29
+ return date.today()
30
+
31
+ def get_queryset(self, *args, **kwargs):
32
+ return (
33
+ super().get_queryset(*args, **kwargs).filter_for_user(self.request.user, validity_date=self.validity_date)
34
+ )
@@ -0,0 +1 @@
1
+ from .activities import ActivityPreviewConfig
@@ -0,0 +1,10 @@
1
+ from wbcore.metadata.configs.display.instance_display.shortcuts import (
2
+ Display,
3
+ create_simple_display,
4
+ )
5
+ from wbcore.metadata.configs.preview import PreviewViewConfig
6
+
7
+
8
+ class ActivityPreviewConfig(PreviewViewConfig):
9
+ def get_display(self) -> Display:
10
+ return create_simple_display([["title", "type", "result"]])
@@ -0,0 +1,56 @@
1
+ from django.db.models import F
2
+ from wbcore import viewsets
3
+ from wbcrm.filters.products import ProductCompanyFilterSet, ProductFilterSet
4
+ from wbcrm.models import Product, ProductCompanyRelationship
5
+ from wbcrm.serializers import (
6
+ ProductCompanyRelationshipModelSerializer,
7
+ ProductModelSerializer,
8
+ ProductRepresentationSerializer,
9
+ )
10
+ from wbcrm.viewsets.display import ProductCompanyRelationshipDisplay, ProductDisplay
11
+ from wbcrm.viewsets.endpoints import ProductCompanyRelationshipEndpointConfig
12
+ from wbcrm.viewsets.titles import ProductTitleConfig
13
+
14
+
15
+ class ProductModelViewSet(viewsets.ModelViewSet):
16
+ IDENTIFIER = "wbcrm:product"
17
+ LIST_DOCUMENTATION = "wbcrm/markdown/documentation/product.md"
18
+ queryset = Product.objects.all()
19
+ serializer_class = ProductModelSerializer
20
+ display_config_class = ProductDisplay
21
+ title_config_class = ProductTitleConfig
22
+ search_fields = ("title",)
23
+
24
+ filterset_class = ProductFilterSet
25
+ ordering_fields = ("title",)
26
+ ordering = ["title", "is_competitor"]
27
+
28
+
29
+ class ProductCompanyRelationshipCompanyModelViewSet(viewsets.ModelViewSet):
30
+ IDENTIFIER = "wbcrm:company-interestedproduct"
31
+ queryset = ProductCompanyRelationship.objects.all()
32
+ serializer_class = ProductCompanyRelationshipModelSerializer
33
+ display_config_class = ProductCompanyRelationshipDisplay
34
+ title_config_class = ProductTitleConfig
35
+ endpoint_config_class = ProductCompanyRelationshipEndpointConfig
36
+ search_fields = ("product__title",)
37
+ ordering_fields = ("product__title",)
38
+ ordering = ("product__title", "company__name")
39
+ filterset_class = ProductCompanyFilterSet
40
+
41
+ def get_queryset(self):
42
+ qs = (
43
+ super()
44
+ .get_queryset()
45
+ .filter(company=self.kwargs["company_id"])
46
+ .annotate(competitor_product=F("product__is_competitor"))
47
+ )
48
+ return qs
49
+
50
+
51
+ class ProductRepresentationViewSet(viewsets.RepresentationViewSet):
52
+ IDENTIFIER = "wbcrm:productrepresentation"
53
+ serializer_class = ProductRepresentationSerializer
54
+ search_fields = ("title",)
55
+ queryset = Product.objects.all()
56
+ ordering = ("title", "is_competitor")
@@ -0,0 +1,26 @@
1
+ from django.contrib.messages import warning
2
+ from django.shortcuts import get_object_or_404
3
+ from django.utils.translation import gettext as _
4
+ from rest_framework import permissions
5
+ from rest_framework.decorators import action
6
+ from rest_framework.response import Response
7
+ from wbcrm.models.recurrence import Recurrence
8
+
9
+
10
+ class RecurrenceModelViewSetMixin:
11
+ @action(detail=True, methods=["DELETE"], permission_classes=[permissions.IsAuthenticated])
12
+ def delete_next_occurrences(self, request, pk=None):
13
+ instance = get_object_or_404(self.queryset.model, pk=pk)
14
+ instance.forward_deletion()
15
+ return Response({})
16
+
17
+ def add_messages(self, request, instance=None, **kwargs):
18
+ if instance:
19
+ # If true, this activity is recurring.
20
+ if instance.is_recurrent:
21
+ warning(
22
+ request,
23
+ _("This is a recurring occurrence with period {repeat_choice}").format(
24
+ repeat_choice=Recurrence.ReoccuranceChoice(instance.repeat_choice).label
25
+ ),
26
+ )
@@ -0,0 +1,13 @@
1
+ from wbcrm.viewsets.titles.activities import (
2
+ ActivityChartModelTitleConfig,
3
+ ActivityParticipantTitleConfig,
4
+ ActivityTitleConfig,
5
+ ActivityTypeTitleConfig,
6
+ )
7
+
8
+ from .accounts import (
9
+ AccountRoleAccountTitleConfig,
10
+ AccountTitleConfig,
11
+ ChildAccountAccountTitleConfig,
12
+ )
13
+ from .products import ProductTitleConfig
@@ -0,0 +1,22 @@
1
+ from wbcore.metadata.configs.titles import TitleViewConfig
2
+ from wbcrm.models.accounts import Account
3
+
4
+
5
+ class AccountTitleConfig(TitleViewConfig):
6
+ def get_instance_title(self):
7
+ return "Account: {{title}}"
8
+
9
+ def get_list_title(self):
10
+ return "Accounts"
11
+
12
+
13
+ class ChildAccountAccountTitleConfig(TitleViewConfig):
14
+ def get_list_title(self):
15
+ account = Account.objects.get(id=self.view.kwargs["account_id"])
16
+ return f"{account.title}: Sub Accounts"
17
+
18
+
19
+ class AccountRoleAccountTitleConfig(TitleViewConfig):
20
+ def get_list_title(self):
21
+ account = Account.objects.get(id=self.view.kwargs["account_id"])
22
+ return f"Roles for Account {str(account)}"
@@ -0,0 +1,61 @@
1
+ from django.utils.translation import gettext as _
2
+ from wbcore.metadata.configs.titles import TitleViewConfig
3
+
4
+
5
+ class ActivityTypeTitleConfig(TitleViewConfig):
6
+ def get_list_title(self):
7
+ return _("Activity Types")
8
+
9
+ def get_create_title(self):
10
+ return _("New Activity Type")
11
+
12
+ def get_instance_title(self):
13
+ return _("Activity Type")
14
+
15
+
16
+ class ActivityTitleConfig(TitleViewConfig):
17
+ def get_instance_title(self):
18
+ if "pk" in self.view.kwargs:
19
+ if self.view.is_private_for_user:
20
+ return _("Private Activity")
21
+
22
+ elif self.view.is_confidential_for_user:
23
+ return _("Confidential Activity")
24
+
25
+ return _("Activity: {{title}}")
26
+
27
+ def get_delete_title(self):
28
+ if "pk" in self.view.kwargs:
29
+ if self.view.is_private_for_user:
30
+ return _("Delete Private Activity")
31
+
32
+ elif self.view.is_confidential_for_user:
33
+ return _("Delete Confidential Activity")
34
+
35
+ return _("Delete Activity: {{title}}")
36
+
37
+ def get_list_title(self):
38
+ if self.view.participants.exists():
39
+ if self.view.participants.count() == 1:
40
+ return _("Activities for {person}").format(person=str(self.view.participants.first()))
41
+ else:
42
+ return _("Activities for Multiple Persons")
43
+
44
+ if self.view.companies.exists():
45
+ return _("Activities for {}").format(", ".join(self.view.companies.values_list("name", flat=True)))
46
+ return _("Activities")
47
+
48
+ def get_create_title(self):
49
+ if self.view.entry:
50
+ return _("New Activity for {entry}").format(entry=self.view.entry.computed_str)
51
+ return _("New Activity")
52
+
53
+
54
+ class ActivityParticipantTitleConfig(TitleViewConfig):
55
+ def get_instance_title(self):
56
+ return _("Participation Status")
57
+
58
+
59
+ class ActivityChartModelTitleConfig(TitleViewConfig):
60
+ def get_list_title(self):
61
+ return _("Activity Chart")
@@ -0,0 +1,13 @@
1
+ from django.utils.translation import gettext as _
2
+ from wbcore.metadata.configs.titles import TitleViewConfig
3
+
4
+
5
+ class ProductTitleConfig(TitleViewConfig):
6
+ def get_list_title(self):
7
+ return _("Products")
8
+
9
+ def get_create_title(self):
10
+ return _("Add Product")
11
+
12
+ def get_instance_title(self):
13
+ return _("Product")
@@ -0,0 +1,46 @@
1
+ from django.utils.translation import gettext as _
2
+ from wbcore.metadata.configs.titles import TitleViewConfig
3
+
4
+
5
+ class CustomerStatusTitleConfig(TitleViewConfig):
6
+ def get_list_title(self):
7
+ return _("Customer Statuses")
8
+
9
+ def get_create_title(self):
10
+ return _("New Customer Status")
11
+
12
+ def get_instance_title(self):
13
+ return _("Customer Status")
14
+
15
+
16
+ class PositionTitleConfig(TitleViewConfig):
17
+ def get_list_title(self):
18
+ return _("Company Positions")
19
+
20
+ def get_create_title(self):
21
+ return _("New Company Position")
22
+
23
+ def get_instance_title(self):
24
+ return _("Company Position")
25
+
26
+
27
+ class CompanyTypeTitleConfig(TitleViewConfig):
28
+ def get_list_title(self):
29
+ return _("Company Types")
30
+
31
+ def get_create_title(self):
32
+ return _("New Company Type")
33
+
34
+ def get_instance_title(self):
35
+ return _("Company Type")
36
+
37
+
38
+ class SpecializationTitleConfig(TitleViewConfig):
39
+ def get_list_title(self):
40
+ return _("Specializations")
41
+
42
+ def get_create_title(self):
43
+ return _("New Specialization")
44
+
45
+ def get_instance_title(self):
46
+ return _("Specialization")
@@ -0,0 +1 @@
1
+ from .assignee_methods import *
@@ -0,0 +1,25 @@
1
+ from django.utils.translation import gettext as _
2
+ from wbcore.contrib.authentication.models import User
3
+ from wbcore.contrib.directory.models import Person
4
+ from wbcore.contrib.workflow.decorators import register_assignee
5
+ from wbcore.contrib.workflow.models import ProcessStep
6
+
7
+ # We need to migrate upon name changes!
8
+
9
+
10
+ # TODO: Generalize this through field filter
11
+ @register_assignee("Activity Assignee")
12
+ def activity_assignee(process_step: ProcessStep, **kwargs) -> User | None:
13
+ if hasattr(process_step.process.instance, "assigned_to"):
14
+ assignee: Person = getattr(process_step.process.instance, "assigned_to")
15
+ if hasattr(assignee, "user_account"):
16
+ return assignee.user_account
17
+ else:
18
+ error_message = _("Assignee has no user account!")
19
+ else:
20
+ error_message = _("No activity attached!")
21
+
22
+ process_step.step.get_casted_step().set_failed(
23
+ process_step, _("Error in assignee method: {}").format(error_message)
24
+ )
25
+ return None
@@ -0,0 +1,11 @@
1
+ Metadata-Version: 2.3
2
+ Name: wbcrm
3
+ Version: 2.2.1
4
+ Summary: A workbench module that contains all the functionality related to a customer relationship management.
5
+ Author-email: Christopher Wittlinger <c.wittlinger@stainly.com>
6
+ Requires-Dist: django-eventtools==1.*
7
+ Requires-Dist: google-api-python-client==2.62.*
8
+ Requires-Dist: google-auth-httplib2==0.1.*
9
+ Requires-Dist: google-auth-oauthlib==0.5.*
10
+ Requires-Dist: wbcore
11
+ Requires-Dist: xlsxwriter==3.*