recurrence: add last-day-of-month
This commit is contained in:
parent
18f194caa5
commit
181f7405d6
5 changed files with 79 additions and 8 deletions
|
@ -366,6 +366,14 @@ msgctxt "help:cashbook.planner,move_event:"
|
||||||
msgid "If the date of execution falls on a weekend or holiday, it can be moved to a business day."
|
msgid "If the date of execution falls on a weekend or holiday, it can be moved to a business day."
|
||||||
msgstr "Wenn das Datum der Ausführung auf ein Wochenende oder Feiertag fällt, kann es auf einen Geschäftstag verschoben werden."
|
msgstr "Wenn das Datum der Ausführung auf ein Wochenende oder Feiertag fällt, kann es auf einen Geschäftstag verschoben werden."
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.planner,last_day_of_month:"
|
||||||
|
msgid "Last day of the month"
|
||||||
|
msgstr "letzer Tag des Monats"
|
||||||
|
|
||||||
|
msgctxt "help:cashbook.planner,last_day_of_month:"
|
||||||
|
msgid "The booking is made on the last day of the month."
|
||||||
|
msgstr "Die Buchung wird am letzten Tag des Monats ausgeführt."
|
||||||
|
|
||||||
|
|
||||||
############################
|
############################
|
||||||
# cashbook.planner.nextrun #
|
# cashbook.planner.nextrun #
|
||||||
|
|
|
@ -374,3 +374,10 @@ msgctxt "view:cashbook.line:"
|
||||||
msgid "Scheduled Bookings"
|
msgid "Scheduled Bookings"
|
||||||
msgstr "Scheduled Bookings"
|
msgstr "Scheduled Bookings"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.planner,last_day_of_month:"
|
||||||
|
msgid "Last day of the month"
|
||||||
|
msgstr "Last day of the month"
|
||||||
|
|
||||||
|
msgctxt "help:cashbook.planner,last_day_of_month:"
|
||||||
|
msgid "The booking is made on the last day of the month."
|
||||||
|
msgstr "The booking is made on the last day of the month."
|
||||||
|
|
59
planner.py
59
planner.py
|
@ -91,7 +91,14 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView):
|
||||||
[('monthday', '>=', 1), ('monthday', '<=', 31)],
|
[('monthday', '>=', 1), ('monthday', '<=', 31)],
|
||||||
('monthday', '=', None))],
|
('monthday', '=', None))],
|
||||||
depends=['weekday', 'frequ'],
|
depends=['weekday', 'frequ'],
|
||||||
states={'required': COND_MONTHDAY, 'invisible': ~COND_MONTHDAY})
|
states={
|
||||||
|
'required': And(COND_MONTHDAY, ~Eval('last_day_of_month', False)),
|
||||||
|
'invisible': ~And(
|
||||||
|
COND_MONTHDAY, ~Eval('last_day_of_month', False))})
|
||||||
|
last_day_of_month = fields.Boolean(
|
||||||
|
string='Last day of the month', depends=['weekday', 'frequ'],
|
||||||
|
help='The booking is made on the last day of the month.',
|
||||||
|
states={'invisible': ~COND_MONTHDAY})
|
||||||
interval = fields.Integer(
|
interval = fields.Integer(
|
||||||
string='Interval', required=True,
|
string='Interval', required=True,
|
||||||
help='Select an interval to run the rule on every n-th date.',
|
help='Select an interval to run the rule on every n-th date.',
|
||||||
|
@ -263,6 +270,8 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView):
|
||||||
count = 5
|
count = 5
|
||||||
count = 1 if count < 1 else 100 if count > 100 else count
|
count = 1 if count < 1 else 100 if count > 100 else count
|
||||||
|
|
||||||
|
last_day_of_month = params.get(
|
||||||
|
'last_day_of_month', self.last_day_of_month)
|
||||||
end_date = params.get('end_date', self.end_date)
|
end_date = params.get('end_date', self.end_date)
|
||||||
frequ = pfrequ[params.get('frequ', self.frequ)]
|
frequ = pfrequ[params.get('frequ', self.frequ)]
|
||||||
|
|
||||||
|
@ -283,6 +292,18 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView):
|
||||||
interval = 1
|
interval = 1
|
||||||
interval = 1 if interval < 1 else 10 if interval > 10 else interval
|
interval = 1 if interval < 1 else 10 if interval > 10 else interval
|
||||||
|
|
||||||
|
# last-day-of-month: set date short before end of month,
|
||||||
|
# then compute move result to end of month
|
||||||
|
updt_lastday = False
|
||||||
|
if last_day_of_month and (frequ == MONTHLY) and not pweekday:
|
||||||
|
monthday = 28
|
||||||
|
updt_lastday = True
|
||||||
|
|
||||||
|
lastday_valid = last_day_of_month and (
|
||||||
|
frequ == MONTHLY) and (pweekday is None)
|
||||||
|
assert (lastday_valid or not last_day_of_month), \
|
||||||
|
('last-day-of-month can only be used with frequ=month ' +
|
||||||
|
'and weekday=99.')
|
||||||
assert (monthday is None) or (pweekday is None), \
|
assert (monthday is None) or (pweekday is None), \
|
||||||
"weekday and monthday cannot be used together"
|
"weekday and monthday cannot be used together"
|
||||||
|
|
||||||
|
@ -297,7 +318,12 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView):
|
||||||
for x in dtrule:
|
for x in dtrule:
|
||||||
if (query_date and (x.date() >= query_date)) or \
|
if (query_date and (x.date() >= query_date)) or \
|
||||||
(query_date is None):
|
(query_date is None):
|
||||||
x_date = get_moved_date(x.date(), move_event)
|
x_date = x.date()
|
||||||
|
if updt_lastday:
|
||||||
|
x_date = (
|
||||||
|
(x_date + timedelta(days=5)).replace(day=1) -
|
||||||
|
timedelta(days=1))
|
||||||
|
x_date = get_moved_date(x_date, move_event)
|
||||||
|
|
||||||
# if date was re-arranged backwards and we are before
|
# if date was re-arranged backwards and we are before
|
||||||
# query_date - skip it
|
# query_date - skip it
|
||||||
|
@ -368,7 +394,7 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView):
|
||||||
|
|
||||||
@fields.depends(
|
@fields.depends(
|
||||||
'start_date', 'end_date', 'frequ', 'weekday', 'monthday',
|
'start_date', 'end_date', 'frequ', 'weekday', 'monthday',
|
||||||
'interval', 'setpos', 'move_event')
|
'interval', 'setpos', 'move_event', 'last_day_of_month')
|
||||||
def on_change_with_nextdates(self, name=None):
|
def on_change_with_nextdates(self, name=None):
|
||||||
""" Calculates the next 5 appointments based on the configured rule,
|
""" Calculates the next 5 appointments based on the configured rule,
|
||||||
returns a formatted date list
|
returns a formatted date list
|
||||||
|
@ -401,7 +427,8 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView):
|
||||||
'weekday': self.weekday,
|
'weekday': self.weekday,
|
||||||
'monthday': self.monthday,
|
'monthday': self.monthday,
|
||||||
'interval': self.interval,
|
'interval': self.interval,
|
||||||
'setpos': self.setpos}
|
'setpos': self.setpos,
|
||||||
|
'last_day_of_month': self.last_day_of_month}
|
||||||
)])
|
)])
|
||||||
|
|
||||||
@fields.depends('cashbook', '_parent_cashbook.owner')
|
@fields.depends('cashbook', '_parent_cashbook.owner')
|
||||||
|
@ -428,26 +455,33 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView):
|
||||||
elif self.bookingtype in ['mvin', 'mvout']:
|
elif self.bookingtype in ['mvin', 'mvout']:
|
||||||
self.category = None
|
self.category = None
|
||||||
|
|
||||||
@fields.depends('frequ', 'setpos', 'weekday', 'monthday')
|
@fields.depends(
|
||||||
|
'frequ', 'setpos', 'weekday', 'monthday', 'last_day_of_month')
|
||||||
def on_change_frequ(self):
|
def on_change_frequ(self):
|
||||||
""" update fields
|
""" update fields
|
||||||
"""
|
"""
|
||||||
if self.frequ and self.frequ == 'month':
|
if self.frequ and self.frequ == 'month':
|
||||||
if self.weekday:
|
if self.weekday:
|
||||||
if self.weekday == '99':
|
if self.weekday == '99':
|
||||||
if self.monthday is None:
|
if self.last_day_of_month:
|
||||||
self.monthday = 1
|
self.monthday = None
|
||||||
|
else:
|
||||||
|
if self.monthday is None:
|
||||||
|
self.monthday = 1
|
||||||
self.setpos = None
|
self.setpos = None
|
||||||
else:
|
else:
|
||||||
if self.setpos is None:
|
if self.setpos is None:
|
||||||
self.setpos = 1
|
self.setpos = 1
|
||||||
self.monthday = None
|
self.monthday = None
|
||||||
|
self.last_day_of_month = False
|
||||||
else:
|
else:
|
||||||
self.setpos = None
|
self.setpos = None
|
||||||
self.monthday = None
|
self.monthday = None
|
||||||
self.weekday = '99'
|
self.weekday = '99'
|
||||||
|
self.last_day_of_month = False
|
||||||
|
|
||||||
@fields.depends('frequ', 'setpos', 'weekday', 'monthday')
|
@fields.depends(
|
||||||
|
'frequ', 'setpos', 'weekday', 'monthday', 'last_day_of_month')
|
||||||
def on_change_weekday(self):
|
def on_change_weekday(self):
|
||||||
""" clear day-of-month if weekday is used
|
""" clear day-of-month if weekday is used
|
||||||
"""
|
"""
|
||||||
|
@ -546,6 +580,15 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView):
|
||||||
"""
|
"""
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def default_last_day_of_month(cls):
|
||||||
|
""" get default for last-day-of-month
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
boolean: False
|
||||||
|
"""
|
||||||
|
return False
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def default_frequ(cls):
|
def default_frequ(cls):
|
||||||
""" get default for frequency
|
""" get default for frequency
|
||||||
|
|
|
@ -245,6 +245,17 @@ class PlannerTestCase(object):
|
||||||
[date(2022, 5, 11), date(2022, 6, 8), date(2022, 7, 13),
|
[date(2022, 5, 11), date(2022, 6, 8), date(2022, 7, 13),
|
||||||
date(2022, 8, 10), date(2022, 9, 14), date(2022, 10, 12)])
|
date(2022, 8, 10), date(2022, 9, 14), date(2022, 10, 12)])
|
||||||
|
|
||||||
|
# last day of month
|
||||||
|
self.assertEqual(
|
||||||
|
job._compute_dates_by_rrule(
|
||||||
|
query_date=date(2022, 5, 1), count=6,
|
||||||
|
params={
|
||||||
|
'weekday': '99', 'end_date': None, 'frequ': 'month',
|
||||||
|
'interval': 1, 'setpos': None, 'monthday': None,
|
||||||
|
'last_day_of_month': True}),
|
||||||
|
[date(2022, 5, 31), date(2022, 6, 30), date(2022, 7, 31),
|
||||||
|
date(2022, 8, 31), date(2022, 9, 30), date(2022, 10, 31)])
|
||||||
|
|
||||||
# set up holidays
|
# set up holidays
|
||||||
cfg1 = Config(
|
cfg1 = Config(
|
||||||
holidays='01-01;05-01;easter:+1;easter:-2;ascension;whitsun:+1')
|
holidays='01-01;05-01;easter:+1;easter:-2;ascension;whitsun:+1')
|
||||||
|
|
|
@ -34,6 +34,8 @@ full copyright notices and license terms. -->
|
||||||
<field name="weekday"/>
|
<field name="weekday"/>
|
||||||
<label name="monthday"/>
|
<label name="monthday"/>
|
||||||
<field name="monthday"/>
|
<field name="monthday"/>
|
||||||
|
<label name="last_day_of_month"/>
|
||||||
|
<field name="last_day_of_month"/>
|
||||||
|
|
||||||
<label name="move_event"/>
|
<label name="move_event"/>
|
||||||
<field name="move_event"/>
|
<field name="move_event"/>
|
||||||
|
|
Loading…
Reference in a new issue