You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
117 lines
4.1 KiB
117 lines
4.1 KiB
# -*- coding: utf-8 -*-
|
|
# © 2016 Therp BV <http://therp.nl>
|
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
|
|
from dateutil.rrule import rrule, rruleset
|
|
from openerp import fields, models
|
|
_DATETIME_FIELDS = ['_until', '_dtstart']
|
|
_SCALAR_FIELDS = [
|
|
'_wkst', '_cache', '_until', '_dtstart', '_count', '_freq', '_interval',
|
|
]
|
|
_ZERO_IS_NOT_NONE = ['_freq']
|
|
|
|
|
|
class SerializableRRuleSet(rruleset, list):
|
|
"""Getting our rule set json stringified is tricky, because we can't
|
|
just inject our own json encoder. Now we pretend our set is a list,
|
|
then json.dumps will try to iterate, which is why we can do our specific
|
|
stuff in __iter__"""
|
|
def __init__(self, *args):
|
|
self._rrule = []
|
|
super(SerializableRRuleSet, self).__init__(self)
|
|
for arg in args:
|
|
self.rrule(arg)
|
|
|
|
def __iter__(self):
|
|
for rule in self._rrule:
|
|
yield dict(type='rrule', **{
|
|
key[1:]:
|
|
fields.Datetime.to_string(getattr(rule, key))
|
|
if key in _DATETIME_FIELDS
|
|
else
|
|
[] if getattr(rule, key) is None and key not in _SCALAR_FIELDS
|
|
else
|
|
list(getattr(rule, key)) if key not in _SCALAR_FIELDS
|
|
else getattr(rule, key)
|
|
for key in [
|
|
'_byhour', '_wkst', '_bysecond', '_bymonthday',
|
|
'_byweekno', '_bysetpos', '_cache', '_bymonth',
|
|
'_byyearday', '_byweekday', '_byminute',
|
|
'_until', '_dtstart', '_count', '_freq', '_interval',
|
|
'_byeaster',
|
|
]
|
|
})
|
|
# TODO: implement rdate, exrule, exdate
|
|
|
|
def __call__(self, default_self=None):
|
|
"""convert self to a proper rruleset for iteration.
|
|
If we use defaults on our field, this will be called too with
|
|
and empty recordset as parameter. In this case, we need self"""
|
|
if isinstance(default_self, models.BaseModel):
|
|
return self
|
|
result = rruleset()
|
|
result._rrule = self._rrule
|
|
result._rdate = self._rdate
|
|
result._exrule = self._exrule
|
|
result._exdate = self._exdate
|
|
return result
|
|
|
|
def __nonzero__(self):
|
|
return bool(self._rrule)
|
|
|
|
def __repr__(self):
|
|
return ', '.join(str(a) for a in self)
|
|
|
|
def __getitem__(self, key):
|
|
return rruleset.__getitem__(self(), key)
|
|
|
|
def __getslice__(self, i, j):
|
|
return rruleset.__getitem__(self(), slice(i, j))
|
|
|
|
def __ne__(self, o):
|
|
return not self.__eq__(o)
|
|
|
|
def __eq__(self, o):
|
|
return self.__repr__() == o.__repr__()
|
|
|
|
def between(self, after, before, inc=False):
|
|
return self().between(after, before, inc=inc)
|
|
|
|
def after(self, dt, inc=False):
|
|
return self().after(dt, inc=inc)
|
|
|
|
def before(self, dt, inc=False):
|
|
return self().before(dt, inc=inc)
|
|
|
|
def count(self):
|
|
return self().count()
|
|
|
|
|
|
class FieldRRule(fields.Serialized):
|
|
def convert_to_cache(self, value, record, validate=True):
|
|
result = SerializableRRuleSet()
|
|
if not value:
|
|
return result
|
|
if isinstance(value, SerializableRRuleSet):
|
|
return value
|
|
assert isinstance(value, list), 'An RRULE\'s content must be a list'
|
|
for data in value:
|
|
assert isinstance(data, dict), 'The list must contain dictionaries'
|
|
assert 'type' in data, 'The dictionary must contain a type'
|
|
data_type = data['type']
|
|
data = {
|
|
key: fields.Datetime.from_string(value)
|
|
if '_%s' % key in _DATETIME_FIELDS
|
|
else map(int, value)
|
|
if value and '_%s' % key not in _SCALAR_FIELDS
|
|
else int(value) if value
|
|
else None if not value and '_%s' % key not in _ZERO_IS_NOT_NONE
|
|
else value
|
|
for key, value in data.iteritems()
|
|
if key != 'type'
|
|
}
|
|
if data_type == 'rrule':
|
|
result.rrule(rrule(**data))
|
|
# TODO: implement rdate, exrule, exdate
|
|
else:
|
|
raise ValueError('Unknown type given')
|
|
return result
|