wbcore 1.54.10__py2.py3-none-any.whl → 1.58.2__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wbcore/cache/decorators.py +3 -3
- wbcore/cache/registry.py +3 -2
- wbcore/configs/decorators.py +1 -1
- wbcore/configurations/configurations/apps.py +2 -2
- wbcore/configurations/configurations/authentication.py +1 -1
- wbcore/configurations/configurations/base.py +1 -1
- wbcore/configurations/configurations/cache.py +1 -1
- wbcore/configurations/configurations/maintenance.py +1 -1
- wbcore/configurations/configurations/media.py +1 -1
- wbcore/configurations/configurations/middleware.py +1 -1
- wbcore/configurations/configurations/rest_framework.py +1 -1
- wbcore/configurations/configurations/static.py +1 -1
- wbcore/configurations/configurations/wbcore.py +1 -1
- wbcore/content_type/serializers.py +1 -1
- wbcore/content_type/utils.py +3 -3
- wbcore/contrib/agenda/viewsets/calendar_items.py +7 -7
- wbcore/contrib/ai/llm/config.py +1 -1
- wbcore/contrib/authentication/admin.py +2 -2
- wbcore/contrib/authentication/filters.py +0 -1
- wbcore/contrib/authentication/models/users.py +3 -3
- wbcore/contrib/authentication/models/users_activities.py +1 -1
- wbcore/contrib/authentication/serializers/users.py +2 -2
- wbcore/contrib/authentication/tests/test_tokens.py +3 -3
- wbcore/contrib/authentication/tests/test_users.py +0 -1
- wbcore/contrib/authentication/viewsets/user_activities.py +2 -1
- wbcore/contrib/authentication/viewsets/users.py +6 -4
- wbcore/contrib/color/models.py +2 -1
- wbcore/contrib/currency/factories.py +1 -1
- wbcore/contrib/currency/import_export/backends/fixerio/currency_fx_rates.py +3 -1
- wbcore/contrib/currency/models.py +28 -8
- wbcore/contrib/currency/serializers.py +5 -1
- wbcore/contrib/currency/tests/test_serializers.py +7 -3
- wbcore/contrib/currency/tests/test_viewsets.py +1 -1
- wbcore/contrib/currency/viewsets/currency.py +2 -2
- wbcore/contrib/dataloader/utils.py +2 -2
- wbcore/contrib/directory/factories/__init__.py +1 -1
- wbcore/contrib/directory/factories/entries.py +1 -1
- wbcore/contrib/directory/models/contacts.py +2 -2
- wbcore/contrib/directory/models/entries.py +18 -4
- wbcore/contrib/directory/models/relationships.py +25 -30
- wbcore/contrib/directory/permissions.py +6 -0
- wbcore/contrib/directory/serializers/companies.py +15 -8
- wbcore/contrib/directory/serializers/contacts.py +8 -8
- wbcore/contrib/directory/serializers/entries.py +24 -15
- wbcore/contrib/directory/serializers/entry_representations.py +4 -2
- wbcore/contrib/directory/serializers/persons.py +8 -9
- wbcore/contrib/directory/serializers/relationships.py +2 -2
- wbcore/contrib/directory/tests/conftest.py +2 -0
- wbcore/contrib/directory/tests/disable_signals.py +11 -1
- wbcore/contrib/directory/tests/signals.py +2 -2
- wbcore/contrib/directory/tests/test_models.py +88 -66
- wbcore/contrib/directory/tests/test_serializers.py +1 -1
- wbcore/contrib/directory/tests/test_viewsets.py +8 -8
- wbcore/contrib/directory/viewsets/buttons/__init__.py +1 -1
- wbcore/contrib/directory/viewsets/buttons/relationships.py +32 -0
- wbcore/contrib/directory/viewsets/contacts.py +6 -6
- wbcore/contrib/directory/viewsets/display/__init__.py +1 -1
- wbcore/contrib/directory/viewsets/display/entries.py +51 -36
- wbcore/contrib/directory/viewsets/display/relationships.py +22 -22
- wbcore/contrib/directory/viewsets/entries.py +4 -5
- wbcore/contrib/directory/viewsets/previews/entries.py +3 -3
- wbcore/contrib/directory/viewsets/relationships.py +16 -2
- wbcore/contrib/directory/viewsets/titles/relationships.py +2 -3
- wbcore/contrib/documents/filters.py +0 -2
- wbcore/contrib/example_app/models.py +4 -4
- wbcore/contrib/example_app/serializers/person_team.py +4 -4
- wbcore/contrib/example_app/tests/e2e/test_teams.py +1 -1
- wbcore/contrib/geography/tests/test_viewsets.py +1 -1
- wbcore/contrib/guardian/tests/test_model_mixins.py +3 -3
- wbcore/contrib/guardian/tests/test_tasks.py +9 -9
- wbcore/contrib/guardian/tests/test_viewsets.py +2 -2
- wbcore/contrib/icons/backends/default.py +1 -0
- wbcore/contrib/icons/backends/material.py +1 -0
- wbcore/contrib/icons/icons.py +5 -8
- wbcore/contrib/io/exceptions.py +8 -0
- wbcore/contrib/io/import_export/backends/stream.py +2 -2
- wbcore/contrib/io/imports.py +10 -5
- wbcore/contrib/io/models.py +17 -14
- wbcore/contrib/io/serializers.py +2 -2
- wbcore/contrib/io/tests/test_backends.py +1 -1
- wbcore/contrib/io/tests/test_imports.py +1 -1
- wbcore/contrib/io/viewset_mixins.py +4 -4
- wbcore/contrib/notifications/dispatch.py +18 -7
- wbcore/contrib/pandas/filterset.py +8 -7
- wbcore/contrib/pandas/views.py +7 -5
- wbcore/contrib/tags/models/tags.py +4 -1
- wbcore/contrib/workflow/factories/display.py +2 -2
- wbcore/contrib/workflow/models/data.py +7 -4
- wbcore/contrib/workflow/models/process.py +2 -2
- wbcore/contrib/workflow/serializers/data.py +8 -8
- wbcore/contrib/workflow/tests/test_models/test_condition.py +1 -1
- wbcore/contrib/workflow/workflows/assignees.py +4 -4
- wbcore/dynamic_preferences_registry.py +23 -9
- wbcore/enums.py +2 -1
- wbcore/filters/fields/content_type.py +5 -4
- wbcore/filters/fields/datetime.py +34 -9
- wbcore/filters/fields/models.py +2 -2
- wbcore/filters/filterset.py +22 -6
- wbcore/filters/mixins.py +6 -2
- wbcore/forms.py +6 -6
- wbcore/fsm/markdown_extensions.py +1 -1
- wbcore/fsm/mixins.py +7 -4
- wbcore/markdown/models.py +8 -5
- wbcore/metadata/configs/buttons/bases.py +6 -6
- wbcore/metadata/configs/buttons/buttons.py +2 -1
- wbcore/metadata/configs/buttons/view_config.py +5 -3
- wbcore/metadata/configs/display/display.py +2 -2
- wbcore/metadata/configs/display/formatting.py +6 -7
- wbcore/metadata/configs/display/list_display.py +6 -7
- wbcore/metadata/configs/display/models.py +6 -0
- wbcore/metadata/configs/fields.py +6 -1
- wbcore/metadata/configs/filter_fields.py +12 -11
- wbcore/models/fields.py +2 -2
- wbcore/permissions/permissions.py +2 -2
- wbcore/permissions/utils.py +2 -2
- wbcore/reversion/viewsets/titles.py +4 -3
- wbcore/serializers/__init__.py +1 -0
- wbcore/serializers/fields/__init__.py +1 -0
- wbcore/serializers/fields/datetime.py +35 -6
- wbcore/serializers/fields/fields.py +1 -1
- wbcore/serializers/fields/fsm.py +1 -1
- wbcore/serializers/fields/list.py +1 -1
- wbcore/serializers/fields/mixins.py +13 -5
- wbcore/serializers/fields/related.py +4 -6
- wbcore/serializers/fields/text.py +1 -1
- wbcore/serializers/fields/types.py +1 -0
- wbcore/serializers/serializers.py +6 -2
- wbcore/tasks.py +2 -2
- wbcore/templates/wbcore/email_base_template.html +3 -3
- wbcore/test/e2e_helpers_methods/e2e_checks.py +10 -4
- wbcore/test/e2e_helpers_methods/e2e_helper_methods.py +4 -2
- wbcore/test/mixins.py +1 -1
- wbcore/test/tests.py +6 -9
- wbcore/test/utils.py +3 -4
- wbcore/tests/e2e/test_e2e.py +2 -2
- wbcore/tests/test_cache/test_decorators.py +3 -3
- wbcore/tests/test_configs.py +1 -1
- wbcore/tests/test_fields/test_number_fields.py +1 -1
- wbcore/tests/test_filters/test_mixins.py +3 -3
- wbcore/tests/test_models/test_mixins.py +1 -1
- wbcore/tests/test_utils/test_date.py +1 -1
- wbcore/tests/test_utils/test_date_builder.py +25 -1
- wbcore/utils/date.py +18 -2
- wbcore/utils/figures.py +2 -2
- wbcore/utils/models.py +3 -2
- wbcore/utils/reportlab.py +7 -0
- wbcore/utils/rrules.py +1 -1
- wbcore/utils/string_loader.py +1 -1
- wbcore/utils/strings.py +2 -2
- wbcore/viewsets/mixins.py +6 -4
- {wbcore-1.54.10.dist-info → wbcore-1.58.2.dist-info}/METADATA +2 -1
- {wbcore-1.54.10.dist-info → wbcore-1.58.2.dist-info}/RECORD +153 -151
- {wbcore-1.54.10.dist-info → wbcore-1.58.2.dist-info}/WHEEL +0 -0
|
@@ -22,11 +22,13 @@ from slugify import slugify
|
|
|
22
22
|
|
|
23
23
|
from wbcore.contrib.agenda.models import CalendarItem
|
|
24
24
|
from wbcore.contrib.authentication.models import User
|
|
25
|
+
from wbcore.contrib.currency.models import Currency
|
|
25
26
|
from wbcore.contrib.directory.models.contacts import (
|
|
26
27
|
AddressContact,
|
|
27
28
|
BankingContact,
|
|
28
29
|
ContactLocationChoices,
|
|
29
30
|
EmailContact,
|
|
31
|
+
SocialMediaContact,
|
|
30
32
|
TelephoneContact,
|
|
31
33
|
WebsiteContact,
|
|
32
34
|
)
|
|
@@ -245,10 +247,6 @@ class EntryDefaultQueryset(models.QuerySet):
|
|
|
245
247
|
EmailContact.objects.filter(primary=True, entry__id=OuterRef("pk")).values("address")[:1],
|
|
246
248
|
output_field=CharField(),
|
|
247
249
|
),
|
|
248
|
-
secondary_email=Subquery(
|
|
249
|
-
EmailContact.objects.filter(primary=False, entry__id=OuterRef("pk")).values("address")[:1],
|
|
250
|
-
output_field=CharField(),
|
|
251
|
-
),
|
|
252
250
|
primary_telephone=Subquery(
|
|
253
251
|
TelephoneContact.objects.filter(primary=True, entry__id=OuterRef("pk")).values("number")[:1],
|
|
254
252
|
output_field=CharField(),
|
|
@@ -263,6 +261,14 @@ class EntryDefaultQueryset(models.QuerySet):
|
|
|
263
261
|
.values("primary_address")[:1],
|
|
264
262
|
output_field=CharField(),
|
|
265
263
|
),
|
|
264
|
+
primary_website=Subquery(
|
|
265
|
+
WebsiteContact.objects.filter(primary=True, entry__id=OuterRef("pk")).values("url")[:1],
|
|
266
|
+
output_field=CharField(),
|
|
267
|
+
),
|
|
268
|
+
primary_social=Subquery(
|
|
269
|
+
SocialMediaContact.objects.filter(primary=True, entry__id=OuterRef("pk")).values("url")[:1],
|
|
270
|
+
output_field=CharField(),
|
|
271
|
+
),
|
|
266
272
|
last_event=Subquery(
|
|
267
273
|
CalendarItem.objects.filter(
|
|
268
274
|
period__endswith__lte=timezone.now(),
|
|
@@ -408,6 +414,14 @@ class Entry(ComplexToStringMixin, DeleteToDisableMixin, WBModel):
|
|
|
408
414
|
if additional_field_key in self.additional_fields:
|
|
409
415
|
del self.additional_fields[additional_field_key]
|
|
410
416
|
|
|
417
|
+
def get_banking_contact(self, currency: Currency) -> BankingContact | None:
|
|
418
|
+
bank_accounts = self.banking.all()
|
|
419
|
+
if bank_accounts.filter(currency=currency).exists():
|
|
420
|
+
bank_accounts = bank_accounts.filter(currency=currency)
|
|
421
|
+
if bank_accounts.filter(primary=True).exists():
|
|
422
|
+
bank_accounts = bank_accounts.filter(primary=True)
|
|
423
|
+
return bank_accounts.first()
|
|
424
|
+
|
|
411
425
|
@classmethod
|
|
412
426
|
def get_endpoint_basename(cls):
|
|
413
427
|
return "wbcore:directory:entry"
|
|
@@ -148,6 +148,22 @@ class ClientManagerRelationship(ComplexToStringMixin, PrimaryMixin, WBModel):
|
|
|
148
148
|
APPROVED = "APPROVED", _("Approved")
|
|
149
149
|
REMOVED = "REMOVED", _("Removed")
|
|
150
150
|
|
|
151
|
+
@property
|
|
152
|
+
def can_update_primary_field(self):
|
|
153
|
+
return super().can_update_primary_field and self.status in [
|
|
154
|
+
ClientManagerRelationship.Status.APPROVED,
|
|
155
|
+
ClientManagerRelationship.Status.PENDINGREMOVE,
|
|
156
|
+
]
|
|
157
|
+
|
|
158
|
+
def get_related_queryset(self):
|
|
159
|
+
return ClientManagerRelationship.objects.filter(
|
|
160
|
+
client=self.client,
|
|
161
|
+
status__in=[
|
|
162
|
+
ClientManagerRelationship.Status.APPROVED,
|
|
163
|
+
ClientManagerRelationship.Status.PENDINGREMOVE,
|
|
164
|
+
],
|
|
165
|
+
)
|
|
166
|
+
|
|
151
167
|
PRIMARY_ATTR_FIELDS = ["client"]
|
|
152
168
|
|
|
153
169
|
relationship_manager = models.ForeignKey(
|
|
@@ -156,10 +172,6 @@ class ClientManagerRelationship(ComplexToStringMixin, PrimaryMixin, WBModel):
|
|
|
156
172
|
verbose_name=_("Relationship Manager"),
|
|
157
173
|
related_name="manager_of",
|
|
158
174
|
)
|
|
159
|
-
primary = models.BooleanField(
|
|
160
|
-
verbose_name=_("Primary"),
|
|
161
|
-
default=False,
|
|
162
|
-
)
|
|
163
175
|
client = models.ForeignKey(
|
|
164
176
|
on_delete=models.CASCADE,
|
|
165
177
|
to="directory.Entry",
|
|
@@ -209,7 +221,7 @@ class ClientManagerRelationship(ComplexToStringMixin, PrimaryMixin, WBModel):
|
|
|
209
221
|
},
|
|
210
222
|
)
|
|
211
223
|
def mngapprove(self, by=None, description=None, **kwargs):
|
|
212
|
-
|
|
224
|
+
pass
|
|
213
225
|
|
|
214
226
|
@transition(
|
|
215
227
|
field=status,
|
|
@@ -251,7 +263,7 @@ class ClientManagerRelationship(ComplexToStringMixin, PrimaryMixin, WBModel):
|
|
|
251
263
|
},
|
|
252
264
|
)
|
|
253
265
|
def approve(self, by=None, description=None, **kwargs):
|
|
254
|
-
|
|
266
|
+
pass
|
|
255
267
|
|
|
256
268
|
@transition(
|
|
257
269
|
field=status,
|
|
@@ -295,8 +307,8 @@ class ClientManagerRelationship(ComplexToStringMixin, PrimaryMixin, WBModel):
|
|
|
295
307
|
def approveremoval(self, by=None, description=None, **kwargs):
|
|
296
308
|
pass
|
|
297
309
|
|
|
298
|
-
def is_not_primary(
|
|
299
|
-
return not
|
|
310
|
+
def is_not_primary(self):
|
|
311
|
+
return not self.primary
|
|
300
312
|
|
|
301
313
|
@transition(
|
|
302
314
|
field=status,
|
|
@@ -319,10 +331,10 @@ class ClientManagerRelationship(ComplexToStringMixin, PrimaryMixin, WBModel):
|
|
|
319
331
|
def makeprimary(self, by=None, description=None, **kwargs):
|
|
320
332
|
self.primary = True
|
|
321
333
|
|
|
322
|
-
def last_primary(
|
|
323
|
-
return not
|
|
324
|
-
ClientManagerRelationship.objects.exclude(id=
|
|
325
|
-
.filter(status=ClientManagerRelationship.Status.APPROVED, client=
|
|
334
|
+
def last_primary(self):
|
|
335
|
+
return not self.primary and (
|
|
336
|
+
ClientManagerRelationship.objects.exclude(id=self.id)
|
|
337
|
+
.filter(status=ClientManagerRelationship.Status.APPROVED, client=self.client, primary=True)
|
|
326
338
|
.exists()
|
|
327
339
|
)
|
|
328
340
|
|
|
@@ -373,24 +385,6 @@ class ClientManagerRelationship(ComplexToStringMixin, PrimaryMixin, WBModel):
|
|
|
373
385
|
def delete(self, **kwargs):
|
|
374
386
|
super().delete(no_deletion=False) # For this model we actually want to delete the object
|
|
375
387
|
|
|
376
|
-
def get_related_queryset(self):
|
|
377
|
-
return (
|
|
378
|
-
super().get_related_queryset().filter(status=self.Status.APPROVED)
|
|
379
|
-
) # only one approved relationship can be primary
|
|
380
|
-
|
|
381
|
-
def _handle_primary_status(self):
|
|
382
|
-
if (
|
|
383
|
-
self.primary is True
|
|
384
|
-
and ClientManagerRelationship.objects.filter(client=self.client, primary=True).exists()
|
|
385
|
-
):
|
|
386
|
-
ClientManagerRelationship.objects.filter(client=self.client, primary=True).update(primary=False)
|
|
387
|
-
|
|
388
|
-
if (
|
|
389
|
-
self.primary is False
|
|
390
|
-
and not ClientManagerRelationship.objects.filter(client=self.client, primary=True).exists()
|
|
391
|
-
):
|
|
392
|
-
self.primary = True
|
|
393
|
-
|
|
394
388
|
class Meta:
|
|
395
389
|
verbose_name = _("Client Manager Relationship")
|
|
396
390
|
verbose_name_plural = _("Client Manager Relationships")
|
|
@@ -561,6 +555,7 @@ class EmployerEmployeeRelationship(PrimaryMixin):
|
|
|
561
555
|
def get_representation_value_key(cls):
|
|
562
556
|
return "id"
|
|
563
557
|
|
|
558
|
+
@classmethod
|
|
564
559
|
def representation_label_key(cls):
|
|
565
560
|
return "{{position_name}}"
|
|
566
561
|
|
|
@@ -26,10 +26,8 @@ class CompanyModelSerializer(EntryModelSerializer):
|
|
|
26
26
|
many=True,
|
|
27
27
|
)
|
|
28
28
|
_employees = PersonRepresentationSerializer(source="employees", many=True)
|
|
29
|
-
is_primary_employer = wb_serializers.BooleanField(
|
|
30
|
-
tier = wb_serializers.CharField(
|
|
31
|
-
help_text=settings.DEFAULT_TIERING_HELP_TEXT, required=False, read_only=True, label=_("Tier")
|
|
32
|
-
)
|
|
29
|
+
is_primary_employer = wb_serializers.BooleanField(read_only=True)
|
|
30
|
+
tier = wb_serializers.CharField(help_text=settings.DEFAULT_TIERING_HELP_TEXT, label=_("Tier"), required=False)
|
|
33
31
|
_type = CompanyTypeRepresentationSerializer(source="type")
|
|
34
32
|
|
|
35
33
|
@wb_serializers.register_resource()
|
|
@@ -63,6 +61,8 @@ class CompanyModelSerializer(EntryModelSerializer):
|
|
|
63
61
|
"primary_email",
|
|
64
62
|
"primary_manager_repr",
|
|
65
63
|
"primary_telephone",
|
|
64
|
+
"primary_website",
|
|
65
|
+
"primary_social",
|
|
66
66
|
"profile_image",
|
|
67
67
|
"salutation",
|
|
68
68
|
"signature",
|
|
@@ -77,7 +77,7 @@ class CompanyModelSerializer(EntryModelSerializer):
|
|
|
77
77
|
|
|
78
78
|
class CompanyModelListSerializer(CompanyModelSerializer):
|
|
79
79
|
eer_id = wb_serializers.CharField(default="", required=False, read_only=True)
|
|
80
|
-
is_primary_employer = wb_serializers.BooleanField(
|
|
80
|
+
is_primary_employer = wb_serializers.BooleanField(read_only=True)
|
|
81
81
|
|
|
82
82
|
@wb_serializers.register_resource()
|
|
83
83
|
def delete(self, instance, request, user):
|
|
@@ -127,7 +127,12 @@ class CompanyModelListSerializer(CompanyModelSerializer):
|
|
|
127
127
|
"_customer_status",
|
|
128
128
|
"eer_id",
|
|
129
129
|
"is_primary_employer",
|
|
130
|
+
"primary_address",
|
|
131
|
+
"primary_email",
|
|
130
132
|
"primary_manager_repr",
|
|
133
|
+
"primary_telephone",
|
|
134
|
+
"primary_website",
|
|
135
|
+
"primary_social",
|
|
131
136
|
"last_event",
|
|
132
137
|
"last_event_period_endswith",
|
|
133
138
|
"tier",
|
|
@@ -138,10 +143,12 @@ class CompanyModelListSerializer(CompanyModelSerializer):
|
|
|
138
143
|
|
|
139
144
|
|
|
140
145
|
class BankModelSerializer(wb_serializers.ModelSerializer):
|
|
141
|
-
primary_address = wb_serializers.CharField(
|
|
142
|
-
|
|
146
|
+
primary_address = wb_serializers.CharField(
|
|
147
|
+
allow_null=True, label=_("Primary Address"), read_only=True, required=False
|
|
148
|
+
)
|
|
149
|
+
primary_email = wb_serializers.CharField(allow_null=True, label=_("Primary Email"), required=False, read_only=True)
|
|
143
150
|
primary_telephone = wb_serializers.TelephoneField(
|
|
144
|
-
allow_null=True,
|
|
151
|
+
allow_null=True, label=_("Primary Telephone"), read_only=True, required=False
|
|
145
152
|
)
|
|
146
153
|
_relationship_managers = PersonRepresentationSerializer(many=True, source="relationship_managers")
|
|
147
154
|
|
|
@@ -126,8 +126,8 @@ class EmailContactSerializer(wb_serializers.ModelSerializer):
|
|
|
126
126
|
if address:
|
|
127
127
|
try:
|
|
128
128
|
validate_email(address)
|
|
129
|
-
except ValidationError:
|
|
130
|
-
raise serializers.ValidationError({"address": _("Invalid e-mail address")})
|
|
129
|
+
except ValidationError as e:
|
|
130
|
+
raise serializers.ValidationError({"address": _("Invalid e-mail address")}) from e
|
|
131
131
|
return data
|
|
132
132
|
|
|
133
133
|
class Meta:
|
|
@@ -261,8 +261,8 @@ class TelephoneContactSerializer(wb_serializers.ModelSerializer):
|
|
|
261
261
|
data["number"] = formatted_number
|
|
262
262
|
else:
|
|
263
263
|
raise serializers.ValidationError({"number": _("Invalid phone number format")})
|
|
264
|
-
except Exception:
|
|
265
|
-
raise serializers.ValidationError({"number": _("Invalid phone number format")})
|
|
264
|
+
except Exception as e:
|
|
265
|
+
raise serializers.ValidationError({"number": _("Invalid phone number format")}) from e
|
|
266
266
|
|
|
267
267
|
if entry and formatting_successful:
|
|
268
268
|
telephone_contact = TelephoneContact.objects.filter(number=formatted_number, entry=entry)
|
|
@@ -310,7 +310,7 @@ class BankingContactSerializer(wb_serializers.ModelSerializer):
|
|
|
310
310
|
iban_formatted = iban.formatted
|
|
311
311
|
data["iban"] = iban_formatted
|
|
312
312
|
except ValueError as e:
|
|
313
|
-
raise serializers.ValidationError({"iban": e})
|
|
313
|
+
raise serializers.ValidationError({"iban": e}) from e
|
|
314
314
|
|
|
315
315
|
if entry and iban_formatted:
|
|
316
316
|
banking_contact = BankingContact.objects.filter(iban=iban_formatted, entry=entry)
|
|
@@ -325,7 +325,7 @@ class BankingContactSerializer(wb_serializers.ModelSerializer):
|
|
|
325
325
|
try:
|
|
326
326
|
BIC(swift_bic_repr)
|
|
327
327
|
except ValueError as e:
|
|
328
|
-
raise serializers.ValidationError({"swift_bic": e})
|
|
328
|
+
raise serializers.ValidationError({"swift_bic": e}) from e
|
|
329
329
|
return data
|
|
330
330
|
|
|
331
331
|
class Meta:
|
|
@@ -364,8 +364,8 @@ class SocialMediaContactSerializer(wb_serializers.ModelSerializer):
|
|
|
364
364
|
url = data.get("url", self.instance.url if self.instance else "")
|
|
365
365
|
try:
|
|
366
366
|
URLValidator()(url)
|
|
367
|
-
except ValidationError:
|
|
368
|
-
raise serializers.ValidationError({"url": _("The URL you provided seems to be wrong.")})
|
|
367
|
+
except ValidationError as e:
|
|
368
|
+
raise serializers.ValidationError({"url": _("The URL you provided seems to be wrong.")}) from e
|
|
369
369
|
|
|
370
370
|
if self.instance and (
|
|
371
371
|
((data_entry := data.get("entry")) != self.instance.entry)
|
|
@@ -181,7 +181,7 @@ class EntryModelSerializer(wb_serializers.ModelSerializer):
|
|
|
181
181
|
read_only=True,
|
|
182
182
|
required=False,
|
|
183
183
|
)
|
|
184
|
-
is_primary_employer = wb_serializers.BooleanField(
|
|
184
|
+
is_primary_employer = wb_serializers.BooleanField(read_only=True)
|
|
185
185
|
position_in_company = wb_serializers.CharField(
|
|
186
186
|
allow_null=True,
|
|
187
187
|
default="",
|
|
@@ -192,19 +192,26 @@ class EntryModelSerializer(wb_serializers.ModelSerializer):
|
|
|
192
192
|
read_only=True,
|
|
193
193
|
required=False,
|
|
194
194
|
)
|
|
195
|
-
primary_address = wb_serializers.CharField(
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
195
|
+
primary_address = wb_serializers.CharField(
|
|
196
|
+
allow_null=True, read_only=True, required=False, label=_("Primary Address")
|
|
197
|
+
)
|
|
198
|
+
primary_email = wb_serializers.CharField(
|
|
199
|
+
allow_null=True, required=False, read_only=False, label=_("Primary Email")
|
|
200
|
+
)
|
|
201
|
+
primary_manager_repr = wb_serializers.CharField(
|
|
202
|
+
allow_null=True, read_only=True, required=False, label=_("Primary Manager")
|
|
203
|
+
)
|
|
204
|
+
primary_telephone = wb_serializers.TelephoneField(
|
|
205
|
+
allow_null=True,
|
|
206
|
+
required=False,
|
|
207
|
+
label=_("Primary Telephone"),
|
|
208
|
+
)
|
|
209
|
+
primary_website = wb_serializers.URLField(allow_null=True, required=False, label=_("Primary Website"))
|
|
210
|
+
primary_social = wb_serializers.URLField(allow_null=True, required=False, label=_("Primary Social"))
|
|
199
211
|
profile_image = wb_serializers.ImageField(allow_null=True, required=False, label=_("Profile Image"))
|
|
200
212
|
_relationship_managers = PersonRepresentationSerializer(many=True, source="relationship_managers")
|
|
201
213
|
_social_media = SocialMediaContactRepresentationSerializer(many=True, read_only=True, source="social_media")
|
|
202
|
-
primary_manager = wb_serializers.PrimaryKeyRelatedField(
|
|
203
|
-
queryset=lambda: Person.objects.filter_only_internal(),
|
|
204
|
-
default=wb_serializers.CurrentUserDefault("profile"),
|
|
205
|
-
label=_("Primary Manager"),
|
|
206
|
-
required=False,
|
|
207
|
-
)
|
|
214
|
+
primary_manager = wb_serializers.PrimaryKeyRelatedField(label=_("Primary Manager"), required=False, read_only=True)
|
|
208
215
|
_primary_manager = InternalUserProfileRepresentationSerializer(source="primary_manager")
|
|
209
216
|
|
|
210
217
|
@wb_serializers.register_resource()
|
|
@@ -252,8 +259,8 @@ class EntryModelSerializer(wb_serializers.ModelSerializer):
|
|
|
252
259
|
if primary_email := data.get("primary_email", None):
|
|
253
260
|
try:
|
|
254
261
|
validate_email(primary_email)
|
|
255
|
-
except ValidationError:
|
|
256
|
-
raise ValidationError({"primary_email": "Invalid e-mail address"})
|
|
262
|
+
except ValidationError as e:
|
|
263
|
+
raise ValidationError({"primary_email": "Invalid e-mail address"}) from e
|
|
257
264
|
|
|
258
265
|
if primary_telephone := data.get("primary_telephone", None):
|
|
259
266
|
try:
|
|
@@ -265,8 +272,8 @@ class EntryModelSerializer(wb_serializers.ModelSerializer):
|
|
|
265
272
|
data["primary_telephone"] = formatted_number
|
|
266
273
|
else:
|
|
267
274
|
raise ValidationError({"primary_telephone": gettext("Invalid phone number format")})
|
|
268
|
-
except Exception:
|
|
269
|
-
raise ValidationError({"primary_telephone": gettext("Invalid phone number format")})
|
|
275
|
+
except Exception as e:
|
|
276
|
+
raise ValidationError({"primary_telephone": gettext("Invalid phone number format")}) from e
|
|
270
277
|
return super().validate(data)
|
|
271
278
|
|
|
272
279
|
def update(self, instance, validated_data):
|
|
@@ -333,6 +340,8 @@ class EntryModelSerializer(wb_serializers.ModelSerializer):
|
|
|
333
340
|
"primary_email",
|
|
334
341
|
"primary_manager_repr",
|
|
335
342
|
"primary_telephone",
|
|
343
|
+
"primary_website",
|
|
344
|
+
"primary_social",
|
|
336
345
|
"profile_image",
|
|
337
346
|
"relationship_managers",
|
|
338
347
|
"_relationship_managers",
|
|
@@ -9,8 +9,10 @@ from ..models import Entry
|
|
|
9
9
|
class EntryRepresentationSerializer(wb_serializers.RepresentationSerializer):
|
|
10
10
|
_detail = wb_serializers.SerializerMethodField()
|
|
11
11
|
_detail_preview = wb_serializers.HyperlinkField(reverse_name="wbcore:directory:entry-detail")
|
|
12
|
-
primary_email = wb_serializers.CharField(
|
|
13
|
-
primary_telephone = wb_serializers.TelephoneField(
|
|
12
|
+
primary_email = wb_serializers.CharField(read_only=True, required=False, label=_("Primary Email"), allow_null=True)
|
|
13
|
+
primary_telephone = wb_serializers.TelephoneField(
|
|
14
|
+
read_only=True, required=False, label=_("Primary Telephone"), allow_null=True
|
|
15
|
+
)
|
|
14
16
|
|
|
15
17
|
def get__detail(self, obj):
|
|
16
18
|
if obj.is_company:
|
|
@@ -15,13 +15,10 @@ from .relationships import PositionRepresentationSerializer
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
class PersonModelSerializer(ModelTranslateSerializerMixin, EntryModelSerializer):
|
|
18
|
-
activites_count = wb_serializers.IntegerField(default=0, read_only=True)
|
|
19
|
-
|
|
20
18
|
primary_employer_repr = wb_serializers.CharField(read_only=True, required=False, label=_("Primary Employer"))
|
|
21
19
|
has_user_account = wb_serializers.CharField(read_only=True, label=_("User Account"))
|
|
22
20
|
name = wb_serializers.CharField(read_only=True)
|
|
23
21
|
last_connection = wb_serializers.DateTimeField(read_only=True, default=None, label=_("Last Connection"))
|
|
24
|
-
secondary_email = wb_serializers.CharField(default="", label=_("Secondary Email"), allow_null=True, read_only=True)
|
|
25
22
|
personality_profile_red = wb_serializers.RangeSelectField(
|
|
26
23
|
color=WBColor.RED_LIGHT.value, required=False, label=_("Personality Profile Red")
|
|
27
24
|
)
|
|
@@ -32,7 +29,7 @@ class PersonModelSerializer(ModelTranslateSerializerMixin, EntryModelSerializer)
|
|
|
32
29
|
color=WBColor.BLUE_LIGHT.value, required=False, label=_("Personality Profile Blue")
|
|
33
30
|
)
|
|
34
31
|
_specializations = SpecializationRepresentationSerializer(source="specializations", many=True)
|
|
35
|
-
tier = wb_serializers.CharField(
|
|
32
|
+
tier = wb_serializers.CharField(help_text=_("Tier of the primary employer"), label=_("Tier"), required=False)
|
|
36
33
|
|
|
37
34
|
def get_user_account_email(self, obj):
|
|
38
35
|
if hasattr(obj, "user_account"):
|
|
@@ -82,7 +79,6 @@ class PersonModelSerializer(ModelTranslateSerializerMixin, EntryModelSerializer)
|
|
|
82
79
|
"name",
|
|
83
80
|
"computed_str",
|
|
84
81
|
"active_employee",
|
|
85
|
-
"activites_count",
|
|
86
82
|
"activity_heat",
|
|
87
83
|
"addresses",
|
|
88
84
|
"cities",
|
|
@@ -104,9 +100,10 @@ class PersonModelSerializer(ModelTranslateSerializerMixin, EntryModelSerializer)
|
|
|
104
100
|
"primary_manager_repr",
|
|
105
101
|
"primary_employer_repr",
|
|
106
102
|
"primary_telephone",
|
|
103
|
+
"primary_website",
|
|
104
|
+
"primary_social",
|
|
107
105
|
"profile_image",
|
|
108
106
|
"salutation",
|
|
109
|
-
"secondary_email",
|
|
110
107
|
"specializations",
|
|
111
108
|
"_specializations",
|
|
112
109
|
"tier",
|
|
@@ -204,12 +201,14 @@ class PersonModelListSerializer(PersonModelSerializer):
|
|
|
204
201
|
"_cities",
|
|
205
202
|
"customer_status",
|
|
206
203
|
"primary_employer_repr",
|
|
204
|
+
"primary_address",
|
|
205
|
+
"primary_email",
|
|
207
206
|
"primary_manager_repr",
|
|
207
|
+
"primary_website",
|
|
208
|
+
"primary_social",
|
|
209
|
+
"primary_telephone",
|
|
208
210
|
"last_event",
|
|
209
211
|
"position_in_company",
|
|
210
|
-
"primary_email",
|
|
211
|
-
"primary_telephone",
|
|
212
|
-
"primary_telephone",
|
|
213
212
|
"tier",
|
|
214
213
|
"_additional_resources",
|
|
215
214
|
)
|
|
@@ -131,8 +131,8 @@ class RelationshipModelSerializer(serializers.ModelSerializer):
|
|
|
131
131
|
data["from_entry_id"] = self.instance.from_entry.id
|
|
132
132
|
else:
|
|
133
133
|
data["from_entry_id"] = self.context["view"].kwargs["entry_id"]
|
|
134
|
-
except KeyError:
|
|
135
|
-
raise ValidationError(_("From entry has to be set."))
|
|
134
|
+
except KeyError as e:
|
|
135
|
+
raise ValidationError(_("From entry has to be set.")) from e
|
|
136
136
|
from_entry = data.get("from_entry", getattr(self.instance, "from_entry", None))
|
|
137
137
|
to_entry = data.get("to_entry", getattr(self.instance, "to_entry", None))
|
|
138
138
|
|
|
@@ -5,6 +5,7 @@ from django.db.models.signals import pre_migrate
|
|
|
5
5
|
from pytest_factoryboy import register
|
|
6
6
|
from wbcore.contrib.authentication.factories import InternalUserFactory, UserFactory
|
|
7
7
|
from wbcore.contrib.geography.tests.signals import app_pre_migration
|
|
8
|
+
from wbcore.contrib.currency.factories import CurrencyFactory
|
|
8
9
|
from wbcore.tests.conftest import *
|
|
9
10
|
|
|
10
11
|
from ..factories import (
|
|
@@ -45,6 +46,7 @@ register(RelationshipFactory)
|
|
|
45
46
|
register(RelationshipTypeFactory)
|
|
46
47
|
register(CustomerStatusFactory)
|
|
47
48
|
register(CompanyTypeFactory)
|
|
49
|
+
register(CurrencyFactory)
|
|
48
50
|
|
|
49
51
|
|
|
50
52
|
@pytest.fixture(autouse=True, scope="session")
|
|
@@ -2,7 +2,17 @@ import inspect
|
|
|
2
2
|
import re
|
|
3
3
|
from collections import defaultdict
|
|
4
4
|
|
|
5
|
-
from django.db.models.signals import
|
|
5
|
+
from django.db.models.signals import (
|
|
6
|
+
ModelSignal,
|
|
7
|
+
post_delete,
|
|
8
|
+
post_init,
|
|
9
|
+
post_migrate,
|
|
10
|
+
post_save,
|
|
11
|
+
pre_delete,
|
|
12
|
+
pre_init,
|
|
13
|
+
pre_migrate,
|
|
14
|
+
pre_save,
|
|
15
|
+
)
|
|
6
16
|
|
|
7
17
|
|
|
8
18
|
class DisableSignals(object):
|
|
@@ -6,7 +6,7 @@ from wbcore.test.signals import custom_update_kwargs, get_custom_factory
|
|
|
6
6
|
from ..factories import (
|
|
7
7
|
BankFactory,
|
|
8
8
|
ParentRelationshipTypeFactory,
|
|
9
|
-
|
|
9
|
+
RandomClientFactory,
|
|
10
10
|
UserIsManagerEntryFactory,
|
|
11
11
|
)
|
|
12
12
|
from ..viewsets import (
|
|
@@ -27,7 +27,7 @@ from ..viewsets import (
|
|
|
27
27
|
|
|
28
28
|
@receiver(get_custom_factory, sender=PersonInChargeRepresentationViewSet)
|
|
29
29
|
def receive_factory_person_in_charge(sender, *args, **kwargs):
|
|
30
|
-
return
|
|
30
|
+
return RandomClientFactory
|
|
31
31
|
|
|
32
32
|
|
|
33
33
|
@receiver(get_custom_factory, sender=RelationshipTypeModelViewSet)
|