From 8aed8a7623ba3ebcba2c471801b833040969d5a1 Mon Sep 17 00:00:00 2001 From: Romain Courteaud <romain@nexedi.com> Date: Mon, 2 Apr 2007 16:47:57 +0000 Subject: [PATCH] Remove Periodicity document. Add PeriodicityMixin class. Rename getNextAlarmDate method to getNextPeriodicalDate. Add some comments. git-svn-id: https://svn.erp5.org/repos/public/erp5/trunk@13865 20353a03-c40f-0410-a6d1-a30d3c3de9de --- product/ERP5/Document/Alarm.py | 524 +++++++++++++++++------- product/ERP5/Document/CalendarPeriod.py | 34 +- product/ERP5/Document/Periodicity.py | 274 ------------- 3 files changed, 395 insertions(+), 437 deletions(-) delete mode 100644 product/ERP5/Document/Periodicity.py diff --git a/product/ERP5/Document/Alarm.py b/product/ERP5/Document/Alarm.py index fe5c41e109..9ab15e105f 100644 --- a/product/ERP5/Document/Alarm.py +++ b/product/ERP5/Document/Alarm.py @@ -1,6 +1,6 @@ ############################################################################## # -# Copyright (c) 2004 Nexedi SARL and Contributors. All Rights Reserved. +# Copyright (c) 2004, 2007 Nexedi SARL and Contributors. All Rights Reserved. # Sebastien Robin <seb@nexedi.com> # # WARNING: This program as such is intended to be used by professional @@ -30,164 +30,388 @@ from AccessControl import ClassSecurityInfo from Products.CMFCore.utils import getToolByName from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface from Products.ERP5Type.XMLObject import XMLObject -from Products.ERP5.Document.Periodicity import Periodicity from Products.CMFCore.WorkflowCore import WorkflowMethod from Acquisition import aq_base, aq_parent, aq_inner, aq_acquire from Products.CMFCore.utils import getToolByName from DateTime import DateTime +from Products.ERP5Type.Message import Message +from Products.ERP5Type.DateUtils import addToDate from zLOG import LOG +class PeriodicityMixin: + """ + Periodicity is a Mixin Class used to calculate date periodicity. + """ + security = ClassSecurityInfo() + security.declareObjectProtected(Permissions.AccessContentsInformation) + def _validateMinute(self, date, previous_date): + """ + Validate if date's minute matches the periodicity definition + """ + periodicity_minute_frequency = self.getPeriodicityMinuteFrequency() + periodicity_minute_list = self.getPeriodicityMinuteList() + if (periodicity_minute_frequency is None) and \ + (periodicity_minute_list in ([], None, ())): + # in this case, we may want to have an periodicity every hour + # based on the start date + # without defining anything about minutes periodicity, + # so we compare with minutes with the one defined + # in the previous alarm date + return (date.minute() == previous_date.minute()) + if periodicity_minute_frequency not in ('', None): + return (date.minute() % periodicity_minute_frequency) == 0 + elif len(periodicity_minute_list) > 0: + return date.minute() in periodicity_minute_list + + def _validateHour(self, date): + """ + Validate if date's hour matches the periodicity definition + """ + periodicity_hour_frequency = self.getPeriodicityHourFrequency() + periodicity_hour_list = self.getPeriodicityHourList() + if (periodicity_hour_frequency is None) and \ + (periodicity_hour_list in ([], None, ())): + return 1 + if periodicity_hour_frequency not in ('', None): + return (date.hour() % periodicity_hour_frequency) == 0 + elif len(periodicity_hour_list) > 0: + return date.hour() in periodicity_hour_list + + def _validateDay(self, date): + """ + Validate if date's day matches the periodicity definition + """ + periodicity_day_frequency = self.getPeriodicityDayFrequency() + periodicity_month_day_list = self.getPeriodicityMonthDayList() + if (periodicity_day_frequency is None) and \ + (periodicity_month_day_list in ([], None, ())): + return 1 + if periodicity_day_frequency not in ('', None): + return (date.day() % periodicity_day_frequency) == 0 + elif len(periodicity_month_day_list) > 0: + return date.day() in periodicity_month_day_list + + def _validateWeek(self, date): + """ + Validate if date's week matches the periodicity definition + """ + periodicity_week_frequency = self.getPeriodicityWeekFrequency() + periodicity_week_day_list = self.getPeriodicityWeekDayList() + periodicity_week_list = self.getPeriodicityWeekList() + if (periodicity_week_frequency is None) and \ + (periodicity_week_day_list in ([], None, ())) and \ + (periodicity_week_list is None): + return 1 + if periodicity_week_frequency not in ('', None): + if not((date.week() % periodicity_week_frequency) == 0): + return 0 + if periodicity_week_day_list not in (None, (), []): + if not (date.Day() in periodicity_week_day_list): + return 0 + if periodicity_week_list not in (None, (), []): + if not (date.week() in periodicity_week_list): + return 0 + return 1 + + def _validateMonth(self, date): + """ + Validate if date's month matches the periodicity definition + """ + periodicity_month_frequency = self.getPeriodicityMonthFrequency() + periodicity_month_list = self.getPeriodicityMonthList() + if (periodicity_month_frequency is None) and \ + (periodicity_month_list in ([], None, ())): + return 1 + if periodicity_month_frequency not in ('', None): + return (date.month() % periodicity_month_frequency) == 0 + elif len(periodicity_month_list) > 0: + return date.month() in periodicity_month_list + + def getNextPeriodicalDate(self, current_date, next_start_date=None): + """ + Get the next date where this periodic event should start. + + We have to take into account the start date, because + sometimes an event may be started by hand. We must be + sure to never forget to start an event, even with some + delays. + + Here are some rules : + - if the periodicity start date is in the past and we never starts + this periodic event, then return the periodicity start date. + - if the periodicity start date is in the past but we already + have started the periodic event, then see + + XXX Better API is needed. It may defined which minimal time duration has to + be added in order to calculate next date. + Ex: here, we use minute as smaller duration. + On CalendarPeriod, day is the smaller duration. + """ + if next_start_date is None: + next_start_date = current_date + if next_start_date > current_date: + return + else: + # Make sure the old date is not too far away + day_count = int(current_date-next_start_date) + next_start_date = next_start_date + day_count -class Alarm(Periodicity, XMLObject): - """ - An Alarm is in charge of checking anything (quantity of a certain - resource on the stock, consistency of some order,....) periodically. - - It should also provide a solution if something wrong happens. - - Some information should be displayed to the user, and also notifications. - """ - - # CMF Type Definition - meta_type = 'ERP5 Alarm' - portal_type = 'Alarm' - add_permission = Permissions.AddPortalContent - isPortalContent = 1 - isRADContent = 1 - - # Declarative security - security = ClassSecurityInfo() - security.declareObjectProtected(Permissions.AccessContentsInformation) - - # Default Properties - property_sheets = ( PropertySheet.Base - , PropertySheet.XMLObject - , PropertySheet.CategoryCore - , PropertySheet.DublinCore - , PropertySheet.Periodicity - , PropertySheet.Document - , PropertySheet.Task - , PropertySheet.Alarm - ) - - security.declareProtected(Permissions.View, 'isActive') - def isActive(self): - """ - This method returns only True or False. - It simply tells if this alarm is currently - active or not. It is activated when it is doing some calculation with - activeSense or solve. - """ - return self.hasActivity() - - security.declareProtected(Permissions.ModifyPortalContent, 'activeSense') - def activeSense(self): - """ - This method checks if there is a problem. This method can launch a very long - activity. We don't care about the response, we just want to start - some calculations. Results should be read with the method 'sense' - later. - - """ - self.setNextAlarmDate() - method_id = self.getActiveSenseMethodId() - if method_id is not None: - method = getattr(self.activate(),method_id) - return method() - - security.declareProtected(Permissions.ModifyPortalContent, 'sense') - def sense(self): - """ - This method returns True or False. False for no problem, True for problem. - - This method should respond quickly. Basically the response depends on some - previous calculation made by activeSense. - """ - method_id = self.getSenseMethodId() - process = self.getLastActiveProcess() - if process is None: - return value - if method_id is not None: - method = getattr(self,method_id) - value = method() + previous_date = next_start_date + next_start_date = addToDate(next_start_date, minute=1) + while 1: + validate_minute = self._validateMinute(next_start_date, previous_date) + validate_hour = self._validateHour(next_start_date) + validate_day = self._validateDay(next_start_date) + validate_week = self._validateWeek(next_start_date) + validate_month = self._validateMonth(next_start_date) + if (next_start_date >= current_date \ + and validate_minute and validate_hour and validate_day \ + and validate_week and validate_month): + break else: - for result in process.getResultList(): - if result.severity > result.INFO: - value = True - break - process.setSenseValue(value) - return value + if not(validate_minute): + next_start_date = addToDate(next_start_date, minute=1) + else: + if not(validate_hour): + next_start_date = addToDate(next_start_date, hour=1) + else: + if not(validate_day and validate_week and validate_month): + next_start_date = addToDate(next_start_date, day=1) + else: + # Everything is right, but the date is still not bigger + # than the current date, so we must continue + next_start_date = addToDate(next_start_date, minute=1) + return next_start_date + + # XXX May be we should create a Date class for following methods ??? + security.declareProtected(Permissions.View, 'getWeekDayList') + def getWeekDayList(self): + """ + returns something like ['Sunday','Monday',...] + """ + return DateTime._days + + security.declareProtected(Permissions.View, 'getWeekDayItemList') + def getWeekDayItemList(self): + """ + returns something like [('Sunday', 'Sunday'), ('Monday', 'Monday'),...] + """ + return [(Message(domain='erp5_ui', message=x), x) \ + for x in self.getWeekDayList()] + + security.declareProtected(Permissions.View, 'getWeekDayItemList') + def getMonthItemList(self): + """ + returns something like [('January', 1), ('February', 2),...] + """ + # DateTime._months return '' as first item + return [(Message(domain='erp5_ui', message=DateTime._months[i]), i) \ + for i in range(1, len(DateTime._months))] + + security.declareProtected(Permissions.View,'getPeriodicityWeekDayList') + def getPeriodicityWeekDayList(self): + """ + Make sure that the list of days is ordered + """ + #LOG('getPeriodicityWeekDayList',0,'we should order') + day_list = self._baseGetPeriodicityWeekDayList() + new_list = [] + for day in self.getWeekDayList(): + if day_list is not None: + if day in day_list: + new_list += [day] + return new_list + +class Alarm(XMLObject, PeriodicityMixin): + """ + An Alarm is in charge of checking anything (quantity of a certain + resource on the stock, consistency of some order,....) periodically. + + It should also provide a solution if something wrong happens. + + Some information should be displayed to the user, and also notifications. + """ + + # CMF Type Definition + meta_type = 'ERP5 Alarm' + portal_type = 'Alarm' + add_permission = Permissions.AddPortalContent + isPortalContent = 1 + isRADContent = 1 + + # Declarative security + security = ClassSecurityInfo() + security.declareObjectProtected(Permissions.AccessContentsInformation) + + # Default Properties + property_sheets = ( PropertySheet.Base + , PropertySheet.XMLObject + , PropertySheet.CategoryCore + , PropertySheet.DublinCore + , PropertySheet.Periodicity + , PropertySheet.Document + , PropertySheet.Task + , PropertySheet.Alarm + ) - security.declareProtected(Permissions.View, 'report') - def report(self,process=None): - """ - This methods produces a report (HTML) - This generate the output of the results. It can be used to nicely - explain the problem. We don't do calculation at this time, it should - be made by activeSense. - """ - method_id = self.getReportMethodId(None) - #LOG('Alarm.report, method_id',0,method_id) - if method_id is None: - return '' + security.declareProtected(Permissions.View, 'isActive') + def isActive(self): + """ + This method returns only True or False. + It simply tells if this alarm is currently + active or not. It is activated when it is doing some calculation with + activeSense or solve. + """ + return self.hasActivity() + + security.declareProtected(Permissions.ModifyPortalContent, 'activeSense') + def activeSense(self): + """ + This method checks if there is a problem. This method can launch a very long + activity. We don't care about the response, we just want to start + some calculations. Results should be read with the method 'sense' + later. + + """ + # Set the new date + LOG('activeSense, self.getPath()',0,self.getPath()) + + self.setNextAlarmDate() + method_id = self.getActiveSenseMethodId() + if method_id is not None: + method = getattr(self.activate(),method_id) + return method() + + security.declareProtected(Permissions.ModifyPortalContent, 'sense') + def sense(self): + """ + This method returns True or False. False for no problem, True for problem. + + This method should respond quickly. Basically the response depends on some + previous calculation made by activeSense. + """ + method_id = self.getSenseMethodId() + process = self.getLastActiveProcess() + if process is None: + return value + if method_id is not None: method = getattr(self,method_id) - process = self.getLastActiveProcess() - result = None - if process is not None: - result = method(process=process) - return result - - security.declareProtected(Permissions.ModifyPortalContent, 'solve') - def solve(self): - """ - This method tries solves the problem detected by sense. - - This solve the problem if there is a problem detected by sense. If - no problems, then nothing to do here. - """ - pass - - security.declareProtected(Permissions.ModifyPortalContent, 'notify') - def _notify(self): - """ - This method is called to notify people that some alarm has - been sensed. - - for example we can send email. - - We define nothing here, because we will use an interaction workflow. - """ - pass - - notify = WorkflowMethod(_notify, id='notify') - - security.declareProtected(Permissions.View, 'getLastActiveProcess') - def getLastActiveProcess(self): - """ - This returns the last active process finished. So it will - not returns the current one - """ - active_process_list = self.getCausalityRelatedValueList( - portal_type='Active Process') - def sort_date(a, b): - return cmp(a.getStartDate(), b.getStartDate()) - active_process_list.sort(sort_date) - active_process = None - if len(active_process_list)>0: - active_process = active_process_list[-1] - return active_process - - security.declareProtected(Permissions.ModifyPortalContent, 'newActiveProcess') - def newActiveProcess(self): - """ - We will create a new active process in order to store - new results, then this process will be added to the list - of processes - """ - portal_activities = getToolByName(self,'portal_activities') - active_process = portal_activities.newActiveProcess() - active_process.setStartDate(DateTime()) - active_process.setCausalityValue(self) - return active_process + value = method() + else: + for result in process.getResultList(): + if result.severity > result.INFO: + value = True + break + process.setSenseValue(value) + return value + + security.declareProtected(Permissions.View, 'report') + def report(self, process=None): + """ + This methods produces a report (HTML) + This generate the output of the results. It can be used to nicely + explain the problem. We don't do calculation at this time, it should + be made by activeSense. + """ + method_id = self.getReportMethodId(None) + #LOG('Alarm.report, method_id',0,method_id) + if method_id is None: + return '' + method = getattr(self,method_id) + process = self.getLastActiveProcess() + result = None + if process is not None: + result = method(process=process) + return result + + security.declareProtected(Permissions.ModifyPortalContent, 'solve') + def solve(self): + """ + This method tries solves the problem detected by sense. + + This solve the problem if there is a problem detected by sense. If + no problems, then nothing to do here. + """ + pass + + security.declareProtected(Permissions.ModifyPortalContent, 'notify') + def _notify(self): + """ + This method is called to notify people that some alarm has + been sensed. + + for example we can send email. + + We define nothing here, because we will use an interaction workflow. + """ + pass + + notify = WorkflowMethod(_notify, id='notify') + + security.declareProtected(Permissions.View, 'getLastActiveProcess') + def getLastActiveProcess(self): + """ + This returns the last active process finished. So it will + not returns the current one + """ + active_process_list = self.getCausalityRelatedValueList( + portal_type='Active Process') + def sort_date(a, b): + return cmp(a.getStartDate(), b.getStartDate()) + active_process_list.sort(sort_date) + active_process = None + if len(active_process_list)>0: + active_process = active_process_list[-1] + return active_process + + security.declareProtected(Permissions.ModifyPortalContent, + 'newActiveProcess') + def newActiveProcess(self): + """ + We will create a new active process in order to store + new results, then this process will be added to the list + of processes + """ + portal_activities = getToolByName(self,'portal_activities') + active_process = portal_activities.newActiveProcess() + active_process.setStartDate(DateTime()) + active_process.setCausalityValue(self) + return active_process + + security.declareProtected(Permissions.View, 'setNextAlarmDate') + def setNextAlarmDate(self, current_date=None): + """ + Save the next alarm date + """ + if self.getPeriodicityStartDate() is None: + return + next_start_date = self.getAlarmDate() + if current_date is None: + # This is usefull to set the current date as parameter for + # unit testing, by default it should be now + current_date = DateTime() + + next_start_date = self.getNextPeriodicalDate(current_date, + next_start_date=next_start_date) + if next_start_date is not None: + self.Alarm_zUpdateAlarmDate(uid=self.getUid(), + alarm_date=next_start_date) + + security.declareProtected(Permissions.View, 'getAlarmDate') + def getAlarmDate(self): + """ + returns something like ['Sunday','Monday',...] + """ + #alarm_date = self._baseGetAlarmDate() + #if alarm_date is None: + # alarm_date = self.getPeriodicityStartDate() + alarm_date=None + result_list = self.Alarm_zGetAlarmDate(uid=self.getUid()) + if len(result_list)==1: + alarm_date = result_list[0].alarm_date + periodicity_start_date = self.getPeriodicityStartDate() + if alarm_date < periodicity_start_date: + alarm_date = periodicity_start_date + return alarm_date diff --git a/product/ERP5/Document/CalendarPeriod.py b/product/ERP5/Document/CalendarPeriod.py index be354e9235..6c3ba184b7 100644 --- a/product/ERP5/Document/CalendarPeriod.py +++ b/product/ERP5/Document/CalendarPeriod.py @@ -33,10 +33,11 @@ from AccessControl import ClassSecurityInfo from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface from Products.ERP5.Document.DeliveryLine import DeliveryLine -from Products.ERP5.Document.Periodicity import Periodicity +from Products.ERP5.Document.Alarm import PeriodicityMixin from Products.ERP5.Document.Movement import Movement +from Products.ERP5Type.DateUtils import addToDate -class CalendarPeriod(Movement, Periodicity): +class CalendarPeriod(Movement, PeriodicityMixin): """ Calendar Period is used to add available time of the user in a period of Time @@ -89,7 +90,8 @@ class CalendarPeriod(Movement, Periodicity): 'getInventoriatedQuantity') def getInventoriatedQuantity(self, default=None, *args, **kw): """ - Surcharged accessor to calculate the Quantity in second. + Surcharged accessor to calculate the Quantity in second + from stop date and start date values. """ quantity = self.getQuantity(*args, **kw) if quantity in [None, 0]: @@ -143,7 +145,7 @@ class CalendarPeriod(Movement, Periodicity): start_date) duration = stop_date - start_date # First date has to respect the periodicity config - next_start_date = self.getNextAlarmDate(start_date-1) + next_start_date = self.getNextPeriodicalDate(start_date-1) while (next_start_date is not None) and \ (next_start_date <= periodicity_stop_date): @@ -171,30 +173,36 @@ class CalendarPeriod(Movement, Periodicity): # SQL method don't like iterator # yield (next_start_date, next_start_date+duration) result.append([next_start_date, next_start_date+duration]) - next_start_date = self.getNextAlarmDate(next_start_date) + next_start_date = self.getNextPeriodicalDate(next_start_date) return result - def getNextAlarmDate(self, current_date, next_start_date=None): + def getNextPeriodicalDate(self, current_date, next_start_date=None): """ Get the next date where this periodic event should start. + + XXX It completely reimplements the PeriodictyMixin method because + the minimal duration between dates is day, and not minute + Better way would be to improve the API of getNextPeriodicalDate, + and optimize addToDate method. """ + # XXX Copy/Paste from PeriodicityMixin if next_start_date is None: next_start_date = current_date if next_start_date > current_date: return else: # Make sure the old date is not too far away - nb_days = int(current_date-next_start_date) - next_start_date = next_start_date + nb_days + day_count = int(current_date-next_start_date) + next_start_date = next_start_date + day_count previous_date = next_start_date - next_start_date += 1 + next_start_date = addToDate(next_start_date, day=1) while 1: - if (self.validateDay(next_start_date)) and \ - (self.validateWeek(next_start_date)) and \ - (self.validateMonth(next_start_date)): + if (self._validateDay(next_start_date)) and \ + (self._validateWeek(next_start_date)) and \ + (self._validateMonth(next_start_date)): break else: - next_start_date += 1 + next_start_date = addToDate(next_start_date, day=1) return next_start_date diff --git a/product/ERP5/Document/Periodicity.py b/product/ERP5/Document/Periodicity.py deleted file mode 100644 index 05c20338d7..0000000000 --- a/product/ERP5/Document/Periodicity.py +++ /dev/null @@ -1,274 +0,0 @@ -############################################################################## -# -# Copyright (c) 2006 Nexedi SARL and Contributors. All Rights Reserved. -# Sebastien Robin <seb@nexedi.com> -# -# WARNING: This program as such is intended to be used by professional -# programmers who take the whole responsability of assessing all potential -# consequences resulting from its eventual inadequacies and bugs -# End users who are looking for a ready-to-use solution with commercial -# garantees and support are strongly adviced to contract a Free Software -# Service Company -# -# This program is Free Software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -# -############################################################################## - -from AccessControl import ClassSecurityInfo -from Products.CMFCore.utils import getToolByName -from Products.ERP5Type import Permissions, PropertySheet, Constraint, Interface -from Products.ERP5Type.Base import Base -from Acquisition import aq_base, aq_parent, aq_inner, aq_acquire -from Products.CMFCore.utils import getToolByName -from DateTime import DateTime -from Products.ERP5Type.DateUtils import addToDate -from Products.ERP5Type.Message import Message - -from zLOG import LOG - -class Periodicity(Base): - """ - An Alarm is in charge of checking anything (quantity of a certain - resource on the stock, consistency of some order,....) periodically. - - It should also provide a solution if something wrong happens. - - Some information should be displayed to the user, and also notifications. - """ - - # CMF Type Definition - meta_type = 'ERP5 Periodicity' - portal_type = 'Periodicity' - add_permission = Permissions.AddPortalContent - isPortalContent = 1 - isRADContent = 1 - - # Declarative security - security = ClassSecurityInfo() - security.declareObjectProtected(Permissions.AccessContentsInformation) - - # Default Properties - property_sheets = ( PropertySheet.Base - , PropertySheet.DublinCore - , PropertySheet.Periodicity - ) - - def validateMinute(self, date, previous_date): - periodicity_minute_frequency = self.getPeriodicityMinuteFrequency() - periodicity_minute_list = self.getPeriodicityMinuteList() - if (periodicity_minute_frequency is None) and \ - (periodicity_minute_list in ([], None, ())): - # in this case, we may want to have an periodicity every hour - # based on the start date - # without defining anything about minutes periodicity, - # so we compare with minutes with the one defined - # in the previous alarm date - return (date.minute() == previous_date.minute()) - if periodicity_minute_frequency not in ('', None): - return (date.minute() % periodicity_minute_frequency) == 0 - elif len(periodicity_minute_list) > 0: - return date.minute() in periodicity_minute_list - - def validateHour(self, date): - periodicity_hour_frequency = self.getPeriodicityHourFrequency() - periodicity_hour_list = self.getPeriodicityHourList() - if (periodicity_hour_frequency is None) and \ - (periodicity_hour_list in ([], None, ())): - return 1 - if periodicity_hour_frequency not in ('', None): - return (date.hour() % periodicity_hour_frequency) == 0 - elif len(periodicity_hour_list) > 0: - return date.hour() in periodicity_hour_list - - def validateDay(self, date): - periodicity_day_frequency = self.getPeriodicityDayFrequency() - periodicity_month_day_list = self.getPeriodicityMonthDayList() - if (periodicity_day_frequency is None) and \ - (periodicity_month_day_list in ([], None, ())): - return 1 - if periodicity_day_frequency not in ('', None): - return (date.day() % periodicity_day_frequency) == 0 - elif len(periodicity_month_day_list) > 0: - return date.day() in periodicity_month_day_list - - def validateWeek(self, date): - periodicity_week_frequency = self.getPeriodicityWeekFrequency() - periodicity_week_day_list = self.getPeriodicityWeekDayList() - periodicity_week_list = self.getPeriodicityWeekList() - if (periodicity_week_frequency is None) and \ - (periodicity_week_day_list in ([], None, ())) and \ - (periodicity_week_list is None): - return 1 - if periodicity_week_frequency not in ('', None): - if not((date.week() % periodicity_week_frequency) == 0): - return 0 - if periodicity_week_day_list not in (None, (), []): - if not (date.Day() in periodicity_week_day_list): - return 0 - if periodicity_week_list not in (None, (), []): - if not (date.week() in periodicity_week_list): - return 0 - return 1 - - def validateMonth(self, date): - periodicity_month_frequency = self.getPeriodicityMonthFrequency() - periodicity_month_list = self.getPeriodicityMonthList() - if (periodicity_month_frequency is None) and \ - (periodicity_month_list in ([], None, ())): - return 1 - if periodicity_month_frequency not in ('', None): - return (date.month() % periodicity_month_frequency) == 0 - elif len(periodicity_month_list) > 0: - return date.month() in periodicity_month_list - - def getNextAlarmDate(self, current_date, next_start_date=None): - """ - Get the next date where this periodic event should start. - - We have to take into account the start date, because - sometimes an event may be started by hand. We must be - sure to never forget to start an event, even with some - delays. - - Here are some rules : - - if the periodicity start date is in the past and we never starts - this periodic event, then return the periodicity start date. - - if the periodicity start date is in the past but we already - have started the periodic event, then see - """ - if next_start_date is None: - next_start_date = current_date - if next_start_date > current_date: - return - else: - # Make sure the old date is not too far away - nb_days = int(current_date-next_start_date) - next_start_date = next_start_date + nb_days - - previous_date = next_start_date - next_start_date = addToDate(next_start_date, minute=1) - while 1: - validate_minute = self.validateMinute(next_start_date, previous_date) - validate_hour = self.validateHour(next_start_date) - validate_day = self.validateDay(next_start_date) - validate_week = self.validateWeek(next_start_date) - validate_month = self.validateMonth(next_start_date) - if (next_start_date >= current_date \ - and validate_minute and validate_hour and validate_day \ - and validate_week and validate_month): - break - else: - if not(validate_minute): - next_start_date = addToDate(next_start_date, minute=1) - else: - if not(validate_hour): - next_start_date = addToDate(next_start_date, hour=1) - else: - if not(validate_day and validate_week and validate_month): - next_start_date = addToDate(next_start_date, day=1) - else: - # Everything is right, but the date is still not bigger - # than the current date, so we must continue - next_start_date = addToDate(next_start_date, minute=1) - return next_start_date - - security.declareProtected(Permissions.View, 'setNextAlarmDate') - def setNextAlarmDate(self, current_date=None): - """ - Save the next alarm date - """ - if self.getPeriodicityStartDate() is None: - return - next_start_date = self.getAlarmDate() - if current_date is None: - # This is usefull to set the current date as parameter for - # unit testing, by default it should be now - current_date = DateTime() - - next_start_date = self.getNextAlarmDate(current_date, - next_start_date=next_start_date) - if next_start_date is not None: - self.Alarm_zUpdateAlarmDate(uid=self.getUid(), - alarm_date=next_start_date) - - security.declareProtected(Permissions.View, 'getAlarmDate') - def getAlarmDate(self): - """ - returns something like ['Sunday','Monday',...] - """ - #alarm_date = self._baseGetAlarmDate() - #if alarm_date is None: - # alarm_date = self.getPeriodicityStartDate() - alarm_date=None - result_list = self.Alarm_zGetAlarmDate(uid=self.getUid()) - if len(result_list)==1: - alarm_date = result_list[0].alarm_date - periodicity_start_date = self.getPeriodicityStartDate() - if alarm_date < periodicity_start_date: - alarm_date = periodicity_start_date - return alarm_date - - # XXX May be we should create a Date class for following methods ??? - security.declareProtected(Permissions.View, 'getWeekDayList') - def getWeekDayList(self): - """ - returns something like ['Sunday','Monday',...] - """ - return DateTime._days - - security.declareProtected(Permissions.View, 'getWeekDayItemList') - def getWeekDayItemList(self): - """ - returns something like [('Sunday', 'Sunday'), ('Monday', 'Monday'),...] - """ - return [(Message(domain='erp5_ui', message=x), x) \ - for x in self.getWeekDayList()] - - security.declareProtected(Permissions.View, 'getWeekDayItemList') - def getMonthItemList(self): - """ - returns something like [('January', 1), ('February', 2),...] - """ - # DateTime._months return '' as first item - return [(Message(domain='erp5_ui', message=DateTime._months[i]), i) \ - for i in range(1, len(DateTime._months))] - - # XXX This look like to not works, so override the getter -# security.declarePrivate('_setPeriodicityWeekDayList') -# def _setPeriodicityWeekDayList(self,value): -# """ -# Make sure that the list of days is ordered -# """ -# LOG('_setPeriodicityWeekDayList',0,'we should order') -# day_list = self._baseGetPeriodicityWeekDayList() -# new_list = [] -# for day in self.getWeekDayList(): -# if day in value: -# new_list += [day] -# self._baseSetPeriodicityWeekDayList(new_list) - - security.declareProtected(Permissions.View,'getPeriodicityWeekDayList') - def getPeriodicityWeekDayList(self): - """ - Make sure that the list of days is ordered - """ - #LOG('getPeriodicityWeekDayList',0,'we should order') - day_list = self._baseGetPeriodicityWeekDayList() - new_list = [] - for day in self.getWeekDayList(): - if day_list is not None: - if day in day_list: - new_list += [day] - return new_list -- 2.30.9