Projet

Général

Profil

0001-templates-add-filters-for-working-days-31851.patch

Lauréline Guérin, 22 juin 2020 10:56

Télécharger (13,9 ko)

Voir les différences:

Subject: [PATCH] templates: add filters for working days (#31851)

 debian/control                    |   1 +
 tests/test_templates.py           | 191 ++++++++++++++++++++++++++++++
 tox.ini                           |   1 +
 wcs/qommon/calendar.py            |  41 +++++++
 wcs/qommon/templatetags/qommon.py |  61 ++++++++++
 wcs/settings.py                   |   3 +
 6 files changed, 298 insertions(+)
 create mode 100644 wcs/qommon/calendar.py
debian/control
33 33
    python3-langdetect,
34 34
    python3-magic,
35 35
    python3-qrcode,
36
    python3-workalendar,
36 37
    python3-xlwt
37 38
Suggests: python3-libxml2
38 39
Description: web application to design and set up online forms
tests/test_templates.py
689 689
def test_datetime_in_past(value, expected):
690 690
    t = Template('{{ value|datetime_in_past }}')
691 691
    assert t.render({'value': value}) == str(expected)
692

  
693

  
694
def test_is_working_day_settings(settings):
695
    settings.WORKING_DAY_CALENDAR = None
696
    t = Template('{{ value|is_working_day }}')
697
    assert t.render({'value': '2020-07-15'}) == 'False'
698
    t = Template('{{ value|is_working_day_with_saturday }}')
699
    assert t.render({'value': '2020-07-15'}) == 'False'
700

  
701
    settings.WORKING_DAY_CALENDAR = ''
702
    t = Template('{{ value|is_working_day }}')
703
    assert t.render({'value': '2020-07-15'}) == 'False'
704
    t = Template('{{ value|is_working_day_with_saturday }}')
705
    assert t.render({'value': '2020-07-15'}) == 'False'
706

  
707
    settings.WORKING_DAY_CALENDAR = 'foobar'
708
    t = Template('{{ value|is_working_day }}')
709
    assert t.render({'value': '2020-07-15'}) == 'False'
710
    t = Template('{{ value|is_working_day_with_saturday }}')
711
    assert t.render({'value': '2020-07-15'}) == 'False'
712

  
713
    settings.WORKING_DAY_CALENDAR = 'workalendar.europe.France'
714
    t = Template('{{ value|is_working_day }}')
715
    assert t.render({'value': '2020-07-15'}) == 'True'
716
    t = Template('{{ value|is_working_day_with_saturday }}')
717
    assert t.render({'value': '2020-07-15'}) == 'True'
718

  
719

  
720
@pytest.mark.parametrize('value, expected', [
721
    (None, False),
722
    ('', False),
723
    ('foobar', False),
724
    (42, False),
725
    ('2020-07-14T12:01:03', False),
726
    ('2020-07-15T12:01:03', True),
727
    ('2020-07-14 02:03', False),
728
    ('2020-07-15 02:03', True),
729
    ('14/07/2020 02h03', False),
730
    ('15/07/2020 02h03', True),
731
    ('2020-07-14', False),
732
    ('2020-07-15', True),
733
    ('14/07/2020', False),
734
    ('15/07/2020', True),
735
    (datetime.datetime(2020, 7, 14, 12, 1, 3), False),
736
    (datetime.datetime(2020, 7, 15, 12, 1, 3), True),
737
    (datetime.date(2020, 7, 14), False),
738
    (datetime.date(2020, 7, 15), True),
739
])
740
def test_is_working_day(settings, value, expected):
741
    settings.WORKING_DAY_CALENDAR = 'workalendar.europe.France'
742
    t = Template('{{ value|is_working_day }}')
743
    assert t.render({'value': value}) == str(expected)
744
    t = Template('{{ value|is_working_day_with_saturday }}')
745
    assert t.render({'value': value}) == str(expected)
746

  
747

  
748
def test_is_working_day_weekend(settings):
749
    settings.WORKING_DAY_CALENDAR = 'workalendar.europe.France'
750
    # check saturday
751
    t = Template('{{ value|is_working_day }}')
752
    assert t.render({'value': '2020-06-20'}) == 'False'
753
    t = Template('{{ value|is_working_day_with_saturday }}')
754
    assert t.render({'value': '2020-06-20'}) == 'True'
755
    # check sunday
756
    t = Template('{{ value|is_working_day }}')
757
    assert t.render({'value': '2020-06-21'}) == 'False'
758
    t = Template('{{ value|is_working_day_with_saturday }}')
759
    assert t.render({'value': '2020-06-21'}) == 'False'
760

  
761

  
762
def test_add_working_days_settings(settings):
763
    settings.WORKING_DAY_CALENDAR = None
764
    t = Template('{{ value|add_working_days:1 }}')
765
    assert t.render({'value': '2020-07-13'}) == ''
766
    t = Template('{{ value|add_working_days_with_saturday:1 }}')
767
    assert t.render({'value': '2020-07-13'}) == ''
768

  
769
    settings.WORKING_DAY_CALENDAR = ''
770
    t = Template('{{ value|add_working_days:1 }}')
771
    assert t.render({'value': '2020-07-13'}) == ''
772
    t = Template('{{ value|add_working_days_with_saturday:1 }}')
773
    assert t.render({'value': '2020-07-13'}) == ''
774

  
775
    settings.WORKING_DAY_CALENDAR = 'foobar'
776
    t = Template('{{ value|add_working_days:1 }}')
777
    assert t.render({'value': '2020-07-13'}) == ''
778
    t = Template('{{ value|add_working_days_with_saturday:1 }}')
779
    assert t.render({'value': '2020-07-13'}) == ''
780

  
781
    settings.WORKING_DAY_CALENDAR = 'workalendar.europe.France'
782
    t = Template('{{ value|add_working_days:1 }}')
783
    assert t.render({'value': '2020-07-13'}) == '2020-07-15'
784
    t = Template('{{ value|add_working_days_with_saturday:1 }}')
785
    assert t.render({'value': '2020-07-13'}) == '2020-07-15'
786

  
787

  
788
def test_add_working_days_arg(settings):
789
    settings.WORKING_DAY_CALENDAR = 'workalendar.europe.France'
790
    t = Template('{{ value|add_working_days:"foobar" }}')
791
    assert t.render({'value': '2020-07-13'}) == ''
792
    t = Template('{{ value|add_working_days_with_saturday:"foobar" }}')
793
    assert t.render({'value': '2020-07-13'}) == ''
794
    t = Template('{{ value|add_working_days:2 }}')
795
    assert t.render({'value': '2020-07-13'}) == '2020-07-16'
796
    t = Template('{{ value|add_working_days_with_saturday:2 }}')
797
    assert t.render({'value': '2020-07-13'}) == '2020-07-16'
798

  
799

  
800
@pytest.mark.parametrize('value, expected', [
801
    (None, ''),
802
    ('', ''),
803
    ('foobar', ''),
804
    (42, ''),
805
    ('2020-07-13T12:01:03', '2020-07-15'),
806
    ('2020-07-13 02:03', '2020-07-15'),
807
    ('13/07/2020 02h03', '2020-07-15'),
808
    ('2020-07-13', '2020-07-15'),
809
    ('13/07/2020', '2020-07-15'),
810
    (datetime.datetime(2020, 7, 13, 12, 1, 3), '2020-07-15'),
811
    (datetime.date(2020, 7, 13), '2020-07-15'),
812
])
813
def test_add_working_days(settings, value, expected):
814
    settings.WORKING_DAY_CALENDAR = 'workalendar.europe.France'
815
    t = Template('{{ value|add_working_days:1 }}')
816
    assert t.render({'value': value}) == str(expected)
817
    t = Template('{{ value|add_working_days_with_saturday:1 }}')
818
    assert t.render({'value': value}) == str(expected)
819

  
820

  
821
def test_add_working_days_weekend(settings):
822
    settings.WORKING_DAY_CALENDAR = 'workalendar.europe.France'
823
    t = Template('{{ value|add_working_days:1 }}')
824
    assert t.render({'value': '2020-06-19'}) == '2020-06-22'
825
    t = Template('{{ value|add_working_days_with_saturday:1 }}')
826
    assert t.render({'value': '2020-06-19'}) == '2020-06-20'
827

  
828

  
829
def test_adjust_to_working_day_settings(settings):
830
    settings.WORKING_DAY_CALENDAR = None
831
    t = Template('{{ value|adjust_to_working_day }}')
832
    assert t.render({'value': '2020-07-13'}) == ''
833
    t = Template('{{ value|adjust_to_working_day_with_saturday }}')
834
    assert t.render({'value': '2020-07-13'}) == ''
835

  
836
    settings.WORKING_DAY_CALENDAR = ''
837
    t = Template('{{ value|adjust_to_working_day }}')
838
    assert t.render({'value': '2020-07-13'}) == ''
839
    t = Template('{{ value|adjust_to_working_day_with_saturday }}')
840
    assert t.render({'value': '2020-07-13'}) == ''
841

  
842
    settings.WORKING_DAY_CALENDAR = 'foobar'
843
    t = Template('{{ value|adjust_to_working_day }}')
844
    assert t.render({'value': '2020-07-13'}) == ''
845
    t = Template('{{ value|adjust_to_working_day_with_saturday }}')
846
    assert t.render({'value': '2020-07-13'}) == ''
847

  
848
    settings.WORKING_DAY_CALENDAR = 'workalendar.europe.France'
849
    t = Template('{{ value|adjust_to_working_day }}')
850
    assert t.render({'value': '2020-07-14'}) == '2020-07-15'
851
    t = Template('{{ value|adjust_to_working_day_with_saturday }}')
852
    assert t.render({'value': '2020-07-14'}) == '2020-07-15'
853

  
854

  
855
@pytest.mark.parametrize('value, expected', [
856
    (None, ''),
857
    ('', ''),
858
    ('foobar', ''),
859
    (42, ''),
860
    ('2020-07-14T12:01:03', '2020-07-15'),
861
    ('2020-07-14 02:03', '2020-07-15'),
862
    ('14/07/2020 02h03', '2020-07-15'),
863
    ('2020-07-14', '2020-07-15'),
864
    ('14/07/2020', '2020-07-15'),
865
    (datetime.datetime(2020, 7, 14, 12, 1, 3), '2020-07-15'),
866
    (datetime.date(2020, 7, 14), '2020-07-15'),
867
    (datetime.date(2020, 7, 15), '2020-07-15'),
868
])
869
def test_adjust_to_working_day(settings, value, expected):
870
    settings.WORKING_DAY_CALENDAR = 'workalendar.europe.France'
871
    t = Template('{{ value|adjust_to_working_day }}')
872
    assert t.render({'value': value}) == str(expected)
873
    t = Template('{{ value|adjust_to_working_day_with_saturday }}')
874
    assert t.render({'value': value}) == str(expected)
875

  
876

  
877
def test_adjust_to_working_day_weekend(settings):
878
    settings.WORKING_DAY_CALENDAR = 'workalendar.europe.France'
879
    t = Template('{{ value|adjust_to_working_day }}')
880
    assert t.render({'value': '2020-06-20'}) == '2020-06-22'
881
    t = Template('{{ value|adjust_to_working_day_with_saturday }}')
882
    assert t.render({'value': '2020-06-20'}) == '2020-06-20'
tox.ini
29 29
    requests
30 30
    vobject
31 31
    qrcode
32
    workalendar
32 33
    Pillow
33 34
    python-magic
34 35
    docutils
wcs/qommon/calendar.py
1
# w.c.s. - web application for online forms
2
# Copyright (C) 2005-2020  Entr'ouvert
3
#
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
8
#
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
# GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, see <http://www.gnu.org/licenses/>.
16

  
17
from django.conf import settings
18
from django.utils.module_loading import import_string
19

  
20
try:
21
    from workalendar.core import SUN
22
except ImportError:
23
    SUN = None
24

  
25

  
26
def get_calendar(saturday_is_a_working_day=False):
27
    # get calendar from settings
28
    try:
29
        calendar_class = import_string(settings.WORKING_DAY_CALENDAR)
30
    except (AttributeError, ImportError):
31
        return
32

  
33
    # saturday is not a working day, return this calendar
34
    if not saturday_is_a_working_day:
35
        return calendar_class()
36

  
37
    # saturday is a working day, build a custom calendar
38
    class CalendarWithSaturday(calendar_class):
39
        WEEKEND_DAYS = (SUN,)
40

  
41
    return CalendarWithSaturday()
wcs/qommon/templatetags/qommon.py
39 39
from django.utils.encoding import force_bytes, force_text
40 40
from django.utils.safestring import mark_safe
41 41
from django.utils.timezone import is_naive, make_aware
42
from wcs.qommon import calendar
42 43
from wcs.qommon import evalutils
43 44
from wcs.qommon import tokens
44 45
from wcs.qommon.admin.texts import TextsDirectory
......
281 282
    return value <= date_now
282 283

  
283 284

  
285
@register.filter(expects_localtime=True)
286
def is_working_day(value, saturday_is_a_working_day=False):
287
    value = parse_date(value)
288
    if not value:
289
        return False
290

  
291
    cal = calendar.get_calendar(saturday_is_a_working_day=saturday_is_a_working_day)
292
    if not cal:
293
        return False
294

  
295
    return cal.is_working_day(value)
296

  
297

  
298
@register.filter(expects_localtime=True)
299
def is_working_day_with_saturday(value):
300
    return is_working_day(value, saturday_is_a_working_day=True)
301

  
302

  
303
@register.filter(expects_localtime=True)
304
def add_working_days(value, arg, saturday_is_a_working_day=False):
305
    value = parse_date(value)
306
    if not value:
307
        return ''
308

  
309
    cal = calendar.get_calendar(saturday_is_a_working_day=saturday_is_a_working_day)
310
    if not cal:
311
        return ''
312

  
313
    try:
314
        return cal.add_working_days(value, int(arg))
315
    except ValueError:
316
        return ''
317

  
318

  
319
@register.filter(expects_localtime=True)
320
def add_working_days_with_saturday(value, arg):
321
    return add_working_days(value, arg, saturday_is_a_working_day=True)
322

  
323

  
324
@register.filter(expects_localtime=True)
325
def adjust_to_working_day(value, saturday_is_a_working_day=False):
326
    value = parse_date(value)
327
    if not value:
328
        return ''
329

  
330
    cal = calendar.get_calendar(saturday_is_a_working_day=saturday_is_a_working_day)
331
    if not cal:
332
        return ''
333

  
334
    if cal.is_working_day(value):
335
        return value
336
    # return next working day
337
    return cal.add_working_days(value, 1)
338

  
339

  
340
@register.filter(expects_localtime=True)
341
def adjust_to_working_day_with_saturday(value):
342
    return adjust_to_working_day(value, saturday_is_a_working_day=True)
343

  
344

  
284 345
@register.simple_tag
285 346
def standard_text(text_id):
286 347
    return mark_safe(TextsDirectory.get_html_text(str(text_id)))
wcs/settings.py
188 188
# w.c.s. can have very large forms, in backoffice and frontoffice
189 189
DATA_UPLOAD_MAX_NUMBER_FIELDS = 2000  # Django default is 1000
190 190

  
191
# workalendar config
192
WORKING_DAY_CALENDAR = 'workalendar.europe.France'
193

  
191 194
local_settings_file = os.environ.get('WCS_SETTINGS_FILE',
192 195
        os.path.join(os.path.dirname(__file__), 'local_settings.py'))
193 196
if os.path.exists(local_settings_file):
194
-