wbcore 1.56.7__py2.py3-none-any.whl → 1.57.0__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.
@@ -22,6 +22,7 @@ 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,
@@ -413,6 +414,14 @@ class Entry(ComplexToStringMixin, DeleteToDisableMixin, WBModel):
413
414
  if additional_field_key in self.additional_fields:
414
415
  del self.additional_fields[additional_field_key]
415
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
+
416
425
  @classmethod
417
426
  def get_endpoint_basename(cls):
418
427
  return "wbcore:directory:entry"
@@ -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")
@@ -405,3 +405,24 @@ class TestSpecificModelsRelationships:
405
405
  to_entry=to_entry,
406
406
  )
407
407
  assert rel.__str__() == "John Doe is Type of Jane Doe"
408
+
409
+
410
+ @pytest.mark.django_db
411
+ class TestEntry:
412
+ def test_get_banking_contact(self, entry, banking_contact_factory, currency_factory):
413
+ eur = currency_factory.create()
414
+ usd = currency_factory.create()
415
+
416
+ euro_banking_contact = banking_contact_factory.create(entry=entry, currency=eur)
417
+ assert entry.get_banking_contact(eur) == euro_banking_contact
418
+ assert (
419
+ entry.get_banking_contact(usd) == euro_banking_contact
420
+ ) # even if usd does not exist, we need to return at least a banking contact
421
+
422
+ usd_banking_contact = banking_contact_factory.create(entry=entry, currency=usd, primary=True)
423
+
424
+ assert entry.get_banking_contact(eur) == euro_banking_contact
425
+ assert entry.get_banking_contact(usd) == usd_banking_contact
426
+
427
+ new_primary_usd_banking_contact = banking_contact_factory.create(entry=entry, currency=usd, primary=True)
428
+ assert entry.get_banking_contact(usd) == new_primary_usd_banking_contact
wbcore/filters/mixins.py CHANGED
@@ -106,7 +106,6 @@ class WBCoreFilterMixin:
106
106
  if initial is not None or self.allow_empty_initial:
107
107
  lookup_expr["input_properties"]["initial"] = initial
108
108
 
109
- if self.required:
110
- lookup_expr["input_properties"]["required"] = True
109
+ lookup_expr["input_properties"]["required"] = self.required
111
110
  representation["depends_on"] = self.depends_on
112
111
  return representation, lookup_expr
@@ -10,8 +10,13 @@ class FieldsViewConfig(WBCoreViewConfig):
10
10
  def get_metadata(self) -> dict:
11
11
  fields = defaultdict(dict)
12
12
  if (serializer_class := getattr(self.view, "get_serializer", None)) and (serializer := serializer_class()):
13
+ related_key_fields = []
13
14
  for field_name, field in serializer.fields.items():
14
15
  field_key, field_representation = field.get_representation(self.request, field_name)
16
+ # we need to get the representation of the related field last so that the key update properly (priority to the related field values)
17
+ if "related_key" in field_representation:
18
+ related_key_fields.append((field_key, field_representation))
19
+ fields[field_key].update(field_representation)
20
+ for field_key, field_representation in related_key_fields:
15
21
  fields[field_key].update(field_representation)
16
-
17
22
  return fields
@@ -33,6 +33,8 @@ class WBCoreSerializerFieldMixin:
33
33
  read_only=False,
34
34
  copyable=None,
35
35
  related_key=None,
36
+ on_unsatisfied_deps="read_only",
37
+ clear_dependent_fields=True,
36
38
  **kwargs,
37
39
  ):
38
40
  if not decorators:
@@ -50,6 +52,8 @@ class WBCoreSerializerFieldMixin:
50
52
  self._callable_read_only = read_only
51
53
  read_only = True
52
54
  self.related_key = related_key
55
+ self.on_unsatisfied_deps = on_unsatisfied_deps
56
+ self.clear_dependent_fields = clear_dependent_fields
53
57
  super().__init__(*args, read_only=read_only, **kwargs)
54
58
 
55
59
  def _evaluate_read_only(self, field_name, parent):
