Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

# Copyright 2014-2015 Luc Saffre 

# License: BSD (see file COPYING for details) 

 

""" 

Defines classes related to date ranges. 

 

.. autosummary:: 

 

""" 

 

from __future__ import unicode_literals 

from builtins import object 

 

import datetime 

 

import logging 

logger = logging.getLogger(__name__) 

 

from django.db import models 

from django.conf import settings 

from django.utils.translation import ugettext_lazy as _ 

from django.utils.translation import pgettext_lazy as pgettext 

from django.core.exceptions import ValidationError 

 

from lino.api import dd 

from lino.core.model import Model 

from lino.core.choicelists import Choice 

from lino.utils.format_date import fdl 

from lino.utils.ranges import isrange 

from lino.utils.format_date import fds 

from lino.core.utils import ParameterPanel 

 

 

def rangefmt(r): 

    return fds(r[0]) + '...' + fds(r[1]) 

 

 

class ObservedEvent(Choice): 

    """Base class for choices of "observed event"-style choicelists.""" 

 

    def __init__(self, value, **kwargs): 

        super(ObservedEvent, self).__init__(value, name=value, **kwargs) 

 

    def add_filter(self, qs, pv): 

        return qs 

 

 

class DatePeriod(Model): 

 

    """A model mixin for models which represent a period whose start and 

    end are date fields. 

 

    Designed for usage with 

    :class:`lino.modlib.system.mixins.PeriodEvents`. 

 

    """ 

 

    class Meta(object): 

        abstract = True 

 

    empty_period_text = "" 

 

    start_date = models.DateField(_("Start date"), blank=True, null=True) 

    end_date = models.DateField(_("End date"), blank=True, null=True) 

 

    def full_clean(self, *args, **kw): 

        if not isrange(self.start_date, self.end_date): 

            raise ValidationError(_("Date period ends before it started.")) 

        super(DatePeriod, self).full_clean(*args, **kw) 

 

    def get_period(self): 

        return (self.start_date, self.end_date) 

 

    def is_past(self): 

        return (self.end_date and self.end_date <= dd.today()) 

 

    def is_future(self): 

        return (self.start_date and self.start_date > settings.SITE.today()) 

 

    def get_period_text(self): 

        if self.start_date and self.end_date: 

            if self.start_date == self.end_date: 

                # s = E.tostring(E.b(fdl(self.start_date))) 

                s = fdl(self.start_date) 

                return pgettext("date", "on %s") % s 

            else: 

                kw = dict() 

                kw.update(a=fdl(self.start_date)) 

                kw.update(b=fdl(self.end_date)) 

                return pgettext("date range", "between %(a)s and %(b)s") % kw 

        elif self.start_date: 

            s = fdl(self.start_date) 

            if self.is_future(): 

                return pgettext("future date range", "from %s") % s 

            else: 

                return pgettext("date range", "from %s") % s 

        elif self.end_date: 

            s = fdl(self.end_date) 

            return pgettext("date range", "until %s") % s 

        return self.empty_period_text 

 

    get_default_start_date = None 

    get_default_end_date = None 

 

    @classmethod 

    def get_parameter_fields(cls, **fields): 

        fields.update( 

            start_date=models.DateField( 

                _("Period from"), blank=True, null=True, 

                default=cls.get_default_start_date, 

                help_text=_("Start date of observed period"))) 

        fields.update( 

            end_date=models.DateField( 

                _("until"), 

                blank=True, null=True, 

                default=cls.get_default_end_date, 

                help_text=_("End date of observed period"))) 

        return super(DatePeriod, cls).get_parameter_fields(**fields) 

 

 

class ObservedPeriod(ParameterPanel): 

    """:class:`lino.core.param_panel.ParameterPanel` with two fields 

    `start_date` and `end_date` which default to empty. 

 

    """ 

 

    get_default_start_date = None 

    get_default_end_date = None 

 

    def __init__(self, 

                 verbose_name_start=_("Period from"), 

                 verbose_name_end=_("until"), **kw): 

        kw.update( 

            start_date=models.DateField( 

                verbose_name_start, blank=True, null=True, 

                default=self.get_default_start_date, 

                help_text=_("Start date of observed period")), 

            end_date=models.DateField( 

                verbose_name_end, 

                blank=True, null=True, 

                default=self.get_default_end_date, 

                help_text=_("End date of observed period")), 

        ) 

        super(ObservedPeriod, self).__init__(**kw) 

 

 

class Yearly(ObservedPeriod): 

 

    """An :class:`ObservedPeriod` for which `start_date` defaults to Jan 

    1st and `end_date` to Dec 31 of the current year. 

 

    """ 

 

    def get_default_start_date(self): 

        D = datetime.date 

        return D(D.today().year, 1, 1) 

 

    def get_default_end_date(self): 

        D = datetime.date 

        return D(D.today().year, 12, 31) 

 

 

class Today(ParameterPanel): 

    """:class:`lino.core.param_panel.ParameterPanel` with a field `today` 

which defaults to today.""" 

    def __init__(self, verbose_name=_("Situation on"), **kw): 

        kw.update( 

            today=models.DateField( 

                verbose_name, blank=True, null=True, 

                default=settings.SITE.today, 

                help_text=_("Date of observation")), 

        ) 

        super(Today, self).__init__(**kw)