Alarm.py 9.91 KB
Newer Older
Sebastien Robin's avatar
Sebastien Robin committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
##############################################################################
#
# Copyright (c) 2004 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.XMLObject import XMLObject
Sebastien Robin's avatar
Sebastien Robin committed
33
from Products.ERP5.Document.Periodicity import Periodicity
Sebastien Robin's avatar
Sebastien Robin committed
34
from Products.CMFCore.WorkflowCore import WorkflowMethod
Sebastien Robin's avatar
Sebastien Robin committed
35
from Acquisition import aq_base, aq_parent, aq_inner, aq_acquire
Sebastien Robin's avatar
Sebastien Robin committed
36 37
from Products.CMFCore.utils import getToolByName
from DateTime import DateTime
Sebastien Robin's avatar
Sebastien Robin committed
38 39 40 41 42

from zLOG import LOG



Sebastien Robin's avatar
Sebastien Robin committed
43
class Alarm(Periodicity, XMLObject):
Sebastien Robin's avatar
Sebastien Robin committed
44
    """
Sebastien Robin's avatar
Sebastien Robin committed
45 46
    An Alarm is in charge of checking anything (quantity of a certain
    resource on the stock, consistency of some order,....) periodically.
Sebastien Robin's avatar
Sebastien Robin committed
47

Sebastien Robin's avatar
Sebastien Robin committed
48 49 50
    It should also provide a solution if something wrong happens.

    Some information should be displayed to the user, and also notifications.
Sebastien Robin's avatar
Sebastien Robin committed
51 52 53 54 55 56 57 58 59 60 61
    """

    # CMF Type Definition
    meta_type = 'ERP5 Alarm'
    portal_type = 'Alarm'
    add_permission = Permissions.AddPortalContent
    isPortalContent = 1
    isRADContent = 1

    # Declarative security
    security = ClassSecurityInfo()
62
    security.declareObjectProtected(Permissions.AccessContentsInformation)
Sebastien Robin's avatar
Sebastien Robin committed
63 64 65 66 67 68

    # Default Properties
    property_sheets = ( PropertySheet.Base
                      , PropertySheet.XMLObject
                      , PropertySheet.CategoryCore
                      , PropertySheet.DublinCore
Sebastien Robin's avatar
Sebastien Robin committed
69
                      , PropertySheet.Periodicity
Sebastien Robin's avatar
Sebastien Robin committed
70 71
                      , PropertySheet.Document
                      , PropertySheet.Task
Sebastien Robin's avatar
Sebastien Robin committed
72
                      , PropertySheet.Alarm
Sebastien Robin's avatar
Sebastien Robin committed
73 74 75 76 77
                      )

    security.declareProtected(Permissions.View, 'isActive')
    def isActive(self):
      """
Sebastien Robin's avatar
Sebastien Robin committed
78
      This method returns only True or False. It simply tells if this alarm is currently
Sebastien Robin's avatar
Sebastien Robin committed
79 80
      active or not. It is activated when it is doing some calculation with
      activeSense or solve.
Sebastien Robin's avatar
Sebastien Robin committed
81
      """
Sebastien Robin's avatar
Sebastien Robin committed
82
      return self.hasActivity()
Sebastien Robin's avatar
Sebastien Robin committed
83 84 85 86

    security.declareProtected(Permissions.ModifyPortalContent, 'activeSense')
    def activeSense(self):
      """
Sebastien Robin's avatar
Sebastien Robin committed
87
      This method checks if there is a problem. This method can launch a very long
Sebastien Robin's avatar
Sebastien Robin committed
88
      activity. We don't care about the response, we just want to start
Sebastien Robin's avatar
Sebastien Robin committed
89 90
      some calculations. Results should be read with the method 'sense'
      later.
Sebastien Robin's avatar
Sebastien Robin committed
91 92
      
      """
Sebastien Robin's avatar
Sebastien Robin committed
93
      # Set the new date
Sebastien Robin's avatar
Sebastien Robin committed
94 95 96 97 98 99
      LOG('activeSense, self.getPath()',0,self.getPath())

      #self.setStartDate(DateTime())
      #self.setStopDate(DateTime())
      self.setNextAlarmDate()
      self.reindexObject()
Sebastien Robin's avatar
Sebastien Robin committed
100
      method_id = self.getActiveSenseMethodId()
Sebastien Robin's avatar
Sebastien Robin committed
101 102 103
      if method_id is not None:
        method = getattr(self.activate(),method_id)
        return method()
Sebastien Robin's avatar
Sebastien Robin committed
104 105 106 107

    security.declareProtected(Permissions.ModifyPortalContent, 'sense')
    def sense(self):
      """
Sebastien Robin's avatar
Sebastien Robin committed
108
      This method returns True or False. False for no problem, True for problem.
Sebastien Robin's avatar
Sebastien Robin committed
109
      
Sebastien Robin's avatar
Sebastien Robin committed
110 111
      This method should respond quickly.  Basically the response depends on some 
      previous calculation made by activeSense.
Sebastien Robin's avatar
Sebastien Robin committed
112
      """
Sebastien Robin's avatar
Sebastien Robin committed
113
      method_id = self.getSenseMethodId()
Sebastien Robin's avatar
Sebastien Robin committed
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
      process = self.getCurrentActiveProcess()
      value = False
      if process is None:
        process = self.getLastActiveProcess()
      if process is None:
        return value
      if method_id is not None:
        method = getattr(self,method_id)
        value = method()
      else:
        for result in process.getResultList():
          if result.severity > result.INFO:
            value = True
            break
      process.setSenseValue(value)
      return value
