Recurrence rule + tests
This commit is contained in:
parent
ebb1efe7a8
commit
ed350ba3e2
6 changed files with 564 additions and 19 deletions
96
locale/de.po
96
locale/de.po
|
@ -58,6 +58,14 @@ msgctxt "model:cashbook.planner,name:"
|
||||||
msgid "Scheduled Booking"
|
msgid "Scheduled Booking"
|
||||||
msgstr "geplante Buchung"
|
msgstr "geplante Buchung"
|
||||||
|
|
||||||
|
msgctxt "view:cashbook.planner:"
|
||||||
|
msgid "Recurrence Rule"
|
||||||
|
msgstr "Wiederholregel"
|
||||||
|
|
||||||
|
msgctxt "view:cashbook.planner:"
|
||||||
|
msgid "Result of the recurrence rule"
|
||||||
|
msgstr "Ergebnis der Wiederholregel"
|
||||||
|
|
||||||
msgctxt "field:cashbook.planner,company:"
|
msgctxt "field:cashbook.planner,company:"
|
||||||
msgid "Company"
|
msgid "Company"
|
||||||
msgstr "Unternehmen"
|
msgstr "Unternehmen"
|
||||||
|
@ -86,6 +94,94 @@ msgctxt "field:cashbook.planner,end_date:"
|
||||||
msgid "End Date"
|
msgid "End Date"
|
||||||
msgstr "Endedatum"
|
msgstr "Endedatum"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.planner,frequ:"
|
||||||
|
msgid "Frequency"
|
||||||
|
msgstr "Frequenz"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.planner,frequ:"
|
||||||
|
msgid "Yearly"
|
||||||
|
msgstr "Jährlich"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.planner,frequ:"
|
||||||
|
msgid "Monthly"
|
||||||
|
msgstr "Monatlich"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.planner,frequ:"
|
||||||
|
msgid "Weekly"
|
||||||
|
msgstr "Wöchentlich"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.planner,frequ:"
|
||||||
|
msgid "Daily"
|
||||||
|
msgstr "Täglich"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.planner,weekday:"
|
||||||
|
msgid "Weekday"
|
||||||
|
msgstr "Wochentag"
|
||||||
|
|
||||||
|
msgctxt "help:cashbook.planner,weekday:"
|
||||||
|
msgid "Select a day of the week if you want the rule to run on that day."
|
||||||
|
msgstr "Wählen Sie einen Wochentag aus, wenn die Regel an diesem Tag ausgeführt werden soll."
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.planner,weekday:"
|
||||||
|
msgid "Monday"
|
||||||
|
msgstr "Montag"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.planner,weekday:"
|
||||||
|
msgid "Tuesday"
|
||||||
|
msgstr "Dienstag"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.planner,weekday:"
|
||||||
|
msgid "Wednesday"
|
||||||
|
msgstr "Mittwoch"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.planner,weekday:"
|
||||||
|
msgid "Thursday"
|
||||||
|
msgstr "Donnerstag"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.planner,weekday:"
|
||||||
|
msgid "Friday"
|
||||||
|
msgstr "Freitag"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.planner,weekday:"
|
||||||
|
msgid "Saturday"
|
||||||
|
msgstr "Samstag"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.planner,weekday:"
|
||||||
|
msgid "Sunday"
|
||||||
|
msgstr "Sonntag"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.planner,monthday:"
|
||||||
|
msgid "Day of month"
|
||||||
|
msgstr "Tag des Monats"
|
||||||
|
|
||||||
|
msgctxt "help:cashbook.planner,monthday:"
|
||||||
|
msgid "If you want the rule to run on a specific day of the month, select the day here."
|
||||||
|
msgstr "Wenn die Regel an einem bestimmten Tag im Monat ausgeführt soll, wählen Siehier den Tag."
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.planner,interval:"
|
||||||
|
msgid "Interval"
|
||||||
|
msgstr "Intervall"
|
||||||
|
|
||||||
|
msgctxt "help:cashbook.planner,interval:"
|
||||||
|
msgid "Select an interval to run the rule on every n-th date."
|
||||||
|
msgstr "Wählen Sie einen Intervall um die Regel an jedem n-ten Datum auszuführen."
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.planner,nextdates:"
|
||||||
|
msgid "Next Dates"
|
||||||
|
msgstr "nächste Termine"
|
||||||
|
|
||||||
|
msgctxt "help:cashbook.planner,nextdates:"
|
||||||
|
msgid "the next 5 appointments based on the configured rule"
|
||||||
|
msgstr "die nächsten 5 Termine anhand der konfigurierten Regel"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.planner,setpos:"
|
||||||
|
msgid "Occurrence"
|
||||||
|
msgstr "Ereignis"
|
||||||
|
|
||||||
|
msgctxt "help:cashbook.planner,setpos:"
|
||||||
|
msgid "For example, if you want to run the rule on the second Wednesday of the month, enter 2 here."
|
||||||
|
msgstr "Wenn Sie die Regel z.B. am zweiten Mittwoch im Monat ausführen möchten, tragen Sie hier 2 ein."
|
||||||
|
|
||||||
|
|
||||||
#################
|
#################
|
||||||
# cashbook.book #
|
# cashbook.book #
|
||||||
|
|
146
locale/en.po
146
locale/en.po
|
@ -2,17 +2,9 @@
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
msgstr "Content-Type: text/plain; charset=utf-8\n"
|
||||||
|
|
||||||
msgctxt "model:res.group,name:group_planner_read"
|
msgctxt "model:res.group,name:group_planner"
|
||||||
msgid "Cashbook - Scheduled Bookings (read)"
|
msgid "Cashbook - Scheduled Bookings"
|
||||||
msgstr "Cashbook - Scheduled Bookings (read)"
|
msgstr "Cashbook - Scheduled Bookings"
|
||||||
|
|
||||||
msgctxt "model:res.group,name:group_planner_write"
|
|
||||||
msgid "Cashbook - Scheduled Bookings (write)"
|
|
||||||
msgstr "Cashbook - Scheduled Bookings (write)"
|
|
||||||
|
|
||||||
msgctxt "model:res.group,name:group_planner_admin"
|
|
||||||
msgid "Cashbook - Scheduled Bookings (admin)"
|
|
||||||
msgstr "Cashbook - Scheduled Bookings (admin)"
|
|
||||||
|
|
||||||
msgctxt "model:ir.ui.menu,name:menu_planner"
|
msgctxt "model:ir.ui.menu,name:menu_planner"
|
||||||
msgid "Scheduled Bookings"
|
msgid "Scheduled Bookings"
|
||||||
|
@ -42,3 +34,135 @@ msgctxt "model:ir.rule.group,name:rg_planner_companies"
|
||||||
msgid "User in companies"
|
msgid "User in companies"
|
||||||
msgstr "User in companies"
|
msgstr "User in companies"
|
||||||
|
|
||||||
|
msgctxt "model:cashbook.planner,name:"
|
||||||
|
msgid "Scheduled Booking"
|
||||||
|
msgstr "Scheduled Booking"
|
||||||
|
|
||||||
|
msgctxt "view:cashbook.planner:"
|
||||||
|
msgid "Recurrence Rule"
|
||||||
|
msgstr "Recurrence Rule"
|
||||||
|
|
||||||
|
msgctxt "view:cashbook.planner:"
|
||||||
|
msgid "Result of the recurrence rule"
|
||||||
|
msgstr "Result of the recurrence rule"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.planner,company:"
|
||||||
|
msgid "Company"
|
||||||
|
msgstr "Company"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.planner,cashbook:"
|
||||||
|
msgid "Cashbook"
|
||||||
|
msgstr "Cashbook"
|
||||||
|
|
||||||
|
msgctxt "help:cashbook.planner,cashbook:"
|
||||||
|
msgid "Cash book for which the planned posting is to be executed."
|
||||||
|
msgstr "Cash book for which the planned posting is to be executed."
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.planner,name:"
|
||||||
|
msgid "Name"
|
||||||
|
msgstr "Name"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.planner,description:"
|
||||||
|
msgid "Description"
|
||||||
|
msgstr "Description"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.planner,start_date:"
|
||||||
|
msgid "Start Date"
|
||||||
|
msgstr "Start Date"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.planner,end_date:"
|
||||||
|
msgid "End Date"
|
||||||
|
msgstr "End Date"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.planner,frequ:"
|
||||||
|
msgid "Frequency"
|
||||||
|
msgstr "Frequency"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.planner,frequ:"
|
||||||
|
msgid "Yearly"
|
||||||
|
msgstr "Yearly"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.planner,frequ:"
|
||||||
|
msgid "Monthly"
|
||||||
|
msgstr "Monthly"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.planner,frequ:"
|
||||||
|
msgid "Weekly"
|
||||||
|
msgstr "Weekly"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.planner,frequ:"
|
||||||
|
msgid "Daily"
|
||||||
|
msgstr "Daily"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.planner,weekday:"
|
||||||
|
msgid "Weekday"
|
||||||
|
msgstr "Weekday"
|
||||||
|
|
||||||
|
msgctxt "help:cashbook.planner,weekday:"
|
||||||
|
msgid "Select a day of the week if you want the rule to run on that day."
|
||||||
|
msgstr "Select a day of the week if you want the rule to run on that day."
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.planner,weekday:"
|
||||||
|
msgid "Monday"
|
||||||
|
msgstr "Monday"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.planner,weekday:"
|
||||||
|
msgid "Tuesday"
|
||||||
|
msgstr "Tuesday"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.planner,weekday:"
|
||||||
|
msgid "Wednesday"
|
||||||
|
msgstr "Wednesday"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.planner,weekday:"
|
||||||
|
msgid "Thursday"
|
||||||
|
msgstr "Thursday"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.planner,weekday:"
|
||||||
|
msgid "Friday"
|
||||||
|
msgstr "Friday"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.planner,weekday:"
|
||||||
|
msgid "Saturday"
|
||||||
|
msgstr "Saturday"
|
||||||
|
|
||||||
|
msgctxt "selection:cashbook.planner,weekday:"
|
||||||
|
msgid "Sunday"
|
||||||
|
msgstr "Sunday"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.planner,monthday:"
|
||||||
|
msgid "Day of month"
|
||||||
|
msgstr "Day of month"
|
||||||
|
|
||||||
|
msgctxt "help:cashbook.planner,monthday:"
|
||||||
|
msgid "If you want the rule to run on a specific day of the month, select the day here."
|
||||||
|
msgstr "If you want the rule to run on a specific day of the month, select the day here."
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.planner,interval:"
|
||||||
|
msgid "Interval"
|
||||||
|
msgstr "Interval"
|
||||||
|
|
||||||
|
msgctxt "help:cashbook.planner,interval:"
|
||||||
|
msgid "Select an interval to run the rule on every n-th date."
|
||||||
|
msgstr "Select an interval to run the rule on every n-th date."
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.planner,nextdates:"
|
||||||
|
msgid "Next Dates"
|
||||||
|
msgstr "Next Dates"
|
||||||
|
|
||||||
|
msgctxt "help:cashbook.planner,nextdates:"
|
||||||
|
msgid "the next 5 appointments based on the configured rule"
|
||||||
|
msgstr "the next 5 appointments based on the configured rule"
|
||||||
|
|
||||||
|
msgctxt "field:cashbook.planner,setpos:"
|
||||||
|
msgid "Occurrence"
|
||||||
|
msgstr "Occurrence"
|
||||||
|
|
||||||
|
msgctxt "help:cashbook.planner,setpos:"
|
||||||
|
msgid "For example, if you want to run the rule on the second Wednesday of the month, enter 2 here."
|
||||||
|
msgstr "For example, if you want to run the rule on the second Wednesday of the month, enter 2 here."
|
||||||
|
|
||||||
|
msgctxt "view:cashbook.book:"
|
||||||
|
msgid "Scheduled Bookings"
|
||||||
|
msgstr "Scheduled Bookings"
|
||||||
|
|
||||||
|
|
213
planner.py
213
planner.py
|
@ -3,12 +3,26 @@
|
||||||
# The COPYRIGHT file at the top level of this repository contains the
|
# The COPYRIGHT file at the top level of this repository contains the
|
||||||
# full copyright notices and license terms.
|
# full copyright notices and license terms.
|
||||||
|
|
||||||
|
from datetime import date
|
||||||
|
from dateutil.rrule import (
|
||||||
|
rrule, YEARLY, MONTHLY, WEEKLY, DAILY, MO, TU, WE, TH, FR, SA, SU)
|
||||||
from trytond.model import ModelSQL, ModelView, fields, Index, DeactivableMixin
|
from trytond.model import ModelSQL, ModelView, fields, Index, DeactivableMixin
|
||||||
from trytond.transaction import Transaction
|
from trytond.transaction import Transaction
|
||||||
from trytond.pool import Pool
|
from trytond.pool import Pool
|
||||||
from trytond.pyson import Eval, Bool
|
from trytond.report import Report
|
||||||
|
from trytond.pyson import Eval, Bool, If, And
|
||||||
|
|
||||||
DEF_NONE = None
|
DEF_NONE = None
|
||||||
|
SEL_FREQU = [
|
||||||
|
('year', 'Yearly'),
|
||||||
|
('month', 'Monthly'),
|
||||||
|
('week', 'Weekly'),
|
||||||
|
('day', 'Daily')]
|
||||||
|
SEL_WEEKDAY = [
|
||||||
|
('99', '-'),
|
||||||
|
('0', 'Monday'), ('1', 'Tuesday'), ('2', 'Wednesday'),
|
||||||
|
('3', 'Thursday'), ('4', 'Friday'), ('5', 'Saturday'),
|
||||||
|
('6', 'Sunday')]
|
||||||
|
|
||||||
|
|
||||||
class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView):
|
class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView):
|
||||||
|
@ -33,6 +47,45 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView):
|
||||||
'OR',
|
'OR',
|
||||||
('end_date', '>', Eval('start_date')),
|
('end_date', '>', Eval('start_date')),
|
||||||
('end_date', '=', DEF_NONE)])
|
('end_date', '=', DEF_NONE)])
|
||||||
|
frequ = fields.Selection(
|
||||||
|
string='Frequency', required=True, selection=SEL_FREQU, sort=False)
|
||||||
|
weekday = fields.Selection(
|
||||||
|
string='Weekday', required=True, selection=SEL_WEEKDAY, sort=False,
|
||||||
|
help='Select a day of the week if you want the rule to ' +
|
||||||
|
'run on that day.',
|
||||||
|
depends=['frequ'],
|
||||||
|
states={'invisible': Eval('frequ') != 'month'})
|
||||||
|
COND_SETPOS = And(Eval('weekday', '') != '99', Eval('frequ') == 'month')
|
||||||
|
setpos = fields.Integer(
|
||||||
|
string='Occurrence', depends=['weekday', 'frequ'],
|
||||||
|
domain=[
|
||||||
|
If(COND_SETPOS,
|
||||||
|
[('setpos', '<=', 4), ('setpos', '>=', 1)],
|
||||||
|
('setpos', '=', None))],
|
||||||
|
help='For example, if you want to run the rule on the second ' +
|
||||||
|
'Wednesday of the month, enter 2 here.',
|
||||||
|
states={'required': COND_SETPOS, 'invisible': ~COND_SETPOS})
|
||||||
|
COND_MONTHDAY = And(Eval('weekday', '') == '99', Eval('frequ') == 'month')
|
||||||
|
monthday = fields.Integer(
|
||||||
|
string='Day of month',
|
||||||
|
help='If you want the rule to run on a specific day of the month, ' +
|
||||||
|
'select the day here.',
|
||||||
|
domain=[
|
||||||
|
If(COND_MONTHDAY,
|
||||||
|
[('monthday', '>=', 1), ('monthday', '<=', 31)],
|
||||||
|
('monthday', '=', None))],
|
||||||
|
depends=['weekday', 'frequ'],
|
||||||
|
states={'required': COND_MONTHDAY, 'invisible': ~COND_MONTHDAY})
|
||||||
|
interval = fields.Integer(
|
||||||
|
string='Interval', required=True,
|
||||||
|
help='Select an interval to run the rule on every n-th date.',
|
||||||
|
domain=[('interval', '>=', 1), ('interval', '<=', 10)])
|
||||||
|
nextdates = fields.Function(fields.Char(
|
||||||
|
string='Next Dates', readonly=True,
|
||||||
|
help='the next 5 appointments based on the configured rule'),
|
||||||
|
'on_change_with_nextdates')
|
||||||
|
|
||||||
|
# rrule: frequ, dtstart, until, bymonthday
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def __setup__(cls):
|
def __setup__(cls):
|
||||||
|
@ -51,6 +104,164 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView):
|
||||||
where=t.end_date != DEF_NONE),
|
where=t.end_date != DEF_NONE),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
def _compute_dates_by_rrule(self, start_date=None, count=5, params={}):
|
||||||
|
""" run rrule with values from record or from 'params'
|
||||||
|
|
||||||
|
Args:
|
||||||
|
start_date (date, optional): Start date as a filter for
|
||||||
|
recurrences. Defaults to None.
|
||||||
|
count (int, optional): number of recurrences in result.
|
||||||
|
Defaults to 5. max value = 100
|
||||||
|
params (dict, optional): Values in the dictionary are
|
||||||
|
used instead of the stored values, Defaults to {},
|
||||||
|
allowed: frequ, weekday, start_date,
|
||||||
|
end_date (preferred over 'count'),
|
||||||
|
monthday, interval, setpos
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
list: date values, result of rrlue
|
||||||
|
"""
|
||||||
|
pfrequ = {
|
||||||
|
'year': YEARLY, 'month': MONTHLY, 'week': WEEKLY, 'day': DAILY}
|
||||||
|
pweekday = {
|
||||||
|
'0': MO, '1': TU, '2': WE, '3': TH, '4': FR, '5': SA, '6': SU,
|
||||||
|
'99': None}
|
||||||
|
|
||||||
|
if (count is None) or (count > 100):
|
||||||
|
count = 100
|
||||||
|
if count < 1:
|
||||||
|
count = 1
|
||||||
|
|
||||||
|
end_date = params.get('end_date', self.end_date)
|
||||||
|
frequ = pfrequ[params.get('frequ', self.frequ)]
|
||||||
|
|
||||||
|
setpos = params.get('setpos', self.setpos)
|
||||||
|
if setpos is not None:
|
||||||
|
setpos = 1 if setpos < 1 else 4 if setpos > 4 else setpos
|
||||||
|
|
||||||
|
monthday = params.get('monthday', self.monthday)
|
||||||
|
if monthday is not None:
|
||||||
|
monthday = 1 if monthday < 1 else 31 if monthday > 31 else monthday
|
||||||
|
|
||||||
|
interval = params.get('interval', self.interval)
|
||||||
|
interval = 1 if interval < 1 else 10 if interval > 10 else interval
|
||||||
|
|
||||||
|
dtrule = rrule(
|
||||||
|
freq=frequ,
|
||||||
|
byweekday=pweekday[params.get('weekday', self.weekday)],
|
||||||
|
dtstart=params.get('start_date', self.start_date),
|
||||||
|
until=end_date,
|
||||||
|
bysetpos=setpos if frequ == MONTHLY else None,
|
||||||
|
bymonthday=monthday, interval=interval)
|
||||||
|
|
||||||
|
result = []
|
||||||
|
for x in dtrule:
|
||||||
|
if (start_date and (x.date() >= start_date)) or \
|
||||||
|
(start_date is None):
|
||||||
|
result.append(x.date())
|
||||||
|
if len(result) >= count:
|
||||||
|
break
|
||||||
|
return result
|
||||||
|
|
||||||
|
@fields.depends(
|
||||||
|
'start_date', 'end_date', 'frequ', 'weekday', 'monthday',
|
||||||
|
'interval', 'setpos')
|
||||||
|
def on_change_with_nextdates(self, name=None):
|
||||||
|
""" Calculates the next 5 appointments based on the configured rule,
|
||||||
|
returns a formatted date list
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name (string, optional): name of field. Defaults to None.
|
||||||
|
|
||||||
|
context:
|
||||||
|
start_date (date, optional): start date for dates in result,
|
||||||
|
defaults to today if not set or None
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
string: formatted list of dates
|
||||||
|
"""
|
||||||
|
IrDate = Pool().get('ir.date')
|
||||||
|
context = Transaction().context
|
||||||
|
|
||||||
|
start_date = context.get('start_date', None)
|
||||||
|
if not isinstance(start_date, date):
|
||||||
|
start_date = IrDate.today()
|
||||||
|
|
||||||
|
return ' | '.join([
|
||||||
|
Report.format_date(x)
|
||||||
|
for x in self._compute_dates_by_rrule(
|
||||||
|
start_date=start_date,
|
||||||
|
params={
|
||||||
|
'start_date': self.start_date,
|
||||||
|
'end_date': self.end_date,
|
||||||
|
'frequ': self.frequ,
|
||||||
|
'weekday': self.weekday,
|
||||||
|
'monthday': self.monthday,
|
||||||
|
'interval': self.interval,
|
||||||
|
'setpos': self.setpos}
|
||||||
|
)])
|
||||||
|
|
||||||
|
@fields.depends('frequ', 'setpos', 'weekday', 'monthday')
|
||||||
|
def on_change_frequ(self):
|
||||||
|
""" update fields
|
||||||
|
"""
|
||||||
|
if self.frequ and self.frequ == 'month':
|
||||||
|
if self.weekday:
|
||||||
|
if self.weekday == '99':
|
||||||
|
if self.monthday is None:
|
||||||
|
self.monthday = 1
|
||||||
|
self.setpos = None
|
||||||
|
else:
|
||||||
|
if self.setpos is None:
|
||||||
|
self.setpos = 1
|
||||||
|
self.monthday = None
|
||||||
|
else:
|
||||||
|
self.setpos = None
|
||||||
|
self.monthday = None
|
||||||
|
self.weekday = '99'
|
||||||
|
|
||||||
|
@fields.depends('frequ', 'setpos', 'weekday', 'monthday')
|
||||||
|
def on_change_weekday(self):
|
||||||
|
""" clear day-of-month if weekday is used
|
||||||
|
"""
|
||||||
|
self.on_change_frequ()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def default_interval(cls):
|
||||||
|
""" get default for interval
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: 1 = each occurence
|
||||||
|
"""
|
||||||
|
return 1
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def default_weekday(cls):
|
||||||
|
""" get default for weekday-rule
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
string: '99' = not set
|
||||||
|
"""
|
||||||
|
return '99'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def default_monthday(cls):
|
||||||
|
""" get default for day-of-month
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
int: 1
|
||||||
|
"""
|
||||||
|
return 1
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def default_frequ(cls):
|
||||||
|
""" get default for frequency
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
string: 'month'
|
||||||
|
"""
|
||||||
|
return 'month'
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def default_company():
|
def default_company():
|
||||||
return Transaction().context.get('company') or None
|
return Transaction().context.get('company') or None
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -45,7 +45,7 @@ with open(path.join(here, 'versiondep.txt'), encoding='utf-8') as f:
|
||||||
major_version = 7
|
major_version = 7
|
||||||
minor_version = 0
|
minor_version = 0
|
||||||
|
|
||||||
requires = []
|
requires = ['python-dateutil']
|
||||||
for dep in info.get('depends', []):
|
for dep in info.get('depends', []):
|
||||||
if not re.match(r'(ir|res|webdav)(\W|$)', dep):
|
if not re.match(r'(ir|res|webdav)(\W|$)', dep):
|
||||||
if dep in modversion.keys():
|
if dep in modversion.keys():
|
||||||
|
|
|
@ -7,12 +7,107 @@ from trytond.tests.test_tryton import with_transaction
|
||||||
from trytond.pool import Pool
|
from trytond.pool import Pool
|
||||||
from trytond.transaction import Transaction
|
from trytond.transaction import Transaction
|
||||||
from trytond.exceptions import UserError
|
from trytond.exceptions import UserError
|
||||||
|
|
||||||
from datetime import date
|
from datetime import date
|
||||||
from decimal import Decimal
|
|
||||||
|
|
||||||
|
|
||||||
class PlannerTestCase(object):
|
class PlannerTestCase(object):
|
||||||
""" test planner
|
""" test planner
|
||||||
"""
|
"""
|
||||||
|
def prep_create_job(self, name='Job 1'):
|
||||||
|
pool = Pool()
|
||||||
|
Book = pool.get('cashbook.book')
|
||||||
|
Planner = pool.get('cashbook.planner')
|
||||||
|
|
||||||
|
types = self.prep_type()
|
||||||
|
company = self.prep_company()
|
||||||
|
job = None
|
||||||
|
with Transaction().set_context({
|
||||||
|
'company': company.id,
|
||||||
|
'start_date': date(2022, 5, 1)}):
|
||||||
|
book, = Book.create([{
|
||||||
|
'name': 'Book 1',
|
||||||
|
'btype': types.id,
|
||||||
|
'company': company.id,
|
||||||
|
'currency': company.currency.id,
|
||||||
|
'number_sequ': self.prep_sequence().id,
|
||||||
|
'start_date': date(2022, 5, 1),
|
||||||
|
}])
|
||||||
|
self.assertEqual(book.rec_name, 'Book 1 | 0.00 usd | Open')
|
||||||
|
|
||||||
|
job, = Planner.create([{
|
||||||
|
'cashbook': book.id,
|
||||||
|
'name': name,
|
||||||
|
'start_date': date(2022, 5, 1)}])
|
||||||
|
# check applied defaults
|
||||||
|
self.assertEqual(job.rec_name, 'Job 1')
|
||||||
|
self.assertEqual(job.start_date, date(2022, 5, 1))
|
||||||
|
self.assertEqual(job.end_date, None)
|
||||||
|
self.assertEqual(job.frequ, 'month')
|
||||||
|
self.assertEqual(job.weekday, '99')
|
||||||
|
self.assertEqual(job.monthday, 1)
|
||||||
|
self.assertEqual(job.interval, 1)
|
||||||
|
self.assertEqual(job.setpos, None)
|
||||||
|
self.assertEqual(
|
||||||
|
job.nextdates,
|
||||||
|
'05/01/2022 | 06/01/2022 | 07/01/2022 | 08/01/2022 |' +
|
||||||
|
' 09/01/2022')
|
||||||
|
return job
|
||||||
|
|
||||||
|
@with_transaction()
|
||||||
|
def test_planner_create_job(self):
|
||||||
|
""" create job, check rule
|
||||||
|
"""
|
||||||
|
Planner = Pool().get('cashbook.planner')
|
||||||
|
|
||||||
|
job = self.prep_create_job()
|
||||||
|
self.assertEqual(
|
||||||
|
job._compute_dates_by_rrule(
|
||||||
|
start_date=date(2022, 5, 1), count=5), [
|
||||||
|
date(2022, 5, 1), date(2022, 6, 1),
|
||||||
|
date(2022, 7, 1), date(2022, 8, 1),
|
||||||
|
date(2022, 9, 1)])
|
||||||
|
|
||||||
|
self.assertRaisesRegex(
|
||||||
|
UserError,
|
||||||
|
r'The value "2022-05-01" for field "End Date" in "Job 1" of ' +
|
||||||
|
r'"Scheduled Booking" is not valid according to its domain\.',
|
||||||
|
Planner.write,
|
||||||
|
*[[job], {'end_date': date(2022, 5, 1)}])
|
||||||
|
|
||||||
|
Planner.write(*[[job], {
|
||||||
|
'end_date': date(2022, 9, 15), 'monthday': 3}])
|
||||||
|
self.assertEqual(
|
||||||
|
job._compute_dates_by_rrule(start_date=date(2022, 5, 1)), [
|
||||||
|
date(2022, 5, 3), date(2022, 6, 3),
|
||||||
|
date(2022, 7, 3), date(2022, 8, 3),
|
||||||
|
date(2022, 9, 3)])
|
||||||
|
|
||||||
|
Planner.write(*[[job], {
|
||||||
|
'end_date': date(2022, 9, 15), 'monthday': 3, 'interval': 2}])
|
||||||
|
self.assertEqual(
|
||||||
|
job._compute_dates_by_rrule(start_date=date(2022, 5, 1)), [
|
||||||
|
date(2022, 5, 3), date(2022, 7, 3),
|
||||||
|
date(2022, 9, 3)])
|
||||||
|
|
||||||
|
# 3rd of each 2nd month
|
||||||
|
Planner.write(*[[job], {
|
||||||
|
'end_date': None, 'monthday': 1, 'interval': 1}])
|
||||||
|
self.assertEqual(
|
||||||
|
job._compute_dates_by_rrule(
|
||||||
|
start_date=date(2022, 5, 1),
|
||||||
|
params={
|
||||||
|
'end_date': date(2022, 9, 15), 'monthday': 3,
|
||||||
|
'interval': 2}),
|
||||||
|
[date(2022, 5, 3), date(2022, 7, 3), date(2022, 9, 3)])
|
||||||
|
|
||||||
|
# 1st wednesday of each 2nd month
|
||||||
|
self.assertEqual(
|
||||||
|
job._compute_dates_by_rrule(
|
||||||
|
start_date=date(2022, 5, 1),
|
||||||
|
params={
|
||||||
|
'end_date': date(2022, 9, 15), 'weekday': '2',
|
||||||
|
'interval': 2, 'setpos': 1}),
|
||||||
|
[date(2022, 5, 4), date(2022, 7, 6), date(2022, 9, 7)])
|
||||||
|
|
||||||
# end PlannerTestCase
|
# end PlannerTestCase
|
||||||
|
|
|
@ -2,23 +2,42 @@
|
||||||
<!-- This file is part of the cashbook-planner from m-ds for Tryton.
|
<!-- This file is part of the cashbook-planner from m-ds for Tryton.
|
||||||
The COPYRIGHT file at the top level of this repository contains the
|
The COPYRIGHT file at the top level of this repository contains the
|
||||||
full copyright notices and license terms. -->
|
full copyright notices and license terms. -->
|
||||||
<form col="4">
|
<form col="6">
|
||||||
<label name="cashbook"/>
|
<label name="cashbook"/>
|
||||||
<field name="cashbook" colspan="3"/>
|
<field name="cashbook" colspan="3"/>
|
||||||
|
<newline/>
|
||||||
|
|
||||||
<label name="name"/>
|
<label name="name"/>
|
||||||
<field name="name"/>
|
<field name="name" colspan="3"/>
|
||||||
<label name="active"/>
|
<newline/>
|
||||||
<field name="active"/>
|
|
||||||
|
|
||||||
<label name="start_date"/>
|
<label name="start_date"/>
|
||||||
<field name="start_date"/>
|
<field name="start_date"/>
|
||||||
<label name="end_date"/>
|
<label name="end_date"/>
|
||||||
<field name="end_date"/>
|
<field name="end_date"/>
|
||||||
|
<label name="active"/>
|
||||||
|
<field name="active"/>
|
||||||
|
|
||||||
|
<separator id="sep1" colspan="6" string="Recurrence Rule"/>
|
||||||
|
<label name="frequ"/>
|
||||||
|
<field name="frequ"/>
|
||||||
|
<label name="interval"/>
|
||||||
|
<field name="interval"/>
|
||||||
|
<label name="setpos"/>
|
||||||
|
<field name="setpos"/>
|
||||||
|
|
||||||
|
<label name="weekday"/>
|
||||||
|
<field name="weekday"/>
|
||||||
|
<label name="monthday"/>
|
||||||
|
<field name="monthday"/>
|
||||||
|
<newline/>
|
||||||
|
|
||||||
|
<separator id="sep2" colspan="6" string="Result of the recurrence rule"/>
|
||||||
|
<field name="nextdates" colspan="6"/>
|
||||||
|
|
||||||
<label name="description"/>
|
<label name="description"/>
|
||||||
<newline/>
|
<newline/>
|
||||||
<field name="description" colspan="4"/>
|
<field name="description" colspan="6"/>
|
||||||
|
|
||||||
|
|
||||||
</form>
|
</form>
|
||||||
|
|
Loading…
Reference in a new issue