2009-10-20 10:52:23 +00:00
# -*- coding: utf-8 -*-
2006-12-07 13:41:40 +00:00
##############################################################################
#
2009-11-24 14:44:05 +00:00
# OpenERP, Open Source Management Solution
2009-01-04 22:13:29 +00:00
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
2008-11-03 18:27:16 +00:00
# $Id$
2008-06-16 11:00:21 +00:00
#
2008-11-03 18:27:16 +00:00
# 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 3 of the License, or
# (at your option) any later version.
2006-12-07 13:41:40 +00:00
#
2008-11-03 18:27:16 +00:00
# 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.
2006-12-07 13:41:40 +00:00
#
2008-11-03 18:27:16 +00:00
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2006-12-07 13:41:40 +00:00
#
##############################################################################
import time
2009-12-13 18:16:01 +00:00
import datetime
from dateutil . relativedelta import *
2006-12-07 13:41:40 +00:00
import netsvc
import tools
import pooler
2009-10-08 19:50:28 +00:00
from osv import fields , osv
2006-12-07 13:41:40 +00:00
2009-10-02 16:00:07 +00:00
def str2tuple ( s ) :
2009-11-04 10:51:34 +00:00
return eval ( ' tuple( %s ) ' % ( s or ' ' ) )
2009-10-02 16:00:07 +00:00
2006-12-07 13:41:40 +00:00
_intervalTypes = {
2009-12-13 18:16:01 +00:00
' work_days ' : lambda interval : relativedelta ( days = interval ) ,
' days ' : lambda interval : relativedelta ( days = interval ) ,
' hours ' : lambda interval : relativedelta ( hours = interval ) ,
' weeks ' : lambda interval : relativedelta ( days = 7 * interval ) ,
' months ' : lambda interval : relativedelta ( months = interval ) ,
' minutes ' : lambda interval : relativedelta ( minutes = interval ) ,
2006-12-07 13:41:40 +00:00
}
class ir_cron ( osv . osv , netsvc . Agent ) :
2008-07-22 14:24:36 +00:00
_name = " ir.cron "
_columns = {
' name ' : fields . char ( ' Name ' , size = 60 , required = True ) ,
' user_id ' : fields . many2one ( ' res.users ' , ' User ' , required = True ) ,
' active ' : fields . boolean ( ' Active ' ) ,
' interval_number ' : fields . integer ( ' Interval Number ' ) ,
' interval_type ' : fields . selection ( [ ( ' minutes ' , ' Minutes ' ) ,
( ' hours ' , ' Hours ' ) , ( ' work_days ' , ' Work Days ' ) , ( ' days ' , ' Days ' ) , ( ' weeks ' , ' Weeks ' ) , ( ' months ' , ' Months ' ) ] , ' Interval Unit ' ) ,
2009-01-26 17:40:29 +00:00
' numbercall ' : fields . integer ( ' Number of Calls ' , help = ' Number of time the function is called, \n a negative number indicates that the function will always be called ' ) ,
' doall ' : fields . boolean ( ' Repeat Missed ' ) ,
' nextcall ' : fields . datetime ( ' Next Call Date ' , required = True ) ,
2008-08-21 13:49:55 +00:00
' model ' : fields . char ( ' Object ' , size = 64 ) ,
2008-07-22 14:24:36 +00:00
' function ' : fields . char ( ' Function ' , size = 64 ) ,
' args ' : fields . text ( ' Arguments ' ) ,
' priority ' : fields . integer ( ' Priority ' , help = ' 0=Very Urgent \n 10=Not urgent ' )
}
2006-12-07 13:41:40 +00:00
2008-07-22 14:24:36 +00:00
_defaults = {
' nextcall ' : lambda * a : time . strftime ( ' % Y- % m- %d % H: % M: % S ' ) ,
' priority ' : lambda * a : 5 ,
' user_id ' : lambda obj , cr , uid , context : uid ,
' interval_number ' : lambda * a : 1 ,
' interval_type ' : lambda * a : ' months ' ,
' numbercall ' : lambda * a : 1 ,
' active ' : lambda * a : 1 ,
' doall ' : lambda * a : 1
}
2006-12-07 13:41:40 +00:00
2009-10-02 16:00:07 +00:00
def _check_args ( self , cr , uid , ids , context = None ) :
try :
for this in self . browse ( cr , uid , ids , context ) :
str2tuple ( this . args )
except :
return False
return True
2009-10-08 19:50:28 +00:00
_constraints = [
2009-10-02 16:00:07 +00:00
( _check_args , ' Invalid arguments ' , [ ' args ' ] ) ,
]
2008-07-22 14:24:36 +00:00
def _callback ( self , cr , uid , model , func , args ) :
2009-10-02 16:00:07 +00:00
args = str2tuple ( args )
m = self . pool . get ( model )
2008-07-22 14:24:36 +00:00
if m and hasattr ( m , func ) :
f = getattr ( m , func )
2009-10-02 16:00:07 +00:00
try :
f ( cr , uid , * args )
except Exception , e :
self . _logger . notifyChannel ( ' timers ' , netsvc . LOG_ERROR , " Job call of self.pool.get( ' %s ' ). %s (cr, uid, * %r ) failed " % ( model , func , args ) )
self . _logger . notifyChannel ( ' timers ' , netsvc . LOG_ERROR , tools . exception_to_unicode ( e ) )
2006-12-07 13:41:40 +00:00
2009-10-08 19:50:28 +00:00
def _poolJobs ( self , db_name , check = False ) :
2008-07-22 14:24:36 +00:00
try :
2009-02-06 13:47:41 +00:00
db , pool = pooler . get_db_and_pool ( db_name )
2008-07-22 14:24:36 +00:00
except :
2009-09-16 09:20:36 +00:00
return False
2009-11-23 17:07:34 +00:00
cr = db . cursor ( )
2009-10-02 16:00:07 +00:00
try :
if not pool . _init :
2009-12-13 18:16:01 +00:00
now = datetime . datetime . now ( )
2009-03-04 23:53:28 +00:00
cr . execute ( ' select * from ir_cron where numbercall<>0 and active and nextcall<=now() order by priority ' )
for job in cr . dictfetchall ( ) :
2009-12-13 18:16:01 +00:00
nextcall = datetime . datetime . strptime ( job [ ' nextcall ' ] , ' % Y- % m- %d % H: % M: % S ' )
2009-03-04 23:53:28 +00:00
numbercall = job [ ' numbercall ' ]
2008-07-22 14:24:36 +00:00
2009-03-04 23:53:28 +00:00
ok = False
while nextcall < now and numbercall :
if numbercall > 0 :
numbercall - = 1
if not ok or job [ ' doall ' ] :
self . _callback ( cr , job [ ' user_id ' ] , job [ ' model ' ] , job [ ' function ' ] , job [ ' args ' ] )
if numbercall :
nextcall + = _intervalTypes [ job [ ' interval_type ' ] ] ( job [ ' interval_number ' ] )
ok = True
2009-10-08 19:50:28 +00:00
addsql = ' '
2009-03-04 23:53:28 +00:00
if not numbercall :
addsql = ' , active=False '
cr . execute ( " update ir_cron set nextcall= %s , numbercall= %s " + addsql + " where id= %s " , ( nextcall . strftime ( ' % Y- % m- %d % H: % M: % S ' ) , numbercall , job [ ' id ' ] ) )
cr . commit ( )
2009-10-02 16:00:07 +00:00
cr . execute ( ' select min(nextcall) as min_next_call from ir_cron where numbercall<>0 and active and nextcall>=now() ' )
next_call = cr . dictfetchone ( ) [ ' min_next_call ' ]
2009-10-08 19:50:28 +00:00
if next_call :
2009-10-02 16:00:07 +00:00
next_call = time . mktime ( time . strptime ( next_call , ' % Y- % m- %d % H: % M: % S ' ) )
else :
next_call = int ( time . time ( ) ) + 3600 # if do not find active cron job from database, it will run again after 1 day
if not check :
self . setAlarm ( self . _poolJobs , next_call , db_name , db_name )
2009-10-08 19:50:28 +00:00
except Exception , ex :
logger = netsvc . Logger ( )
logger . notifyChannel ( ' cron ' , netsvc . LOG_WARNING ,
' Exception in cron: ' + str ( ex ) )
2009-10-02 16:00:07 +00:00
finally :
cr . commit ( )
cr . close ( )
2009-09-16 09:20:36 +00:00
def create ( self , cr , uid , vals , context = None ) :
res = super ( ir_cron , self ) . create ( cr , uid , vals , context = context )
cr . commit ( )
self . _poolJobs ( cr . dbname )
return res
def write ( self , cr , user , ids , vals , context = None ) :
res = super ( ir_cron , self ) . write ( cr , user , ids , vals , context = context )
cr . commit ( )
self . _poolJobs ( cr . dbname )
return res
def unlink ( self , cr , uid , ids , context = None ) :
res = super ( ir_cron , self ) . unlink ( cr , uid , ids , context = context )
cr . commit ( )
self . _poolJobs ( cr . dbname )
return res
2006-12-07 13:41:40 +00:00
ir_cron ( )
2008-07-23 15:01:27 +00:00
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: