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 ...
随机推荐
- JSONP跨域原理和jQuery.getJSON用法
JSONP是一个非官方的协议,它允许在服务器端集成Script tags返回至客户端,通过javascript callback的形式实现跨域访问(这仅仅是JSONP简单的实现形式).本文主要介绍JS ...
- 【MongoDB】MongoDB VS SQL数据库
MongoDB和SQL数据库都能满足数据库的基本功能:1.有组织的存放数据:2.按照需求查询数据 传统的SQL数据库(e.g.Oracle, MySQL) 对表的运用不够灵活,横向扩展不太容易,而它的 ...
- html2canvas 踩坑总结
需求:将html表格导出为图片,表格可以自己编辑数据,并适配各种屏幕大小.上网搜了下,找到了html2canvas,一开始使用的是最新版0.5.0,最终因为需要支持自定义div编辑框自动换行选择了v0 ...
- 简直喝血!H.265要被专利费活活玩死
转自 http://news.mydrivers.com/1/440/440145.htm H.264是如今最流行的视频编码格式之一,不但技术先进,而且专利费很低,企业每年只需支付650万美元,而个人 ...
- Android DiffUtil
Android 的recyclerview-v7:24.2.0 发布后多了个DiffUtil工具类,这个工具类能够大大解放了Android开发者的一个苦恼:RecyclerView局部刷新和重新刷新时 ...
- MySQL之建设工程监管信息系统
--创建SelfStudy数据库 CREATE DATABASE ConstructionDB ON PRIMARY --创建主数据库文件 ( NAME=' ConstructionDB', --数据 ...
- Swiper之滑块2
对比之前Swiper滑块1来说,我们添加一下背景颜色来看看: <!DOCTYPE html> <html> <head> <meta http-equiv=& ...
- shell语法基础
一.变量 1.linux大小写敏感,变量取名要注意大小写.可以通过变量名前面加$来访问变量的内容.可以通过使用read命令来将用户输入的值赋给一个变量. 2.给变量赋值时,如果字符串中包含空格,就必须 ...
- C#中如何查找Dictionary中的重复值
简介 在这篇帮助文档中,我将向你展示如何实现c#里字典中重复值的查找.你知道的对于一个老鸟来说,这是非常简单的代码.但是尽管如此,这也是一篇对c#初学者非常有用的帮助文档. 背景 多数程序员对小型数据 ...
- MVC 模型js远程校验的使用方法
我们在网站注册的时候往往需要在用户注册完毕的时候显示用户名是否可用,这就要用到模型的远程校验了.具体如下. [Required(ErrorMessage = "用户名不能为空"), ...