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()#对象定义结束

posted @ 2013-07-01 13:20  cnshen  阅读(373)  评论(0编辑  收藏  举报