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()#对象定义结束
openerp学习笔记 跟踪状态,记录日志,发送消息的更多相关文章
- RocketMQ 源码学习笔记————Producer 是怎么将消息发送至 Broker 的?
目录 RocketMQ 源码学习笔记----Producer 是怎么将消息发送至 Broker 的? 前言 项目结构 rocketmq-client 模块 DefaultMQProducerTest ...
- RocketMQ 源码学习笔记 Producer 是怎么将消息发送至 Broker 的?
目录 RocketMQ 源码学习笔记 Producer 是怎么将消息发送至 Broker 的? 前言 项目结构 rocketmq-client 模块 DefaultMQProducerTest Roc ...
- 【Visual C++】游戏编程学习笔记之八:鼠标输入消息(小demo)
本系列文章由@二货梦想家张程 所写,转载请注明出处. 作者:ZeeCoder 微博链接:http://weibo.com/zc463717263 我的邮箱:michealfloyd@126.c ...
- APUE学习笔记——10.9 信号发送函数kill、 raise、alarm、pause
转载注明出处:Windeal学习笔记 kil和raise kill()用来向进程或进程组发送信号 raise()用来向自身进程发送信号. #include <signal.h> int k ...
- webservice系统学习笔记5-手动构建/发送/解析SOAP消息
手动拼接SOAP消息调用webservice SOAP消息的组成: 1.创建需要发送的SOAP消息的XML(add方法为例子) /** * 创建访问add方法的SOAP消息的xml */ @Test ...
- rabbitMQ学习笔记(二) 简单的发送与接收消息 HelloWorld
首先要下载rabbitmq的javaClient库,然后加入到项目中,下载地址为:http://www.rabbitmq.com/releases/rabbitmq-java-client/v3.1. ...
- ucos实时操作系统学习笔记——任务间通信(消息)
ucos另一种任务间通信的机制是消息(mbox),个人感觉是它是queue中只有一个信息的特殊情况,从代码中可以很清楚的看到,因为之前有关于queue的学习笔记,所以一并讲一下mbox.为什么有了qu ...
- 【Visual C++】游戏编程学习笔记之七:键盘输入消息
本系列文章由@二货梦想家张程 所写,转载请注明出处. 作者:ZeeCoder 微博链接:http://weibo.com/zc463717263 我的邮箱:michealfloyd@126.c ...
- RabbitMQ学习系列二-C#代码发送消息
RabbitMQ学习系列二:.net 环境下 C#代码使用 RabbitMQ 消息队列 http://www.80iter.com/blog/1437455520862503 上一篇已经讲了Rabbi ...
随机推荐
- 【Android车载系统 News | Tech 1】News 谷歌开发车载Android系统 2014-12-19
据外国媒体报道,Android和iOS两大操作系统在垄断手机和平板之后,开始向智能家居.智能汽车.客厅娱乐.物联网等领域扩张.谷歌和苹果此 前均推出了连接智能手机和车载信息系统的平台产品.2014年1 ...
- 【Android 界面效果35】管理Fragments
http://www.cnblogs.com/mengdd/archive/2013/01/09/2853254.html
- 【Android Api 翻译1】Android Texting(2)Testing Fundamentals 测试基础篇
Testing Fundamentals The Android testing framework, an integral part of the development environment, ...
- View的setOnClickListener的添加方法
1)第一种,也是最长见的添加方法(一下都以Button为例) 1 Button btn = (Button) findViewById(R.id.myButton);2 btn .setOnClick ...
- 九、Android学习笔记_ Android开发中使用软引用和弱引用防止内存溢出
在<Effective Java 2nd Edition>中,第6条“消除过期的对象引用”提到,虽然Java有 垃圾回收机制,但是只要是自己管理的内存,就应该警惕内存泄露的问题,例如的对象 ...
- sql server存储过程相关
1,创建存储过程 create proc proc_test with encryption[这里是对存储过程加密],如果存储过程不常用可以加with recompile[这样存储过程就不会放到缓存里 ...
- Warning: Permanently added '...' (RSA) to the list of known hosts --Windows下git bash 警告处理
原链接地址 StackOverflow 处理方法: 创建文件~/.ssh/config, 此处对应windows当前用户目录下的.ssh文件夹 增加如下语句 UserKnownHostsFile ~/ ...
- Mysql按时间段分组查询来统计会员的个数
1.使用case when方法(不建议使用)- 代码如下 复制代码 SELECT COUNT(DISTINCT user_id) user_count, CASE WHEN cre ...
- Jquery判断$("#id")获取的对象是否存在的方法
如果是下面的 jquery 代码判断一个对象是否存在,是不能用的 if($("#id")){ }else{} 因为 $(“#id”) 不管对象是否存在都会返回 object . 正 ...
- Swiper API
本文分享自 http://www.cnblogs.com/scavengers/p/3760449.html 最近使用Swipe.js,发现中文的资料很少,试着翻译了一下.能力有限,翻译难免错漏,欢迎 ...