Alarm.py 9.94 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):
      """
Romain Courteaud's avatar
Romain Courteaud committed
78 79
      This method returns only True or False. 
      It simply tells if this alarm is currently
Sebastien Robin's avatar
Sebastien Robin committed
80 81
      active or not. It is activated when it is doing some calculation with
      activeSense or solve.
Sebastien Robin's avatar
Sebastien Robin committed
82
      """
Sebastien Robin's avatar
Sebastien Robin committed
83
      return self.hasActivity()
Sebastien Robin's avatar
Sebastien Robin committed
84 85 86 87

    security.declareProtected(Permissions.ModifyPortalContent, 'activeSense')
    def activeSense(self):
      """
Sebastien Robin's avatar
Sebastien Robin committed
88
      This method checks if there is a problem. This method can launch a very long
Sebastien Robin's avatar
Sebastien Robin committed
89
      activity. We don't care about the response, we just want to start
Sebastien Robin's avatar
Sebastien Robin committed
90 91
      some calculations. Results should be read with the method 'sense'
      later.
92

Sebastien Robin's avatar
Sebastien Robin committed
93
      """
Sebastien Robin's avatar
Sebastien Robin committed
94
      # Set the new date
Sebastien Robin's avatar
Sebastien Robin committed
95 96 97 98 99 100
      LOG('activeSense, self.getPath()',0,self.getPath())

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

    security.declareProtected(Permissions.ModifyPortalContent, 'sense')
    def sense(self):
      """
Sebastien Robin's avatar
Sebastien Robin committed
109
      This method returns True or False. False for no problem, True for problem.
110 111

      This method should respond quickly.  Basically the response depends on some
Sebastien Robin's avatar
Sebastien Robin committed
112
      previous calculation made by activeSense.
Sebastien Robin's avatar
Sebastien Robin committed
113
      """
Sebastien Robin's avatar
Sebastien Robin committed
114
      method_id = self.getSenseMethodId()
Sebastien Robin's avatar
Sebastien Robin committed
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
      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
131 132

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

    security.declareProtected(Permissions.ModifyPortalContent, 'solve')
    def solve(self):
      """
Sebastien Robin's avatar
Sebastien Robin committed
155
      This method tries solves the problem detected by sense.
156

Sebastien Robin's avatar
Sebastien Robin committed
157 158
      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
159 160 161 162
      """
      pass

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

Sebastien Robin's avatar
Sebastien Robin committed
168
      for example we can send email.
Sebastien Robin's avatar
Sebastien Robin committed
169 170

      We define nothing here, because we will use an interaction workflow.
Sebastien Robin's avatar
Sebastien Robin committed
171 172 173
      """
      pass

Sebastien Robin's avatar
Sebastien Robin committed
174
    notify = WorkflowMethod(_notify, id='notify')
Sebastien Robin's avatar
Sebastien Robin committed
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 232 233 234

    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
235 236
      active_process.setStartDate(DateTime())
      active_process.setCausalityValue(self)
Sebastien Robin's avatar
Sebastien Robin committed
237 238 239 240 241 242 243 244 245 246 247 248 249
      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
250 251 252 253 254 255 256 257
    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
258 259 260 261 262 263
    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