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."
|
||||
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 #
|
||||
|
|
|
@ -374,3 +374,10 @@ msgctxt "view:cashbook.line:"
|
|||
msgid "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."
|
||||
|
|
55
planner.py
55
planner.py
|
@ -91,7 +91,14 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView):
|
|||
[('monthday', '>=', 1), ('monthday', '<=', 31)],
|
||||
('monthday', '=', None))],
|
||||
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(
|
||||
string='Interval', required=True,
|
||||
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 = 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)
|
||||
frequ = pfrequ[params.get('frequ', self.frequ)]
|
||||
|
||||
|
@ -283,6 +292,18 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView):
|
|||
interval = 1
|
||||
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), \
|
||||
"weekday and monthday cannot be used together"
|
||||
|
||||
|
@ -297,7 +318,12 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView):
|
|||
for x in dtrule:
|
||||
if (query_date and (x.date() >= query_date)) or \
|
||||
(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
|
||||
# query_date - skip it
|
||||
|
@ -368,7 +394,7 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView):
|
|||
|
||||
@fields.depends(
|
||||
'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):
|
||||
""" Calculates the next 5 appointments based on the configured rule,
|
||||
returns a formatted date list
|
||||
|
@ -401,7 +427,8 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView):
|
|||
'weekday': self.weekday,
|
||||
'monthday': self.monthday,
|
||||
'interval': self.interval,
|
||||
'setpos': self.setpos}
|
||||
'setpos': self.setpos,
|
||||
'last_day_of_month': self.last_day_of_month}
|
||||
)])
|
||||
|
||||
@fields.depends('cashbook', '_parent_cashbook.owner')
|
||||
|
@ -428,13 +455,17 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView):
|
|||
elif self.bookingtype in ['mvin', 'mvout']:
|
||||
self.category = None
|
||||
|
||||
@fields.depends('frequ', 'setpos', 'weekday', 'monthday')
|
||||
@fields.depends(
|
||||
'frequ', 'setpos', 'weekday', 'monthday', 'last_day_of_month')
|
||||
def on_change_frequ(self):
|
||||
""" update fields
|
||||
"""
|
||||
if self.frequ and self.frequ == 'month':
|
||||
if self.weekday:
|
||||
if self.weekday == '99':
|
||||
if self.last_day_of_month:
|
||||
self.monthday = None
|
||||
else:
|
||||
if self.monthday is None:
|
||||
self.monthday = 1
|
||||
self.setpos = None
|
||||
|
@ -442,12 +473,15 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView):
|
|||
if self.setpos is None:
|
||||
self.setpos = 1
|
||||
self.monthday = None
|
||||
self.last_day_of_month = False
|
||||
else:
|
||||
self.setpos = None
|
||||
self.monthday = None
|
||||
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):
|
||||
""" clear day-of-month if weekday is used
|
||||
"""
|
||||
|
@ -546,6 +580,15 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView):
|
|||
"""
|
||||
return 1
|
||||
|
||||
@classmethod
|
||||
def default_last_day_of_month(cls):
|
||||
""" get default for last-day-of-month
|
||||
|
||||
Returns:
|
||||
boolean: False
|
||||
"""
|
||||
return False
|
||||
|
||||
@classmethod
|
||||
def default_frequ(cls):
|
||||
""" 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, 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
|
||||
cfg1 = Config(
|
||||
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"/>
|
||||
<label name="monthday"/>
|
||||
<field name="monthday"/>
|
||||
<label name="last_day_of_month"/>
|
||||
<field name="last_day_of_month"/>
|
||||
|
||||
<label name="move_event"/>
|
||||
<field name="move_event"/>
|
||||
|
|
Loading…
Reference in a new issue