wbcrm 1.56.8__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 (182) hide show
  1. wbcrm/__init__.py +1 -0
  2. wbcrm/admin/__init__.py +5 -0
  3. wbcrm/admin/accounts.py +60 -0
  4. wbcrm/admin/activities.py +104 -0
  5. wbcrm/admin/events.py +43 -0
  6. wbcrm/admin/groups.py +8 -0
  7. wbcrm/admin/products.py +9 -0
  8. wbcrm/apps.py +5 -0
  9. wbcrm/configurations/__init__.py +1 -0
  10. wbcrm/configurations/base.py +16 -0
  11. wbcrm/dynamic_preferences_registry.py +38 -0
  12. wbcrm/factories/__init__.py +14 -0
  13. wbcrm/factories/accounts.py +57 -0
  14. wbcrm/factories/activities.py +124 -0
  15. wbcrm/factories/groups.py +24 -0
  16. wbcrm/factories/products.py +11 -0
  17. wbcrm/filters/__init__.py +10 -0
  18. wbcrm/filters/accounts.py +80 -0
  19. wbcrm/filters/activities.py +204 -0
  20. wbcrm/filters/groups.py +21 -0
  21. wbcrm/filters/products.py +38 -0
  22. wbcrm/filters/signals.py +95 -0
  23. wbcrm/fixtures/wbcrm.json +1215 -0
  24. wbcrm/kpi_handlers/activities.py +171 -0
  25. wbcrm/locale/de/LC_MESSAGES/django.mo +0 -0
  26. wbcrm/locale/de/LC_MESSAGES/django.po +1557 -0
  27. wbcrm/locale/de/LC_MESSAGES/django.po.translated +1630 -0
  28. wbcrm/locale/en/LC_MESSAGES/django.mo +0 -0
  29. wbcrm/locale/en/LC_MESSAGES/django.po +1466 -0
  30. wbcrm/locale/fr/LC_MESSAGES/django.mo +0 -0
  31. wbcrm/locale/fr/LC_MESSAGES/django.po +1467 -0
  32. wbcrm/migrations/0001_initial_squashed_squashed_0032_productcompanyrelationship_alter_product_prospects_and_more.py +3948 -0
  33. wbcrm/migrations/0002_alter_activity_repeat_choice.py +32 -0
  34. wbcrm/migrations/0003_remove_activity_external_id_and_more.py +63 -0
  35. wbcrm/migrations/0004_alter_activity_status.py +28 -0
  36. wbcrm/migrations/0005_account_accountrole_accountroletype_and_more.py +182 -0
  37. wbcrm/migrations/0006_alter_activity_location.py +17 -0
  38. wbcrm/migrations/0007_alter_account_status.py +23 -0
  39. wbcrm/migrations/0008_alter_activity_options.py +16 -0
  40. wbcrm/migrations/0009_alter_account_is_public.py +19 -0
  41. wbcrm/migrations/0010_alter_account_reference_id.py +17 -0
  42. wbcrm/migrations/0011_activity_summary.py +22 -0
  43. wbcrm/migrations/0012_alter_activity_summary.py +17 -0
  44. wbcrm/migrations/0013_account_action_plan_account_relationship_status_and_more.py +34 -0
  45. wbcrm/migrations/0014_alter_account_relationship_status.py +24 -0
  46. wbcrm/migrations/0015_alter_activity_type.py +23 -0
  47. wbcrm/migrations/0016_auto_20241205_1015.py +106 -0
  48. wbcrm/migrations/0017_event.py +40 -0
  49. wbcrm/migrations/0018_activity_search_vector.py +24 -0
  50. wbcrm/migrations/__init__.py +0 -0
  51. wbcrm/models/__init__.py +5 -0
  52. wbcrm/models/accounts.py +648 -0
  53. wbcrm/models/activities.py +1419 -0
  54. wbcrm/models/events.py +15 -0
  55. wbcrm/models/groups.py +119 -0
  56. wbcrm/models/llm/activity_summaries.py +41 -0
  57. wbcrm/models/llm/analyze_relationship.py +50 -0
  58. wbcrm/models/products.py +86 -0
  59. wbcrm/models/recurrence.py +280 -0
  60. wbcrm/preferences.py +13 -0
  61. wbcrm/report/activity_report.py +110 -0
  62. wbcrm/serializers/__init__.py +23 -0
  63. wbcrm/serializers/accounts.py +141 -0
  64. wbcrm/serializers/activities.py +525 -0
  65. wbcrm/serializers/groups.py +30 -0
  66. wbcrm/serializers/products.py +58 -0
  67. wbcrm/serializers/recurrence.py +91 -0
  68. wbcrm/serializers/signals.py +71 -0
  69. wbcrm/static/wbcrm/markdown/documentation/activity.md +86 -0
  70. wbcrm/static/wbcrm/markdown/documentation/activitytype.md +20 -0
  71. wbcrm/static/wbcrm/markdown/documentation/group.md +2 -0
  72. wbcrm/static/wbcrm/markdown/documentation/product.md +11 -0
  73. wbcrm/synchronization/__init__.py +0 -0
  74. wbcrm/synchronization/activity/__init__.py +0 -0
  75. wbcrm/synchronization/activity/admin.py +73 -0
  76. wbcrm/synchronization/activity/backend.py +214 -0
  77. wbcrm/synchronization/activity/backends/__init__.py +0 -0
  78. wbcrm/synchronization/activity/backends/google/__init__.py +2 -0
  79. wbcrm/synchronization/activity/backends/google/google_calendar_backend.py +406 -0
  80. wbcrm/synchronization/activity/backends/google/request_utils/__init__.py +16 -0
  81. wbcrm/synchronization/activity/backends/google/request_utils/external_to_internal/create.py +75 -0
  82. wbcrm/synchronization/activity/backends/google/request_utils/external_to_internal/delete.py +78 -0
  83. wbcrm/synchronization/activity/backends/google/request_utils/external_to_internal/update.py +155 -0
  84. wbcrm/synchronization/activity/backends/google/request_utils/internal_to_external/update.py +181 -0
  85. wbcrm/synchronization/activity/backends/google/tasks.py +21 -0
  86. wbcrm/synchronization/activity/backends/google/tests/__init__.py +0 -0
  87. wbcrm/synchronization/activity/backends/google/tests/conftest.py +1 -0
  88. wbcrm/synchronization/activity/backends/google/tests/test_data.py +81 -0
  89. wbcrm/synchronization/activity/backends/google/tests/test_google_backend.py +319 -0
  90. wbcrm/synchronization/activity/backends/google/tests/test_utils.py +274 -0
  91. wbcrm/synchronization/activity/backends/google/typing_informations.py +139 -0
  92. wbcrm/synchronization/activity/backends/google/utils.py +217 -0
  93. wbcrm/synchronization/activity/backends/outlook/__init__.py +0 -0
  94. wbcrm/synchronization/activity/backends/outlook/backend.py +593 -0
  95. wbcrm/synchronization/activity/backends/outlook/msgraph.py +436 -0
  96. wbcrm/synchronization/activity/backends/outlook/parser.py +432 -0
  97. wbcrm/synchronization/activity/backends/outlook/tests/__init__.py +0 -0
  98. wbcrm/synchronization/activity/backends/outlook/tests/conftest.py +1 -0
  99. wbcrm/synchronization/activity/backends/outlook/tests/fixtures.py +606 -0
  100. wbcrm/synchronization/activity/backends/outlook/tests/test_admin.py +118 -0
  101. wbcrm/synchronization/activity/backends/outlook/tests/test_backend.py +274 -0
  102. wbcrm/synchronization/activity/backends/outlook/tests/test_controller.py +249 -0
  103. wbcrm/synchronization/activity/backends/outlook/tests/test_parser.py +174 -0
  104. wbcrm/synchronization/activity/controller.py +627 -0
  105. wbcrm/synchronization/activity/dynamic_preferences_registry.py +119 -0
  106. wbcrm/synchronization/activity/preferences.py +27 -0
  107. wbcrm/synchronization/activity/shortcuts.py +16 -0
  108. wbcrm/synchronization/activity/tasks.py +21 -0
  109. wbcrm/synchronization/activity/urls.py +7 -0
  110. wbcrm/synchronization/activity/utils.py +46 -0
  111. wbcrm/synchronization/activity/views.py +41 -0
  112. wbcrm/synchronization/admin.py +1 -0
  113. wbcrm/synchronization/apps.py +14 -0
  114. wbcrm/synchronization/dynamic_preferences_registry.py +1 -0
  115. wbcrm/synchronization/management.py +36 -0
  116. wbcrm/synchronization/tasks.py +1 -0
  117. wbcrm/synchronization/urls.py +5 -0
  118. wbcrm/tasks.py +264 -0
  119. wbcrm/templates/email/activity.html +98 -0
  120. wbcrm/templates/email/activity_report.html +6 -0
  121. wbcrm/templates/email/daily_summary.html +72 -0
  122. wbcrm/templates/email/global_daily_summary.html +85 -0
  123. wbcrm/tests/__init__.py +0 -0
  124. wbcrm/tests/accounts/__init__.py +0 -0
  125. wbcrm/tests/accounts/test_models.py +393 -0
  126. wbcrm/tests/accounts/test_viewsets.py +88 -0
  127. wbcrm/tests/conftest.py +76 -0
  128. wbcrm/tests/disable_signals.py +62 -0
  129. wbcrm/tests/e2e/__init__.py +1 -0
  130. wbcrm/tests/e2e/e2e_wbcrm_utility.py +83 -0
  131. wbcrm/tests/e2e/test_e2e.py +370 -0
  132. wbcrm/tests/test_assignee_methods.py +40 -0
  133. wbcrm/tests/test_chartviewsets.py +112 -0
  134. wbcrm/tests/test_dto.py +64 -0
  135. wbcrm/tests/test_filters.py +52 -0
  136. wbcrm/tests/test_models.py +217 -0
  137. wbcrm/tests/test_recurrence.py +292 -0
  138. wbcrm/tests/test_report.py +21 -0
  139. wbcrm/tests/test_serializers.py +171 -0
  140. wbcrm/tests/test_tasks.py +95 -0
  141. wbcrm/tests/test_viewsets.py +967 -0
  142. wbcrm/tests/tests.py +121 -0
  143. wbcrm/typings.py +109 -0
  144. wbcrm/urls.py +67 -0
  145. wbcrm/viewsets/__init__.py +22 -0
  146. wbcrm/viewsets/accounts.py +122 -0
  147. wbcrm/viewsets/activities.py +341 -0
  148. wbcrm/viewsets/buttons/__init__.py +7 -0
  149. wbcrm/viewsets/buttons/accounts.py +27 -0
  150. wbcrm/viewsets/buttons/activities.py +89 -0
  151. wbcrm/viewsets/buttons/signals.py +17 -0
  152. wbcrm/viewsets/display/__init__.py +12 -0
  153. wbcrm/viewsets/display/accounts.py +110 -0
  154. wbcrm/viewsets/display/activities.py +444 -0
  155. wbcrm/viewsets/display/groups.py +22 -0
  156. wbcrm/viewsets/display/products.py +105 -0
  157. wbcrm/viewsets/endpoints/__init__.py +8 -0
  158. wbcrm/viewsets/endpoints/accounts.py +25 -0
  159. wbcrm/viewsets/endpoints/activities.py +30 -0
  160. wbcrm/viewsets/endpoints/groups.py +7 -0
  161. wbcrm/viewsets/endpoints/products.py +9 -0
  162. wbcrm/viewsets/groups.py +38 -0
  163. wbcrm/viewsets/menu/__init__.py +8 -0
  164. wbcrm/viewsets/menu/accounts.py +18 -0
  165. wbcrm/viewsets/menu/activities.py +49 -0
  166. wbcrm/viewsets/menu/groups.py +16 -0
  167. wbcrm/viewsets/menu/products.py +20 -0
  168. wbcrm/viewsets/mixins.py +35 -0
  169. wbcrm/viewsets/previews/__init__.py +1 -0
  170. wbcrm/viewsets/previews/activities.py +10 -0
  171. wbcrm/viewsets/products.py +57 -0
  172. wbcrm/viewsets/recurrence.py +27 -0
  173. wbcrm/viewsets/titles/__init__.py +13 -0
  174. wbcrm/viewsets/titles/accounts.py +23 -0
  175. wbcrm/viewsets/titles/activities.py +61 -0
  176. wbcrm/viewsets/titles/products.py +13 -0
  177. wbcrm/viewsets/titles/utils.py +46 -0
  178. wbcrm/workflows/__init__.py +1 -0
  179. wbcrm/workflows/assignee_methods.py +25 -0
  180. wbcrm-1.56.8.dist-info/METADATA +11 -0
  181. wbcrm-1.56.8.dist-info/RECORD +182 -0
  182. wbcrm-1.56.8.dist-info/WHEEL +5 -0
