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,173 @@
1
+ from datetime import datetime
2
+
3
+ import pytest
4
+ from psycopg.types.range import TimestamptzRange
5
+ from wbcore.contrib.agenda.factories import ConferenceRoomFactory
6
+ from wbcrm.models.recurrence import Recurrence
7
+ from wbcrm.synchronization.activity.backends.outlook.parser import OutlookParser
8
+
9
+ from .fixtures import TestOutlookSyncFixture
10
+
11
+
12
+ @pytest.mark.django_db
13
+ class TestOutlookSyncParser(TestOutlookSyncFixture):
14
+ def test_convert_string_to_datetime(self, organizer_event_fixture_parsed):
15
+ start = OutlookParser.convert_string_to_datetime(
16
+ organizer_event_fixture_parsed["start.date_time"], organizer_event_fixture_parsed["start.time_zone"]
17
+ )
18
+ assert isinstance(start, datetime)
19
+
20
+ def test_convert_to_all_day_period(self, organizer_event_fixture_parsed):
21
+ start = OutlookParser.convert_string_to_datetime(
22
+ organizer_event_fixture_parsed["start.date_time"], organizer_event_fixture_parsed["start.time_zone"]
23
+ )
24
+ end = OutlookParser.convert_string_to_datetime(
25
+ organizer_event_fixture_parsed["end.date_time"], organizer_event_fixture_parsed["end.time_zone"]
26
+ )
27
+ period = OutlookParser.convert_to_all_day_period(TimestamptzRange(start, end))
28
+ assert period
29
+ assert isinstance(period, TimestamptzRange)
30
+
31
+ def test_deserialize_participants(self, organizer_event_fixture_parsed):
32
+ participants, conference_rooms = OutlookParser.deserialize_participants(organizer_event_fixture_parsed)
33
+ assert len(conference_rooms) == 0
34
+ assert len(participants) == len(organizer_event_fixture_parsed["attendees"]) + 1 # include the organizer
35
+
36
+ def test_deserialize_recurring_activities(
37
+ self, organizer_event_fixture_parsed, organizer_master_event_fixture_parsed
38
+ ):
39
+ assert OutlookParser.deserialize_recurring_activities(organizer_event_fixture_parsed) == {
40
+ "recurrence_count": 0,
41
+ "recurrence_end": None,
42
+ "repeat_choice": "NEVER",
43
+ }
44
+ assert OutlookParser.deserialize_recurring_activities(organizer_master_event_fixture_parsed) != {
45
+ "recurrence_count": 0,
46
+ "recurrence_end": None,
47
+ "repeat_choice": "NEVER",
48
+ }
49
+
50
+ def test_deserialize_person(self, organizer_event_fixture_parsed):
51
+ person_dto = OutlookParser.deserialize_person("test@test.ch", "test")
52
+ person_dto1 = OutlookParser.deserialize_person("test@test.ch", "first_name_test last_name_test")
53
+ person_dto2 = OutlookParser.deserialize_person(
54
+ organizer_event_fixture_parsed["organizer.email_address.address"],
55
+ organizer_event_fixture_parsed["organizer.email_address.name"],
56
+ )
57
+ assert person_dto.email == person_dto1.email == "test@test.ch"
58
+ assert person_dto2.email == organizer_event_fixture_parsed["organizer.email_address.address"]
59
+ assert person_dto.first_name == person_dto.last_name == "test"
60
+ assert person_dto1.first_name == "first_name_test"
61
+ assert person_dto1.last_name == "last_name_test"
62
+
63
+ @pytest.mark.parametrize(
64
+ "visibility, sensitivity",
65
+ [("PUBLIC", "normal"), ("PRIVATE", "private"), ("CONFIDENTIAL", "confidential"), ("PUBLIC", None)],
66
+ )
67
+ def test_convert_sensitivity_to_visibility(self, visibility, sensitivity):
68
+ assert OutlookParser.convert_sensitivity_to_visibility(sensitivity) == visibility
69
+
70
+ @pytest.mark.parametrize(
71
+ "visibility, sensitivity",
72
+ [("PUBLIC", "normal"), ("PRIVATE", "private"), ("CONFIDENTIAL", "confidential"), (None, "normal")],
73
+ )
74
+ def test_convert_visibility_to_sensitivity(self, visibility, sensitivity):
75
+ assert OutlookParser.convert_visibility_to_sensitivity(visibility) == sensitivity
76
+
77
+ @pytest.mark.parametrize(
78
+ "reminder_choice, reminder_minute",
79
+ [
80
+ ("NEVER", -1),
81
+ ("EVENT_TIME", 0),
82
+ ("MINUTES_5", 5),
83
+ ("MINUTES_15", 15),
84
+ ("MINUTES_30", 30),
85
+ ("HOURS_1", 60),
86
+ ("HOURS_2", 120),
87
+ ("HOURS_12", 720),
88
+ ("WEEKS_1", 10080),
89
+ ("MINUTES_15", None),
90
+ ],
91
+ )
92
+ def test_convert_reminder_minutes_to_choice(self, reminder_choice, reminder_minute):
93
+ assert OutlookParser.convert_reminder_minutes_to_choice(reminder_minute) == reminder_choice
94
+
95
+ @pytest.mark.parametrize(
96
+ "reminder_choice, reminder_minute",
97
+ [
98
+ ("NEVER", -1),
99
+ ("EVENT_TIME", 0),
100
+ ("MINUTES_5", 5),
101
+ ("MINUTES_15", 15),
102
+ ("MINUTES_30", 30),
103
+ ("HOURS_1", 60),
104
+ ("HOURS_2", 120),
105
+ ("HOURS_12", 720),
106
+ ("WEEKS_1", 10080),
107
+ ],
108
+ )
109
+ def test_convert_reminder_choice_to_minutes(self, reminder_choice, reminder_minute):
110
+ assert OutlookParser.convert_reminder_choice_to_minutes(reminder_choice) == reminder_minute
111
+
112
+ def test_serialize_person(self, person_factory):
113
+ person_dto = person_factory()._build_dto()
114
+ person_dict = OutlookParser.serialize_person(person_dto)
115
+ assert set(person_dict.keys()) == {"emailAddress"}
116
+ assert person_dict["emailAddress"]["address"] == person_dto.email
117
+ assert person_dict["emailAddress"]["name"] == f"{person_dto.first_name} {person_dto.last_name}"
118
+
119
+ @pytest.mark.parametrize(
120
+ "participant_status, attendee_status",
121
+ [
122
+ ("NOTRESPONDED", "notResponded"),
123
+ ("ATTENDS", "accepted"),
124
+ ("CANCELLED", "declined"),
125
+ ("MAYBE", "tentativelyAccepted"),
126
+ ("ATTENDS_DIGITALLY", "accepted"),
127
+ ],
128
+ )
129
+ def test_convert_participant_status_to_attendee_status(self, participant_status, attendee_status):
130
+ assert OutlookParser.convert_participant_status_to_attendee_status(participant_status) == attendee_status
131
+
132
+ @pytest.mark.parametrize(
133
+ "participant_status, attendee_status",
134
+ [
135
+ ("NOTRESPONDED", "notResponded"),
136
+ ("ATTENDS", "accepted"),
137
+ ("CANCELLED", "declined"),
138
+ ("MAYBE", "tentativelyAccepted"),
139
+ ("NOTRESPONDED", None),
140
+ ("ATTENDS", "organizer"),
141
+ ],
142
+ )
143
+ def test_convert_attendee_status_to_participant_status(self, participant_status, attendee_status):
144
+ assert OutlookParser.convert_attendee_status_to_participant_status(attendee_status) == participant_status
145
+
146
+ def test_serialize_participants(self, activity_factory, person_factory):
147
+ activity = activity_factory(preceded_by=None, participants=(person_factory(),))
148
+ activity_dto = activity._build_dto()
149
+ assert activity_dto.participants
150
+ attendees = OutlookParser.serialize_participants(activity_dto.participants)
151
+ assert attendees
152
+ assert attendees[0]
153
+
154
+ def test_serialize_conference_room(self):
155
+ cf_dto = ConferenceRoomFactory()._build_dto()
156
+ cf_dict = OutlookParser.serialize_conference_room(cf_dto)
157
+ assert set(cf_dict.keys()) == {"emailAddress", "type"}
158
+ assert cf_dict["type"] == "resource"
159
+ assert cf_dict["emailAddress"]["address"] == cf_dto.email
160
+ assert cf_dict["emailAddress"]["name"] == cf_dto.name
161
+
162
+ def test_serialize_recurring_activities(self, activity_factory):
163
+ act_dto0 = activity_factory()._build_dto()
164
+ act_dto = activity_factory(
165
+ repeat_choice=Recurrence.ReoccuranceChoice.DAILY, recurrence_count=3, preceded_by=None
166
+ )._build_dto()
167
+ reccurence_dict = OutlookParser.serialize_recurring_activities(act_dto)
168
+ assert OutlookParser.serialize_recurring_activities(act_dto0) == {}
169
+ assert set(reccurence_dict.keys()) == {"recurrence"}
170
+ assert reccurence_dict["recurrence"]["pattern"]["type"] == "daily"
171
+ assert reccurence_dict["recurrence"]["range"]["type"] == "numbered"
172
+ assert reccurence_dict["recurrence"]["range"]["numberOfOccurrences"] == 4
173
+ assert reccurence_dict["recurrence"]["range"]["startDate"] == act_dto.period.lower.strftime("%Y-%m-%d")