creme-crm 2.7.3__py3-none-any.whl → 2.7.5__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 (36) hide show
  1. creme/__init__.py +1 -1
  2. creme/creme_config/bricks.py +2 -0
  3. creme/creme_config/locale/fr/LC_MESSAGES/django.mo +0 -0
  4. creme/creme_config/locale/fr/LC_MESSAGES/django.po +2 -2
  5. creme/creme_config/static/chantilly/creme_config/css/creme_config.css +1 -1
  6. creme/creme_config/static/icecream/creme_config/css/creme_config.css +3 -2
  7. creme/creme_config/tests/test_custom_form.py +13 -0
  8. creme/creme_config/views/custom_form.py +5 -4
  9. creme/creme_core/apps.py +5 -1
  10. creme/creme_core/core/enumerable.py +6 -4
  11. creme/creme_core/creme_jobs/notification_emails_sender.py +9 -4
  12. creme/creme_core/enumerators.py +17 -1
  13. creme/creme_core/forms/enumerable.py +24 -10
  14. creme/creme_core/locale/fr/LC_MESSAGES/django.mo +0 -0
  15. creme/creme_core/locale/fr/LC_MESSAGES/django.po +4 -1
  16. creme/creme_core/models/fields_config.py +3 -4
  17. creme/creme_core/static/chantilly/creme_core/css/header_menu.css +2 -0
  18. creme/creme_core/static/icecream/creme_core/css/header_menu.css +2 -0
  19. creme/creme_core/tests/core/test_enumerable.py +28 -0
  20. creme/creme_core/tests/creme_jobs/test_notification_emails_sender.py +2 -3
  21. creme/creme_core/tests/forms/test_enumerable.py +143 -0
  22. creme/creme_core/tests/forms/test_widgets.py +3 -2
  23. creme/recurrents/migrations/0001_initial.py +4 -3
  24. creme/recurrents/models/recurrentgenerator.py +7 -4
  25. creme/reports/locale/fr/LC_MESSAGES/django.mo +0 -0
  26. creme/reports/locale/fr/LC_MESSAGES/django.po +4 -1
  27. creme/reports/templates/reports/bricks/report-hat-bar.html +6 -2
  28. creme/reports/templates/reports/preview_report.html +6 -1
  29. creme/reports/tests/test_report.py +37 -1
  30. creme/reports/views/export.py +2 -1
  31. {creme_crm-2.7.3.dist-info → creme_crm-2.7.5.dist-info}/METADATA +2 -2
  32. {creme_crm-2.7.3.dist-info → creme_crm-2.7.5.dist-info}/RECORD +36 -36
  33. {creme_crm-2.7.3.dist-info → creme_crm-2.7.5.dist-info}/WHEEL +1 -1
  34. {creme_crm-2.7.3.dist-info → creme_crm-2.7.5.dist-info}/entry_points.txt +0 -0
  35. {creme_crm-2.7.3.dist-info → creme_crm-2.7.5.dist-info}/licenses/LICENSE.txt +0 -0
  36. {creme_crm-2.7.3.dist-info → creme_crm-2.7.5.dist-info}/top_level.txt +0 -0
creme/__init__.py CHANGED
@@ -1,4 +1,4 @@
1
- __version__ = '2.7.3'
1
+ __version__ = '2.7.5'
2
2
 
3
3
 
4
4
  def get_version():
@@ -358,6 +358,8 @@ class CustomFieldsBrick(Brick):
358
358
  _ContentTypeWrapper(get_ct(ct_id), ct_cfields)
359
359
  for ct_id, ct_cfields in cfields_per_ct_id.items()
360
360
  ]
361
+ sort_key = collator.sort_key
362
+ ctypes.sort(key=lambda wrp: sort_key(str(wrp.ctype)))
361
363
 
