1510173fdaec740f0e2e66a3a447f118e212680a
[odoo/odoo.git] / bin / addons / base / ir / ir_cron.py
1 # -*- encoding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution   
5 #    Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). All Rights Reserved
6 #    $Id$
7 #
8 #    This program is free software: you can redistribute it and/or modify
9 #    it under the terms of the GNU General Public License as published by
10 #    the Free Software Foundation, either version 3 of the License, or
11 #    (at your option) any later version.
12 #
13 #    This program is distributed in the hope that it will be useful,
14 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
15 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 #    GNU General Public License for more details.
17 #
18 #    You should have received a copy of the GNU General Public License
19 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
20 #
21 ##############################################################################
22
23 from mx import DateTime
24 import time
25 import netsvc
26 import tools
27 import pooler
28 from osv import fields,osv
29
30 next_wait = 60
31
32 _intervalTypes = {
33     'work_days': lambda interval: DateTime.RelativeDateTime(days=interval),
34     'days': lambda interval: DateTime.RelativeDateTime(days=interval),
35     'hours': lambda interval: DateTime.RelativeDateTime(hours=interval),
36     'weeks': lambda interval: DateTime.RelativeDateTime(days=7*interval),
37     'months': lambda interval: DateTime.RelativeDateTime(months=interval),
38     'minutes': lambda interval: DateTime.RelativeDateTime(minutes=interval),
39 }
40
41 class ir_cron(osv.osv, netsvc.Agent):
42     _name = "ir.cron"
43     _columns = {
44         'name': fields.char('Name', size=60, required=True),
45         'user_id': fields.many2one('res.users', 'User', required=True),
46         'active': fields.boolean('Active'),
47         'interval_number': fields.integer('Interval Number'),
48         'interval_type': fields.selection( [('minutes', 'Minutes'),
49             ('hours', 'Hours'), ('work_days','Work Days'), ('days', 'Days'),('weeks', 'Weeks'), ('months', 'Months')], 'Interval Unit'),
50         'numbercall': fields.integer('Number of calls', help='Number of time the function is called,\na negative number indicates that the function will always be called'),        
51         'doall' : fields.boolean('Repeat missed'),
52         'nextcall' : fields.datetime('Next call date', required=True),
53         'model': fields.char('Object', size=64),
54         'function': fields.char('Function', size=64),
55         'args': fields.text('Arguments'),
56         'priority': fields.integer('Priority', help='0=Very Urgent\n10=Not urgent')
57     }
58
59     _defaults = {
60         'nextcall' : lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
61         'priority' : lambda *a: 5,
62         'user_id' : lambda obj,cr,uid,context: uid,
63         'interval_number' : lambda *a: 1,
64         'interval_type' : lambda *a: 'months',
65         'numbercall' : lambda *a: 1,
66         'active' : lambda *a: 1,
67         'doall' : lambda *a: 1
68     }
69
70     def _callback(self, cr, uid, model, func, args):
71         args = (args or []) and eval(args)
72         m=self.pool.get(model)
73         if m and hasattr(m, func):
74             f = getattr(m, func)
75             f(cr, uid, *args)
76
77     def _poolJobs(self, db_name, check=False):
78         now = DateTime.now()
79         #FIXME: multidb. Solution: a l'instanciation d'une nouvelle connection bd (ds pooler) fo que j'instancie
80         # un nouveau pooljob avec comme parametre la bd
81         try:
82             cr = pooler.get_db(db_name).cursor()
83         except:
84             return False
85
86         try:
87             cr.execute('select * from ir_cron where numbercall<>0 and active and nextcall<=now() order by priority')
88             for job in cr.dictfetchall():
89                 nextcall = DateTime.strptime(job['nextcall'], '%Y-%m-%d %H:%M:%S')
90                 numbercall = job['numbercall']
91                 
92                 ok = False
93                 while nextcall<now and numbercall:
94                     if numbercall > 0:
95                         numbercall -= 1
96                     if not ok or job['doall']:
97                         self._callback(cr, job['user_id'], job['model'], job['function'], job['args'])
98                     if numbercall:
99                         nextcall += _intervalTypes[job['interval_type']](job['interval_number'])
100                     ok = True
101                 addsql=''
102                 if not numbercall:
103                     addsql = ', active=False'
104                 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']))
105                 cr.commit()
106         finally:
107             cr.close()
108         #
109         # Can be improved to do at the min(min(nextcalls), time()+next_wait)
110         # But is this an improvement ?
111         # 
112         if not check:
113             self.setAlarm(self._poolJobs, int(time.time())+next_wait, [db_name])
114 ir_cron()
115
116 # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
117