Sebastien Robin's avatar
Sebastien Robin committed
130 131

    security.declareProtected(Permissions.View, 'report')
Sebastien Robin's avatar
Sebastien Robin committed
132
    def report(self,process=None):
Sebastien Robin's avatar
Sebastien Robin committed
133
      """
Sebastien Robin's avatar
Sebastien Robin committed
134
      This methods produces a report (HTML) 
Sebastien Robin's avatar
Sebastien Robin committed
135 136 137 138
      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.
      """
Sebastien Robin's avatar
Sebastien Robin committed
139
      method_id = self.getReportMethodId()
Sebastien Robin's avatar
Sebastien Robin committed
140
      LOG('Alarm.report, method_id',0,method_id)
Sebastien Robin's avatar
Sebastien Robin committed
141
      method = getattr(self,method_id)
Sebastien Robin's avatar
Sebastien Robin committed
142 143 144 145 146 147
      process = self.getCurrentActiveProcess()
      if process is None:
        process = self.getLastActiveProcess()
      result = method(process=process)
      process.setDescription(result)
      return result
Sebastien Robin's avatar
Sebastien Robin committed
148 149 150 151

    security.declareProtected(Permissions.ModifyPortalContent, 'solve')
    def solve(self):
      """
Sebastien Robin's avatar
Sebastien Robin committed
152 153 154 155
      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.
Sebastien Robin's avatar
Sebastien Robin committed
156 157 158 159
      """
      pass

    security.declareProtected(Permissions.ModifyPortalContent, 'notify')
Sebastien Robin's avatar
Sebastien Robin committed
160
    def _notify(self):
Sebastien Robin's avatar
Sebastien Robin committed
161
      """
Sebastien Robin's avatar
Sebastien Robin committed
162 163 164 165
      This method is called to notify people that some alarm has 
      been sensed.
      
      for example we can send email.
Sebastien Robin's avatar
Sebastien Robin committed
166 167

      We define nothing here, because we will use an interaction workflow.
Sebastien Robin's avatar
Sebastien Robin committed
168 169 170
      """
      pass

Sebastien Robin's avatar
Sebastien Robin committed
171
    notify = WorkflowMethod(_notify, id='notify')
Sebastien Robin's avatar
Sebastien Robin committed
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231

    security.declareProtected(Permissions.View, 'getActiveProcessList')
    def getActiveProcessList(self):
      """
      Returns the list of active processes used with
      this alarm. The list of processes will allow to
      retrieve the results history of this alarm
      """
      process_id_list = self.getActiveProcessIdList()
      portal_activities = getToolByName(self,'portal_activities')
      process_list = []
      if process_id_list is not None:
        for process_id in process_id_list:
          process = portal_activities._getOb(process_id)
          process_list.append(process)
      return process_list

    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_id_list = self.getActiveProcessIdList()
      portal_activities = getToolByName(self,'portal_activities')
      last_process = None
      if active_process_id_list is not None:
        if len(active_process_id_list)>0 and not self.isActive():
          last_process_id = active_process_id_list[len(active_process_id_list)-1]
          last_process = portal_activities._getOb(last_process_id)
        elif len(active_process_id_list)>1 and self.isActive():
          last_process_id = active_process_id_list[len(active_process_id_list)-2]
          last_process = portal_activities._getOb(last_process_id)
      return last_process

    security.declareProtected(Permissions.View, 'getCurrentActiveProcess')
    def getCurrentActiveProcess(self):
      """
      Returns the list of active processes used with
      this alarm. The list of processes will allow to
      retrieve the results history of this alarm
      """
      current_process = None
      active_process_id_list = self.getActiveProcessIdList()
      if active_process_id_list is not None:
        if len(active_process_id_list)>0 and self.isActive():
          current_process_id = active_process_id_list[len(active_process_id_list)-1]
          portal_activities = getToolByName(self,'portal_activities')
          current_process = portal_activities._getOb(current_process_id)
      return current_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()
Sebastien Robin's avatar
Sebastien Robin committed
232 233
      active_process.setStartDate(DateTime())
      active_process.setCausalityValue(self)
Sebastien Robin's avatar
Sebastien Robin committed
234 235 236 237 238 239 240 241 242 243 244 245 246
      process_id = active_process.getId()
      active_process_id_list = self.getActiveProcessIdList()
      active_process_id_list.append(process_id)
      self.setActiveProcessIdList(active_process_id_list)
      return active_process

    security.declareProtected(Permissions.View, 'getActiveProcessIdList')
    def getActiveProcessIdList(self):
      """
      Returns the list of process ids used to store results of this alarm
      """
      return getattr(self,'_active_process_id_list',[])

Sebastien Robin's avatar
Sebastien Robin committed
247 248 249 250 251 252 253 254
    security.declareProtected(Permissions.View, 'getActiveProcessValueList')
    def getActiveProcessValueList(self,**kw):
      """
      Returns the list of process used to store results of this alarm
      """
      portal_activities = getToolByName(self,'portal_activities')
      return [portal_activities._getOb(x) for x in self.getActiveProcessIdList()]

Sebastien Robin's avatar
Sebastien Robin committed
255 256 257 258 259 260
    security.declareProtected(Permissions.ModifyPortalContent, 'setActiveProcessIdList')
    def setActiveProcessIdList(self, value):
      """
      Set the list of process ids used to store results of this alarm
      """
      self._active_process_id_list = value