openerp学习笔记 跟踪状态,记录日志,发送消息
跟踪状态基础数据:
kl_qingjd/kl_qingjd_data.xml
<?xml version="1.0"?>
<openerp>
<data
noupdate="1">
<!-- kl_qingjd-related subtypes
for messaging / Chatter -->
<record id="mt_qingjd_confirm"
model="mail.message.subtype">
<field
name="name">已提交</field>
<field
name="res_model">kl.qingjd</field>
<field
name="description">请假申请已提交</field>
</record>
<record
id="mt_qingjd_validate"
model="mail.message.subtype">
<field
name="name">已批准</field>
<field
name="res_model">kl.qingjd</field>
<field
name="description">请假申请已批准</field>
</record>
<record
id="mt_qingjd_refuse"
model="mail.message.subtype">
<field
name="name">已拒绝</field>
<field
name="res_model">kl.qingjd</field>
<field name="default" eval="True"/> <!-- 订阅时,默认激活 -->
<field
name="description">请假申请已拒绝</field>
</record>
</data>
</openerp>
跟踪状态,记录日志,发送消息后台代码:
kl_qingjd/kl_qingjd.py
# -*- encoding: utf-8 -*-
import pooler
import logging
import
netsvc
import tools
logger = netsvc.Logger()
import datetime
import
time
import math
from osv import fields,osv
from
openerp.tools.translate import _ #用于翻译代码中的静态字符串
#假期类型对象
class kl_qingjd_type(osv.osv):
_name =
"kl.qingjd.type"
_description =
u"假期类型"
_order = "num asc, id asc"
#对象字段
_columns =
{
'num':
fields.integer(u'序号'),
'name':
fields.char(u'假期类型', size=64, required=True,
translate=True),
'notes':
fields.char(u'说明', size=200),
}
#数据库约束
_sql_constraints =
[
('name_check', "unique(name)",
u"假期类型已经存在且不允许重复."),
]
kl_qingjd_type()#对象定义结束
#请假单对象
class kl_qingjd(osv.osv):
_name =
'kl.qingjd'
_description = u'kl 请假单'
_order = "date_from asc, type_id asc"
_inherit =
['mail.thread'] #继承消息模块,用于发消息
_track =
{
'state':
{
'kl_qingjd.mt_qingjd_validate': lambda self, cr, uid, obj, ctx=None:
obj['state'] ==
'validate',
'kl_qingjd.mt_qingjd_refuse': lambda self, cr, uid, obj, ctx=None: obj['state']
==
'refuse',
'kl_qingjd.mt_qingjd_confirm': lambda self, cr, uid, obj, ctx=None: obj['state']
== 'confirm',
},
#自动发送系统消息,可用于记录日志或在邮件中显示,在邮件中显示时需要定义消息的子类型(kl_qingjd_data.xml)和指定消息相关用户(self.message_subscribe_users)
}
#获取当前用户所属的员工
def _employee_get(self, cr, uid,
context=None):
ids =
self.pool.get('hr.employee').search(cr, uid, [('user_id', '=', uid)],
context=context)
if
ids:
return ids[0]
return
False
#获取当前用户所属部门的id和名称
def _get_user_department(self, cr, uid,
context={}):
obj =
self.pool.get('hr.employee')
ids
= obj.search(cr, uid, [('user_id','=',uid)])
res = obj.read(cr, uid, ids,
['id','department_id'], context)
return res and res[0]['department_id'] or 0
#检测同一时间段内是否存在相同的请假单,False 是存在,不允许创建
def _check_date(self, cr, uid,
ids):
for rec in self.browse(cr,
uid, ids):
search_ids = self.search(cr, uid, [('date_from', '<=', rec.date_to),
('date_to', '>=', rec.date_from), ('employee_id', '=', rec.employee_id.id),
('id', '<>',
rec.id)])
if
search_ids:
return False
return
True
# TODO: can be improved using
resource calendar method
#计算日期间隔对应的天数
def _get_number_of_days(self, date_from,
date_to):
"""Returns a float
equals to the timedelta between two dates given as string."""
DATETIME_FORMAT = "%Y-%m-%d
%H:%M:%S"
from_dt =
datetime.datetime.strptime(date_from,
DATETIME_FORMAT)
to_dt =
datetime.datetime.strptime(date_to,
DATETIME_FORMAT)
timedelta = to_dt
- from_dt
diff_day =
timedelta.days + float(timedelta.seconds) /
86400
return
diff_day
#对象字段
_columns =
{
'employee_id': fields.many2one('hr.employee', u"申请人",required=True, select=True,
invisible=False, readonly=True,
states={'draft':[('readonly',False)]}),
'department_id':fields.many2one('hr.department', u'申请部门', invisible=False,
readonly=True, states={'draft':[('readonly',False)]}),
#修改职员所属部门后显示原部门
#'department_id':fields.related('employee_id', 'department_id', string=u'申请部门',
type='many2one', relation='hr.department', readonly=True, store=True),
#修改职员所属部门后显示新部门
'type_id': fields.many2one("kl.qingjd.type", u"假期类型",
required=True,readonly=True,
states={'draft':[('readonly',False)]}),
'date_from': fields.datetime(u'起始日期',required=True, readonly=True,
states={'draft':[('readonly',False)]},
select=True),
'date_to': fields.datetime(u'结束日期', readonly=True,
states={'draft':[('readonly',False)]}),
'days': fields.float(u'天数', digits=(8, 2), readonly=True,
states={'draft':[('readonly',False)]}),
'notes': fields.text(u'请假原因',readonly=True,
states={'draft':[('readonly',False)]}),
'manager_id': fields.many2one('hr.employee', u'审批人', invisible=False,
readonly=True,
help=u'审批和拒绝时自动记录审批人'),
'refuse_notes': fields.char(u'拒绝原因', size=200, invisible=False, readonly=True,
states={'confirm':[('readonly',False)],
'validate':[('readonly',False)]}),
'state': fields.selection([('draft', u'草稿'), ('cancel', u'已作废'),('confirm',
u'待审批'), ('refuse', u'已拒绝'), ('validate', u'已审批')], u'状态', readonly=True,
track_visibility='onchange'),
'create_uid': fields.many2one('res.users', u"创建用户", invisible=False,
readonly=True),
#需要在记录中读取该字段或者在视图、打印中显示该字段时,对象中必须包含
'create_date': fields.datetime(u"创建日期", invisible=True, readonly=True),
#需要在记录中读取该字段或者在视图、打印中显示该字段时,对象中必须包含
}
#字段默认值
_defaults = {
'state':
'draft',
'employee_id':
_employee_get,
'department_id': lambda self,cr,uid,context:
self._get_user_department(cr,uid,context),
}
#对象约束
_constraints =
[
(_check_date, u'您在相同的时间段内不允许创建多张请假单!',
[u'起始日期',u'结束日期']),
]
#数据库约束
_sql_constraints = [
('date_check', "CHECK (date_from <= date_to)",
u"开始日期必须小于结束日期."),
('days_check',
"CHECK (days > 0 )", u"请假天数必须大于 0 ."),
]
#创建,此处取消自动记录创建
def create(self, cr, uid, values,
context=None):
""" Override to
avoid automatic logging of creation
"""
if context is
None:
context = {}
context =
dict(context,
mail_create_nolog=True)
return super(kl_qingjd, self).create(cr, uid, values, context=context)
#复制(未知用途)
def copy(self, cr, uid,
id, default=None, context=None):
#if default is None:
# default = {}
#if context is None:
# context = {}
#default = default.copy()
#default['date_from'] = False
#default['date_to'] = False
raise
osv.except_osv(_(u'警告!'),_(u'请假单暂不支持复制功能.'))
return super(kl_qingjd, self).copy(cr, uid, id, default,
context=context)
#写入,可用于校验写入和更改数据的合法性
def write(self, cr, uid, ids, vals,
context=None):
return
super(kl_qingjd, self).write(cr, uid, ids, vals,
context=context)
#删除当前请假单,需要验证请假单的状态
def unlink(self, cr, uid, ids,
context=None):
for rec in
self.browse(cr, uid, ids,
context=context):
if rec.state not in ['draft', 'cancel', 'confirm',
'refuse']:
raise osv.except_osv(_(u'警告!'),_(u'您不能删除以下状态的请假单 %s
.')%(rec.state))
#当请假单不是自己创建的时,不能删除
if (rec.create_uid.id != uid):
#此处需要读取创建者ID时,必须在对象中包含create_uid列
raise
osv.except_osv(_(u'警告!'),_(u'您只能删除自己创建的单据.'))
return super(kl_qingjd, self).unlink(cr, uid, ids,
context)
#更换员工时自动修改员工所属的部门
def onchange_employee(self, cr, uid,
ids, employee_id):
result =
{'value': {'department_id':
False}}
if
employee_id:
employee = self.pool.get('hr.employee').browse(cr, uid,
employee_id)
result['value'] = {'department_id':
employee.department_id.id}
return
result
#更改起始日期,自动计算请假天数
def onchange_date_from(self, cr, uid,
ids, date_to, date_from):
"""
If there are no date set for
date_to, automatically set one 8 hours later
than
the
date_from.
Also update the
number_of_days.
"""
# date_to has to be greater
than date_from
if (date_from and
date_to) and (date_from >
date_to):
raise osv.except_osv(_(u'警告!'),_(u'开始日期必须小于结束日期.'))
result = {'value': {}}
# No date_to set so far:
automatically compute one 8 hours
later
if date_from and not
date_to:
date_to_with_delta = datetime.datetime.strptime(date_from,
tools.DEFAULT_SERVER_DATETIME_FORMAT) +
datetime.timedelta(hours=8)
result['value']['date_to'] = str(date_to_with_delta)
# Compute and update the number of
days
if (date_to and date_from)
and (date_from <=
date_to):
diff_day = self._get_number_of_days(date_from,
date_to)
result['value']['days'] =
round(math.floor(diff_day))+1
else:
result['value']['days'] = 0
return
result
#更改结束日期,自动计算请假天数
def onchange_date_to(self, cr, uid, ids,
date_to, date_from):
"""
Update the
number_of_days.
"""
# date_to has to be greater
than date_from
if (date_from and
date_to) and (date_from >
date_to):
raise osv.except_osv(_(u'警告!'),_(u'开始日期必须小于结束日期.'))
result = {'value': {}}
# Compute and update the number of
days
if (date_to and date_from)
and (date_from <=
date_to):
diff_day = self._get_number_of_days(date_from,
date_to)
result['value']['days'] =
round(math.floor(diff_day))+1
else:
result['value']['days'] = 0
return
result
#设置为草稿状态,需要重新初始化工作流
def set_to_draft(self, cr, uid, ids,
context=None):
for rec in
self.browse(cr, uid, ids,
context=context):
#当请假单不是自己创建的时,不能设置为草稿
if rec.create_uid.id !=
uid:
raise
osv.except_osv(_(u'警告!'),_(u'您不能设置他人创建的单据为草稿状态.'))
self.write(cr, uid, ids,
{
'state':
'draft',
'manager_id':
False,
'refuse_notes':False
})
#重新初始化工作流
wf_service =
netsvc.LocalService("workflow")
for id in
ids:
wf_service.trg_delete(uid, 'kl.qingjd', id, cr)
#传入对象名称
wf_service.trg_create(uid, 'kl.qingjd', id,
cr)
return
True
#审批请假单,自动记录审批人
def set_to_validate(self, cr, uid, ids,
context=None):
#审批时,此处可以增加审批权限的校验
for rec in
self.browse(cr, uid, ids,
context=context):
#当请假单的主管不是自己时,不能审批
if rec.employee_id and rec.employee_id.parent_id and
rec.employee_id.parent_id.user_id:
if rec.employee_id.parent_id.user_id.id !=
uid:
raise
osv.except_osv(_(u'警告!'),_(u'您不能审批当前单据,应由申请人的主管审批.'))
else:
raise
osv.except_osv(_(u'警告!'),_(u'您不能审批当前单据,应由申请人的主管审批.'))
obj_emp =
self.pool.get('hr.employee')
ids2
= obj_emp.search(cr, uid, [('user_id', '=',
uid)])
manager = ids2 and ids2[0]
or False
#self.send_validate_notificate(cr, uid, ids, context=context)
#批准时发送消息给自己,跟系统自动发送的消息重复
return self.write(cr, uid, ids, {'state':'validate', 'manager_id':
manager})
#发送消息给自己,已批准
#def send_validate_notificate(self, cr, uid,
ids, context=None):
# for obj in
self.browse(cr, uid, ids, context=context):
# self.message_post(cr, uid, [obj.id],
body=_(u'您的请假申请已批准!'), context=context)
#提交请假单,发送消息给主管
def
set_to_confirm(self, cr, uid, ids,
context=None):
#发送消息给主管
for rec in
self.browse(cr, uid, ids,
context=context):
#当请假单不是自己创建的时,不能提交
if rec.create_uid.id !=
uid:
raise
osv.except_osv(_(u'警告!'),_(u'您不能提交他人创建的单据.'))
#提交请假单时发送系统消息,指定消息相关的用户(发送消息给主管和自己),消息的起始点,如果接收人只有自己则消息不在邮件中显示
if rec.employee_id and rec.employee_id.parent_id and
rec.employee_id.parent_id.user_id:
self.message_subscribe_users(cr, uid, [rec.id],
user_ids=[rec.employee_id.parent_id.user_id.id],
context=context)
return
self.write(cr, uid, ids, {'state': 'confirm'})
#拒绝请假单,自动记录审批人
def
set_to_refuse(self, cr, uid, ids,
context=None):
for rec in self.browse(cr, uid,
ids,
context=context):
#当请假单的主管不是自己时,不能拒绝
if rec.employee_id and rec.employee_id.parent_id and
rec.employee_id.parent_id.user_id:
if rec.employee_id.parent_id.user_id.id !=
uid:
raise
osv.except_osv(_(u'警告!'),_(u'您不能拒绝当前单据,应由申请人的主管拒绝.'))
else:
raise
osv.except_osv(_(u'警告!'),_(u'您不能拒绝当前单据,应由申请人的主管拒绝.'))
#拒绝时验证决绝原因不能为空
if (rec.refuse_notes == False) or (rec.refuse_notes.strip() ==
''):
raise
osv.except_osv(_(u'警告!'),_(u'拒绝原因不能为空,请编辑并填写.'))
obj_emp =
self.pool.get('hr.employee')
ids2
= obj_emp.search(cr, uid, [('user_id', '=',
uid)])
manager = ids2 and ids2[0]
or False
#self.send_refuse_notificate(cr, uid, ids, context=context)
#拒绝时发送消息给自己,跟系统自动发送的消息重复
return self.write(cr, uid, ids, {'state':'refuse', 'manager_id':
manager})
#发送消息给自己,已拒绝
#def send_refuse_notificate(self, cr, uid,
ids, context=None):
# for obj in
self.browse(cr, uid, ids, context=context):
# self.message_post(cr, uid, [obj.id],
body=_(u'您的请假申请已拒绝!'), context=context)
kl_qingjd()#对象定义结束