@@ -131,6 +135,10 @@ class WBCoreSerializerFieldMixin:
131
135
  representation["math"] = self.math
132
136
  if self.copyable:
133
137
  representation["copyable"] = self.copyable
138
+ if self.on_unsatisfied_deps != "read_only":
139
+ representation["on_unsatisfied_deps"] = self.on_unsatisfied_deps
140
+ if self.clear_dependent_fields is not True:
141
+ representation["clear_dependent_fields"] = self.clear_dependent_fields
134
142
  return field_name, representation
135
143
 
136
144
  def validate_empty_values(self, data):
@@ -58,7 +58,7 @@ class PrimaryKeyRelatedField(WBCoreSerializerFieldMixin, serializers.PrimaryKeyR
58
58
  )
59
59
 
60
60
  def __init__(self, *args, queryset=None, read_only=False, **kwargs):
61
- self.field_type = kwargs.pop("field_type", WBCoreType.SELECT.value)
61
+ self.field_type = kwargs.pop("field_type", WBCoreType.PRIMARY_KEY.value)
62
62
  if callable(read_only) and queryset is not None:
63
63
  self._queryset = queryset # we unset any given queryset to be compliant with the RelatedField assertion
64
64
  queryset = None
@@ -0,0 +1,7 @@
1
+ from reportlab.platypus import Paragraph as BaseParagraph
2
+
3
+
4
+ class FormattedParagraph(BaseParagraph):
5
+ def __init__(self, text, *args, **kwargs):
6
+ text = text.replace("<br>", "<br/>") # convert the HTML line break into a compatible XML line break tag
7
+ super().__init__(text, *args, **kwargs)
wbcore/utils/strings.py CHANGED
@@ -15,7 +15,7 @@ def enumerated_string_join(array):
15
15
  return ""
16
16
 
17
17
 
