wbcrm 1.56.0__py2.py3-none-any.whl → 1.56.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.
Potentially problematic release.
This version of wbcrm might be problematic. Click here for more details.
- wbcrm/migrations/0018_activity_search_vector.py +24 -0
- wbcrm/models/activities.py +79 -4
- wbcrm/serializers/activities.py +1 -1
- wbcrm/signals.py +4 -0
- wbcrm/synchronization/activity/controller.py +0 -3
- wbcrm/synchronization/activity/shortcuts.py +6 -4
- wbcrm/tasks.py +22 -43
- wbcrm/viewsets/activities.py +2 -6
- {wbcrm-1.56.0.dist-info → wbcrm-1.56.2.dist-info}/METADATA +1 -1
- {wbcrm-1.56.0.dist-info → wbcrm-1.56.2.dist-info}/RECORD +11 -9
- {wbcrm-1.56.0.dist-info → wbcrm-1.56.2.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Generated by Django 5.0.12 on 2025-10-15 13:24
|
|
2
|
+
|
|
3
|
+
import django.contrib.postgres.search
|
|
4
|
+
import django.contrib.postgres.indexes
|
|
5
|
+
from django.db import migrations
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Migration(migrations.Migration):
|
|
9
|
+
|
|
10
|
+
dependencies = [
|
|
11
|
+
('wbcrm', '0017_event'),
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
operations = [
|
|
15
|
+
migrations.AddField(
|
|
16
|
+
model_name='activity',
|
|
17
|
+
name='search_vector',
|
|
18
|
+
field=django.contrib.postgres.search.SearchVectorField(null=True),
|
|
19
|
+
),
|
|
20
|
+
migrations.AddIndex(
|
|
21
|
+
model_name='activity',
|
|
22
|
+
index=django.contrib.postgres.indexes.GinIndex(fields=['search_vector'], name='activity_sv_gin_idx'),
|
|
23
|
+
),
|
|
24
|
+
]
|
wbcrm/models/activities.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import zoneinfo
|
|
2
2
|
from contextlib import suppress
|
|
3
|
-
from datetime import date, datetime, timedelta
|
|
3
|
+
from datetime import date, datetime, time, timedelta
|
|
4
4
|
from typing import Any
|
|
5
5
|
|
|
6
6
|
import arrow
|
|
@@ -8,8 +8,12 @@ import numpy as np
|
|
|
8
8
|
from celery import shared_task
|
|
9
9
|
from dateutil.rrule import rrulestr
|
|
10
10
|
from django.conf import settings
|
|
11
|
+
from django.contrib.postgres.aggregates import StringAgg
|
|
12
|
+
from django.contrib.postgres.indexes import GinIndex
|
|
13
|
+
from django.contrib.postgres.search import SearchVector, SearchVectorField
|
|
11
14
|
from django.db import models, transaction
|
|
12
|
-
from django.db.
|
|
15
|
+
from django.db.backends.postgresql.psycopg_any import DateTimeTZRange
|
|
16
|
+
from django.db.models import Exists, OuterRef, Q, Value
|
|
13
17
|
from django.db.models.query import QuerySet
|
|
14
18
|
from django.db.models.signals import m2m_changed, post_delete, post_save
|
|
15
19
|
from django.dispatch import receiver
|
|
@@ -21,6 +25,7 @@ from django_fsm import FSMField, transition
|
|
|
21
25
|
from dynamic_preferences.registries import global_preferences_registry
|
|
22
26
|
from ics.alarm import DisplayAlarm
|
|
23
27
|
from psycopg.types.range import TimestamptzRange
|
|
28
|
+
from rest_framework.reverse import reverse
|
|
24
29
|
from slugify import slugify
|
|
25
30
|
from wbcore.contrib import workflow
|
|
26
31
|
from wbcore.contrib.agenda.models import CalendarItem
|
|
@@ -51,6 +56,7 @@ from wbcore.utils.models import (
|
|
|
51
56
|
|
|
52
57
|
from wbcrm.models.llm.activity_summaries import analyze_activity
|
|
53
58
|
from wbcrm.models.recurrence import Recurrence
|
|
59
|
+
from wbcrm.signals import add_employee_activity_to_daily_brief
|
|
54
60
|
from wbcrm.synchronization.activity.shortcuts import get_backend
|
|
55
61
|
from wbcrm.typings import Activity as ActivityDTO
|
|
56
62
|
from wbcrm.typings import ParticipantStatus as ParticipantStatusDTO
|
|
@@ -216,6 +222,9 @@ class Activity(Recurrence):
|
|
|
216
222
|
class Meta:
|
|
217
223
|
verbose_name = _("Activity")
|
|
218
224
|
verbose_name_plural = _("Activities")
|
|
225
|
+
indexes = [
|
|
226
|
+
GinIndex(fields=["search_vector"], name="activity_sv_gin_idx"), # type: ignore
|
|
227
|
+
]
|
|
219
228
|
notification_types = [
|
|
220
229
|
create_notification_type(
|
|
221
230
|
"wbcrm.activity.participant",
|
|
@@ -233,9 +242,18 @@ class Activity(Recurrence):
|
|
|
233
242
|
gettext("Notifies a user of a finished activity that can be reviewed."),
|
|
234
243
|
),
|
|
235
244
|
create_notification_type(
|
|
236
|
-
"wbcrm.activity.
|
|
245
|
+
"wbcrm.activity.global_daily_summary",
|
|
237
246
|
gettext("Daily Summary"),
|
|
238
|
-
gettext("Sends out a
|
|
247
|
+
gettext("Sends out a the global employees daily activities report"),
|
|
248
|
+
web=False,
|
|
249
|
+
mobile=False,
|
|
250
|
+
email=True,
|
|
251
|
+
is_lock=True,
|
|
252
|
+
),
|
|
253
|
+
create_notification_type(
|
|
254
|
+
"wbcrm.activity.daily_brief",
|
|
255
|
+
gettext("Daily Brief"),
|
|
256
|
+
gettext("Sends out a daily brief for the user's upcoming day."),
|
|
239
257
|
web=False,
|
|
240
258
|
mobile=False,
|
|
241
259
|
email=True,
|
|
@@ -447,10 +465,25 @@ class Activity(Recurrence):
|
|
|
447
465
|
verbose_name=_("Without Participating Company"),
|
|
448
466
|
)
|
|
449
467
|
metadata = models.JSONField(default=dict, blank=True)
|
|
468
|
+
search_vector = SearchVectorField(null=True)
|
|
450
469
|
|
|
451
470
|
def __str__(self):
|
|
452
471
|
return "%s" % (self.title,)
|
|
453
472
|
|
|
473
|
+
def update_search_vectors(self):
|
|
474
|
+
# Create the combined search vector manually
|
|
475
|
+
vector = (
|
|
476
|
+
SearchVector(Value(self.title), weight="A", config="english")
|
|
477
|
+
+ SearchVector(Value(self.description), weight="B", config="english")
|
|
478
|
+
+ SearchVector(Value(self.result), weight="B", config="english")
|
|
479
|
+
)
|
|
480
|
+
if self.id:
|
|
481
|
+
if participants_str := self.participants.aggregate(agg=StringAgg("computed_str", delimiter=" "))["agg"]:
|
|
482
|
+
vector += SearchVector(Value(participants_str), weight="C", config="english")
|
|
483
|
+
if companies_str := self.companies.aggregate(agg=StringAgg("computed_str", delimiter=" "))["agg"]:
|
|
484
|
+
vector += SearchVector(Value(companies_str), weight="C", config="english")
|
|
485
|
+
self.search_vector = vector
|
|
486
|
+
|
|
454
487
|
def is_private_for_user(self, user) -> bool:
|
|
455
488
|
return (
|
|
456
489
|
self.visibility == CalendarItem.Visibility.PRIVATE
|
|
@@ -520,6 +553,7 @@ class Activity(Recurrence):
|
|
|
520
553
|
) # type
|
|
521
554
|
self.is_cancelled = self.status == self.Status.CANCELLED
|
|
522
555
|
|
|
556
|
+
self.update_search_vectors()
|
|
523
557
|
# Logic to be called after a save happens (e.g synchronization). We get the activity DTO before saving that we passed around in the signal
|
|
524
558
|
super().save(*args, **kwargs)
|
|
525
559
|
|
|
@@ -851,6 +885,9 @@ def m2m_changed_participants(sender, instance: Activity, action: str, pk_set: se
|
|
|
851
885
|
send_employee_notification.delay(instance.id, participant_id)
|
|
852
886
|
else:
|
|
853
887
|
rel.delete()
|
|
888
|
+
if action == "post_add":
|
|
889
|
+
instance.update_search_vectors()
|
|
890
|
+
Activity.objects.filter(id=instance.id).update(search_vector=instance.search_vector)
|
|
854
891
|
|
|
855
892
|
|
|
856
893
|
@receiver(m2m_changed, sender=Activity.companies.through)
|
|
@@ -879,6 +916,10 @@ def m2m_changed_companies(sender, instance: Activity, action: str, pk_set: set[i
|
|
|
879
916
|
activity=instance,
|
|
880
917
|
).save()
|
|
881
918
|
|
|
919
|
+
if action == "post_add":
|
|
920
|
+
instance.update_search_vectors()
|
|
921
|
+
Activity.objects.filter(id=instance.id).update(search_vector=instance.search_vector)
|
|
922
|
+
|
|
882
923
|
|
|
883
924
|
@receiver(m2m_changed, sender=Activity.groups.through) # type: ignore
|
|
884
925
|
def m2m_changed_groups(sender, instance: Activity, action, pk_set, **kwargs):
|
|
@@ -1345,3 +1386,37 @@ def add_employer_to_activities(eer_id: int):
|
|
|
1345
1386
|
activity.entities.add(eer_obj.employer)
|
|
1346
1387
|
if eer_obj.employer not in activity.companies.all():
|
|
1347
1388
|
activity.companies.add(eer_obj.employer)
|
|
1389
|
+
|
|
1390
|
+
|
|
1391
|
+
@receiver(add_employee_activity_to_daily_brief, sender="directory.Person")
|
|
1392
|
+
def daily_activity_summary(sender, instance: Person, val_date: date, **kwargs) -> tuple[str, str] | None:
|
|
1393
|
+
tz_info = timezone.get_current_timezone()
|
|
1394
|
+
period = DateTimeTZRange(
|
|
1395
|
+
lower=datetime.combine(val_date, time(0, 0, 0), tzinfo=tz_info),
|
|
1396
|
+
upper=datetime.combine(val_date + timedelta(days=1), time(0, 0, 0), tzinfo=tz_info),
|
|
1397
|
+
)
|
|
1398
|
+
|
|
1399
|
+
# Get all the employee's activities from that day
|
|
1400
|
+
activity_qs: QuerySet[Activity] = (
|
|
1401
|
+
Activity.objects.exclude(status=Activity.Status.CANCELLED)
|
|
1402
|
+
.filter(period__overlap=period, participants=instance)
|
|
1403
|
+
.order_by("period__startswith")
|
|
1404
|
+
)
|
|
1405
|
+
|
|
1406
|
+
# Create the formatted activity dictionaries
|
|
1407
|
+
activity_list = []
|
|
1408
|
+
message = ""
|
|
1409
|
+
for activity in activity_qs:
|
|
1410
|
+
activity_list.append(
|
|
1411
|
+
{
|
|
1412
|
+
"type": activity.type.title,
|
|
1413
|
+
"title": activity.title,
|
|
1414
|
+
"start": activity.period.lower,
|
|
1415
|
+
"end": activity.period.upper,
|
|
1416
|
+
"endpoint": reverse("wbcrm:activity-detail", args=[activity.pk]),
|
|
1417
|
+
}
|
|
1418
|
+
)
|
|
1419
|
+
if activity_list:
|
|
1420
|
+
context = {"activities": activity_list}
|
|
1421
|
+
message = render_to_string("email/daily_summary.html", context)
|
|
1422
|
+
return "Daily Activity Summary", message
|
wbcrm/serializers/activities.py
CHANGED
|
@@ -140,7 +140,7 @@ class ActivityCompanyThroughModelRepresentationSerializer(wb_serializers.Represe
|
|
|
140
140
|
|
|
141
141
|
def to_representation(self, value):
|
|
142
142
|
rep = super().to_representation(value)
|
|
143
|
-
rep["id"] = value.
|
|
143
|
+
rep["id"] = value.company_id
|
|
144
144
|
return rep
|
|
145
145
|
|
|
146
146
|
class Meta:
|
wbcrm/signals.py
ADDED
|
@@ -4,7 +4,6 @@ import operator
|
|
|
4
4
|
from functools import reduce
|
|
5
5
|
from typing import Any
|
|
6
6
|
|
|
7
|
-
from django.conf import settings
|
|
8
7
|
from django.db import transaction
|
|
9
8
|
from django.db.models import Q, QuerySet
|
|
10
9
|
from django.http import HttpRequest, HttpResponse
|
|
@@ -47,8 +46,6 @@ class ActivityController:
|
|
|
47
46
|
]
|
|
48
47
|
|
|
49
48
|
def __init__(self, backend: SyncBackend):
|
|
50
|
-
if settings.DEBUG:
|
|
51
|
-
raise ValueError("DEBUG Mode -> activity sync disabled")
|
|
52
49
|
self.backend = backend()
|
|
53
50
|
|
|
54
51
|
def _is_valid(self, activity_dto: ActivityDTO) -> bool:
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from contextlib import suppress
|
|
2
2
|
|
|
3
|
+
from django.conf import settings
|
|
3
4
|
from dynamic_preferences.exceptions import NotFoundInRegistry
|
|
4
5
|
from dynamic_preferences.registries import global_preferences_registry
|
|
5
6
|
from wbcore.utils.importlib import import_from_dotted_path
|
|
@@ -8,7 +9,8 @@ from wbcore.utils.importlib import import_from_dotted_path
|
|
|
8
9
|
def get_backend():
|
|
9
10
|
from wbcrm.synchronization.activity.controller import ActivityController
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
backend
|
|
14
|
-
|
|
12
|
+
if not settings.DEBUG:
|
|
13
|
+
with suppress(NotFoundInRegistry):
|
|
14
|
+
if backend := global_preferences_registry.manager()["wbactivity_sync__sync_backend_calendar"]:
|
|
15
|
+
backend = import_from_dotted_path(backend)
|
|
16
|
+
return ActivityController(backend=backend)
|
wbcrm/tasks.py
CHANGED
|
@@ -5,6 +5,7 @@ from datetime import date, datetime, time, timedelta
|
|
|
5
5
|
|
|
6
6
|
from celery import shared_task
|
|
7
7
|
from django.contrib.auth import get_user_model
|
|
8
|
+
from django.db.backends.postgresql.psycopg_any import DateTimeTZRange
|
|
8
9
|
from django.db.models import (
|
|
9
10
|
F,
|
|
10
11
|
FloatField,
|
|
@@ -23,12 +24,12 @@ from django.utils import timezone
|
|
|
23
24
|
from django.utils.timezone import make_aware
|
|
24
25
|
from django.utils.translation import gettext as _
|
|
25
26
|
from dynamic_preferences.registries import global_preferences_registry
|
|
26
|
-
from psycopg.types.range import TimestamptzRange
|
|
27
27
|
from rest_framework.reverse import reverse
|
|
28
28
|
from wbcore.contrib.directory.models import Company, Person
|
|
29
29
|
from wbcore.contrib.notifications.dispatch import send_notification
|
|
30
30
|
|
|
31
31
|
from wbcrm.models import Activity, ActivityType
|
|
32
|
+
from wbcrm.signals import add_employee_activity_to_daily_brief
|
|
32
33
|
|
|
33
34
|
logger = logging.getLogger()
|
|
34
35
|
User = get_user_model()
|
|
@@ -54,10 +55,10 @@ def notify(time_offset: int = 60, now: datetime | None = None):
|
|
|
54
55
|
for reminder in reminder_choices:
|
|
55
56
|
# get the reminder correspondance in minutes
|
|
56
57
|
reminder_minutes = Activity.ReminderChoice.get_minutes_correspondance(reminder)
|
|
57
|
-
reminder_range =
|
|
58
|
+
reminder_range = DateTimeTZRange(
|
|
58
59
|
now + timedelta(minutes=reminder_minutes),
|
|
59
60
|
now + timedelta(minutes=reminder_minutes) + timedelta(seconds=time_offset),
|
|
60
|
-
) # type: ignore #ErrMsg: Expected no arguments to "
|
|
61
|
+
) # type: ignore #ErrMsg: Expected no arguments to "DateTimeTZRange" constructor
|
|
61
62
|
# get all incoming activity with same reminder that happen during the notify interval
|
|
62
63
|
upcoming_occurence = base_queryset.filter(
|
|
63
64
|
reminder_choice=reminder, period__startswith__contained_by=reminder_range
|
|
@@ -108,7 +109,7 @@ def yesterdays_activity_summary(yesterday: date | None = None, report_receiver_u
|
|
|
108
109
|
if not yesterday:
|
|
109
110
|
yesterday = date.today() - timedelta(days=1)
|
|
110
111
|
yesterday = datetime.combine(yesterday, time(0, 0, 0)) # we convert the date to datetime
|
|
111
|
-
time_range =
|
|
112
|
+
time_range = DateTimeTZRange(make_aware(yesterday), make_aware(yesterday + timedelta(days=1))) # type: ignore #ErrMsg: Expected no arguments to "DateTimeTZRange" constructor
|
|
112
113
|
|
|
113
114
|
# Create the list of all employees' activities for yesterday
|
|
114
115
|
employees_list: list[Person] = list(Person.objects.filter_only_internal())
|
|
@@ -132,8 +133,8 @@ def yesterdays_activity_summary(yesterday: date | None = None, report_receiver_u
|
|
|
132
133
|
{
|
|
133
134
|
"type": activity.type.title,
|
|
134
135
|
"title": activity.title,
|
|
135
|
-
"start": activity.period.lower, # type: ignore #ErrMsg: Cannot access member "lower" for type "
|
|
136
|
-
"end": activity.period.upper, # type: ignore #ErrMsg: Cannot access member "upper" for type "
|
|
136
|
+
"start": activity.period.lower, # type: ignore #ErrMsg: Cannot access member "lower" for type "DateTimeTZRange"
|
|
137
|
+
"end": activity.period.upper, # type: ignore #ErrMsg: Cannot access member "upper" for type "DateTimeTZRange"
|
|
137
138
|
"endpoint": reverse("wbcrm:activity-detail", args=[activity.pk]),
|
|
138
139
|
}
|
|
139
140
|
for activity in employees_activities
|
|
@@ -150,7 +151,7 @@ def yesterdays_activity_summary(yesterday: date | None = None, report_receiver_u
|
|
|
150
151
|
}
|
|
151
152
|
message = render_to_string("email/global_daily_summary.html", context)
|
|
152
153
|
send_notification(
|
|
153
|
-
code="wbcrm.activity.
|
|
154
|
+
code="wbcrm.activity.global_daily_summary",
|
|
154
155
|
title=_("Activity Summary {}").format(yesterday.strftime("%d.%m.%Y")),
|
|
155
156
|
body=message,
|
|
156
157
|
user=user,
|
|
@@ -158,50 +159,28 @@ def yesterdays_activity_summary(yesterday: date | None = None, report_receiver_u
|
|
|
158
159
|
|
|
159
160
|
|
|
160
161
|
@shared_task
|
|
161
|
-
def
|
|
162
|
-
"""Creates a summary of the daily
|
|
163
|
-
|
|
162
|
+
def daily_brief(today: date | None = None, **kwargs):
|
|
163
|
+
"""Creates a summary of the daily brief for all internal employees
|
|
164
164
|
Args:
|
|
165
165
|
today (date | None, optional): Date of today. Defaults to None.
|
|
166
166
|
"""
|
|
167
167
|
|
|
168
168
|
if not today:
|
|
169
169
|
today = date.today()
|
|
170
|
-
tz_info = timezone.get_current_timezone()
|
|
171
|
-
today_range = TimestamptzRange(
|
|
172
|
-
lower=datetime.combine(today, time(0, 0, 0)).replace(tzinfo=tz_info),
|
|
173
|
-
upper=datetime.combine(today + timedelta(days=1), time(0, 0, 0).replace(tzinfo=tz_info)),
|
|
174
|
-
)
|
|
175
|
-
|
|
176
170
|
for employee in Person.objects.filter_only_internal():
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
for activity in activity_qs:
|
|
187
|
-
activity_list.append(
|
|
188
|
-
{
|
|
189
|
-
"type": activity.type.title,
|
|
190
|
-
"title": activity.title,
|
|
191
|
-
"start": activity.period.lower,
|
|
192
|
-
"end": activity.period.upper,
|
|
193
|
-
"endpoint": reverse("wbcrm:activity-detail", args=[activity.pk]),
|
|
194
|
-
}
|
|
195
|
-
)
|
|
196
|
-
|
|
197
|
-
# Create the proper notification for each employee
|
|
198
|
-
if activity_list and employee.primary_email_contact():
|
|
199
|
-
context = {"activities": activity_list}
|
|
200
|
-
message = render_to_string("email/daily_summary.html", context)
|
|
171
|
+
daily_brief = ""
|
|
172
|
+
for receiver, res in add_employee_activity_to_daily_brief.send( # noqa: B007
|
|
173
|
+
sender=Person, instance=employee, val_date=today, **kwargs
|
|
174
|
+
):
|
|
175
|
+
if res:
|
|
176
|
+
title, html = res
|
|
177
|
+
daily_brief += f"<h2 text-align: center;>{title}</h2>\n<div style='margin-bottom: 1.5em; text-align: left;'>{html}</div>\n"
|
|
178
|
+
|
|
179
|
+
if daily_brief:
|
|
201
180
|
send_notification(
|
|
202
|
-
code="wbcrm.activity.
|
|
203
|
-
title=_("Your
|
|
204
|
-
body=
|
|
181
|
+
code="wbcrm.activity.daily_brief",
|
|
182
|
+
title=_("Your Daily Brief"),
|
|
183
|
+
body=daily_brief,
|
|
205
184
|
user=employee.user_account,
|
|
206
185
|
)
|
|
207
186
|
|
wbcrm/viewsets/activities.py
CHANGED
|
@@ -95,7 +95,7 @@ class ActivityViewSet(RecurrenceModelViewSetMixin, CalendarItemViewSet):
|
|
|
95
95
|
LIST_DOCUMENTATION = "wbcrm/markdown/documentation/activity.md"
|
|
96
96
|
|
|
97
97
|
ordering = ["-edited", "id"]
|
|
98
|
-
search_fields = ("
|
|
98
|
+
search_fields = ("search_vector",)
|
|
99
99
|
serializer_class = crm_serializers.ActivityModelSerializer
|
|
100
100
|
display_config_class = ActivityDisplay
|
|
101
101
|
title_config_class = ActivityTitleConfig
|
|
@@ -180,11 +180,7 @@ class ActivityViewSet(RecurrenceModelViewSetMixin, CalendarItemViewSet):
|
|
|
180
180
|
return (
|
|
181
181
|
Activity.get_activities_for_user(user, base_qs=super().get_queryset())
|
|
182
182
|
.select_related("latest_reviewer", "type")
|
|
183
|
-
.prefetch_related(
|
|
184
|
-
"groups",
|
|
185
|
-
"participants",
|
|
186
|
-
"companies",
|
|
187
|
-
)
|
|
183
|
+
.prefetch_related("groups", "participants", "companies", "activity_companies")
|
|
188
184
|
)
|
|
189
185
|
|
|
190
186
|
def add_messages(self, request, instance: Activity | None = None, **kwargs):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wbcrm
|
|
3
|
-
Version: 1.56.
|
|
3
|
+
Version: 1.56.2
|
|
4
4
|
Summary: A workbench module that contains all the functionality related to a customer relationship management.
|
|
5
5
|
Author-email: Christopher Wittlinger <c.wittlinger@stainly.com>
|
|
6
6
|
Requires-Dist: django-eventtools==1.*
|
|
@@ -2,7 +2,8 @@ wbcrm/__init__.py,sha256=J-j-u0itpEFT6irdmWmixQqYMadNl1X91TxUmoiLHMI,22
|
|
|
2
2
|
wbcrm/apps.py,sha256=gT5ZryLzvq-ftpU48IzzQWM5XKn608lHwao7gCZW0Og,85
|
|
3
3
|
wbcrm/dynamic_preferences_registry.py,sha256=Vy4VSfbHoZnQ71gdEMpZEz-mKWvmTGZfb1eO-UVBqo8,1490
|
|
4
4
|
wbcrm/preferences.py,sha256=BhM_lWfFMZLhP3D1dE7Ja6ZXo-sF3q_YTyJtYkhPqxM,485
|
|
5
|
-
wbcrm/
|
|
5
|
+
wbcrm/signals.py,sha256=TASaTxZasod_LPyqDtsn4RLfc9YFnDWSA0v78lIViqM,204
|
|
6
|
+
wbcrm/tasks.py,sha256=soHEceboaztn8FguUb14HHiZPozZZJfH-NaklMY0kHM,12219
|
|
6
7
|
wbcrm/typings.py,sha256=jMX666cYItSYHN9Cb55HoffyPRG49S1dh6xB8AZpBtE,3312
|
|
7
8
|
wbcrm/urls.py,sha256=5_b4mYUy76KOgSEJL2ggnEnxZpEK7jFzQAAckLNOcxE,2573
|
|
8
9
|
wbcrm/admin/__init__.py,sha256=P_r2hm3DjYhVik8j5t-bT2qJgi6ExMQ0Afg3BnLZ5yc,227
|
|
@@ -50,10 +51,11 @@ wbcrm/migrations/0014_alter_account_relationship_status.py,sha256=_U8vkzOZu3A_1l
|
|
|
50
51
|
wbcrm/migrations/0015_alter_activity_type.py,sha256=yyPfueEZ8nz9_TwFiJq4qH3GoAei7auN7M1CMImymjs,612
|
|
51
52
|
wbcrm/migrations/0016_auto_20241205_1015.py,sha256=E82BmOegfyJmmmaKemL_bT2OEVywiRuCj11eBA3tFe8,4058
|
|
52
53
|
wbcrm/migrations/0017_event.py,sha256=PzhAVAa2z4itzctQBz-6i__aRDh3TDe029F8leE34W0,1422
|
|
54
|
+
wbcrm/migrations/0018_activity_search_vector.py,sha256=34Bh6wy8mR3R3rQl6XJL8813y7NPOTXI59M-qjSIN_E,665
|
|
53
55
|
wbcrm/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
54
56
|
wbcrm/models/__init__.py,sha256=23U2eBeZStYgUKSGfi3q88JtfqfbNTk7MbnLEAGw1gk,287
|
|
55
57
|
wbcrm/models/accounts.py,sha256=Stqn4NIzCS7fxHmVkHea2fA6rL_ng3nrES804al3n88,25421
|
|
56
|
-
wbcrm/models/activities.py,sha256=
|
|
58
|
+
wbcrm/models/activities.py,sha256=MD_VX3B5GNd3lD4ojYcxGae8Ra507WSwvJz7FSoVhA0,57393
|
|
57
59
|
wbcrm/models/events.py,sha256=JuGfmMZOVoszK3C6uHUVEWXNOUh8xOnoZAteCPRTAPM,452
|
|
58
60
|
wbcrm/models/groups.py,sha256=att5YADwTLoI5NmSoiMhOBJ8qyBbdKubPGMI2dXUCf0,4345
|
|
59
61
|
wbcrm/models/products.py,sha256=iz6eGDvZEglieWUJDpTAJwHEJLu_rXg_ciGx32haVSk,2553
|
|
@@ -63,7 +65,7 @@ wbcrm/models/llm/analyze_relationship.py,sha256=A4oXdOS1C1kydRjccptlsxBsAjFjkH6X
|
|
|
63
65
|
wbcrm/report/activity_report.py,sha256=Y2NveP9u6CeXImXtxR4XfZK-2CFBa5CnUG-jx35Msnc,4843
|
|
64
66
|
wbcrm/serializers/__init__.py,sha256=qKwo5e-Ix-Iow1RRdKFC0uZQmuSHzc8DIypIhi_E8HI,726
|
|
65
67
|
wbcrm/serializers/accounts.py,sha256=F7fJAa4lamkuQxfiLU08iE4vCaDtiMtcxwTFowxHnMk,5552
|
|
66
|
-
wbcrm/serializers/activities.py,sha256=
|
|
68
|
+
wbcrm/serializers/activities.py,sha256=oeRKAxVeKQy_d4l2BMSrhiRzZqlG9K8ubfwJQ0mqK7s,21599
|
|
67
69
|
wbcrm/serializers/groups.py,sha256=YqiHGiytbD1lIuSUEBk4CwlwipAFs_uh2V9DZG7JukQ,783
|
|
68
70
|
wbcrm/serializers/products.py,sha256=xBv5l2xgrUQRIjlqe_qKTiWDcp0lOq5FHDBms9lm_V0,2002
|
|
69
71
|
wbcrm/serializers/recurrence.py,sha256=0I42almPuwWDsRfpxig3rt_U_xGPsekBr8jQKF1BKrA,4589
|
|
@@ -82,10 +84,10 @@ wbcrm/synchronization/urls.py,sha256=3zhKivWitCw3BuaN6Ksi2e_WnHGRBL4DFqBx1LHWdmU
|
|
|
82
84
|
wbcrm/synchronization/activity/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
83
85
|
wbcrm/synchronization/activity/admin.py,sha256=QFgm5f1fimNPLRO8a8U1E34yxbs1qbpygj7Pr_5pCHY,2686
|
|
84
86
|
wbcrm/synchronization/activity/backend.py,sha256=UnZuOaH_F6R2z7ghcJ6tp_maEyOk9QPTbwfNdL_wLc4,8308
|
|
85
|
-
wbcrm/synchronization/activity/controller.py,sha256=
|
|
87
|
+
wbcrm/synchronization/activity/controller.py,sha256=JL27luA_IvCR9Slb5gY1-C7TDLBMgNSLW49ffSPueQ8,31371
|
|
86
88
|
wbcrm/synchronization/activity/dynamic_preferences_registry.py,sha256=59K5Xq50IRg4yrBUevefi-0jDZtmT3JoVT3qbniJFDQ,4247
|
|
87
89
|
wbcrm/synchronization/activity/preferences.py,sha256=7grSPy1oECqBK598UP8kO_t7sUNFCv6mRkEmz3LEYng,1009
|
|
88
|
-
wbcrm/synchronization/activity/shortcuts.py,sha256=
|
|
90
|
+
wbcrm/synchronization/activity/shortcuts.py,sha256=PZbajycBAnjaRG1G9Mw08RGKCqjCt_uhRJ_PxvXLvLk,652
|
|
89
91
|
wbcrm/synchronization/activity/tasks.py,sha256=NrCjx8WMhdsFwe1PbLwV2tdFBLg-XrnuFJt4yjlv9Ow,607
|
|
90
92
|
wbcrm/synchronization/activity/urls.py,sha256=yNld96CD88zeWimGbUmuiq5OjTBLEGKpwvF2I25oBD8,168
|
|
91
93
|
wbcrm/synchronization/activity/utils.py,sha256=tMp_Xm3PQ_9XVpqBX_EiUYT7uRSOWe9KN5n4eAecKY4,1423
|
|
@@ -143,7 +145,7 @@ wbcrm/tests/e2e/e2e_wbcrm_utility.py,sha256=NB2pQXEzr8-S7cMGOs6w5IrT3gdcuzwz5x3a
|
|
|
143
145
|
wbcrm/tests/e2e/test_e2e.py,sha256=NCAh-ZteI9yNRiS3xLd46HGBf_3zTs9XXwTVHP2VINI,16570
|
|
144
146
|
wbcrm/viewsets/__init__.py,sha256=aoi2Hry7C6CixqV7ZIVrVPSjrcRcdRkE3zBmm1Va1Qo,668
|
|
145
147
|
wbcrm/viewsets/accounts.py,sha256=gO7nb4cYtm4qZO5tpcQ2akoH54F6Uq01VFpshq5pdvQ,4458
|
|
146
|
-
wbcrm/viewsets/activities.py,sha256=
|
|
148
|
+
wbcrm/viewsets/activities.py,sha256=xBOwUxknPZeRdTOYJqdcSFt075EINIdj5HH5X7U3t-8,12816
|
|
147
149
|
wbcrm/viewsets/groups.py,sha256=2W529zW2m1DIRYTxn8nEDYjWjQAHzh6yV7Owvf3KZA4,1414
|
|
148
150
|
wbcrm/viewsets/mixins.py,sha256=pqyP00VNA5jJL9LwvIw7Mfc-zN-z5yJ-cAblZY7o7c4,1113
|
|
149
151
|
wbcrm/viewsets/products.py,sha256=aby4V6F-7WzosKIbYV_CEguXrNo2IN8ZjUTcUGGmX8w,2157
|
|
@@ -176,6 +178,6 @@ wbcrm/viewsets/titles/products.py,sha256=cFAK5zljjybabk2U0KzPT2PVfV5vmO_UlJd6QlI
|
|
|
176
178
|
wbcrm/viewsets/titles/utils.py,sha256=IaHQTmEG2OwIHS1bRv7sjuT950wefUJNi3yvPdrpNEs,1144
|
|
177
179
|
wbcrm/workflows/__init__.py,sha256=biwXXPkVJugT9Vc1cwbInAUY8EnVmOauxdPz7e_2w_A,32
|
|
178
180
|
wbcrm/workflows/assignee_methods.py,sha256=xlCMnY07TVtVt1pqotARLKtYulQIY4qxdCXrbzP9lig,987
|
|
179
|
-
wbcrm-1.56.
|
|
180
|
-
wbcrm-1.56.
|
|
181
|
-
wbcrm-1.56.
|
|
181
|
+
wbcrm-1.56.2.dist-info/METADATA,sha256=zpcsbMb5iI-3qbXJP3rIcMR5-bXE36eF8Z5OgnjYnuo,450
|
|
182
|
+
wbcrm-1.56.2.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
|
|
183
|
+
wbcrm-1.56.2.dist-info/RECORD,,
|
|
File without changes
|