wbcrm/__init__.py ADDED
@@ -0,0 +1 @@
1
+ __version__ = "1.0.0"
@@ -0,0 +1,5 @@
1
+ from .accounts import AccountRoleModelAdmin, AccountModelAdmin
2
+ from .activities import ActivityAdmin, ActivityTypeAdmin
3
+ from .groups import GroupModelAdmin
4
+ from .products import ProductAdmin
5
+ from .events import EventModelAdmin
@@ -0,0 +1,60 @@
1
+ from django.contrib import admin
2
+ from mptt.admin import MPTTModelAdmin
3
+
4
+ from wbcrm.models.accounts import (
5
+ Account,
6
+ AccountRole,
7
+ AccountRoleType,
8
+ AccountRoleValidity,
9
+ )
10
+
11
+
12
+ class AccountRoleValidityTabularInline(admin.TabularInline):
13
+ model = AccountRoleValidity
14
+ fields = ("timespan",)
15
+ extra = 0
16
+
17
+
18
+ class AccountRoleTabularInline(admin.TabularInline):
19
+ model = AccountRole
20
+ fields = ("role_type", "entry", "weighting", "is_hidden")
21
+ autocomplete_fields = ["entry", "account"]
22
+ extra = 0
23
+ show_change_link = True
24
+
25
+
26
+ class AccountTabularInline(admin.TabularInline):
27
+ model = Account
28
+ fields = ("title", "status", "owner", "is_terminal_account", "is_active", "is_public")
29
+ autocomplete_fields = ["owner", "parent"]
30
+ fk_name = "parent"
31
+ show_change_link = True
32
+ extra = 0
33
+
34
+
35
+ @admin.register(AccountRoleType)
36
+ class AccountRoleTypeModelAdmin(admin.ModelAdmin):
37
+ list_display = ("title", "key")
38
+ search_fields = ("title", "key")
39
+
40
+
41
+ @admin.register(AccountRole)
42
+ class AccountRoleModelAdmin(admin.ModelAdmin):
43
+ list_display = ("role_type", "entry", "account", "is_hidden")
44
+ inlines = [AccountRoleValidityTabularInline]
45
+
46
+ def get_queryset(self, request):
47
+ return super().get_queryset(request).select_related("entry", "account")
48
+
49
+
50
+ @admin.register(Account)
51
+ class AccountModelAdmin(MPTTModelAdmin):
52
+ mptt_level_indent = 20
53
+ fsm_field = ["status"]
54
+ search_fields = ["title"]
55
+ list_display = ["computed_str", "status", "is_active", "is_terminal_account", "is_public", "owner"]
56
+ inlines = [AccountRoleTabularInline, AccountTabularInline]
57
+ autocomplete_fields = ["owner", "parent"]
58
+
59
+ def get_queryset(self, request):
60
+ return Account.all_objects.select_related("owner", "parent")
@@ -0,0 +1,104 @@
1
+ from django.contrib import admin
2
+ from django.utils.translation import gettext_lazy as _
3
+ from reversion.admin import VersionAdmin
4
+
5
+ from wbcrm.models import Activity, ActivityParticipant, ActivityType
6
+ from wbcrm.models.activities import ActivityCompanyThroughModel
7
+
8
+
9
+ class ParticipantInline(admin.TabularInline):
10
+ model = ActivityParticipant
11
+
12
+
13
+ class CompanyInline(admin.TabularInline):
14
+ model = ActivityCompanyThroughModel
15
+
16
+
17
+ @admin.register(ActivityType)
18
+ class ActivityTypeAdmin(admin.ModelAdmin):
19
+ search_fields = ("title",)
20
+ list_display = ("id", "title")
21
+
22
+
23
+ class ActivityInline(admin.StackedInline):
24
+ model = Activity
25
+ fk_name = "parent_occurrence"
26
+ extra = 0
27
+ fieldsets = (
28
+ (
29
+ _("Main information"),
30
+ {
31
+ "fields": (
32
+ "title",
33
+ "description",
34
+ )
35
+ },
36
+ ),
37
+ )
38
+
39
+
40
+ @admin.register(Activity)
41
+ class ActivityAdmin(VersionAdmin):
42
+ search_fields = ("title",)
43
+ list_display = ("id", "status", "title", "period", "is_active", "parent_occurrence_id", "metadata")
44
+ fieldsets = (
45
+ (_("Main information"), {"fields": ("title", "description", "result", "creator")}),
46
+ (_("Meta"), {"fields": ("status", "type", "visibility", "is_active", "metadata")}),
47
+ (_("Temporal Information"), {"fields": ("period", "all_day")}),
48
+ (_("Geographical Information"), {"fields": ("location", "location_longitude", "location_latitude")}),
49
+ (_("Linked Entries"), {"fields": ("assigned_to", "groups")}),
50
+ (_("Linked Activities"), {"fields": ("preceded_by",)}),
51
+ (_("LLM"), {"fields": ("heat", "summary")}),
52
+ (
53
+ _("Recurrence"),
54
+ {
55
+ "fields": (
56
+ "repeat_choice",
57
+ "parent_occurrence",
58
+ ("recurrence_count", "recurrence_end"),
59
+ "propagate_for_all_children",
60
+ )
61
+ },
62
+ ),
63
+ )
64
+
65
+ raw_id_fields = (
66
+ "assigned_to",
67
+ "participants",
68
+ "groups",
69
+ "preceded_by",
70
+ "creator",
71
+ "latest_reviewer",
72
+ "parent_occurrence",
73
+ )
74
+
75
+ inlines = [ActivityInline, ParticipantInline, CompanyInline]
76
+
77
+ def reversion_register(self, model, **options):
78
+ options = {
79
+ "exclude": (
80
+ "created",
81
+ "creator",
82
+ "edited",
83
+ ),
84
+ }
85
+ super().reversion_register(model, **options)
86
+
87
+ def get_queryset(self, request):
88
+ return Activity.all_objects.all()
89
+
90
+
91
+ @admin.register(ActivityParticipant)
92
+ class ActivityParticipantAdmin(VersionAdmin):
93
+ search_fields = ("activity", "participant")
94
+ list_display = ("id", "activity", "participant", "participation_status")
95
+
96
+ def reversion_register(self, model, **options):
97
+ options = {
98
+ "follow": (
99
+ "activity",
100
+ "participant",
101
+ "participation_status",
102
+ )
103
+ }
104
+ super().reversion_register(model, **options)
wbcrm/admin/events.py ADDED
@@ -0,0 +1,43 @@
1
+ from django.contrib import admin
2
+
3
+ from wbcrm.models.events import Event
4
+
5
+
6
+ @admin.register(Event)
7
+ class EventModelAdmin(admin.ModelAdmin):
8
+ list_display = (
9
+ "id",
10
+ "resource",
11
+ "change_type",
12
+ "subject",
13
+ "resource_uuid",
14
+ "action_type",
15
+ "action",
16
+ "created",
17
+ "updated",
18
+ )
19
+ search_fields = ("data", "result")
20
+
21
+ @staticmethod
22
+ def change_type(obj):
23
+ return obj.data.get("change_type", "")
24
+
25
+ @staticmethod
26
+ def resource(obj):
27
+ return obj.data.get("resource", "")
28
+
29
+ @staticmethod
30
+ def subject(obj):
31
+ return obj.data.get("subject", "")
32
+
33
+ @staticmethod
34
+ def resource_uuid(obj):
35
+ return obj.data.get("uid", "")
36
+
37
+ @staticmethod
38
+ def action_type(obj):
39
+ return obj.result.get("action_type", "")
40
+
41
+ @staticmethod
42
+ def action(obj):
43
+ return obj.result.get("action", "")
wbcrm/admin/groups.py ADDED
@@ -0,0 +1,8 @@
1
+ from django.contrib import admin
2
+
3
+ from wbcrm.models import Group
4
+
5
+
6
+ @admin.register(Group)
7
+ class GroupModelAdmin(admin.ModelAdmin):
8
+ autocomplete_fields = ("members",)
@@ -0,0 +1,9 @@
1
+ from django.contrib import admin
2
+
3
+ from wbcrm.models import Product
4
+
5
+
6
+ @admin.register(Product)
7
+ class ProductAdmin(admin.ModelAdmin):
8
+ search_fields = ("title",)
9
+ list_display = ("title", "id")
wbcrm/apps.py ADDED
@@ -0,0 +1,5 @@
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class WbcrmConfig(AppConfig):
5
+ name = "wbcrm"
@@ -0,0 +1 @@
1
+ from .base import CRMDevBaseConfiguration, CRMProductionBaseConfiguration
@@ -0,0 +1,16 @@
1
+ from configurations import values
2
+ from wbcore.configurations import DevBaseConfiguration, ProductionBaseConfiguration
3
+
4
+
5
+ class CRMDevBaseConfiguration(DevBaseConfiguration):
6
+ SECRET_KEY = values.Value("THIS-IS-NOT-A-SECRET-KEY", environ_prefix=None)
7
+ DEBUG = values.BooleanValue(True, environ_prefix=None)
8
+ DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
9
+ DISABLE_NOTIFICATION = values.BooleanValue(False, environ_prefix=None)
10
+ DEV_USER = values.Value(None, environ_prefix=None)
11
+ ADD_REVERSION_ADMIN = True
12
+ DEFAULT_CREATE_ENDPOINT_BASENAME = values.Value("wbcrm:activity-list", environ_prefix=None)
13
+
14
+
15
+ class CRMProductionBaseConfiguration(ProductionBaseConfiguration):
16
+ pass
@@ -0,0 +1,38 @@
1
+ from django.utils.translation import gettext as _
2
+ from dynamic_preferences.preferences import Section
3
+ from dynamic_preferences.registries import global_preferences_registry
4
+ from dynamic_preferences.types import BooleanPreference, IntegerPreference
5
+
6
+ general = Section("wbcrm")
7
+
8
+
9
+ @global_preferences_registry.register
10
+ class CheckForMandatoryParticipants(BooleanPreference):
11
+ section = general
12
+ name = "mandatory_participants"
13
+ default = True
14
+
15
+ verbose_name = _("Check for mandatory participants")
16
+ help_text = _(
17
+ 'Determines whether or not companies must be entered as participants in the "Companies" field for activities.'
18
+ )
19
+
20
+
21
+ @global_preferences_registry.register
22
+ class RecurrenceActivityEndDate(IntegerPreference):
23
+ section = general
24
+ name = "recurrence_maximum_allowed_days"
25
+ # this short default value, is just for the moment to test the process and until we know how to handle the recurring activities more efficient
26
+ default = 10 * 365
27
+
28
+ verbose_name = _("The default Maximum allowed days")
29
+
30
+
31
+ @global_preferences_registry.register
32
+ class RecurrenceActivityDateListLength(IntegerPreference):
33
+ section = general
34
+ name = "recurrence_maximum_count"
35
+ # this short default value, is just for the moment to test the process and until we know how to handle the recurring activities more efficient
36
+ default = 366
37
+
38
+ # verbose_name = _("For each date in the date list we create a child activity.number at which the date list will be cut.")
@@ -0,0 +1,14 @@
1
+ # from wbcore.contrib.currency.tests import factories
2
+
3
+ from .accounts import AccountFactory, AccountRoleFactory, AccountRoleTypeFactory, AccountWithOwnerFactory
4
+ from .activities import (
5
+ ActivityCompanyFactory,
6
+ ActivityFactory,
7
+ ActivityParticipantFactory,
8
+ ActivityPersonFactory,
9
+ ActivityTypeCALLFactory,
10
+ ActivityTypeFactory,
11
+ RecurringActivityFactory,
12
+ )
13
+ from .groups import GroupFactory
14
+ from .products import ProductFactory
@@ -0,0 +1,57 @@
1
+ import factory
2
+ from slugify import slugify
3
+
4
+ from wbcrm.models.accounts import Account, AccountRole, AccountRoleType
5
+
6
+
7
+ class AccountFactory(factory.django.DjangoModelFactory):
8
+ title = factory.Faker("company")
9
+ status = Account.Status.OPEN
10
+ # owner =
11
+ is_public = True
12
+ is_active = True
13
+ is_terminal_account = True
14
+
15
+ class Meta:
16
+ model = Account
17
+
18
+
19
+ class AccountWithOwnerFactory(AccountFactory):
20
+ owner = factory.SubFactory("wbcore.contrib.directory.factories.entries.EntryFactory")
21
+
22
+
23
+ class AccountRoleTypeFactory(factory.django.DjangoModelFactory):
24
+ title = factory.Faker("word")
25
+ key = factory.LazyAttribute(lambda o: slugify(o.title))
26
+
27
+ class Meta:
28
+ model = AccountRoleType
29
+ django_get_or_create = ["key"]
30
+
31
+
32
+ class AccountRoleFactory(factory.django.DjangoModelFactory):
33
+ role_type = factory.SubFactory("wbcrm.factories.AccountRoleTypeFactory")
34
+ entry = factory.SubFactory("wbcore.contrib.directory.factories.entries.EntryFactory")
35
+ account = factory.SubFactory("wbcrm.factories.AccountFactory", parent=None)
36
+ is_hidden = False
37
+
38
+ @factory.post_generation
39
+ def authorized_hidden_users(self, create, extracted, **kwargs):
40
+ if not create:
41
+ return
42
+
43
+ if extracted:
44
+ for user in extracted:
45
+ self.authorized_hidden_users.add(user)
46
+
47
+ @factory.post_generation
48
+ def visibility_daterange(self, create, extracted, **kwargs):
49
+ if not create:
50
+ return
51
+ if extracted:
52
+ v = self.validity_set.first()
53
+ v.timespan = extracted
54
+ v.save()
55
+
56
+ class Meta:
57
+ model = AccountRole
@@ -0,0 +1,124 @@
1
+ import datetime
2
+ import random
3
+
4
+ import factory
5
+ import pytz
6
+ from dynamic_preferences.registries import global_preferences_registry
7
+ from faker import Faker
8
+ from wbcore.contrib.authentication.factories import InternalUserFactory
9
+ from wbcore.contrib.directory.factories import CompanyFactory, PersonFactory
10
+
11
+ from wbcrm.models.activities import Activity, ActivityParticipant, ActivityType
12
+
13
+ fake = Faker()
14
+
15
+
16
+ class ActivityTypeFactory(factory.django.DjangoModelFactory):
17
+ title = factory.Faker("text", max_nb_chars=32)
18
+ color = factory.Faker("color")
19
+ score = factory.Iterator([ActivityType.Score.HIGH, ActivityType.Score.MEDIUM, ActivityType.Score.LOW])
20
+
21
+ class Meta:
22
+ model = ActivityType
23
+ django_get_or_create = ("title",)
24
+
25
+
26
+ class ActivityTypeCALLFactory(ActivityTypeFactory):
27
+ title = "Call"
28
+
29
+
30
+ class ActivityFactory(factory.django.DjangoModelFactory):
31
+ class Meta:
32
+ model = Activity
33
+
34
+ title = factory.Faker("text", max_nb_chars=64)
35
+ description = factory.Faker("paragraph", nb_sentences=5)
36
+ start = factory.LazyAttribute(lambda _: fake.date_time(tzinfo=pytz.utc))
37
+ end = factory.LazyAttribute(
38
+ lambda _self: _self.start + datetime.timedelta(days=fake.pyint(0, 100), hours=fake.pyint(1, 23))
39
+ )
40
+ disable_participant_check = True
41
+ location = factory.Faker("local_latlng")
42
+ location_longitude = factory.Faker("longitude")
43
+ location_latitude = factory.Faker("latitude")
44
+ created = factory.Faker("date_time", tzinfo=pytz.utc)
45
+ creator = factory.LazyAttribute(lambda _: InternalUserFactory.create().profile)
46
+ latest_reviewer = factory.SubFactory(PersonFactory)
47
+ reviewed_at = factory.Faker("date_time", tzinfo=pytz.utc)
48
+ edited = factory.Faker("date_time", tzinfo=pytz.utc)
49
+ assigned_to = factory.SubFactory(PersonFactory)
50
+ preceded_by = None
51
+ parent_occurrence = None
52
+ propagate_for_all_children = False
53
+ recurrence_end = None
54
+ recurrence_count = None
55
+ repeat_choice = Activity.ReoccuranceChoice.NEVER
56
+ type = factory.SubFactory(ActivityTypeFactory)
57
+ item_type = "wbcrm.Activity"
58
+
59
+ @factory.post_generation
60
+ def participants(self, create, extracted, **kwargs):
61
+ if not create:
62
+ return
63
+
64
+ if extracted:
65
+ for participant in extracted:
66
+ self.participants.add(participant)
67
+
68
+ @factory.post_generation
69
+ def companies(self, create, extracted, **kwargs):
70
+ if not create:
71
+ return
72
+
73
+ if extracted:
74
+ for company in extracted:
75
+ self.companies.add(company)
76
+
77
+ @factory.post_generation
78
+ def groups(self, create, extracted, **kwargs):
79
+ if not create:
80
+ return
81
+
82
+ if extracted:
83
+ for group in extracted:
84
+ self.groups.add(group)
85
+
86
+ @factory.post_generation
87
+ def entities(self, create, extracted, **kwargs):
88
+ if not create:
89
+ return
90
+
91
+ if extracted:
92
+ for entity in extracted:
93
+ self.entities.add(entity)
94
+
95
+
96
+ class RecurringActivityFactory(ActivityFactory):
97
+ repeat_choice = random.choice(list(filter(lambda x: x != "NEVER", Activity.ReoccuranceChoice.names)))
98
+ recurrence_count = 3
99
+
100
+
101
+ class ActivityCompanyFactory(ActivityFactory):
102
+ @factory.post_generation
103
+ def companies(self, create, extracted, **kwargs):
104
+ # Create company
105
+ company = CompanyFactory()
106
+ # Set global config main_company=company.id
107
+ global_preferences_registry.manager()["directory__main_company"] = company.id
108
+ self.companies.add(company)
109
+
110
+
111
+ class ActivityPersonFactory(ActivityFactory):
112
+ @factory.post_generation
113
+ def participants(self, create, extracted, **kwargs):
114
+ # Create person
115
+ person = PersonFactory()
116
+ self.participants.add(person)
117
+
118
+
119
+ class ActivityParticipantFactory(factory.django.DjangoModelFactory):
120
+ class Meta:
121
+ model = ActivityParticipant
122
+
123
+ participant = factory.SubFactory(PersonFactory)
124
+ activity = factory.SubFactory(ActivityFactory)
@@ -0,0 +1,24 @@
1
+ import random
2
+
3
+ import factory
4
+ from wbcore.contrib.directory.factories import EntryFactory
5
+
6
+ from wbcrm.models.groups import Group
7
+
8
+
9
+ class GroupFactory(factory.django.DjangoModelFactory):
10
+ class Meta:
11
+ model = Group
12
+
13
+ title = factory.Faker("text", max_nb_chars=64)
14
+
15
+ @factory.post_generation
16
+ def members(self, create, extracted, **kwargs):
17
+ if not create:
18
+ return
19
+ elif extracted:
20
+ for member in extracted:
21
+ self.members.add(member)
22
+ else:
23
+ for _ in range(1, random.randrange(2, 10)):
24
+ self.members.add(EntryFactory())
@@ -0,0 +1,11 @@
1
+ import factory
2
+
3
+ from wbcrm.models import Product
4
+
5
+
6
+ class ProductFactory(factory.django.DjangoModelFactory):
7
+ title = factory.Faker("text", max_nb_chars=32)
8
+ is_competitor = factory.Faker("pybool")
9
+
10
+ class Meta:
11
+ model = Product
@@ -0,0 +1,10 @@
1
+ from .accounts import AccountFilter, AccountRoleFilterSet
2
+ from .activities import (
3
+ ActivityChartFilter,
4
+ ActivityFilter,
5
+ ActivityParticipantFilter,
6
+ ActivityTypeFilter,
7
+ )
8
+ from .groups import GroupFilter
9
+ from .products import ProductCompanyFilterSet, ProductFilterSet
10
+ from .signals import *
@@ -0,0 +1,80 @@
1
+ from wbcore import filters as wb_filters
2
+ from wbcore.contrib.directory.models import Entry
3
+
4
+ from wbcrm.models.accounts import Account, AccountRole
5
+
6
+
7
+ class AccountFilter(wb_filters.FilterSet):
8
+ parent = wb_filters.ModelChoiceFilter(
9
+ label="Parent",
10
+ queryset=Account.objects.all(),
11
+ endpoint=Account.get_representation_endpoint(),
12
+ value_key=Account.get_representation_value_key(),
13
+ label_key=Account.get_representation_label_key(),
14
+ hidden=True,
15
+ )
16
+ parent__isnull = wb_filters.BooleanFilter(field_name="parent", lookup_expr="isnull", hidden=True)
17
+ customer = wb_filters.ModelChoiceFilter(
18
+ label="Customer",
19
+ queryset=Entry.objects.all(),
20
+ endpoint=Entry.get_representation_endpoint(),
21
+ value_key=Entry.get_representation_value_key(),
22
+ label_key=Entry.get_representation_label_key(),
23
+ method="filter_customer",
24
+ )
25
+
26
+ owner = wb_filters.ModelMultipleChoiceFilter(
27
+ label="Owner",
28
+ queryset=Entry.objects.all(),
29
+ endpoint=Entry.get_representation_endpoint(),
30
+ value_key=Entry.get_representation_value_key(),
31
+ label_key=Entry.get_representation_label_key(),
32
+ )
33
+
34
+ not_owner = wb_filters.ModelMultipleChoiceFilter(
35
+ column_field_name="owner",
36
+ lookup_icon="!=",
37
+ lookup_label="Not Equals",
38
+ queryset=Entry.objects.all(),
39
+ endpoint=Entry.get_representation_endpoint(),
40
+ value_key=Entry.get_representation_value_key(),
41
+ label_key=Entry.get_representation_label_key(),
42
+ method="filter_not_owner",
43
+ )
44
+
45
+ status = wb_filters.MultipleChoiceFilter(
46
+ choices=Account.Status.choices, label="Status", initial=[Account.Status.OPEN.value]
47
+ )
48
+
49
+ def filter_not_owner(self, queryset, name, value):
50
+ if value:
51
+ return queryset.exclude(owner__in=value)
52
+ return queryset
53
+
54
+ def filter_customer(self, queryset, name, value):
55
+ if value:
56
+ return queryset.filter(id__in=Account.get_accounts_for_customer(value))
57
+ return queryset
58
+
59
+ class Meta:
60
+ model = Account
61
+ fields = {
62
+ "reference_id": ["icontains"],
63
+ "is_active": ["exact"],
64
+ "parent": ["exact", "isnull"],
65
+ "is_terminal_account": ["exact"],
66
+ "is_public": ["exact"],
67
+ }
68
+
69
+
70
+ class AccountRoleFilterSet(wb_filters.FilterSet):
71
+ is_currently_valid = wb_filters.BooleanFilter(label="Valid", initial=True, field_name="is_currently_valid")
72
+
73
+ class Meta:
74
+ model = AccountRole
75
+ fields = {
76
+ "role_type": ["exact"],
77
+ "entry": ["exact"],
78
+ "is_hidden": ["exact"],
79
+ "authorized_hidden_users": ["exact"],
80
+ }