362
364
  return self._render(self.get_template_context(
363
365
  context,
@@ -8,7 +8,7 @@ msgid ""
8
8
  msgstr ""
9
9
  "Project-Id-Version: Creme Creme-Config 2.7\n"
10
10
  "Report-Msgid-Bugs-To: \n"
11
- "POT-Creation-Date: 2025-07-28 16:00+0200\n"
11
+ "POT-Creation-Date: 2026-01-12 18:00+0100\n"
12
12
  "Last-Translator: Hybird <contact@hybird.org>\n"
13
13
  "Language: fr\n"
14
14
  "MIME-Version: 1.0\n"
@@ -2087,7 +2087,7 @@ msgid "Change the password"
2087
2087
  msgstr "Changer le mot de passe"
2088
2088
 
2089
2089
  msgid "Edit this user"
2090
- msgstr "Modifier cette utilisateur"
2090
+ msgstr "Modifier cet utilisateur"
2091
2091
 
2092
2092
  msgid "You can't delete the current user."
2093
2093
  msgstr "Vous ne pouvez pas supprimer l'utilisateur courant."
@@ -942,7 +942,7 @@ li.ui-creme-navigation-item-id_creme_config-main > svg:nth-child(2) {
942
942
  white-space: nowrap;
943
943
  }
944
944
 
945
- .creme_config-instances-bricks-brick td.instancebrick-config-error {
945
+ .creme_config-instances-bricks-brick td.instancebrick-config-errors span {
946
946
  font-weight: 600;
947
947
  color: red;
948
948
  }
@@ -938,9 +938,10 @@ li.ui-creme-navigation-item-id_creme_config-main > svg:nth-child(2) {
938
938
  white-space: nowrap;
939
939
  }
940
940
 
941
- .creme_config-instances-bricks-brick td.instancebrick-config-error {
941
+ .creme_config-instances-bricks-brick td.instancebrick-config-errors span {
942
942
  font-weight: 600;
943
- color: red;
943
+ color: rgb(215, 61, 0);
944
+ text-transform: uppercase;
944
945
  }
945
946
 
946
947
  /* CustomBricksConfig brick */
@@ -1598,6 +1598,19 @@ class CustomFormTestCase(BrickTestCaseMixin, CremeTestCase):
1598
1598
  reverse('creme_config__delete_custom_form_cell', args=(cfci.id,)),
1599
1599
  data={'cell_key': cell_to_dell.key},
1600
1600
  )
1601
+ self.assertListEqual(
1602
+ [
1603
+ {
1604
+ 'name': 'General', 'layout': LAYOUT_REGULAR,
1605
+ 'cells': [
1606
+ {'type': 'regular_field', 'value': 'user'},
1607
+ {'type': 'regular_field', 'value': 'name'},
1608
+ ]
1609
+ },
1610
+ {'group_id': FakeAddressGroup.extra_group_id},
1611
+ ],
1612
+ self.refresh(cfci).groups_as_dicts(),
1613
+ )
1601
1614
 
1602
1615
  @parameterized.expand([
1603
1616
  (0, LAYOUT_DUAL_FIRST),
@@ -1,6 +1,6 @@
1
1
  ################################################################################
2
2
  # Creme is a free/open-source Customer Relationship Management software
3
- # Copyright (C) 2020-2025 Hybird
3
+ # Copyright (C) 2020-2026 Hybird
4
4
  #
5
5
  # This program is free software: you can redistribute it and/or modify
6
6
  # it under the terms of the GNU Affero General Public License as published by
@@ -318,8 +318,9 @@ class CustomFormCellDeletion(BaseCustomFormDeletion):
318
318
  desc = self.get_customform_descriptor()
319
319
 
320
320
  groups = []
321
- found = False
321
+ found = False # Found in any group
322
322
  for group in self.get_groups():
323
+ found_in_group = False
323
324
  cells = []
324
325
 
325
326
  # TODO: better API for group.cells ?
@@ -327,11 +328,11 @@ class CustomFormCellDeletion(BaseCustomFormDeletion):
327
328
  if cell.key != cell_key:
328
329
  cells.append(cell)
329
330
  else:
330
- found = True
331
+ found = found_in_group = True
331
332
 
332
333
  groups.append(
333
334
  FieldGroup(name=group.name, cells=cells, layout=group.layout)
334
- if found else
335
+ if found_in_group else
335
336
  group
336
337
  )
337
338
 
creme/creme_core/apps.py CHANGED
@@ -1,6 +1,6 @@
1
1
  ################################################################################
2
2
  # Creme is a free/open-source Customer Relationship Management software
3
- # Copyright (C) 2015-2025 Hybird
3
+ # Copyright (C) 2015-2026 Hybird
4
4
  #
5
5
  # This program is free software: you can redistribute it and/or modify
6
6
  # it under the terms of the GNU Affero General Public License as published by
@@ -547,6 +547,7 @@ class CremeCoreConfig(CremeAppConfig):
547
547
 
548
548
  def register_enumerable(self, enumerable_registry):
549
549
  from django.contrib.auth import get_user_model
550
+ from django.contrib.contenttypes.models import ContentType
550
551
 
551
552
  from . import enumerators, models
552
553
  from .core.enumerable import QSEnumerator
@@ -558,6 +559,9 @@ class CremeCoreConfig(CremeAppConfig):
558
559
  # enumerators.EntityEnumerator,
559
560
  # )
560
561
  enumerable_registry.register_related_model(
562
+ model=ContentType,
563
+ enumerator_class=enumerators.ContentTypeEnumerator,
564
+ ).register_related_model(
561
565
  model=get_user_model(),
562
566
  enumerator_class=enumerators.UserEnumerator,
563
567
  ).register_related_model(
@@ -1,6 +1,6 @@
1
1
  ################################################################################
2
2
  # Creme is a free/open-source Customer Relationship Management software
3
- # Copyright (C) 2018-2025 Hybird
3
+ # Copyright (C) 2018-2026 Hybird
4
4
  #
5
5
  # This program is free software: you can redistribute it and/or modify
6
6
  # it under the terms of the GNU Affero General Public License as published by
@@ -119,7 +119,8 @@ def get_enum_search_fields(field):
119
119
 
120
120
  class EmptyEnumerator(Enumerator):
121
121
  """Class which can enumerate nothing. Used as a placeholder if the enumerator
122
- cannot be found in the registry"""
122
+ cannot be found in the registry.
123
+ """
123
124
  def choices(self, *args, **kwargs):
124
125
  # To keep compatibility with previous versions, calling an EmptyEnumerator will
125
126
  # not raise but just create a log and a broken select.
@@ -158,8 +159,9 @@ class QSEnumerator(Enumerator):
158
159
 
159
160
  if not search_fields:
160
161
  raise ValueError(
161
- f'This field has no search fields : the model {field.model} of {field} do not'
162
- 'have _search_fields attribute or visible CharField'
162
+ f'This field has no search fields; the model {field.remote_field.model} '
163
+ f'referenced by the field <{field}> do not have "_search_fields" '
164
+ f'attribute or visible CharField'
163
165
  )
164
166
 
165
167
  self.search_fields = search_fields
@@ -1,6 +1,6 @@
1
1
  ################################################################################
2
2
  # Creme is a free/open-source Customer Relationship Management software
3
- # Copyright (C) 2024 Hybird
3
+ # Copyright (C) 2024-2026 Hybird
4
4
  #
5
5
  # This program is free software: you can redistribute it and/or modify
6
6
  # it under the terms of the GNU Affero General Public License as published by
@@ -52,15 +52,20 @@ class _NotificationEmailsSenderType(JobType):
52
52
  EMAIL_SENDER = settings.EMAIL_SENDER
53
53
  messages = []
54
54
 
55
+ def clean_subject(subject):
56
+ return ' '.join(
57
+ stripped for line in subject.splitlines() if (stripped := line.strip())
58
+ )
59
+
55
60
  for notif in notifications:
56
61
  user = notif.user
57
62
  content = notif.content
58
63
 
59
64
  msg = EmailMultiAlternatives(
60
- subject=self.subject_prefix.format(
65
+ subject=clean_subject(self.subject_prefix.format(
61
66
  software=settings.SOFTWARE_LABEL,
62
67
  subject=content.get_subject(user=user),
63
- ),
68
+ )),
64
69
  body=content.get_body(user=user),
65
70
  from_email=EMAIL_SENDER,
66
71
  to=[user.email],
@@ -75,7 +80,7 @@ class _NotificationEmailsSenderType(JobType):
75
80
  with get_connection() as connection:
76
81
  connection.send_messages(messages)
77
82
  except Exception as e:
78
- logger.critical('Error while sending reminder emails (%s)', e)
83
+ logger.critical('Error while sending notification emails (%s)', e)
79
84
  JobResult.objects.create(
80
85
  job=job,
81
86
  messages=[
@@ -1,6 +1,6 @@
1
1
  ################################################################################
2
2
  # Creme is a free/open-source Customer Relationship Management software
3
- # Copyright (C) 2018-2024 Hybird
3
+ # Copyright (C) 2018-2026 Hybird
4
4
  #
5
5
  # This program is free software: you can redistribute it and/or modify
6
6
  # it under the terms of the GNU Affero General Public License as published by
@@ -53,6 +53,22 @@ class EntityEnumerator(enumerable.QSEnumerator):
53
53
  return EntityCredentials.filter(user=user, queryset=qs)
54
54
 
55
55
 
56
+ class ContentTypeEnumerator(enumerable.Enumerator):
57
+ def choices(self, user, *, term=None, only=None, limit=None):
58
+ logger.critical(
59
+ 'The field %s seems to be a basic FK to ContentType; use an '
60
+ 'EntityCTypeForeignKey if you reference only CremeEntities, or '
61
+ 'tag the field as not viewable.',
62
+ self.field
63
+ )
64
+
65
+ return [{'value': 0, 'label': _('Error (please contact your administrator)')}]
66
+
67
+ # TODO ??
68
+ # def to_python(self, user, values):
69
+ # return [c for c in entity_ctypes() if c.id in values]
70
+
71
+
56
72
  class UserEnumerator(enumerable.QSEnumerator):
57
73
  search_fields = ('first_name', 'last_name', 'username')
58
74
 
@@ -1,6 +1,6 @@
1
1
  ################################################################################
2
2
  # Creme is a free/open-source Customer Relationship Management software
3
- # Copyright (C) 2022-2025 Hybird
3
+ # Copyright (C) 2022-2026 Hybird
4
4
  #
5
5
  # This program is free software: you can redistribute it and/or modify
6
6
  # it under the terms of the GNU Affero General Public License as published by
@@ -260,30 +260,35 @@ class EnumerableSelect(widgets.Select):
260
260
 
261
261
  def get_context(self, name, value, attrs):
262
262
  context = super().get_context(name, value, attrs)
263
- enumerable = self.enumerable
264
-
265
- choices, more = enumerable.groups(
266
- selected_values=[value] if value else None
267
- ) if enumerable is not None else ((), False)
263
+ choices, more = self.get_enum_groups(value)
268
264
 
269
265
  context['widget']['choices'] = choices
270
266
  self.build_enum_attrs(context['widget']['attrs'], more)
271
267
 
272
268
  return context
273
269
 
270
+ def get_enum_groups(self, value):
271
+ enumerable = self.enumerable
272
+
273
+ return enumerable.groups(
274
+ selected_values=[value] if value else None
275
+ ) if enumerable is not None else ((), False)
276
+
274
277
  def build_enum_attrs(self, attrs, more):
278
+ enumerable = self.enumerable
279
+
275
280
  if more:
276
281
  attrs.update({
277
- 'data-enum-url': self.enumerable.url,
278
- 'data-enum-limit': self.enumerable.limit,
282
+ 'data-enum-url': enumerable.url,
283
+ 'data-enum-limit': enumerable.limit,
279
284
  })
280
285
  attrs.setdefault('data-enum-cache', 'true')
281
286
  attrs.setdefault('data-enum-debounce', self.ENUMERABLE_DEFAULT_DEBOUNCE_DELAY)
282
287
 
283
288
  attrs['data-allow-clear'] = str(not self.is_required).lower()
284
289
 
285
- if self.enumerable.empty_label:
286
- attrs['data-placeholder'] = self.enumerable.empty_label
290
+ if enumerable.empty_label:
291
+ attrs['data-placeholder'] = enumerable.empty_label
287
292
 
288
293
  if self.create_url:
289
294
  attrs['data-create-url'] = self.create_url
@@ -294,6 +299,15 @@ class EnumerableSelect(widgets.Select):
294
299
  class EnumerableSelectMultiple(EnumerableSelect):
295
300
  allow_multiple_selected = True
296
301
 
302
+ def get_enum_groups(self, value):
303
+ # The value is already a list here, so we need to override the default
304
+ # behaviour
305
+ enumerable = self.enumerable
306
+
307
+ return enumerable.groups(
308
+ selected_values=value if value else None
309
+ ) if enumerable is not None else ((), False)
310
+
297
311
  def value_from_datadict(self, data, files, name):
298
312
  try:
299
313
  getter = data.getlist
@@ -8,7 +8,7 @@ msgid ""
8
8
  msgstr ""
9
9
  "Project-Id-Version: Creme Creme-Core 2.7\n"
10
10
  "Report-Msgid-Bugs-To: \n"
11
- "POT-Creation-Date: 2025-10-20 17:01+0200\n"
11
+ "POT-Creation-Date: 2026-01-22 17:37+0100\n"
12
12
  "Last-Translator: Hybird <contact@hybird.org>\n"
13
13
  "Language: fr\n"
14
14
  "MIME-Version: 1.0\n"
@@ -889,6 +889,9 @@ msgid_plural "{count} entities deleted."
889
889
  msgstr[0] "{count} Fiche supprimée"
890
890
  msgstr[1] "{count} Fiches supprimées"
891
891
 
892
+ msgid "Error (please contact your administrator)"
893
+ msgstr "Erreur (veuillez contacter votre administrateur)"
894
+
892
895
  msgid "Teams"
893
896
  msgstr "Équipes"
894
897
 
@@ -427,12 +427,11 @@ class FieldsConfig(CremeModel):
427
427
  try:
428
428
  form_fields[field_name].required = True
429
429
  except KeyError:
430
- # TODO: we need the form class for a better message
431
- logger.info(
430
+ logger.warning(
432
431
  'The field "%s" has been configured to be required '
433
- 'but the current form does not use this field ; '
432
+ 'but the form %s does not use this field; '
434
433
  'so we add it.',
435
- field_name,
434
+ field_name, type(form),
436
435
  )
437
436
  # TODO: is it possible that field does not exist any more ?
438
437
  form_fields[field_name] = (
@@ -397,6 +397,8 @@ span.create-group-entry {
397
397
 
398
398
  .notification-box .notification-panel {
399
399
  position: absolute;
400
+ overflow: auto;
401
+ max-height: 80vh;
400
402
  width: 512px;
401
403
  top: 35px;
402
404
  left: -380px;
@@ -397,6 +397,8 @@ span.create-group-entry {
397
397
 
398
398
  .notification-box .notification-panel {
399
399
  position: absolute;
400
+ overflow: auto;
401
+ max-height: 80vh;
400
402
  width: 512px;
401
403
  top: 35px;
402
404
  left: -380px;
@@ -5,6 +5,7 @@ from unittest.case import skipIf
5
5
  from django.contrib.contenttypes.models import ContentType
6
6
  from django.core.exceptions import FieldDoesNotExist
7
7
  from django.db import connection, models
8
+ from django.db.models import ForeignKey
8
9
  from django.utils.translation import gettext as _
9
10
  from django.utils.translation import override as override_language
10
11
 
@@ -14,6 +15,7 @@ from creme.creme_core.core.enumerable import (
14
15
  EnumerableRegistry,
15
16
  Enumerator,
16
17
  QSEnumerator,
18
+ enumerable_registry,
17
19
  get_enum_search_fields,
18
20
  )
19
21
  from creme.creme_core.models import (
@@ -28,6 +30,7 @@ from creme.creme_core.models import (
28
30
  FakeOrganisation,
29
31
  FakeReport,
30
32
  FakeTodo,
33
+ HistoryLine,
31
34
  Language,
32
35
  Vat,
33
36
  )
@@ -542,6 +545,31 @@ class EnumerableTestCase(CremeTestCase):
542
545
  ],
543
546
  )
544
547
 
548
+ def test_content_type_enumerator(self):
549
+ user = self.user
550
+ ctype_fk = HistoryLine._meta.get_field('entity_ctype')
551
+ self.assertIsInstance(ctype_fk, ForeignKey)
552
+ self.assertEqual(ContentType, ctype_fk.related_model)
553
+
554
+ e = enumerators.ContentTypeEnumerator(ctype_fk)
555
+
556
+ with self.assertLogs(level='CRITICAL') as logs_manager:
557
+ choices = e.choices(user)
558
+ self.assertListEqual(
559
+ [{'value': 0, 'label': _('Error (please contact your administrator)')}],
560
+ choices,
561
+ )
562
+ self.assertIn(
563
+ 'use an EntityCTypeForeignKey if you reference only CremeEntities',
564
+ logs_manager.output[0],
565
+ )
566
+
567
+ # TODO: need a fake model with a ForeignKey(ContentType, ...)
568
+ self.assertEqual(
569
+ enumerators.ContentTypeEnumerator,
570
+ enumerable_registry._enums_4_models.get(ContentType)
571
+ )
572
+
545
573
  def test_entity_enumerator(self):
546
574
  role = self.create_role(allowed_apps=['creme_core'])
547
575
  self.add_credentials(role, own=['VIEW'])
@@ -64,7 +64,6 @@ class NotificationEmailsSenderTestCase(CremeTestCase):
64
64
  subject1 = 'Hello...'
65
65
  body1 = '...world'
66
66
  html_body1 = '<b>world</b>!'
67
- subject2 = 'Hi!'
68
67
  body2 = 'How are you?'
69
68
  create_notif = partial(
70
69
  Notification.objects.create, channel=chan, user=user, output=OUTPUT_EMAIL,
@@ -72,7 +71,7 @@ class NotificationEmailsSenderTestCase(CremeTestCase):
72
71
  notif1 = create_notif(
73
72
  content=SimpleNotifContent(subject=subject1, body=body1, html_body=html_body1),
74
73
  )
75
- create_notif(content=SimpleNotifContent(subject=subject2, body=body2))
74
+ create_notif(content=SimpleNotifContent(subject='Hi!\nworld\r\n', body=body2))
76
75
  create_notif(
77
76
  content=SimpleNotifContent(subject='Not email', body='Ignored'),
78
77
  output=OUTPUT_WEB,
@@ -97,7 +96,7 @@ class NotificationEmailsSenderTestCase(CremeTestCase):
97
96
  self.assertFalse(message1.attachments)
98
97
  self.assertEqual(
99
98
  _('[Notification from {software}] {subject}').format(
100
- software=SOFTWARE_LABEL, subject=subject2,
99
+ software=SOFTWARE_LABEL, subject='Hi! world',
101
100
  ),
102
101
  message1.subject,
103
102
  )
@@ -19,6 +19,7 @@ from creme.creme_core.forms.enumerable import (
19
19
  EnumerableChoice,
20
20
  EnumerableModelChoiceField,
21
21
  EnumerableSelect,
22
+ EnumerableSelectMultiple,
22
23
  FieldEnumerableChoiceSet,
23
24
  )
24
25
  from creme.creme_core.models import (
@@ -451,6 +452,148 @@ class EnumerableSelectTestCase(CremeTestCase):
451
452
  )
452
453
 
453
454
 
455
+ @override_settings(FORM_ENUMERABLE_LIMIT=100)
456
+ class EnumerableSelectMultipleTestCase(CremeTestCase):
457
+ maxDiff = None
458
+
459
+ def test_render_no_url(self):
460
+ farming, industry, software = FakeSector.objects.order_by('pk')[:3]
461
+ sector_A = FakeSector.objects.create(title='Sector A')
462
+ sector_B = FakeSector.objects.create(title='Sector B')
463
+ sector_C = FakeSector.objects.create(title='Sector C')
464
+
465
+ enumerable = FieldEnumerableChoiceSet(FakeContact._meta.get_field('sector'))
466
+ widget = EnumerableSelectMultiple(enumerable)
467
+
468
+ self.assertHTMLEqual(
469
+ f'''
470
+ <select class="ui-creme-input ui-creme-widget ui-creme-dselect widget-auto is-enum"
471
+ widget="ui-creme-dselect"
472
+ name="testfield" autocomplete
473
+ data-allow-clear="true" multiple>
474
+ <option value="{farming.pk}">Farming</option>
475
+ <option selected value="{industry.pk}">Industry</option>
476
+ <option value="{software.pk}">Software</option>
477
+ <option value="{sector_A.pk}">Sector A</option>
478
+ <option value="{sector_B.pk}">Sector B</option>
479
+ <option selected value="{sector_C.pk}">Sector C</option>
480
+ </select>
481
+ ''',
482
+ widget.render('testfield', value=(industry.pk, sector_C.pk)),
483
+ )
484
+
485
+ def test_render_url(self):
486
+ farming, industry, software = FakeSector.objects.order_by('pk')[:3]
487
+
488
+ enumerable = FieldEnumerableChoiceSet(FakeContact._meta.get_field('sector'))
489
+ widget = EnumerableSelectMultiple(enumerable)
490
+ widget.create_url = url = reverse(
491
+ 'creme_config__create_instance_from_widget', args=('creme_core', 'fake_sector'),
492
+ )
493
+
494
+ self.assertHTMLEqual(
495
+ f'''
496
+ <select class="ui-creme-input ui-creme-widget ui-creme-dselect widget-auto is-enum"
497
+ widget="ui-creme-dselect"
498
+ name="testfield" autocomplete
499
+ data-create-url="{url}"
500
+ data-allow-clear="true" multiple>
501
+ <option value="{farming.pk}">Farming</option>
502
+ <option selected value="{industry.pk}">Industry</option>
503
+ <option selected value="{software.pk}">Software</option>
504
+ </select>
505
+ ''',
506
+ widget.render('testfield', value=(industry.pk, software.pk)),
507
+ )
508
+
509
+ def test_render__more(self):
510
+ farming, industry, software = FakeSector.objects.order_by('pk')[:3]
511
+ sector_A = FakeSector.objects.create(title='Sector A')
512
+ FakeSector.objects.create(title='Sector B')
513
+ FakeSector.objects.create(title='Sector C')
514
+
515
+ enumerable = FieldEnumerableChoiceSet(FakeContact._meta.get_field('sector'), limit=4)
516
+ widget = EnumerableSelectMultiple(enumerable)
517
+
518
+ self.assertHTMLEqual(
519
+ f'''
520
+ <select class="ui-creme-input ui-creme-widget ui-creme-dselect widget-auto is-enum"
521
+ widget="ui-creme-dselect"
522
+ name="testfield" autocomplete
523
+ data-allow-clear="true"
524
+ data-enum-url="{enumerable.url}"
525
+ data-enum-limit="{enumerable.limit}"
526
+ data-enum-cache="true"
527
+ data-enum-debounce="300"
528
+ multiple>
529
+ <option value="{farming.pk}">Farming</option>
530
+ <option selected value="{industry.pk}">Industry</option>
531
+ <option value="{software.pk}">Software</option>
532
+ <option selected value="{sector_A.pk}">Sector A</option>
533
+ </select>
534
+ ''',
535
+ widget.render('testfield', value=(industry.pk, sector_A.pk)),
536
+ )
537
+
538
+ def test_render__more__outside_limit(self):
539
+ """Selected values outside the choice limit are added anyway"""
540
+ farming, industry, software = FakeSector.objects.order_by('pk')[:3]
541
+ sector_A = FakeSector.objects.create(title='Sector A')
542
+ FakeSector.objects.create(title='Sector B')
543
+ sector_C = FakeSector.objects.create(title='Sector C')
544
+
545
+ enumerable = FieldEnumerableChoiceSet(FakeContact._meta.get_field('sector'), limit=4)
546
+ widget = EnumerableSelectMultiple(enumerable)
547
+
548
+ self.assertHTMLEqual(
549
+ f'''
550
+ <select class="ui-creme-input ui-creme-widget ui-creme-dselect widget-auto is-enum"
551
+ widget="ui-creme-dselect"
552
+ name="testfield" autocomplete
553
+ data-allow-clear="true"
554
+ data-enum-url="{enumerable.url}"
555
+ data-enum-limit="{enumerable.limit}"
556
+ data-enum-cache="true"
557
+ data-enum-debounce="300"
558
+ multiple>
559
+ <option value="{farming.pk}">Farming</option>
560
+ <option selected value="{industry.pk}">Industry</option>
561
+ <option value="{software.pk}">Software</option>
562
+ <option value="{sector_A.pk}">Sector A</option>
563
+ <option selected value="{sector_C.pk}">Sector C</option>
564
+ </select>
565
+ ''',
566
+ widget.render('testfield', value=(industry.pk, sector_C.pk)),
567
+ )
568
+
569
+ def test_render__more_custom_attrs(self):
570
+ farming, industry, software = FakeSector.objects.order_by('pk')[:3]
571
+
572
+ enumerable = FieldEnumerableChoiceSet(FakeContact._meta.get_field('sector'), limit=2)
573
+ widget = EnumerableSelectMultiple(enumerable, attrs={
574
+ 'data-enum-cache': 'false',
575
+ 'data-enum-debounce': 500,
576
+ })
577
+
578
+ self.assertHTMLEqual(
579
+ f'''
580
+ <select class="ui-creme-input ui-creme-widget ui-creme-dselect widget-auto is-enum"
581
+ widget="ui-creme-dselect"
582
+ name="testfield" autocomplete
583
+ data-allow-clear="true"
584
+ data-enum-url="{enumerable.url}"
585
+ data-enum-limit="{enumerable.limit}"
586
+ data-enum-cache="false"
587
+ data-enum-debounce="500"
588
+ multiple>
589
+ <option value="{farming.pk}">Farming</option>
590
+ <option selected value="{industry.pk}">Industry</option>
591
+ </select>
592
+ ''',
593
+ widget.render('testfield', value=(industry.pk,)),
594
+ )
595
+
596
+
454
597
  @override_settings(FORM_ENUMERABLE_LIMIT=100)
455
598
  class EnumerableModelChoiceFieldTestCase(CremeTestCase):
456
599
  maxDiff = None
@@ -1,4 +1,5 @@
1
1
  import difflib
2
+ from datetime import date
2
3
  from json import loads as json_load
3
4
  from unittest.util import safe_repr
4
5
 
@@ -79,7 +80,7 @@ class CalendarWidgetTestCase(CremeTestCase):
79
80
  def test_render__en(self):
80
81
  name = 'my_calendar'
81
82
  value = self.formfield_value_date(2023, 3, 26)
82
- help_text = _('E.g. {}').format('2025-12-31')
83
+ help_text = _('E.g. {}').format(f'{date.today().year}-12-31')
83
84
  self.assertHTMLEqual(
84
85
  f'<div class="creme-datepicker">'
85
86
  f' <div class="help-text-format">{help_text}</div>'
@@ -96,7 +97,7 @@ class CalendarWidgetTestCase(CremeTestCase):
96
97
  def test_render__fr(self):
97
98
  name = 'calendar'
98
99
  value = self.formfield_value_date(2024, 4, 27)
99
- help_text = _('E.g. {}').format('31/12/2025')
100
+ help_text = _('E.g. {}').format(f'31/12/{date.today().year}')
100
101
  self.assertHTMLEqual(
101
102
  f'<div class="creme-datepicker">'
102
103
  f' <div class="help-text-format">{help_text}</div>'
@@ -35,9 +35,10 @@ class Migration(migrations.Migration):
35
35
  ('is_working', models.BooleanField(default=True, verbose_name='Active?', editable=False)),
36
36
  (
37
37
  'ct',
38
- core_fields.CTypeForeignKey(
38
+ # core_fields.CTypeForeignKey(
39
+ core_fields.EntityCTypeForeignKey(
39
40
  to='contenttypes.ContentType',
40
- editable=False, verbose_name='Type of the recurrent resource'
41
+ editable=False, verbose_name='Type of the recurrent resource',
41
42
  )
42
43
  ),
43
44
  (
@@ -45,7 +46,7 @@ class Migration(migrations.Migration):
45
46
  models.ForeignKey(
46
47
  to='creme_core.CremeEntity', on_delete=CASCADE,
47
48
  related_name='template_set', editable=False,
48
- verbose_name='Related model'
49
+ verbose_name='Related model',
49
50
  )
50
51
  ),
51
52
  ],
@@ -1,6 +1,6 @@
1
1
  ################################################################################
2
2
  # Creme is a free/open-source Customer Relationship Management software
3
- # Copyright (C) 2009-2024 Hybird
3
+ # Copyright (C) 2009-2026 Hybird
4
4
  #
5
5
  # This program is free software: you can redistribute it and/or modify
6
6
  # it under the terms of the GNU Affero General Public License as published by
@@ -21,7 +21,7 @@ from django.urls import reverse
21
21
  from django.utils.translation import gettext_lazy as _
22
22
 
23
23
  from creme.creme_core.models import CremeEntity
24
- from creme.creme_core.models.fields import CTypeForeignKey, DatePeriodField
24
+ from creme.creme_core.models import fields as core_fields
25
25
 
26
26
 
27
27
  class AbstractRecurrentGenerator(CremeEntity):
@@ -31,9 +31,12 @@ class AbstractRecurrentGenerator(CremeEntity):
31
31
  last_generation = models.DateTimeField(
32
32
  _('Date of the last generation'), null=True, editable=False,
33
33
  )
34
- periodicity = DatePeriodField(_('Periodicity of the generation'))
34
+ periodicity = core_fields.DatePeriodField(_('Periodicity of the generation'))
35
35
 
36
- ct = CTypeForeignKey(verbose_name=_('Type of the recurrent resource'), editable=False)
36
+ # ct = core_fields.CTypeForeignKey(
37
+ ct = core_fields.EntityCTypeForeignKey(
38
+ verbose_name=_('Type of the recurrent resource'), editable=False,
39
+ )
37
40
  template = models.ForeignKey(
38
41
  CremeEntity,
39
42
  verbose_name=_('Related model'),
@@ -8,7 +8,7 @@ msgid ""
8
8
  msgstr ""
9
9
  "Project-Id-Version: Creme Reports 2.7\n"
10
10
  "Report-Msgid-Bugs-To: \n"
11
- "POT-Creation-Date: 2025-07-31 10:52+0200\n"
11
+ "POT-Creation-Date: 2026-01-09 18:30+0100\n"
12
12
  "Last-Translator: Hybird <contact@hybird.org>\n"
13
13
  "Language: fr\n"
14
14
  "MIME-Version: 1.0\n"
@@ -613,6 +613,9 @@ msgstr "Type de graphique"
613
613
  msgid "Download CSV"
614
614
  msgstr "Télécharger CSV"
615
615
 
616
+ msgid "You cannot export this type of entity"
617
+ msgstr "Vous ne pouvez pas exporter ce type de fiche"
618
+
616
619
  msgid "Go to the configuration of Reports' filters"
617
620
  msgstr "Aller à la configuration des filtres de Rapports"
618
621
 
@@ -1,5 +1,5 @@
1
1
  {% extends 'creme_core/bricks/generic/hat-bar.html' %}
2
- {% load i18n creme_bricks creme_widgets %}
2
+ {% load i18n creme_bricks creme_perms creme_widgets %}
3
3
  {% load url from creme_core_tags %}
4
4
 
5
5
  {% block buttons %}
@@ -9,7 +9,11 @@
9
9
  </a>
10
10
  </div>
11
11
  <div class='bar-action'>
12
- {% brick_action id='reports-export' url='reports__export_report_filter'|url:object.id label=_('Download CSV') class='bar-button' icon_size='brick-hat-bar-button' icon='document_csv' display='icon' %}
12
+ {% if user|has_perm_to_export:object.ct %}
13
+ {% brick_bar_button action='reports-export' url='reports__export_report_filter'|url:object.id label=_('Download CSV') icon='document_csv' %}
14
+ {% else %}
15
+ {% brick_bar_button action='reports-export' url='' label=_('Download CSV') icon='document_csv' help_text=_('You cannot export this type of entity') enabled=False %}
16
+ {% endif%}
13
17
  </div>
14
18
  {{block.super}}
15
19
  {% endblock %}
@@ -1,5 +1,6 @@
1
1
  {% extends 'creme_core/detailview.html' %}
2
2
  {% load i18n creme_widgets reports_tags %}
3
+ {% load i18n creme_perms creme_widgets %}{# reports_tags #}
3
4
 
4
5
  {% block page_title %}{% blocktranslate %}Preview {{object}}{% endblocktranslate %} - {% endblock %}
5
6
 
@@ -34,7 +35,11 @@
34
35
  <form>{% include 'reports/frags/report_preview_format.html' %}</form>
35
36
  <div class="report-preview-buttons">
36
37
  <button class="ui-creme-actionbutton" type="button" name="generate">{% translate 'Preview' context 'reports-preview' %}</button>
37
- <button class="ui-creme-actionbutton" type="button" name="download">{% translate 'Download as file' %}</button>
38
+ {% if user|has_perm_to_export:object.ct %}
39
+ <button class="ui-creme-actionbutton" type="button" name="download">{% translate 'Download as file' %}</button>
40
+ {% else %}
41
+ <button disabled class="ui-creme-actionbutton" type="button" name="download" title="{% translate 'You cannot export this type of entity'%}" >{% translate 'Download as file' %}</button>
42
+ {% endif %}
38
43
  </div>
39
44
  </div>
40
45
 
@@ -1545,8 +1545,44 @@ class ReportTestCase(BrickTestCaseMixin, BaseReportsTestCase):
1545
1545
  response.text,
1546
1546
  )
1547
1547
 
1548
+ def test_perms(self):
1549
+ user = self.login_as_standard(
1550
+ allowed_apps=['creme_core'], # 'reports'
1551
+ # exportable_models=[FakeContact],
1552
+ )
1553
+ role = user.role
1554
+ self.add_credentials(role=role, own=['VIEW'])
1555
+
1556
+ report = self._create_contacts_report(user=user, name='trinita')
1557
+ url = self._build_export_url(report)
1558
+ data = {'doc_type': 'csv'}
1559
+
1560
+ # App permission --
1561
+ response1 = self.client.get(url, data=data)
1562
+ self.assertContains(
1563
+ response1,
1564
+ status_code=403,
1565
+ text=_('You are not allowed to access to the app: {}').format(_('Reports')),
1566
+ html=True,
1567
+ )
1568
+
1569
+ # Export permission --
1570
+ role.allowed_apps = ['creme_core', 'reports']
1571
+ role.save()
1572
+ response2 = self.client.get(url, data=data)
1573
+ self.assertContains(
1574
+ response2,
1575
+ status_code=403,
1576
+ text=_('You are not allowed to export: {}').format('Test Contact'),
1577
+ html=True,
1578
+ )
1579
+
1548
1580
  def test_report_csv__no_filter(self):
1549
- user = self.login_as_root_and_get()
1581
+ user = self.login_as_standard(
1582
+ allowed_apps=['creme_core', 'reports'],
1583
+ exportable_models=[FakeContact],
1584
+ )
1585
+ self.add_credentials(role=user.role, own=['VIEW'])
1550
1586
 
1551
1587
  self._create_persons(user=user)
1552
1588
  self.assertEqual(3, FakeContact.objects.count())
@@ -1,6 +1,6 @@
1
1
  ################################################################################
2
2
  # Creme is a free/open-source Customer Relationship Management software
3
- # Copyright (C) 2009-2025 Hybird
3
+ # Copyright (C) 2009-2026 Hybird
4
4
  #
5
5
  # This program is free software: you can redistribute it and/or modify
6
6
  # it under the terms of the GNU Affero General Public License as published by
@@ -123,6 +123,7 @@ class Export(generic.base.EntityRelatedMixin, generic.CheckedView):
123
123
 
124
124
  def check_related_entity_permissions(self, entity, user):
125
125
  user.has_perm_to_view_or_die(entity)
126
+ user.has_perm_to_export_or_die(entity.ct)
126
127
 
127
128
  def get_form(self, *, report, request):
128
129
  form = self.form_class(instance=report, user=request.user, data=request.GET)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: creme-crm
3
- Version: 2.7.3
3
+ Version: 2.7.5
4
4
  Summary: A CRM software using the django web framework
5
5
  Home-page: https://www.cremecrm.com
6
6
  Author: hybird.org
@@ -29,7 +29,7 @@ Classifier: Topic :: Office/Business
29
29
  Requires-Python: >=3.10
30
30
  Description-Content-Type: text/markdown
31
31
  License-File: LICENSE.txt
32
- Requires-Dist: django~=5.2.9
32
+ Requires-Dist: django~=5.2.11
33
33
  Requires-Dist: redis~=6.2.0
34
34
  Requires-Dist: Pillow~=11.3.0
35
35
  Requires-Dist: python-dateutil~=2.8.2
@@ -1,4 +1,4 @@
1
- creme/__init__.py,sha256=-fLXAWytd4GaQAXzOpCEPEGKT2bgV8ZnVgqZsbxQqZU,1078
1
+ creme/__init__.py,sha256=8ufKGFm-8CwLXBkQnyjehi3c4t3F8jHij92-zH4dQg8,1078
2
2
  creme/manage.py,sha256=9TahLBSSW_WbL1SZnDw0l1vM69w7MZ7P2BIfLLzquIw,968
3
3
  creme/settings.py,sha256=vFdSBTywLk_rJehLv643xAYJuuwY8nFcaKhUfTEwq-A,62248
4
4
  creme/urls.py,sha256=Dz1YwuwAKPpI3LmI8YdCuS3-2fZtX48xMhJajmqMe5o,2681
@@ -398,7 +398,7 @@ creme/commercial/views/salesman.py,sha256=NpGdoift5OOQl8IIPxi1E1SH8DcQyXffjs41sj
398
398
  creme/commercial/views/strategy.py,sha256=uLiuQVyLJ64TfU74SxE_wrq9nW2hdlszbw_1gK4nNo4,11603
399
399
  creme/creme_config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
400
400
  creme/creme_config/apps.py,sha256=x-JNOK3sbL3syiV0FELoWwG5cdvl41JUp8DxGNrrJuw,5677
401
- creme/creme_config/bricks.py,sha256=lDNVPWILS8mMh_an_A2Wzh4ShVHlShc52xIzun-36wA,54190
401
+ creme/creme_config/bricks.py,sha256=X4d8V62O3QcZO1XeI_zh5cDvRHNducUkEwlE0mKtSDE,54289
402
402
  creme/creme_config/constants.py,sha256=wsFnrmpPHXQIV_OtHU-6PZZXE6zmXzgsNe5bzj9LtTY,894
403
403
  creme/creme_config/menu.py,sha256=I0wTo9Dv0gX9n5210UFNUNL3-Y7MdWKkNzTP7k9zLVg,10344
404
404
  creme/creme_config/models.py,sha256=4vcd-aQDdDv1prId1rzWZ_sAhEQoIbDtlw0MAsi0CiQ,119
@@ -433,13 +433,13 @@ creme/creme_config/forms/user_settings.py,sha256=bux3w9OGDovwVLCCI5fAM8Iaqry2OHR
433
433
  creme/creme_config/forms/widgets.py,sha256=dcK5xDf3ssWPqeIM8EXNCdhChQq_WuzIjf2cRDOUZpo,7594
434
434
  creme/creme_config/forms/workflow.py,sha256=zDCfWd-QaG2ZlWsNCroc1VWbi1QZRreDo1MOjos7agY,7387
435
435
  creme/creme_config/forms/world_settings.py,sha256=S_6yrrqXEvEDl14aLB0Dvo3HQUMA46aFgk2klsfZHQU,3820
436
- creme/creme_config/locale/fr/LC_MESSAGES/django.mo,sha256=K6K-ut1rMID9jMddydUu4vfN1wVyhZMOcHd3zhUYPCA,80859
437
- creme/creme_config/locale/fr/LC_MESSAGES/django.po,sha256=b6cv0Fv1SQeFhyclzwQZbnuI_KMwTRxyG5b9Dc9isNo,92705
436
+ creme/creme_config/locale/fr/LC_MESSAGES/django.mo,sha256=oiHE380EVgNfM0owYAv3gsr-NyFe0F8_UFyrFlnbGLo,80857
437
+ creme/creme_config/locale/fr/LC_MESSAGES/django.po,sha256=DFMzgXaF2E-Scr3XW0_btuFWUlBgmSSpKqD-K-enMPQ,92703
438
438
  creme/creme_config/locale/fr/LC_MESSAGES/djangojs.mo,sha256=ZHWbwGiKj99h5Lb4acUtoyloKpsh8qPbobKCtimVXVc,783
439
439
  creme/creme_config/locale/fr/LC_MESSAGES/djangojs.po,sha256=Us3Bk0N94_2Sr5-sMEMcQYwib-dqqILB5zaYHxeC_n8,1136
440
440
  creme/creme_config/migrations/0001_initial.py,sha256=9rspz_ed0YlIGONcQLvh3-4pxThWEtO6tXpT6613X70,1205
441
441
  creme/creme_config/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
442
- creme/creme_config/static/chantilly/creme_config/css/creme_config.css,sha256=tZLF3jo_FRcX9iYth0W3kTr-j9UQeELDuYeQU_yOiis,31499
442
+ creme/creme_config/static/chantilly/creme_config/css/creme_config.css,sha256=eefiHIyKnbNP9fz7R-CNYHa1R7Fht2kiC2AfP2SqvDw,31505
443
443
  creme/creme_config/static/chantilly/creme_config/css/widgets.css,sha256=NgIheqcQ3L53pRowhrcnAIrXVNbw2D2ZYSTRXmt5kCM,4042
444
444
  creme/creme_config/static/creme_config/js/bricks-config-editor.js,sha256=IK2IqavqQm-dTbweF7uERIupI1RWGj0gx4eTKix6qEA,3424
445
445
  creme/creme_config/static/creme_config/js/button-menu-editor.js,sha256=i95ccfQ63Lvu181Ksib7LZ2HNJiBl0Gze-8mEtqNJSI,3050
@@ -453,7 +453,7 @@ creme/creme_config/static/creme_config/js/tests/button-menu-editor.js,sha256=wsF
453
453
  creme/creme_config/static/creme_config/js/tests/custom-forms-brick.js,sha256=eUknCQuCNvp6uNUTiIi2Ute75O0bk6cNZ52jFTnrFh4,15319
454
454
  creme/creme_config/static/creme_config/js/tests/menu-editor.js,sha256=NoAaFeCIRO0sObv5VV-yyuQpTmw--WU189UKzHRDGpU,16264
455
455
  creme/creme_config/static/creme_config/js/tests/settings-menu.js,sha256=eWydR3Jf-zNcbN6whoSr7VBEiQgCZdPkPC_RKsa_slI,2226
456
- creme/creme_config/static/icecream/creme_config/css/creme_config.css,sha256=Lt7PK8xVjCAm0a_C56stK5pXO5M9Ge8aT6vNg7BqAr8,30607
456
+ creme/creme_config/static/icecream/creme_config/css/creme_config.css,sha256=-ho71txQ3vPkmooMJ1NoUpd4IuakYxJF0ETr3hW1pFc,30656
457
457
  creme/creme_config/static/icecream/creme_config/css/widgets.css,sha256=NZH2QayPOFLbMED0p31hXUCoc-4HxFu2v0GSgq01Mh0,4001
458
458
  creme/creme_config/templates/creme_config/deletion-job-popup.html,sha256=vjZQKWjT5b2hIeWwWb9DYryEwPhMTdLTUfolwxUP0I0,1404
459
459
  creme/creme_config/templates/creme_config/portal.html,sha256=RWZveasarTs23c_M5fqlidgLceihYVhCCQ0K3VYaMak,8522
@@ -534,7 +534,7 @@ creme/creme_config/tests/test_button_menu.py,sha256=geq3jRGDt4APzjnN5WInw0u699Je
534
534
  creme/creme_config/tests/test_creme_property_type.py,sha256=G_l-z-ODN0nfGDAUGG83XHSLwYZbBuWHx46Wj_jCRqs,6381
535
535
  creme/creme_config/tests/test_custom_entity.py,sha256=OK4PSvxTSId4eL764l309-bkeISGDuuzo2FWrRvLdkQ,18723
536
536
  creme/creme_config/tests/test_custom_field.py,sha256=tj0QLpZZJ50lu5hAdL9iYUQrkRer8qxjVgGMRZMA0A8,53479
537
- creme/creme_config/tests/test_custom_form.py,sha256=PnAPfFxpuxzTvextb2oljaRGnzURoXlrwFS3GzvCv4o,76265
537
+ creme/creme_config/tests/test_custom_form.py,sha256=B0MlxsP9rTdiqUhZu59a1M5P0BNnAb3bPdW1mWvGO5c,76738
538
538
  creme/creme_config/tests/test_entity_filter.py,sha256=PuQKubj-FHngpei9h36Rv-oiKzP29t9yqYhuL8DNsHo,7990
539
539
  creme/creme_config/tests/test_fields.py,sha256=rknpgYv-cy0Jk9icsc2arngxvlQo6KGTislnbK38rV8,45769
540
540
  creme/creme_config/tests/test_fields_config.py,sha256=QHWdHT4A2qzCYxjgboY9_4l1lHHAMyAkhO4W8x2oplI,12250
@@ -565,7 +565,7 @@ creme/creme_config/views/button_menu.py,sha256=QmoLBAgPWLQ6WQglDL62LIlZBmspRxGeR
565
565
  creme/creme_config/views/creme_property_type.py,sha256=k_5HecMK5gPOnTekrYSUyTxRIhKID1zVaejO9MThPjw,2562
566
566
  creme/creme_config/views/custom_entity.py,sha256=B6ZTJSdWVXK1002vRdPhm62Q0roS0hW6EaPZMVQPLCA,12199
567
567
  creme/creme_config/views/custom_field.py,sha256=m2yUatZXgq8JFoYPX5QZ5ssEey41nZzUzntMESGlfFE,11284
568
- creme/creme_config/views/custom_form.py,sha256=XY2HCu8Bc8cqlk9FwPdFVi21E_DUscpov_VR4IxwHYE,15315
568
+ creme/creme_config/views/custom_form.py,sha256=fdxOldQfOqljIORnMX-pHJqa1VU1znHuDNSpUde90Sg,15398
569
569
  creme/creme_config/views/entity_filter.py,sha256=A81rgXhPg0-Do7VWoAjGDG6CfXqQY-maY5oaMK150sU,3575
570
570
  creme/creme_config/views/fields_config.py,sha256=p60cnPymn7iiSpQOfOBVozgOz2cPYDkWm4KckpePrz8,3470
571
571
  creme/creme_config/views/file_ref.py,sha256=I48H3RcEW_Zw6eK52LOeCiydKdzLMmo_1SRWMsX_K3E,1221
@@ -586,13 +586,13 @@ creme/creme_config/views/workflow.py,sha256=zK7r3hZDdiZYQunUjX-vNGCBrpWSvakQuVeX
586
586
  creme/creme_config/views/world_settings.py,sha256=tbjTPVS_dTcZer5GAKsyMTkfCEhO6m1KGmMQrlM5ga4,2637
587
587
  creme/creme_core/__init__.py,sha256=AcfRbt8TImci-VGuVaQy2WwkyKm1i8LHUSKxlXqS2ko,2682
588
588
  creme/creme_core/actions.py,sha256=W4xXkKcK6G9h-bcaf2554sRchdb6BL16vdFRs7RAIxs,6947
589
- creme/creme_core/apps.py,sha256=6iIQiNOVhRu9nyWvkfZiQT95vFmnFI3UyATWBa8XHeU,33921
589
+ creme/creme_core/apps.py,sha256=UZu5qOyalhsVtXltRFcZYOII05qP_T4m8u5MTbA-Xiw,34117
590
590
  creme/creme_core/bricks.py,sha256=eVGHSFsDJwdnyjRXd9MIXE54B2Qc4IrwxLa28ten7e4,23381
591
591
  creme/creme_core/buttons.py,sha256=USnNzvcTvYXo8S37DbSKpW9NzY6Y43k9natmNIDQtJo,2060
592
592
  creme/creme_core/checks.py,sha256=HKvGEIDchfmbaRwkOvvOHzlKkNMdnyXwve2sbobzT4c,6396
593
593
  creme/creme_core/constants.py,sha256=4TAOeUnTWoJ6h27GTI6Uz3ALN2M-8OKYYQaNxYkwOPk,1710
594
594
  creme/creme_core/context_processors.py,sha256=kd2TjDHh2s6kqDSfGpA1bSqFwfpxC15fjrzHHu3nEkw,2957
595
- creme/creme_core/enumerators.py,sha256=SV7eEkHwJexYaqnFCsdKQXZ-eWLfD1d_kY4nSiaWLAE,5906
595
+ creme/creme_core/enumerators.py,sha256=uF-yb0rXd3EM6b5m_y1avHT1XGw6TvfN9mm90A4xaJ0,6489
596
596
  creme/creme_core/function_fields.py,sha256=8kFOeI9edSqs2b9kUBApKbDtynFDceaOBb6kb-zMxkU,2708
597
597
  creme/creme_core/global_info.py,sha256=cHyJ9FtMWjnjtGfMxG09DdoUDSsYbVwgPDZEalhOP3A,3216
598
598
  creme/creme_core/http.py,sha256=v0YFUlXcOKq09JS1_9hxdhChANk6v99RZYRwY8t79FQ,2887
@@ -638,7 +638,7 @@ creme/creme_core/core/copying.py,sha256=WGfyhVdoPd958xFukE_SEyCMYm3yVlkMmTW40n84
638
638
  creme/creme_core/core/deletion.py,sha256=AmM6o9aWptp5JHybzRsCwDLYYnCbcHhLppIF71NsveA,10209
639
639
  creme/creme_core/core/download.py,sha256=mFHQO1mOTaqy02a0sOf-XGcHXsR5x0SWFGNqtpVP77g,7436
640
640
  creme/creme_core/core/entity_cell.py,sha256=ilWKjLR2tCLcnKMeS1MkjBxHmvTosoSmftplfAUeh_4,32360
641
- creme/creme_core/core/enumerable.py,sha256=vSS2oi6zjHrb6V9TcdDkXJcPYlSYJ1OCjJW7gRuaLhY,15764
641
+ creme/creme_core/core/enumerable.py,sha256=KRQpJS8psHZrZk6YVukrejqT-7Zoe8UFj3ObJPJcVSI,15829
642
642
  creme/creme_core/core/exceptions.py,sha256=5v4Z1ZA0zTFRV7XRTZJurpWOPa_iwBzKdY2HuL5kFe4,1675
643
643
  creme/creme_core/core/field_tags.py,sha256=J-fUkvX1iptgRP41-2jZWxZ3D-4rBjk8UAFAH0iY3NI,3257
644
644
  creme/creme_core/core/function_field.py,sha256=GNotBPnW12f_fOBK4453MOXALjXS0eAWjagicP2LI_E,10581
@@ -671,7 +671,7 @@ creme/creme_core/creme_jobs/base.py,sha256=en4BjpSE2He5AN60UbzK-qCPxY4pGTFJHFOSA
671
671
  creme/creme_core/creme_jobs/batch_process.py,sha256=kjrmG_t1pWKMj6ej_ejAtK4StDV-fDgtbZhqM4WzLxs,6831
672
672
  creme/creme_core/creme_jobs/deletor.py,sha256=MZgj8P2Xe8hgfWqulXIci5JDs12IVLNT5_wTi98riWw,5866
673
673
  creme/creme_core/creme_jobs/mass_import.py,sha256=OUGrbYa_lGWF2obx4yHBBnPvSwAKRoWVS3THlC-xVss,5982
674
- creme/creme_core/creme_jobs/notification_emails_sender.py,sha256=zLSdqIJJzA30kPYBKTC-jyV_9d7ywYay-3lP8jOzc8A,3701
674
+ creme/creme_core/creme_jobs/notification_emails_sender.py,sha256=l016lNO9P1EpjfQWQ8C1VRcuXqTNpK6Sz0hH_RUW-as,3893
675
675
  creme/creme_core/creme_jobs/reminder.py,sha256=sshkJJKtiLavqwxKRCd0w9r1XOU78HZY0QA7SQp9Wcw,2327
676
676
  creme/creme_core/creme_jobs/session_cleaner.py,sha256=CkJDCunopDiTxRupIe_vF-GQT5W6IBOQAsCg0GK7PfA,2267
677
677
  creme/creme_core/creme_jobs/temp_files_cleaner.py,sha256=svGLnJiKFkBD6hek0YjtKsGP3cSSjR_mB246lY_pZY0,5130
@@ -680,7 +680,7 @@ creme/creme_core/forms/__init__.py,sha256=DffGY4x0CW3CY0AJmZQIQ8HtQvawnbpULkHvdE
680
680
  creme/creme_core/forms/base.py,sha256=9YNPWqQsOWXnj2d9vUhkUMlzeSwjpq8munS123A-s24,31857
681
681
  creme/creme_core/forms/batch_process.py,sha256=E48GUXM33XORmF_k0Pft6gRgxeffXyq7CwTuj6sOzLU,9462
682
682
  creme/creme_core/forms/creme_property.py,sha256=_3XO6SRIC6nrS0_NsTYeUq6uEgwcorm0bRU4aZeRJe8,3323
683
- creme/creme_core/forms/enumerable.py,sha256=PBhh0kruwohhgAbbALGaM-fyz1Aeg_did6P_wtS6HFM,14124
683
+ creme/creme_core/forms/enumerable.py,sha256=7f3m7MGh5zL5kXxlteq8eSwRUtzkBRM1DhTDBGOXr-U,14540
684
684
  creme/creme_core/forms/fields.py,sha256=P-2_72s-qZTBK5t_hmM_Hn6RRWRLDhzJGBZy0qWlgDU,76380
685
685
  creme/creme_core/forms/header_filter.py,sha256=XmnVcCLasyNPg5ZKwBvn0JPtVOZPAPcYlU3rG3ZQWwo,25331
686
686
  creme/creme_core/forms/job.py,sha256=tAQFFrgeAYCJ4kpCNg2gx84v3XujVb9VtcXi_RvwOwU,1105
@@ -722,8 +722,8 @@ creme/creme_core/gui/listview/buttons.py,sha256=gP_jK_CHQr4AaWD35r3DmW8DPNy_Xw4t
722
722
  creme/creme_core/gui/listview/search.py,sha256=e8j21bvj0zjtYKiaxDa4tzeYfDER2vG79deV46sNPHs,21926
723
723
  creme/creme_core/gui/listview/smart_columns.py,sha256=20lnmtoEdAkKeIF4yClp1vzsR6cT8DGqbS9MwsCOVrU,6830
724
724
  creme/creme_core/gui/listview/state.py,sha256=jPf0OM2whsV6jizriUj86D03jA7qyDxkHhB8GPfGAkU,4574
725
- creme/creme_core/locale/fr/LC_MESSAGES/django.mo,sha256=k32sM9dL-hm4JpF6xPF8fR_BrXj1KJAQBPEuPipAKhQ,121341
726
- creme/creme_core/locale/fr/LC_MESSAGES/django.po,sha256=gzmGR4G7UTbBq-6cJfoyRxZk9vsfm2VOkTym8-20P18,135125
725
+ creme/creme_core/locale/fr/LC_MESSAGES/django.mo,sha256=WdYwYszuJdtPA9KmINFLR-c5x314tk12C2-HJ0kpfZI,121448
726
+ creme/creme_core/locale/fr/LC_MESSAGES/django.po,sha256=uoiWRAIhIHLAW-sZJi1LT7IUX1_QZHL5kQPaBcIskcw,135234
727
727
  creme/creme_core/locale/fr/LC_MESSAGES/djangojs.mo,sha256=Z8n0ArJPLjDQ_8LG34zxDbZ2pEPsPV8REicTRnRtr18,6519
728
728
  creme/creme_core/locale/fr/LC_MESSAGES/djangojs.po,sha256=jDNznGkzeo7h_b5wkBm5Ige49apFE41d4U4PJySgoZ4,8930
729
729
  creme/creme_core/management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -782,7 +782,7 @@ creme/creme_core/models/deletion.py,sha256=QfkRm8b27mzJK8NOCC5rMz1A8Oy3wLCxU_rYW
782
782
  creme/creme_core/models/entity.py,sha256=hY73BUAXqLYbrbpjfnpJKzyQcJBNZxoiL4TLnN9bXg4,22228
783
783
  creme/creme_core/models/entity_filter.py,sha256=Pc6aUZSdD5IaW_d2VWJ9Y1vtSBfEaIlOcchiW8cQ5cc,41896
784
784
  creme/creme_core/models/fields.py,sha256=PUxRq5LgxexSxOUhMifixkGrFb72dSZP64zN0537fR0,26037
785
- creme/creme_core/models/fields_config.py,sha256=8gCcb4sq3qHiGhsfFHEDZv3iDadISYNbz-470FoIg9Y,16198
785
+ creme/creme_core/models/fields_config.py,sha256=bax6o0XH8PAtty9J21JXuiv2h_wa8dm_bIr-2TBa1qI,16139
786
786
  creme/creme_core/models/file_ref.py,sha256=7YFpTmWcTmWFMmP173TwjUubAl5k4DXo3OaJ0SpqfZ0,2946
787
787
  creme/creme_core/models/header_filter.py,sha256=y_UKiGARQZ0sosd5cWYTruFVbq810Gue9UpKpx6X5rs,10986
788
788
  creme/creme_core/models/history.py,sha256=ijN8wxU9x2njdakGPE1AhtipPSad_9nAW0PkaO_UHjw,46468
@@ -806,7 +806,7 @@ creme/creme_core/static/chantilly/creme_core/css/creme-ui.css,sha256=0_uSYnIBkE0
806
806
  creme/creme_core/static/chantilly/creme_core/css/creme.css,sha256=2CeKXxEWTKckMbAq77CpEh-1B1z7bkovwI0_EPBgV1Q,10840
807
807
  creme/creme_core/static/chantilly/creme_core/css/detail_view.css,sha256=wdAGIBQ0PeBEaTW3Y75RzKZ5LiEw-2uNZ4AWek1Z7bs,8488
808
808
  creme/creme_core/static/chantilly/creme_core/css/forms.css,sha256=o9KXC3sxYtxeG1AtPUc9KeTYRDCB95tLBaVCfnJlyXY,21820
809
- creme/creme_core/static/chantilly/creme_core/css/header_menu.css,sha256=Xq3igi-OZT3K-Fl8UfM_Vi0prPmeoZh-f4rXoYK5oP8,15760
809
+ creme/creme_core/static/chantilly/creme_core/css/header_menu.css,sha256=KpOjLg8gUKoen0baOgIxAhZTkE_-fuxvNifpkErrg9M,15802
810
810
  creme/creme_core/static/chantilly/creme_core/css/home.css,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
811
811
  creme/creme_core/static/chantilly/creme_core/css/list_view.css,sha256=ukiuZL639vkFCD8xuRGVLL3Ttja6spDj2lo_1fbMytk,21294
812
812
  creme/creme_core/static/chantilly/creme_core/css/my_page.css,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -1087,7 +1087,7 @@ creme/creme_core/static/icecream/creme_core/css/creme-ui.css,sha256=ZNXZb2jYwDvA
1087
1087
  creme/creme_core/static/icecream/creme_core/css/creme.css,sha256=OO_iGsUNqtGh7-xUudkhPaDINlQqmC_bywAcL0rtUtU,12471
1088
1088
  creme/creme_core/static/icecream/creme_core/css/detail_view.css,sha256=5T2LanX3aQKXlP4nlKr0wg1R62Dg8hLWJqfxlZhUytU,8913
1089
1089
  creme/creme_core/static/icecream/creme_core/css/forms.css,sha256=UbJVxoDoTXXg61P0dlTWuG1vcgop9nkoeuO_GMqbwco,21074
1090
- creme/creme_core/static/icecream/creme_core/css/header_menu.css,sha256=GT5SPSmiWcxyn5TzvvDwZHQi6Vv70IGN99-k0ncUTp0,16172
1090
+ creme/creme_core/static/icecream/creme_core/css/header_menu.css,sha256=EJt7_ihz4Oh3Bis4hi34uX9gNWxpgXK8i4BakT7hnuw,16214
1091
1091
  creme/creme_core/static/icecream/creme_core/css/home.css,sha256=fqR9_rOuGLjbgdRKQEEGTfQH_2CfufU4-l_liJHJTLw,174
1092
1092
  creme/creme_core/static/icecream/creme_core/css/list_view.css,sha256=XVMBYYEE1VgCjBzToAPYdAliK6T1IoRVs9DVdqEC70I,25836
1093
1093
  creme/creme_core/static/icecream/creme_core/css/my_page.css,sha256=xF7GYHLJzR8gcFZ9gnaf4wsqRBHLEhu-9VRunFDl6s8,183
@@ -1390,7 +1390,7 @@ creme/creme_core/tests/core/test_copying.py,sha256=YLWLsY0xOVtg5DKtgZgqLX3eS6UgW
1390
1390
  creme/creme_core/tests/core/test_deletion.py,sha256=hOVh2XY0ovvrX6MutENimPkMLoEBbVagXxUfVIm00vU,15664
1391
1391
  creme/creme_core/tests/core/test_download.py,sha256=PGo-OCRKtGzSn1vsT2jps1horHVNGNTQlLjhmSRKHTM,9654
1392
1392
  creme/creme_core/tests/core/test_entity_cell.py,sha256=CoS9tdLly96PMaWotSsLyvhwrqPJ5bavZ3yn_yYAoqA,54125
1393
- creme/creme_core/tests/core/test_enumerable.py,sha256=x9eNjFAQwEJTJX58b3nYD9B1qjtwxeF7XAOJM_BXxL0,32501
1393
+ creme/creme_core/tests/core/test_enumerable.py,sha256=xvScrVDAtHz6s06dQge6svYuJVkrRBFfBfb1HizPCbY,33504
1394
1394
  creme/creme_core/tests/core/test_function_field.py,sha256=7TdGnLM5DBNu5Zb_-guaHBp0_JltxQHQzhL9VbJVEX4,15008
1395
1395
  creme/creme_core/tests/core/test_history.py,sha256=Nr_HaOBzuHx0ZU2gSjdd0R-u9rCrSDOeME_vvatF4nk,4178
1396
1396
  creme/creme_core/tests/core/test_imprint.py,sha256=3eDK3IS35BZDnG2zp5EkxWTjLxRnNRGozDkXRQsa1hw,3974
@@ -1410,20 +1410,20 @@ creme/creme_core/tests/core/entity_filter/test_operands.py,sha256=TnQ4iu1KVE5IQ1
1410
1410
  creme/creme_core/tests/core/entity_filter/test_operators.py,sha256=sj81WF2c-1qYPW6DoZ2PQqIOygbcLS3gp1lJuyE6fuo,48834
1411
1411
  creme/creme_core/tests/core/entity_filter/test_registry.py,sha256=5K2l9OXrnslSLXbYWin82UYC3T-8uLT1E_i9b0eamKI,8599
1412
1412
  creme/creme_core/tests/creme_jobs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1413
- creme/creme_core/tests/creme_jobs/test_notification_emails_sender.py,sha256=Yqw3MoUMKUmF81hfVR1e6cWkpqnXI_R7Wu1WnwkqgHY,4907
1413
+ creme/creme_core/tests/creme_jobs/test_notification_emails_sender.py,sha256=_a4W-qMOgL61tcay7cIgPtf26YcY11NNO41Hasn1xKw,4893
1414
1414
  creme/creme_core/tests/forms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1415
1415
  creme/creme_core/tests/forms/test_base.py,sha256=yEMNSA59sD2AJJF0mn8h8ZWWEqCVfB62E6DJCoEPvKo,45364
1416
1416
  creme/creme_core/tests/forms/test_batch_process.py,sha256=UrtshBZS-NEWtN4LDpP0ZOkVUTSFG0k5eawvHck24Aw,6657
1417
1417
  creme/creme_core/tests/forms/test_entity_cell.py,sha256=nVq_feD7iqhOAYkFlHHLI9UBQypZuUfBc8VgLRCZJHc,44861
1418
1418
  creme/creme_core/tests/forms/test_entity_filter.py,sha256=h0uQjX2tXVlR4N1Ai-r-P6bNrtnpoSyBzWidcgsIyLA,126917
1419
- creme/creme_core/tests/forms/test_enumerable.py,sha256=MnYY2JhR-KZNpJeHhI1edBtNnXJxoBcFY8mFvbviFlA,24071
1419
+ creme/creme_core/tests/forms/test_enumerable.py,sha256=0cXiHIt-DZ6XhGOPK2CxRr1z79x9NQUdpE1ISCyg7nI,30500
1420
1420
  creme/creme_core/tests/forms/test_field_block_manager.py,sha256=iMI3Lmw3SC6E5IsWSKtrvvaRMw50IGzSRndcMKP0cPY,19952
1421
1421
  creme/creme_core/tests/forms/test_fields.py,sha256=OdeabNEav7WGnRGKPaXrblxCZUZX9qula9MfSfr4kOs,67607
1422
1422
  creme/creme_core/tests/forms/test_json_fields.py,sha256=l2QrextXbu0DSvEakaHRZtFuaJ4T8HL4w5x3GqdVmrI,107513
1423
1423
  creme/creme_core/tests/forms/test_listview.py,sha256=rBp0jAsO_FGZQS9GLO5TV5W-etOiWVD3BdytVYdFKxs,51278
1424
1424
  creme/creme_core/tests/forms/test_mass_import.py,sha256=9uqDy-df123Ix_EpanlCzL8w30y3l8D3_oQm8agYXDs,19192
1425
1425
  creme/creme_core/tests/forms/test_validators.py,sha256=DIXAScNc63encmGmfQ8gc22LTBFCZiIFpKvG8En-3to,20340
1426
- creme/creme_core/tests/forms/test_widgets.py,sha256=l-155lXqfdxUt0k2VbPhbfWfj0yEKEo7XvHEXIO32GA,61923
1426
+ creme/creme_core/tests/forms/test_widgets.py,sha256=oQ-58ptQMLmukEa6CpJwMKnocVuJlYYMbXDHcvZG4yA,61981
1427
1427
  creme/creme_core/tests/forms/test_workflows.py,sha256=cROnaQ_mQ5etjq0yeygNgWkHXJ92L0huNHQJ2lRayQk,46980
1428
1428
  creme/creme_core/tests/gui/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
1429
1429
  creme/creme_core/tests/gui/test_actions.py,sha256=ywx4S8FJclLfUXqJxCu9BP1hh9RpelPCc4qiWlj98Po,40363
@@ -2662,10 +2662,10 @@ creme/recurrents/forms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
2662
2662
  creme/recurrents/forms/recurrentgenerator.py,sha256=pSVDUt98kJHnEOO8m4s0VhMchiTJcvKt6e0KDlDrymY,2195
2663
2663
  creme/recurrents/locale/fr/LC_MESSAGES/django.mo,sha256=NXVA3mi7Ax9gHrffDUNkL8vj8_yr2nZxyDKbaDWqCn4,1603
2664
2664
  creme/recurrents/locale/fr/LC_MESSAGES/django.po,sha256=gMPXIDwQx5uYBEheHPnmgz8dpMyUVE3FKl4buXYw1ZA,3314
2665
- creme/recurrents/migrations/0001_initial.py,sha256=dqnwiKp3Py-zTleVb6MxbsEiobHC3tKvcENW6LyS6D4,4099
2665
+ creme/recurrents/migrations/0001_initial.py,sha256=rA3CT5jE2B0sbwuz9Du70lH34-6JypScqV9TQ3yWaCE,4158
2666
2666
  creme/recurrents/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2667
2667
  creme/recurrents/models/__init__.py,sha256=fgFryOQ8Ejo2i5W0ZazfwNcc7ttiQ050VqtQBEc1Rxc,232
2668
- creme/recurrents/models/recurrentgenerator.py,sha256=Y-L9HzWp8blF4VL4znwF0krt8jLDIkw7Pto698frOMo,3727
2668
+ creme/recurrents/models/recurrentgenerator.py,sha256=jzdYjSg40roUZG6bQ-bO6a-COgQzdrY6IVbX2mVR5n0,3794
2669
2669
  creme/recurrents/templates/recurrents/view_generator.html,sha256=9Z4NGocyzS-77PajoSlQLBQzSFOwrD1GnlIsoub97FA,53
2670
2670
  creme/recurrents/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2671
2671
  creme/recurrents/tests/base.py,sha256=oJ_NdeL3Tw_vq3aSrpxp1p6aN6W8oT-4b7pESqPAHH0,921
@@ -2706,8 +2706,8 @@ creme/reports/forms/bulk.py,sha256=wKFywtkPCDG--o4kbu6WLIYNPn8Cyiqjie9Y3hvKQ0M,5
2706
2706
  creme/reports/forms/entity_filter.py,sha256=t3FYluAudOcZRDEDoa9FS9XMnIAW23NQenLVnt4XszQ,1142
2707
2707
  creme/reports/forms/graph.py,sha256=2Vc_YeNOtJ332DokrGT_US_TbyTsjYmnyt8nipES4MY,26076
2708
2708
  creme/reports/forms/report.py,sha256=oV2OjZANjjCTD5nBDu5U7x2gcrBSn98dqGbMiRIQ1NM,26186
2709
- creme/reports/locale/fr/LC_MESSAGES/django.mo,sha256=Njfe_BHz9i835eIMsiGCuKYZGiQjdHL1g5eBT29Zuo4,16491
2710
- creme/reports/locale/fr/LC_MESSAGES/django.po,sha256=bMcZyPg6KYPRZP4Uaf6pQSQL8AKUHY_D6XIYKPdl6sY,20588
2709
+ creme/reports/locale/fr/LC_MESSAGES/django.mo,sha256=zQyK7YYEntRTFMm2m3dvJJWY8_iohB7iVfws9Z6CAKI,16590
2710
+ creme/reports/locale/fr/LC_MESSAGES/django.po,sha256=TEJ6Q6b6poyyMfldVqreLd4hAgToUe7RUhCixScJZ9k,20689
2711
2711
  creme/reports/locale/fr/LC_MESSAGES/djangojs.mo,sha256=7nlj4So9k-ErHv0mgk82SpHiBQkKmQmLIQnahmdhbfw,449
2712
2712
  creme/reports/locale/fr/LC_MESSAGES/djangojs.po,sha256=eyCK6yLKRSFPciluW5Ws6DiC7L5f_PatH72jsueWdw4,1220
2713
2713
  creme/reports/migrations/0001_initial.py,sha256=w1cZ4Wk_5e3r2hnE-2dem80HW7fj4odBSaqMc8vGzUo,10570
@@ -2727,7 +2727,7 @@ creme/reports/static/reports/js/tests/reports-actions.js,sha256=TowXAbsTbbbExIkO
2727
2727
  creme/reports/static/reports/js/tests/reports-brick.js,sha256=JocsI4VWwjtGWt8NeHYHVup-MiKhVwNcjrgE_ZGkSCo,19412
2728
2728
  creme/reports/static/reports/js/tests/reports-listview.js,sha256=VPsK_ZfGFVT920L31EGQd8CvegNJngQynbOLHL-I0Ek,9161
2729
2729
  creme/reports/static/reports/js/tests/tube-chart.js,sha256=vkqy56Ub_TQaPT7AdGNi0Oaf8QFqLERzX6B6mpk7G-g,3260
2730
- creme/reports/templates/reports/preview_report.html,sha256=2BqIEIlek4sQy55TPkCQ_fUMTHrKfog3eUEo5LUMavI,1715
2730
+ creme/reports/templates/reports/preview_report.html,sha256=eawDGCNGJdkIjZhwN4-Ph3wQngQqeWypU3YnsP2ppeg,2092
2731
2731
  creme/reports/templates/reports/view_graph.html,sha256=qwlC-eJ0A3MkJOHl8Y1Y5JO3FA49AgrWYHukalUgL8Q,731
2732
2732
  creme/reports/templates/reports/view_report.html,sha256=9Z4NGocyzS-77PajoSlQLBQzSFOwrD1GnlIsoub97FA,53
2733
2733
  creme/reports/templates/reports/bricks/entity-filters.html,sha256=ghr9rUFig1qAjq5_uVDEFyKtX5DNxuVuMNu0neNlQgI,1019
@@ -2736,7 +2736,7 @@ creme/reports/templates/reports/bricks/instance-bricks-info.html,sha256=iBAsw-Pr
2736
2736
  creme/reports/templates/reports/bricks/preview.html,sha256=cRdq80WTwq75eS0YwJ9WQJMQAeqWMWzVO1gaRVgnDN0,1230
2737
2737
  creme/reports/templates/reports/bricks/report-chart-list.html,sha256=sYHI7BLRdl3yBWc5eYXvdOj7ngpn5d2Qp9L7mxl2c34,8115
2738
2738
  creme/reports/templates/reports/bricks/report-chart.html,sha256=sJI8xDi_MNuNUwG4fg_7Hg27kjuBGX_b2AESLiXDWto,4527
2739
- creme/reports/templates/reports/bricks/report-hat-bar.html,sha256=aSNGi0Y5FAB4mA4s7UIi1I5HrXBFtPUUUMmW-4MhVy4,740
2739
+ creme/reports/templates/reports/bricks/report-hat-bar.html,sha256=K0x2Z6NOnomV8eTPRW6lR5yEjsQbbXxvP394P7F8eAg,949
2740
2740
  creme/reports/templates/reports/detail/entity-filter.html,sha256=9Co16RLUYRlSuA21Y2Ep-u4SrGKMv7pVK5LOv1pZKrQ,435
2741
2741
  creme/reports/templates/reports/forms/report-export-filter.html,sha256=QjPyjkvHqS7yIL9h3WwboXOPYACbkB8MHovAowKX4xw,639
2742
2742
  creme/reports/templates/reports/forms/widgets/report-hands/custom-aggregates.html,sha256=ejTaJdmGcX5TFEWdT3BjXFslZC0QHfwdw4m5fjN6Vi4,514
@@ -2757,7 +2757,7 @@ creme/reports/tests/test_entity_filter.py,sha256=Bm2WkW5CeeDAoQh2IOFfoG2K6vdbycK
2757
2757
  creme/reports/tests/test_forms.py,sha256=d7Sz3UfsdFW5GspuABA5DNk_Hl5V3IjW6H32Vq713gc,81698
2758
2758
  creme/reports/tests/test_graph.py,sha256=N2896eLl6baw0lG22LmOCWoxrv0Hs50OgwRgGRcTKnc,133541
2759
2759
  creme/reports/tests/test_registries.py,sha256=_BtYECcKIMxAzFZRxeNBD_lWCgY0xRToVEc5d6HOzg0,4992
2760
- creme/reports/tests/test_report.py,sha256=FvJVJq9r4-bAdF3wNOT4M5Z2IbokcxYlzsWNPg0o23s,142764
2760
+ creme/reports/tests/test_report.py,sha256=BAfyEUQgG1Rl2dulsiwqCr11-pcg03_dDblxG_E9mJE,143971
2761
2761
  creme/reports/tests/test_templatetags.py,sha256=Sr0eNuqB2zSwcFZKIj-vEhOXKwMznL1VxDYhv0a6w-Q,3395
2762
2762
  creme/reports/tests/test_utils.py,sha256=3ImrZueMK-xqgXHjlui-zMvQjMQFcwWcX7E27aI6RHc,2512
2763
2763
  creme/reports/tests/test_views.py,sha256=v_PlsSXSMc9RkhWxXY9-s4aIWHoIQSgLVkWWm0leF2U,6333
@@ -2771,7 +2771,7 @@ creme/reports/tests/core/graph/test_hand.py,sha256=LJb6nVwWVK5-49DvBjNnHQ6I6xL1s
2771
2771
  creme/reports/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2772
2772
  creme/reports/views/bricks.py,sha256=MdeUZKFAJaRmb_Sk-Py-ojh1fUgMw6fCjEeJwca8x3Q,2442
2773
2773
  creme/reports/views/entity_filter.py,sha256=4cF2stqj-fQuFs2lvrGUyCeVc5d8Lb5Ua6J6zMT1fYE,2514
2774
- creme/reports/views/export.py,sha256=Ygmgw44lQbDHQ9Z3VKTzWcfMSzg4B4GOdgu3nyaWM8M,5707
2774
+ creme/reports/views/export.py,sha256=eCM29j8nFEXxc-zGgLnWjW-ZJhP7gcD4yzQAQ7xABDQ,5757
2775
2775
  creme/reports/views/graph.py,sha256=0VUTaTAJUOx0LXlPg5mBO2kHOFyL_x9RyiZmNUbpcDI,5581
2776
2776
  creme/reports/views/report.py,sha256=UoZHXekGWWb77Oj1g8TsmXpVf6vmgQY7J6cMjBkNNr4,7853
2777
2777
  creme/sketch/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -3822,7 +3822,7 @@ creme/vcfs/vcf_lib/utils.py,sha256=rofX2grUVZLg1qSYrvVLQe832rX9QDDqjqSfq9_rpnA,2
3822
3822
  creme/vcfs/vcf_lib/vcard.py,sha256=EIDdegf8HC5f4j19tfJYQ1NKc_-NZO8NaYinpVwj7vQ,8275
3823
3823
  creme/vcfs/views/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3824
3824
  creme/vcfs/views/vcf.py,sha256=7rsRCL7U0cgwtYghN6yAAbNN_e5lJVGrLH5IpSOIPYI,3795
3825
- creme_crm-2.7.3.dist-info/licenses/LICENSE.txt,sha256=fvS1_rSUtxH8CO9sMpw9BQFU3nLMK6ssGpyZU6ZVPMU,1130
3825
+ creme_crm-2.7.5.dist-info/licenses/LICENSE.txt,sha256=fvS1_rSUtxH8CO9sMpw9BQFU3nLMK6ssGpyZU6ZVPMU,1130
3826
3826
  mediagenerator/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3827
3827
  mediagenerator/api.py,sha256=58FqOcH2NCJVdtKN_MxyW3xydWAYPBexTDa2LQTaMsY,1883
3828
3828
  mediagenerator/base.py,sha256=2zr8DCnL48UgVM1M9LILuHTgT_xvKLMSwVnzGa47zCc,1003
@@ -3853,8 +3853,8 @@ mediagenerator/management/commands/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQe
3853
3853
  mediagenerator/management/commands/generatemedia.py,sha256=3-uIk3h83F16n2z7vG_xBteWiq7JWoB7d0vWSxVn-po,328
3854
3854
  mediagenerator/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
3855
3855
  mediagenerator/templatetags/media.py,sha256=6EeohgP8srqzNRxgGr47BARO6Vx4AMn_dQuHwEQnnHE,1495
3856
- creme_crm-2.7.3.dist-info/METADATA,sha256=bcUWfaNRkn8zw4wyk59NyGjMJlPWumq058ScgddGsLk,12232
3857
- creme_crm-2.7.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
3858
- creme_crm-2.7.3.dist-info/entry_points.txt,sha256=GWm5VHgyz1DROd4UbhrelZ8d581uQNOtbjPz2TWfi_A,47
3859
- creme_crm-2.7.3.dist-info/top_level.txt,sha256=y_WAe0QGma0mhzRFEOIVJsB-xJrvhHV6MEk862EMweA,21
3860
- creme_crm-2.7.3.dist-info/RECORD,,
3856
+ creme_crm-2.7.5.dist-info/METADATA,sha256=yOA80SASItQNipU2vRaMKyrxWNmbSt__BTzNcw2hRB8,12233
3857
+ creme_crm-2.7.5.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
3858
+ creme_crm-2.7.5.dist-info/entry_points.txt,sha256=GWm5VHgyz1DROd4UbhrelZ8d581uQNOtbjPz2TWfi_A,47
3859
+ creme_crm-2.7.5.dist-info/top_level.txt,sha256=y_WAe0QGma0mhzRFEOIVJsB-xJrvhHV6MEk862EMweA,21
3860
+ creme_crm-2.7.5.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5