18
- def format_number(number, decimal: int = 2, **kwargs) -> float | None:
18
+ def format_number(number, decimal: int = 2, **kwargs) -> float | str:
19
19
  """
20
20
  utility function used to serialize an aggregate to a json compatible value
21
21
  Args:
@@ -28,7 +28,7 @@ def format_number(number, decimal: int = 2, **kwargs) -> float | None:
28
28
  try:
29
29
  return float(round(number, decimal))
30
30
  except TypeError:
31
- return None
31
+ return ""
32
32
 
33
33
 
34
34
  class ReferenceIDMixin:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wbcore
3
- Version: 1.56.7
3
+ Version: 1.57.0
4
4
  Author-email: Christopher Wittlinger <c.wittlinger@stainly.com>
5
5
  Requires-Dist: boto3==1.35.*
6
6
  Requires-Dist: celery[redis]==5.*
@@ -318,7 +318,7 @@ wbcore/contrib/directory/migrations/0013_alter_clientmanagerrelationship_options
318
318
  wbcore/contrib/directory/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
319
319
  wbcore/contrib/directory/models/__init__.py,sha256=XtnmU5YUr3SGig6PsSfGsWUaiBaX6kaHShBv3sbxZ14,526
320
320
  wbcore/contrib/directory/models/contacts.py,sha256=8KVCmzNARTzeQgRtXe78QKhJr0SvEJ-aZcsRuYaMIbE,18322
321
- wbcore/contrib/directory/models/entries.py,sha256=S53zghpS18sqZGquAEirMGVuenHhq2Yhdh8ijTScPCw,31904
321
+ wbcore/contrib/directory/models/entries.py,sha256=XXEWJ3UOvs8CgN0AekY7FOy4sNOww5jTpPTdDedYYb0,32365
322
322
  wbcore/contrib/directory/models/relationships.py,sha256=7SZFo1tA7NRzS7_gv_fKwMsPPhawu90eWSrEvij_0rk,22108
323
323
  wbcore/contrib/directory/release_notes/1_0_0.md,sha256=Twbl9RMLO6dbbm5dVoKorw8BecRqAYsKeobcNmDWHu8,165
324
324
  wbcore/contrib/directory/release_notes/1_0_1.md,sha256=yHolV-HwBmIavaPn9pg0ABRgxQ-eKIuiAs-phKb_ix0,285
@@ -352,12 +352,12 @@ wbcore/contrib/directory/static/directory/markdown/documentation/userisclient.md
352
352
  wbcore/contrib/directory/static/directory/markdown/documentation/userismanager.md,sha256=I3ojIVTFZ_bEk8-67jO2Jrctk90kSzX-WrREDfplwpg,1037
353
353
  wbcore/contrib/directory/static/directory/markdown/documentation/website.md,sha256=n8VAXbgxQh9zslLfLB0UhRgliMCvNS2N6gR-K0oTrkY,1453
354
354
  wbcore/contrib/directory/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
355
- wbcore/contrib/directory/tests/conftest.py,sha256=6Png5NaERN8WBcnpw3mM8F6Xg7erCHh0IO-6hdPyT6E,1738
355
+ wbcore/contrib/directory/tests/conftest.py,sha256=54xK711IfBc6Cj7MweNOGNdkP-ojjMcfqjP1G2XrSn0,1826
356
356
  wbcore/contrib/directory/tests/disable_signals.py,sha256=kgVeTtzItEtLJ7MOVo9KdnRABsMvKBTub-vhHIMKO_M,1727
357
357
  wbcore/contrib/directory/tests/signals.py,sha256=DqQkJWnq2Y0wTTLh3ICY3qZJLUpGJqiTTSV6YypqsDQ,3217
358
358
  wbcore/contrib/directory/tests/test_configs.py,sha256=VouLg3TpDuxi_ljh8MtJGMhtW_h8OzCo15GyyApW16c,189
359
359
  wbcore/contrib/directory/tests/test_filters.py,sha256=tc4G0XoUoDoiisECXtaftYCG69fdE42-EmkmLcjbN78,2492
360
- wbcore/contrib/directory/tests/test_models.py,sha256=OhqzBiI6B3-yrdsKV1PS0LyJcWwayGPdR7OwU2BDi54,18323
360
+ wbcore/contrib/directory/tests/test_models.py,sha256=L2029y7pTUznRYHXJOKFpy_jdTBZvvbx3KwHMEcNSAM,19304
361
361
  wbcore/contrib/directory/tests/test_permissions.py,sha256=lmGAiE0wtIDJkHEfNk_8NDwqN71FdPuu2qXvSMm0FbM,4231
362
362
  wbcore/contrib/directory/tests/test_serializers.py,sha256=AIa-Rktw4EG2eywMSCz-X1rYcBSmw7Zzx38CghBVGzo,9202
363
363
  wbcore/contrib/directory/tests/test_viewsets.py,sha256=pZJ-D-pxRP1IWNZDrKML_6j4iBcFzv8qpo59qX9MpOU,32624
@@ -966,7 +966,7 @@ wbcore/filters/backends.py,sha256=7XX5LcFrAFE5jvFj5qSjww4VMux8aKRlcQKmZxdIiKY,73
966
966
  wbcore/filters/defaults.py,sha256=poSD8Ww2NumwYjZ01zS0iBsNCmv6Bee1z3bDSYdX17A,1988
967
967
  wbcore/filters/filterset.py,sha256=TTk4mQq9DFCXdyzMq3Ig6e5uIbmjsr4HT2kswOgiuPc,11775
968
968
  wbcore/filters/lookups.py,sha256=IYuQqEcYutiXk9UpzY3qKSCaCR2vyllB0RXBj98o8Ao,1186
969
- wbcore/filters/mixins.py,sha256=_CT4Nrn8vwsANLrIRO4Ghal2aZD6XYTnFOubPPzGuSE,4508
969
+ wbcore/filters/mixins.py,sha256=eIXW2Wq_VO3sXioQKcYdyTvZPHS06tytcGo4ZHEasvA,4487
970
970
  wbcore/filters/utils.py,sha256=wSs0g7mKF6n_ziSEDItfFYcuHwZTXyu78D6LHxzY2Bk,786
971
971
  wbcore/filters/fields/__init__.py,sha256=ZucwBossNTlvcUfRullicg0ovghQEGO0jxY5eQ3UaEs,546
972
972
  wbcore/filters/fields/booleans.py,sha256=6BrK3p1Bv_KIlVCeMOgJ7V8_P8tWQKBnxTOBOBSsGvE,175
@@ -1009,7 +1009,7 @@ wbcore/metadata/configs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG
1009
1009
  wbcore/metadata/configs/base.py,sha256=jxOuuisAAEMjvdvQY_1WSruEaNR9onmXn7W6NN95ogw,2790
1010
1010
  wbcore/metadata/configs/documentations.py,sha256=Wv6vToaalOFkCY_KU8HOddpkfeMKsBoGlla_4LTbJ40,348
1011
1011
  wbcore/metadata/configs/endpoints.py,sha256=peGTXR53IpOYcm0kBqDwMuIxxjjLYHRhDv0XWt6-OYQ,7143
1012
- wbcore/metadata/configs/fields.py,sha256=t_GFdQUUDiCUkk7i9TffFEBDBhRCuD_yaoyUIu9tCMQ,634
1012
+ wbcore/metadata/configs/fields.py,sha256=4R-C_wzz9R5BttzfiWH0MeCDF5_tkvJUGo8sk4XaWPI,1091
1013
1013
  wbcore/metadata/configs/filter_fields.py,sha256=1jZyZHU8rBse2P69xFFRAn8VitEdevz5bPeniMk0vKs,2000
1014
1014
  wbcore/metadata/configs/identifiers.py,sha256=4cntC5IarkENLrBnFf26uyfrZY3b4QDXtugvNc_VRhI,1025
1015
1015
  wbcore/metadata/configs/ordering_fields.py,sha256=9ww1zwCFfL6XKGxMI2RKCcMhRS-dkFi3pYbQVbuKN_A,878
@@ -1103,11 +1103,11 @@ wbcore/serializers/fields/file.py,sha256=tDDK2bITiP7zxl9Ilzja2_gWae_lf9CkO1rDEBP
1103
1103
  wbcore/serializers/fields/fsm.py,sha256=xUYxDj166PDnmDLggI4fShXdSunJVzbc8quFQioM3Yc,700
1104
1104
  wbcore/serializers/fields/json.py,sha256=8SmEOW2hXnTTfuCztaxA8AA3qtTxhCZtft7BJm1yO6o,2225
1105
1105
  wbcore/serializers/fields/list.py,sha256=cYmMBg9M10Qb_5z98CeP3SjE2bV-u7Z0xkzXr-C3xoA,4178
1106
- wbcore/serializers/fields/mixins.py,sha256=_KbdxJDGWFMAH_y6MX_7bXICZ-MXH9ZXV0QAi4uegWk,7155
1106
+ wbcore/serializers/fields/mixins.py,sha256=sP1mEiD5tMZ4yCr-X0IkIY3RZwJcT0JokvontvRsDKw,7613
1107
1107
  wbcore/serializers/fields/number.py,sha256=Lxhiy8KBMA8dzv2nKsHVtAaPgjZMNt0TQTgVujh_2BI,3473
1108
1108
  wbcore/serializers/fields/other.py,sha256=3r_70JH_A_daS99LuwQWwa0LNtyosKW7QKJzZgQA-zo,1131
1109
1109
  wbcore/serializers/fields/primary_key.py,sha256=yTbs5B2QlUX-XKEtop3JpwIPeP-FhM8u-2qDXM5q6u0,676
1110
- wbcore/serializers/fields/related.py,sha256=7LYfPLz-7Kfs4b_tlRdIJGKp34UcfK3M4TbwyD5LjO8,6350
1110
+ wbcore/serializers/fields/related.py,sha256=mq7QhcjSG273G400ZueYJnNVNDlGgnUHLoAHaKRjW_Q,6355
1111
1111
  wbcore/serializers/fields/text.py,sha256=8cmRiH1RpCDGzuUmO1zMmm8uiybXDMqyuBkjFblNMmQ,5060
1112
1112
  wbcore/serializers/fields/types.py,sha256=eiSOajWwlZjFfXnMGjIakAa7WGzXHjtRQwT0LH-2_oA,983
1113
1113
  wbcore/shares/__init__.py,sha256=uhHkbgHoFgbcsxHUPxNNzNs11oIjjQ7zIxG8FzsREAI,32
@@ -1211,12 +1211,13 @@ wbcore/utils/numbers.py,sha256=KaC2yNmaVMwe05uRvGvC_ayWJW_1dOgjswlqsB-QeoM,2289
1211
1211
  wbcore/utils/prettytable.py,sha256=RnZ9VZpSZBaOVPyvcbdD17PeKp6pNN57PDfyILy1nlg,877
1212
1212
  wbcore/utils/print.py,sha256=_CBbuAf2ZbjXQBedcvhe6jZAfNq2kjC_ImWlWDbeRCc,725
1213
1213
  wbcore/utils/renderers.py,sha256=2q1ATrmzFFe03ofuKn2WZ3hK53aFwyEwCVbK0YxkdDM,520
1214
+ wbcore/utils/reportlab.py,sha256=gAvcZqpsx0-M9DxW_GvnXQbPFilmf18tQKhK3DqU-9Q,309
1214
1215
  wbcore/utils/rrules.py,sha256=oqg1eY_X7CLN--UkTjPsKuF_FrtKi1no9-ITvYerrXM,2743
1215
1216
  wbcore/utils/serializers.py,sha256=fn__UYJolYjg063OHmAt7zC9zxMxsqrVERpGhLzUK3o,418
1216
1217
  wbcore/utils/settings.py,sha256=MCt48ZJO9nOzGPAFYJ-_o0uRCDUt3_yzEek6m4oZTYg,198
1217
1218
  wbcore/utils/signals.py,sha256=sNDbYKcjTsACpod50dB_TgYC-f37aN0N_M_DMJgTiMA,1132
1218
1219
  wbcore/utils/string_loader.py,sha256=AWmn40nM8A1cxoVwpO2lF6YidEfL3JC1du2cank4Dw4,1169
1219
- wbcore/utils/strings.py,sha256=_7IzcjOQqPVbqxnRwGI4PAJrwJa7NmnXqXWxMuw5kew,1859
1220
+ wbcore/utils/strings.py,sha256=DvMm2vrEjfxH6Hjf7XvRSo-3eAnLf4oLzxki8xonmNs,1856
1220
1221
  wbcore/utils/task.py,sha256=HlPyALx78lSprsY_ICeI-SrXTPBmRpx8nyVIIrRtKb4,84
1221
1222
  wbcore/utils/urls.py,sha256=BjmavE84QYECWDKyV3dENn8GQqwdBmX6MqXyCjmwmbA,2137
1222
1223
  wbcore/utils/views.py,sha256=XnWQqMjAi6dXTF-ZYF9FHU1a7cDpAymcuZRt8g_cEqI,8541
@@ -1229,6 +1230,6 @@ wbcore/viewsets/generics.py,sha256=lKDq9UY_Tyc56u1bqaIEvHGgoaXwXxpZ1c3fLVteptI,1
1229
1230
  wbcore/viewsets/mixins.py,sha256=IdHd_uixOv3ExKoHxTgL5Bt8OELIwfYwhBZm0nsvZfc,12054
1230
1231
  wbcore/viewsets/utils.py,sha256=4520Ij3ASM8lOa8QZkCqbBfOexVRiZu688eW-PGqMOA,882
1231
1232
  wbcore/viewsets/viewsets.py,sha256=FPPESunEjlunDr5VFsjTfsquTS3iDSQkw0H6QjMKPqk,6574
1232
- wbcore-1.56.7.dist-info/METADATA,sha256=wUZw8P3Rfudayh6ulfJYieR4lWeV-w62wavr1ocxJDk,2332
1233
- wbcore-1.56.7.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
1234
- wbcore-1.56.7.dist-info/RECORD,,
1233
+ wbcore-1.57.0.dist-info/METADATA,sha256=S2Im_-ZfGaGiK-1IaNBNvJUXbQuMDoR0jGNSOc7UDgQ,2332
1234
+ wbcore-1.57.0.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
1235
+ wbcore-1.57.0.dist-info/RECORD,,