From 0fc0c4c8b99ef5e59c3eec04cdcbcb58d5a85a49 Mon Sep 17 00:00:00 2001 From: Frederik Jaeckel Date: Thu, 29 Feb 2024 23:20:19 +0100 Subject: [PATCH] add form for nextrun-records, update of nextrun-records, tests --- locale/de.po | 22 ++- locale/en.po | 380 +++++++++++++++++++++++------------------- nextrun.xml | 145 ++++++++++++++++ planner.py | 50 ++++-- tests/planner.py | 50 ++++-- tryton.cfg | 1 + view/nextrun_form.xml | 10 ++ view/nextrun_list.xml | 8 + 8 files changed, 472 insertions(+), 194 deletions(-) create mode 100644 nextrun.xml create mode 100644 view/nextrun_form.xml create mode 100644 view/nextrun_list.xml diff --git a/locale/de.po b/locale/de.po index a08bed0..eddec41 100644 --- a/locale/de.po +++ b/locale/de.po @@ -38,7 +38,7 @@ msgstr "geplante Buchungen" ################# # ir.rule.group # ################# -msgctxt "model:ir.rule.group,name:rg_planner_write_admin" +msgctxt "model:ir.rule.group,name:rg_planner_admin" msgid "Administrators: scheduled bookings read/write" msgstr "Administratoren: geplante Buchungen schreiben" @@ -58,6 +58,26 @@ msgctxt "model:ir.rule.group,name:rg_planner_companies" msgid "User in companies" msgstr "Benutzer im Unternehmen" +msgctxt "model:ir.rule.group,name:rg_nextrun_admin" +msgid "Administrators: scheduled bookings read/write" +msgstr "Administratoren: geplante Buchungen schreiben" + +msgctxt "model:ir.rule.group,name:rg_planner_owner" +msgid "Owners: scheduled bookings" +msgstr "Eigentümer: geplante Buchungen" + +msgctxt "model:ir.rule.group,name:rg_planner_read_nonowner" +msgid "Observers: scheduled bookings read" +msgstr "Beobachter: geplante Buchungen lesen" + +msgctxt "model:ir.rule.group,name:rg_planner_write_nonowner" +msgid "Reviewer: scheduled bookings write" +msgstr "Bearbeiter: geplante Buchungen schreiben" + +msgctxt "model:ir.rule.group,name:rg_nextrun_companies" +msgid "User in companies" +msgstr "Benutzer im Unternehmen" + #################### # cashbook.planner # diff --git a/locale/en.po b/locale/en.po index ba49c61..58f7e96 100644 --- a/locale/en.po +++ b/locale/en.po @@ -1,172 +1,208 @@ -# -msgid "" -msgstr "Content-Type: text/plain; charset=utf-8\n" - -msgctxt "selection:ir.cron,method:" -msgid "Execute scheduled bookings" -msgstr "Execute scheduled bookings" - -msgctxt "model:res.group,name:group_planner" -msgid "Cashbook - Scheduled Bookings" -msgstr "Cashbook - Scheduled Bookings" - -msgctxt "model:ir.ui.menu,name:menu_planner" -msgid "Scheduled Bookings" -msgstr "Scheduled Bookings" - -msgctxt "model:ir.action,name:act_planner_view" -msgid "Scheduled Bookings" -msgstr "Scheduled Bookings" - -msgctxt "model:ir.rule.group,name:rg_planner_write_admin" -msgid "Administrators: scheduled bookings read/write" -msgstr "Administrators: scheduled bookings read/write" - -msgctxt "model:ir.rule.group,name:rg_planner_owner" -msgid "Owners: scheduled bookings" -msgstr "Owners: scheduled bookings" - -msgctxt "model:ir.rule.group,name:rg_planner_read_nonowner" -msgid "Observers: scheduled bookings read" -msgstr "Observers: scheduled bookings read" - -msgctxt "model:ir.rule.group,name:rg_planner_write_nonowner" -msgid "Reviewer: scheduled bookings write" -msgstr "Reviewer: scheduled bookings write" - -msgctxt "model:ir.rule.group,name:rg_planner_companies" -msgid "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" - +# +msgid "" +msgstr "Content-Type: text/plain; charset=utf-8\n" + +msgctxt "selection:ir.cron,method:" +msgid "Execute scheduled bookings" +msgstr "Execute scheduled bookings" + +msgctxt "model:res.group,name:group_planner" +msgid "Cashbook - Scheduled Bookings" +msgstr "Cashbook - Scheduled Bookings" + +msgctxt "model:ir.ui.menu,name:menu_planner" +msgid "Scheduled Bookings" +msgstr "Scheduled Bookings" + +msgctxt "model:ir.action,name:act_planner_view" +msgid "Scheduled Bookings" +msgstr "Scheduled Bookings" + +msgctxt "model:ir.rule.group,name:rg_planner_admin" +msgid "Administrators: scheduled bookings read/write" +msgstr "Administrators: scheduled bookings read/write" + +msgctxt "model:ir.rule.group,name:rg_planner_owner" +msgid "Owners: scheduled bookings" +msgstr "Owners: scheduled bookings" + +msgctxt "model:ir.rule.group,name:rg_planner_read_nonowner" +msgid "Observers: scheduled bookings read" +msgstr "Observers: scheduled bookings read" + +msgctxt "model:ir.rule.group,name:rg_planner_write_nonowner" +msgid "Reviewer: scheduled bookings write" +msgstr "Reviewer: scheduled bookings write" + +msgctxt "model:ir.rule.group,name:rg_planner_companies" +msgid "User in companies" +msgstr "User in companies" + +msgctxt "model:ir.rule.group,name:rg_nextrun_admin" +msgid "Administrators: scheduled bookings read/write" +msgstr "Administrators: scheduled bookings read/write" + +msgctxt "model:ir.rule.group,name:rg_planner_owner" +msgid "Owners: scheduled bookings" +msgstr "Owners: scheduled bookings" + +msgctxt "model:ir.rule.group,name:rg_planner_read_nonowner" +msgid "Observers: scheduled bookings read" +msgstr "Observers: scheduled bookings read" + +msgctxt "model:ir.rule.group,name:rg_planner_write_nonowner" +msgid "Reviewer: scheduled bookings write" +msgstr "Reviewer: scheduled bookings write" + +msgctxt "model:ir.rule.group,name:rg_nextrun_companies" +msgid "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 "field:cashbook.planner,nextrun:" +msgid "Next Execution Date" +msgstr "Next Execution Date" + +msgctxt "model:cashbook.planner.nextrun,name:" +msgid "Next Execution Date" +msgstr "Next Execution Date" + +msgctxt "field:cashbook.planner.nextrun,planner:" +msgid "Planner" +msgstr "Planner" + +msgctxt "field:cashbook.planner.nextrun,date:" +msgid "Date" +msgstr "Date" + +msgctxt "view:cashbook.book:" +msgid "Scheduled Bookings" +msgstr "Scheduled Bookings" + diff --git a/nextrun.xml b/nextrun.xml new file mode 100644 index 0000000..ff25d39 --- /dev/null +++ b/nextrun.xml @@ -0,0 +1,145 @@ + + + + + + + + cashbook.planner.nextrun + tree + + nextrun_list + + + cashbook.planner.nextrun + form + + nextrun_form + + + + + + + + + + + + + + + + + + + + + + + + + Administrators: scheduled bookings read/write + + + + + + + + + + + + + + + + + + + + Owners: scheduled bookings + + + + + + + + + + + + + + + + + + + + Observers: scheduled bookings read + + + + + + + + + + + + + + + + + + + + Reviewer: scheduled bookings write + + + + + + + + + + + + + + + + + + User in companies + + + + + + + + + + diff --git a/planner.py b/planner.py index 5b33c9e..6dbe3ed 100644 --- a/planner.py +++ b/planner.py @@ -105,11 +105,11 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView): where=t.end_date != DEF_NONE), }) - def _compute_dates_by_rrule(self, start_date=None, count=5, params={}): + def _compute_dates_by_rrule(self, query_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 + query_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 @@ -160,8 +160,8 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView): result = [] for x in dtrule: - if (start_date and (x.date() >= start_date)) or \ - (start_date is None): + if (query_date and (x.date() >= query_date)) or \ + (query_date is None): result.append(x.date()) if len(result) >= count: break @@ -178,7 +178,7 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView): name (string, optional): name of field. Defaults to None. context: - start_date (date, optional): start date for dates in result, + nextrun_querydate (date, optional): start date for dates in result, defaults to today if not set or None Returns: @@ -187,14 +187,14 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView): 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() + query_date = context.get('nextrun_querydate', None) + if not isinstance(query_date, date): + query_date = IrDate.today() return ' | '.join([ Report.format_date(x) for x in self._compute_dates_by_rrule( - start_date=start_date, + query_date=query_date, params={ 'start_date': self.start_date, 'end_date': self.end_date, @@ -291,6 +291,7 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView): pool = Pool() IrDate = pool.get('ir.date') NextRun = pool.get('cashbook.planner.nextrun') + context = Transaction().context to_create = [] to_write = [] @@ -303,10 +304,14 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView): elif record.active: # get next-run date next_date = record._compute_dates_by_rrule( - start_date=IrDate.today(), count=1) + query_date=context.get( + 'nextrun_querydate', IrDate.today()), + count=1) if next_date: next_date = next_date[0] else: + if record.nextrun: + to_delete.extend(record.nextrun) continue if not record.nextrun: @@ -324,6 +329,31 @@ class ScheduledBooking(DeactivableMixin, ModelSQL, ModelView): if to_write: NextRun.write(*to_write) + @classmethod + def create(cls, vlist): + """ update nextrun-records on create of planner-records + + Args: + vlist (list of dict): values to create records + + Returns: + list: created records + """ + records = super(ScheduledBooking, cls).create(vlist) + cls.update_next_occurence(records) + return records + + @classmethod + def write(cls, *args): + """ update nextrun-records on create of planner-records + """ + to_update = [] + actions = iter(args) + for records, values in zip(actions, actions): + to_update.extend(records) + super(ScheduledBooking, cls).write(*args) + cls.update_next_occurence(records) + @classmethod def cronjob(cls): pass diff --git a/tests/planner.py b/tests/planner.py index a731280..887cf6d 100644 --- a/tests/planner.py +++ b/tests/planner.py @@ -24,7 +24,7 @@ class PlannerTestCase(object): job = None with Transaction().set_context({ 'company': company.id, - 'start_date': date(2022, 5, 1)}): + 'nextrun_querydate': date(2022, 5, 1)}): book, = Book.create([{ 'name': 'Book 1', 'btype': types.id, @@ -63,7 +63,7 @@ class PlannerTestCase(object): job = self.prep_create_job() self.assertEqual( job._compute_dates_by_rrule( - start_date=date(2022, 5, 1), count=5), [ + query_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)]) @@ -78,7 +78,7 @@ class PlannerTestCase(object): Planner.write(*[[job], { 'end_date': date(2022, 9, 15), 'monthday': 3}]) self.assertEqual( - job._compute_dates_by_rrule(start_date=date(2022, 5, 1)), [ + job._compute_dates_by_rrule(query_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)]) @@ -86,7 +86,7 @@ class PlannerTestCase(object): 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)), [ + job._compute_dates_by_rrule(query_date=date(2022, 5, 1)), [ date(2022, 5, 3), date(2022, 7, 3), date(2022, 9, 3)]) @@ -95,7 +95,7 @@ class PlannerTestCase(object): 'end_date': None, 'monthday': 1, 'interval': 1}]) self.assertEqual( job._compute_dates_by_rrule( - start_date=date(2022, 5, 1), + query_date=date(2022, 5, 1), params={ 'end_date': date(2022, 9, 15), 'monthday': 3, 'interval': 2}), @@ -104,7 +104,7 @@ class PlannerTestCase(object): # 1st wednesday of each 2nd month self.assertEqual( job._compute_dates_by_rrule( - start_date=date(2022, 5, 1), + query_date=date(2022, 5, 1), params={ 'end_date': date(2022, 9, 15), 'weekday': '2', 'interval': 2, 'setpos': 1, 'monthday': None}), @@ -113,7 +113,7 @@ class PlannerTestCase(object): # 2nd wednesday of each 2nd month self.assertEqual( job._compute_dates_by_rrule( - start_date=date(2022, 5, 1), + query_date=date(2022, 5, 1), params={ 'end_date': date(2022, 9, 15), 'weekday': '2', 'interval': 2, 'setpos': 2, 'monthday': None}), @@ -122,7 +122,7 @@ class PlannerTestCase(object): # 2nd wednesday of each month, 6x occurences self.assertEqual( job._compute_dates_by_rrule( - start_date=date(2022, 5, 1), count=6, + query_date=date(2022, 5, 1), count=6, params={ 'weekday': '2', 'end_date': None, 'interval': 1, 'setpos': 2, 'monthday': None}), @@ -216,10 +216,38 @@ class PlannerTestCase(object): job = self.prep_create_job() self.assertEqual( job._compute_dates_by_rrule( - count=1, start_date=date(2022, 5, 1)), [ + count=1, query_date=date(2022, 5, 1)), [ date(2022, 5, 1)]) - job.update_next_occurence([job]) - self.assertEqual(len(job.nextrun), 1) + with Transaction().set_context({ + 'nextrun_querydate': date(2022, 5, 25)}): + Planner.update_next_occurence([job]) + self.assertEqual(len(job.nextrun), 1) + self.assertEqual(job.nextrun[0].date, date(2022, 6, 1)) + + with Transaction().set_context({ + 'nextrun_querydate': date(2022, 5, 30)}): + Planner.update_next_occurence([job]) + self.assertEqual(len(job.nextrun), 1) + self.assertEqual(job.nextrun[0].date, date(2022, 6, 1)) + + with Transaction().set_context({ + 'nextrun_querydate': date(2022, 6, 1)}): + Planner.update_next_occurence([job]) + self.assertEqual(len(job.nextrun), 1) + self.assertEqual(job.nextrun[0].date, date(2022, 6, 1)) + + with Transaction().set_context({ + 'nextrun_querydate': date(2022, 6, 2)}): + Planner.update_next_occurence([job]) + self.assertEqual(len(job.nextrun), 1) + self.assertEqual(job.nextrun[0].date, date(2022, 7, 1)) + + with Transaction().set_context({ + 'nextrun_querydate': date(2022, 6, 2)}): + # set end-date to check delete of futore runs + Planner.write(*[[job], {'end_date': date(2022, 6, 20)}]) + # write to planner-record updates nextrun-records too + self.assertEqual(len(job.nextrun), 0) # end PlannerTestCase diff --git a/tryton.cfg b/tryton.cfg index 41b8434..e414f70 100644 --- a/tryton.cfg +++ b/tryton.cfg @@ -7,6 +7,7 @@ extras_depend: xml: group.xml planner.xml + nextrun.xml cashbook.xml cron.xml menu.xml diff --git a/view/nextrun_form.xml b/view/nextrun_form.xml new file mode 100644 index 0000000..05c5de9 --- /dev/null +++ b/view/nextrun_form.xml @@ -0,0 +1,10 @@ + + +
+