# -*- coding: utf-8 -*-
from ladon.ladonizer import ladonize
from ladon.types.ladontype import LadonType
from django.conf import settings
from mysite.utils import get_option
import time
from mysite.personnel.models.model_dept import Department
from mysite.personnel.models.model_leave import LeaveLog as model_leave
from mysite.personnel.models.model_area import Area as model_area
from mysite.personnel.models.model_emp import Employee as model_Employee,format_pin
from mysite.personnel.models.model_issuecard import IssueCard,CARD_VALID,CARD_OVERDUE
from mysite.pywebsv.webservice.issuecard_service import format_valid
from base.crypt import encryption
import datetime
import re
import os
import json
from comm.att.struct.sync_action import *
class Employee(LadonType):
    u"""人员基本信息"""
    pin =  { 'type': unicode,
			 'nullable': False,
			 'doc': u'人员编号'}
    EName =  { 'type': unicode,
			 'nullable': True,
			 'default': u'Jone',
			 'doc': u'姓名'}
    Card ={ 'type': str,
			 'nullable': True,
			 'doc': u'卡号'}
    Password = { 'type': str,
			 'nullable': True,
			 'doc': u'密码'}
    AccGroup = { 'type': str,
			 'nullable': True,
			 'doc': u'门禁组'}
    Privilege = { 'type': str,
			 'nullable': True,
			 'doc': u'人员设备权限'}
    TimeZones = { 'type': str,
			 'nullable': True,
			 'doc': u'门禁时间段'}
    DeptID = { 'type': str,
             'nullable': False,
             'doc': u'部门编号'}
    country = { 'type': str,
             'nullable': True,
             'doc': u'国家'}
    state = { 'type': str,
             'nullable': True,
             'doc': u'省份'}
    city = { 'type': str,
             'nullable': True,
             'doc': u'城市'}
    area = { 'type': str,
             'nullable': False,
             'doc': u'考勤区域'}
    Political = { 'type': str,
             'nullable': True,
             'doc': u'政治面貌'}
    education = { 'type': str,
             'nullable': True,
             'doc': u'学历：1-小学，2-初中，3-普通高中，4-职高，5-中专，6-技校，7-大专，8-本科，9-硕士研究生，10-博士研究生'}
    national = { 'type': str,
             'nullable': True,
             'doc': u'民族'}
    lastname = { 'type': str,
             'nullable': True,
             'doc': u'姓氏'}
    Gender = { 'type': str,
             'nullable': True,
             'doc': u'性别'}
    Birthday = { 'type': str,
             'nullable': True,
             'doc': u'生日'}
    Address = { 'type': str,
             'nullable': True,
             'doc': u'办公地址'}
    PostCode = { 'type': str,
             'nullable': True,
             'doc': u'邮编'}
    Tele = { 'type': str,
             'nullable': True,
             'doc': u'办公电话'}
    FPHONE = { 'type': str,
             'nullable': True,
             'doc': u'家庭电话'}
    Mobile = { 'type': str,
             'nullable': True,
             'doc': u'手机'}
    identitycard = { 'type': str,
             'nullable': True,
             'doc': u'身份证号码'}
    hiretype = { 'type': str,
             'nullable': True,
             'doc': u'雇佣类型'}
    email = { 'type': str,
             'nullable': True,
             'doc': u'邮箱'}
    birthplace = { 'type': str,
             'nullable': True,
             'doc': u'籍贯'}
    emptype = { 'type': str,
             'nullable': True,
             'doc': u'员工类型'}
    position = { 'type': str,
             'nullable': True,
             'doc': u'职位'}
    selfpassword = { 'type': str,
             'nullable': True,
             'doc': u'登录密码'}
    Hiredday = { 'type': str,
             'nullable': True,
             'doc': u'聘用日期'}
    homeaddress = { 'type': str,
             'nullable': True,
             'doc': u'家庭地址'}
    
class Device(LadonType):
    u"""设备基本信息"""
    area =  { 'type': str,
             'nullable': True,
             'doc': u'设备区域'}
    alias ={ 'type': unicode,
             'nullable': True,
             'doc': u'设备别名'}
    push_status = { 'type': str,
             'nullable': True,
             'doc': u'数据下发标识位'}
    update_db = { 'type': str,
             'nullable': True,
             'doc': u'数据更新标识位'}
    trans_times = { 'type': str,
             'nullable': True,
             'doc': u'定时传送时间'}
    trans_interval = { 'type': str,
             'nullable': True,
             'doc': u'刷新间隔时间(分钟)'}
    tz_adj = { 'type': str,
             'nullable': True,
             'doc': u'时区'}

    
class Area(LadonType):
    u"""区域/组织信息"""
    name =  { 'type': str,
             'nullable': True,
             'doc': u'区域/组织名称'}
    parent =  { 'type': str,
             'nullable': True,
             'default': '0',
             'doc': u'父区域/组织ID'}
    reserve = { 'type': str,
             'nullable': True,
             'doc': u'保留字段'}
class Leave(LadonType):
    u"""设备基本信息"""
    leavedate =  { 'type': str,
             'nullable': False,
             'doc': u'离职日期(必填)：格式‘2013-12-12’'}
    leavetype ={ 'type': str,
             'nullable': False,
             'doc': u'离职类型(必填):1-自离、2-辞退、3-辞职、4-调离、5-停薪留职'}
    reason = { 'type': str,
             'nullable': True,
             'doc': u'离职原因'}
    isReturnTools = { 'type': bool,
             'nullable': True,
             'default': True,
             'doc': u'是否归还工具'}
    isReturnClothes = { 'type': bool,
             'nullable': True,
             'default': True,
             'doc': u'是否归还工衣'}
    isReturnCard = { 'type': bool,
             'nullable': True,
             'default': False,
             'doc': u'是否归还卡'}
    isblacklist = { 'type': bool,
             'nullable': True,
             'default': False,
             'doc': u'是否黑名单'}
    isClassAtt = { 'type': bool,
             'nullable': True,
             'default': True,
             'doc': u'立即关闭考勤'}
    isClassAccess = { 'type': bool,
             'nullable': True,
             'default': True,
             'doc': u'立即关闭门禁'}
    is_close_pos = { 'type': bool,
             'nullable': True,
             'default': True,
             'doc': u'立即关闭消费'}    
class EmployeeService(object):
    u"""
    【人员操作】包含更新或新增人员、设置考勤区域、获取考勤区域、删除人员、重新分发人员等操作
    """
    @ladonize(str,Leave,rtype=str)
    def leaveEmp(self,pin,leave_info):
        """
              人员离职
        @param pin: 参数一 人员工号
        @rtype: 返回 执行结果信息
             0    成功
            -91    人员编号只支持数字
            -92    人员编号只支持数字或字母
            -93    人员编号不能为0
            -94    人员编号的长度不能大于指定长度
            -97    人员编号不存在
            -114    离职日期格式不正确
            -115    离职类型只能是1,2,3,4,5
        """
        RET_INFO={}
        RET_INFO['option'] = 'leaveEmp'
        RET_INFO['ret'] = format_valid(pin,'',check_cardno = False)#人员编号验证
        if RET_INFO['ret'] != '-1' :
            return json.dumps(RET_INFO)
        if not leave_info.leavedate :
            RET_INFO['ret'] = '-114' 
            return json.dumps(RET_INFO)
        else:
            try:
                datetime.datetime.strptime(leave_info.leavedate, '%Y-%m-%d')
            except:
                RET_INFO['ret'] = '-114' 
                return json.dumps(RET_INFO)
        if not leave_info.leavetype or leave_info.leavetype not in ('1','2','3','4','5'):
            RET_INFO['ret'] = '-115' 
            return json.dumps(RET_INFO)
        try:
            t_emp = model_Employee.objects.get(PIN = format_pin(pin))#验证人员是否存在
        except :
            RET_INFO['ret'] = '-97'
            return json.dumps(RET_INFO)
        iscard = IssueCard.objects.filter(UserID=t_emp,cardstatus__in = [CARD_VALID,CARD_OVERDUE])
        t = model_leave(UserID = t_emp,leavedate = leave_info.leavedate,leavetype = leave_info.leavetype,reason = leave_info.reason,isReturnTools = leave_info.isReturnTools,isReturnClothes = leave_info.isReturnClothes)
        t_emp.isblacklist = leave_info.isblacklist
        t_emp.status = 3#设置成离职状态
        if not get_option("POS"):
            t.isReturnCard = leave_info.isReturnCard
            if  leave_info.isReturnCard and iscard:
                for e in iscard:e.delete()
        t_emp.save()
        t.save()
        if leave_info.isClassAtt:
                t.OpCloseAtt(t).action()
        if leave_info.isClassAccess:
                t.OpCloseAccess(t).action()
        if leave_info.is_close_pos:
                t.OpClosePos(t).action()
        ret=del_Employee(pin)
        RET_INFO['ret'] = '0'
        RET_INFO['id'] = t_emp.id
        return json.dumps(RET_INFO)
    
    @ladonize(Employee,rtype=str)
    def setEmp(self,emp_info):
        """
        更新或新增人员基本信息
        @param pin: 参数一 人员工号
        @param emp_info: 参数二 人员基本信息字典
        @rtype: 返回 执行结果信息
             0    成功
            -91    人员编号只支持数字
            -92    人员编号只支持数字或字母
            -93    人员编号不能为0
            -94    人员编号的长度不能大于指定长度
            -95    卡号只支持数字
            -96    卡号不能为0
            -98    部门编号不存在
            -99    职位编号不存在
            -100    部门编号对应的职位编号不一致
            -101    卡号已被使用
            -102    区域编号不存在
            -103    设备权限必须为4,8,10
            -104    该卡号有注册了消费卡账号
            -105    已有一张ID有效卡，请先挂失，在换卡号
            -106    人员密码必须是整数
            -107    出生日期格式错误
            -108    邮箱格式不正确
            -109    手机号码格式不正确
            -110    雇佣日期格式错误
            -111    雇佣类型只能是1,2
            -112    员工类型只能是1,2
            -113    身份证号码格式错误
        """
        from mysite.personnel.models.model_dept import Department
        from mysite.personnel.models.model_position import Position 
        from mysite.personnel.models.model_area import Area
        from mysite.personnel.models.model_issuecard import CARD_VALID,CARD_STOP 
        RET_INFO={}
        RET_INFO['option'] = 'setEmp'
        RET_INFO['ret'] = format_valid(emp_info.pin,emp_info.Card,check_cardno = False)#人员编号与卡号验证
        if RET_INFO['ret'] != '-1' :
            return json.dumps(RET_INFO)
        dept = Department.objects.filter(code = u'%s'%emp_info.DeptID)
        if not dept:
            RET_INFO['ret'] = '-98'
            return json.dumps(RET_INFO)
        if emp_info.position:
            position = Position.objects.filter(code = u'%s'%emp_info.position)
            if not position:
                RET_INFO['ret'] = '-99'
                return json.dumps(RET_INFO)
            else:
                if dept.code != position.DeptID.code:
                    RET_INFO['ret'] = '-100'
                    return json.dumps(RET_INFO)
        else:
            position = None
        areas = Area.objects.filter(areaid__in = emp_info.area.split(','))
        if not areas:
            RET_INFO['ret'] = '-102'
            return json.dumps(RET_INFO)
        if emp_info.Password and not emp_info.Password.isdigit():#人员密码校验
            RET_INFO['ret'] = '-106'#人员密码必须是整数
            return json.dumps(RET_INFO)
        if emp_info.Privilege and emp_info.Privilege not in ['4','8','10']:#人员密码校验
            RET_INFO['ret'] = '-103'
            return json.dumps(RET_INFO)
        else:
            emp_info.Privilege = '4'
        if emp_info.Birthday :#出生日期验证
            try:
                time.strptime(emp_info.Birthday, '%Y-%m-%d')
            except:
                RET_INFO['ret'] = '-107'
                return json.dumps(RET_INFO)#出生日期格式错误
        if emp_info.Hiredday :#聘用日期验证
            try:
                time.strptime(emp_info.Hiredday, '%Y-%m-%d')
            except:
                RET_INFO['ret'] = '-110'#聘用日期格式错误
                return json.dumps(RET_INFO)
        telephone = re.compile('^[0-9]+$')
        email = re.compile('^([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+@([a-zA-Z0-9]+[_|\_|\.]?)*[a-zA-Z0-9]+\.[a-zA-Z]{2,3}$')
        if emp_info.email and not email.search(emp_info.email):#email验证
            RET_INFO['ret'] = '-108'#邮箱格式不正确
            return json.dumps(RET_INFO)
        if emp_info.Mobile and not telephone.search(emp_info.Mobile):#手机号码验证
            RET_INFO['ret'] = '-109'#手机号码格式不正确
            return json.dumps(RET_INFO)
        if emp_info.hiretype and int(emp_info.hiretype) not in (1,2):#雇佣类型验证
            RET_INFO['ret'] = '-111'#雇佣类型错误
            return json.dumps(RET_INFO)
        if emp_info.emptype and int(emp_info.emptype) not in (1,2):#员工类型验证
            RET_INFO['ret'] = '-112'#员工类型错误
            return json.dumps(RET_INFO)
        if emp_info.identitycard:#身份证号码验证
            RET_INFO['ret'] = identitycard_valid(emp_info.identitycard)#身份证号码验证
            if RET_INFO['ret'] != '-1':
                return json.dumps(RET_INFO)
        if emp_info.Card: 
            try:
                old_card = IssueCard.objects.get(cardno = emp_info.Card)#验证卡是否被使用
            except:
                RET_INFO['ret'] = '-101'#卡已被使用
                return json.dumps(RET_INFO)
        pin = format_pin(emp_info.pin)
        t_emp = model_Employee.objects.filter(PIN = pin)
        if t_emp :#修改人员
            t_card= IssueCard.objects.filter(UserID=t_emp[0],cardstatus=CARD_VALID)#验证当前人员是否拥有的有效卡
            if t_card and emp_info.Card and emp_info.Card != t_card.cardno :
                if get_option("ONLY_ATT"):
                    t_card.cardstatus = CARD_STOP#修改为停用卡号
                    t_card.save()
                    super(IssueCard,IssueCard(UserID=t_emp[0],cardno=emp_info.Card,cardstatus = CARD_VALID)).save()
                if get_option("POS_ID"):
                    RET_INFO['ret'] = '-105'#已有一张ID有效卡，请先挂失，在换卡号
                    return json.dumps(RET_INFO)
                if get_option("POS_IC"):
                    if t_card.sys_card_no:
                        RET_INFO['ret'] = '-104'#该卡号有注册了消费卡账号
                        return json.dumps(RET_INFO)
                    else:
                        t_card.cardstatus = CARD_STOP#修改为停用卡号
                        t_card.save()
                        super(IssueCard,IssueCard(UserID=t_emp[0],cardno=emp_info.Card,cardstatus = CARD_VALID)).save()
            else:
                if emp_info.Card:#有卡号,增加操作
                    super(IssueCard,IssueCard(UserID=t_emp[0],cardno=emp_info.Card,cardstatus = CARD_VALID)).save()
            t_emp[0].DeptID = dept[0]
            if position:
                t_emp[0].position=position[0]
            else:
                t_emp[0].position = None
            emp = covert_emp(emp_info,t_emp[0],areas)
            super(model_Employee,emp).save()
            RET_INFO['id'] = t_emp[0].id
            RET_INFO['ret'] = '0'
            return json.dumps(RET_INFO)
        else :#增加人员
            if position:
                t_emp = model_Employee(PIN=pin,DeptID = dept[0],position=position[0])
            else:
                t_emp = model_Employee(PIN=pin,DeptID = dept[0])
            super(model_Employee,t_emp).save()
            t_emp = covert_emp(emp_info,t_emp,areas)
            super(model_Employee,t_emp).save()
            if emp_info.Card:#处理卡
                IssueCard(UserID=t_emp,cardno=emp_info.Card,cardstatus = CARD_VALID).save()
            RET_INFO['ret'] = '0'#增加人员成功
            RET_INFO['id'] = t_emp.id
            return json.dumps(RET_INFO)
       
    @ladonize(str,str,str,str,rtype=str)
    def setArea(self,pin,areano_list,changereason,remark):
        """
        修改人员考勤区域
        @param pin: 参数一 人员遍号
        @param areano_list: 参数二 新区域编号列表,例1,2,3
        @param changereason: 参数二 调动原因（选填）
        @param remark: 参数二 备注（选填）
        @rtype: 返回 执行结果信息
             0    成功
            -91    人员编号只支持数字
            -92    人员编号只支持数字或字母
            -93    人员编号不能为0
            -94    人员编号的长度不能大于指定长度
            -97    人员编号不存在
            -102    区域编号不存在
        """
        from mysite.iclock.models.model_device import Device as model_Device,DEVICE_TIME_RECORDER
        RET_INFO={}
        RET_INFO['option'] = 'setArea'
        RET_INFO['ret'] = format_valid(pin,'',check_cardno=False)
        if RET_INFO['ret'] != '-1' :
            return json.dumps(RET_INFO)
        temp_pin = format_pin(pin)
        try:
            temp_emp = model_Employee.objects.get(PIN = temp_pin)
        except:
            RET_INFO['ret'] = '-97'
            return json.dumps(RET_INFO)
        areano_list = areano_list.split(',')
        temp_areas = model_area.objects.filter(areaid__in = areano_list)
        if not temp_areas:
            RET_INFO['ret'] = '-102'
            return json.dumps(RET_INFO)
        empchange = temp_emp.__class__.empchange_set.related.model()
        empchange.changepostion = 4
        empchange.changereason=changereason #加入调整区域加入原因 by ycm 2011-06-10
        empchange.remark=remark
        empchange.newvalue = ",".join(["%s" % i.pk for i in  temp_areas])
        empchange.newids = [i.pk for i in temp_areas]
        empchange.changedate = datetime.datetime.now()
        new_devs = None
        import copy
        old_attarea = copy.deepcopy(temp_emp.attarea.select_related())
        devs = set(list(model_Device.objects.filter(area__in=old_attarea).filter(device_type=DEVICE_TIME_RECORDER)))    #只管理考勤
        empchange.oldvalue = ",".join(["%s" % i.pk for i in old_attarea])
        #print "empchange.oldvalue:%s" % empchange.oldvalue
        empchange.UserID = temp_emp
        empchange.changeno = None
        empchange.save()
        temp_emp.attarea = temp_areas
        temp_emp.save(log_msg=False)
        RET_INFO['id'] = temp_emp.id
        RET_INFO['ret'] = '0'
        return json.dumps(RET_INFO)
       
    @ladonize(str,rtype=[str])
    def GetArea(self,pin):
        """
        获取人员考勤区域
        @param pin: 参数一 人员工号
        @rtype: 返回 人员所在的区域
        """
        return list(get_area(pin))
    
    @ladonize(str,rtype=str)
    def delEmp(self,pin):
        """
        删除人员
        @param pin: 参数一 人员工号
        @rtype: 返回 执行结果信息
             0    成功
            -91    人员编号只支持数字
            -92    人员编号只支持数字或字母
            -93    人员编号不能为0
            -94    人员编号的长度不能大于指定长度
            -97    人员编号不存在
            -116    当前有在使用的消费卡，不可删除
        """
        from mysite import settings
        RET_INFO={}
        RET_INFO['option'] = 'delEmp'
        RET_INFO['ret'] = format_valid(pin,'',check_cardno=False)
        if RET_INFO['ret'] != '-1' :
            return json.dumps(RET_INFO)
        temp_pin = format_pin(pin)
        try:
            temp_emp = model_Employee.objects.get(PIN = temp_pin)
        except:
            RET_INFO['ret'] = '-97'
            return json.dumps(RET_INFO)
        if get_option("POS"):
            if get_option("POS_ID"):
                iscard = IssueCard.objects.filter(UserID=temp_emp)
            else:
                iscard = IssueCard.objects.filter(UserID=temp_emp,sys_card_no__isnull=False)
            if iscard:
                RET_INFO['ret'] = '-116'
                return json.dumps(RET_INFO)
        filepath = settings.ADDITION_FILE_ROOT + "photo/" + temp_emp.PIN + ".jpg"
        if os.path.exists(filepath):
            os.remove(filepath)
        temp_emp.delete_cache_template_count()#删除模板数目缓存
        temp_emp.delete_cache_face_count()#删除面部模板数目缓存
        temp_emp.delete_cache_area()    
        RET_INFO['id'] = temp_emp.id
        super(model_Employee, temp_emp).delete()
        RET_INFO['ret'] = '0'
        return json.dumps(RET_INFO)
    
    @ladonize(str,rtype=str)
    def sprEmp(self,pin):
        """
        重新分发人员
        @param pin: 参数一 人员工号
        @rtype: 返回 执行结果信息
             0    成功
            -91    人员编号只支持数字
            -92    人员编号只支持数字或字母
            -93    人员编号不能为0
            -94    人员编号的长度不能大于指定长度
            -97    人员编号不存在
        """
        from base.sync_api import spread_emp
        RET_INFO={}
        RET_INFO['option'] = 'sprEmp'
        RET_INFO['ret'] = format_valid(pin,'',check_cardno = False)#人员编号验证
        if RET_INFO['ret'] != '-1' :
            return json.dumps(RET_INFO)
        temp_pin = format_pin(pin)
        try:
            temp_emp = model_Employee.objects.get(PIN = temp_pin)
        except:
            RET_INFO['ret'] = '-97'
            return json.dumps(RET_INFO)
        spread_emp(temp_emp)
        RET_INFO['ret'] = '0'
        RET_INFO['id'] = temp_emp.id
        return json.dumps(RET_INFO)
        
    @ladonize(str,rtype=[str])
    def GetPinList(self,key):
        """
        获取人员工号列表
        @param key: 参数一 查询关键字
        @rtype: 返回 人员工号列表
        """
        ret = get_emp_pin_list(key)
        return ret

def identitycard_valid(identitycard):  
    #权重数组
    iW = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2, 1];
    #身份证号码中可能的字符
    values = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'x']
    #使用正则表达式检测
    icre = re.compile('^[1-9][0-9]{16}[x0-9]$', re.IGNORECASE);
    m = icre.match(identitycard);
    if not m:
        #不是合法的身份证号码，直接退出
        return '-113';   
    return '-1'
   
def covert_emp(emp_info,emp,areas):
    """
        将字典转换为人员对象
    """
    if emp_info.AccGroup:
        emp.AccGroup = emp_info.AccGroup
        
    if emp_info.EName:
        emp.EName = u"%s"%emp_info.EName
                        
    if emp_info.Privilege:
        emp.Privilege =emp_info.Privilege
        
    if emp_info.TimeZones:
        emp.TimeZones = emp_info.TimeZones

    if emp_info.Password:
        emp.Password = encryption(emp_info.Password)
        
    if emp_info.area:
        emp.attarea.clear()
        for area in areas:
            emp.attarea.add(area)
    else :#新增默认
        emp.attarea.add(model_area.objects.get(pk=1))
                    
    if emp_info.national:
        emp.national_name = u"%s"%emp_info.national
        
    if emp_info.lastname:
        emp.lastname =u"%s"%emp_info.lastname
        
    if emp_info.Gender:
        emp.Gender =emp_info.Gender
        
    if emp_info.Birthday:
        emp.Birthday =emp_info.Birthday
        
    if emp_info.Address:
        emp.Address =u"%s"%emp_info.Address
        
    if emp_info.PostCode:
        emp.PostCode =emp_info.PostCode
        
    if emp_info.Tele:
        emp.Tele =emp_info.Tele
        
    if emp_info.FPHONE:
        emp.FPHONE =emp_info.FPHONE
        
    if emp_info.Mobile:
        emp.Mobile =emp_info.Mobile
        
    if emp_info.identitycard:
        emp.identitycard =emp_info.identitycard
        
    if emp_info.hiretype:
        emp.hiretype =emp_info.hiretype
        
    if emp_info.email:
        emp.email =emp_info.email
        
    if emp_info.birthplace:
        emp.birthplace =u"%s"%emp_info.birthplace
        
    if emp_info.emptype:
        emp.emptype =emp_info.emptype
        
    if emp_info.selfpassword:
        emp.selfpassword =emp_info.selfpassword
        
    if emp_info.Hiredday:
        emp.Hiredday =emp_info.Hiredday
        
    if emp_info.homeaddress:
        emp.homeaddress =u"%s"%emp_info.homeaddress
    return emp

class FingerPrintService(object):
    u"""
    【指纹操作】包含登记指纹、删除指纹、获取指纹数、重新分发指纹等操作
    """
    @ladonize(str,int,str,bool,rtype=str)
    def setFP(self, pin, fid, data, force=False):
        """
        登记人员指纹
        @param pin: 参数一 人员工号
        @param fid: 参数二 指头编号
        @param data: 参数三 指纹数据
        @param force: 参数四 是否为胁迫指纹
        @rtype: 返回值 执行结果信息
             0    成功
            -91    人员编号只支持数字
            -92    人员编号只支持数字或字母
            -93    人员编号不能为0
            -94    人员编号的长度不能大于指定长度
            -97    人员编号不存在
        """
        from base.sync_api import update_emp_fp
        from mysite.iclock.models.model_bio import Template
        RET_INFO={}
        RET_INFO['option'] = 'setFP'
        RET_INFO['ret'] = format_valid(pin,'',check_cardno = False)#人员编号验证
        if RET_INFO['ret'] != '-1' :
            return json.dumps(RET_INFO)
        temp_pin = format_pin(pin)
        try:
            temp_emp = model_Employee.objects.get(PIN = temp_pin)
        except:
            RET_INFO['ret'] = '-97'
            return json.dumps(RET_INFO)
        update_emp_fp(temp_pin, '10', fid, data,force)
        t = Template.objects.filter(UserID=temp_pin, FingerID__exact=fid, Fpversion="10")
        if not t:
            t = Template()
        else:
            t = t[0]
        t.UserID = temp_pin
        t.Template = data
        t.FingerID = fid
        t.Valid = '1'
        t.Fpversion = "10"
        t.save()
        RET_INFO['ret'] = '0'
        RET_INFO['id'] = temp_emp.id
        return json.dumps(RET_INFO)
        
    @ladonize(str,rtype=str)
    def delFP(self,pin):
        """
        删除人员指纹
        @param pin: 参数一 人员工号
        @rtype: 返回 执行结果信息
             0    成功
            -91    人员编号只支持数字
            -92    人员编号只支持数字或字母
            -93    人员编号不能为0
            -94    人员编号的长度不能大于指定长度
            -97    人员编号不存在
        """
        from base.sync_api import delete_emp_fp
        RET_INFO={}
        RET_INFO['option'] = 'delFP'
        RET_INFO['ret'] = format_valid(pin,'',check_cardno = False)#人员编号验证
        if RET_INFO['ret'] != '-1' :
            return json.dumps(RET_INFO)
        temp_pin = format_pin(pin)
        try:
            temp_emp = model_Employee.objects.get(PIN = temp_pin)
        except:
            RET_INFO['ret'] = '-97'
            return json.dumps(RET_INFO)
        delete_emp_fp(temp_pin)
        RET_INFO['ret'] = '0'
        RET_INFO['id'] = temp_emp.id
        return json.dumps(RET_INFO)
        
    @ladonize(str,rtype=str)
    def SprFP(self,pin):
        """
        重新分发人员指纹
        @param pin: 参数一 人员工号
        @rtype: 返回 执行结果信息
        """
        ret = spread_FingerPrint(pin)
        if ret==0:
            return 'RPC200'
        else:
            return ret
        
    @ladonize(str,rtype=[str])
    def GetFPCount(self,pin):
        """
        获取版本信息
        @param pin: 参数一 人员工号
        @rtype: 返回 人员的指纹有无情况(例: 返回[9,10]表示有9.0和10.0版本的指纹)
        """
        ret = get_FingerPrint_count(pin)
        if ret==0:
            return 'RPC200'
        else:
            return ret
       
class FaceService(object):
    u"""
    【面部模板操作】包含登记人脸、删除人脸、获取人脸数、重新分发人脸等操作
    """
    @ladonize(str,str,int,str,rtype=str)
    def SetFace(self, pin, fver, fid, data):
        """
        登记人脸
        @param pin: 参数一 人员工号
        @param fver: 参数二 人脸版本
        @param fid: 参数三 人脸编号
        @param data: 参数四 人脸模板数据
        @rtype: 返回值 执行结果信息
        """
        ret = set_Face(pin, fver, fid, data)
        if ret==0:
            return 'RPC200'
        else:
            return ret
        
    @ladonize(str,rtype=str)
    def delFace(self,pin):
        """
        删除人脸
        @param pin: 参数一 人员工号
        @rtype: 返回 执行结果信息
             0    成功
            -91    人员编号只支持数字
            -92    人员编号只支持数字或字母
            -93    人员编号不能为0
            -94    人员编号的长度不能大于指定长度
            -97    人员编号不存在
        """
        from base.sync_api import delete_emp_fc
        RET_INFO={}
        RET_INFO['option'] = 'delFace'
        RET_INFO['ret'] = format_valid(pin,'',check_cardno = False)#人员编号验证
        if RET_INFO['ret'] != '-1' :
            return json.dumps(RET_INFO)
        temp_pin = format_pin(pin)
        try:
            temp_emp = model_Employee.objects.get(PIN = temp_pin)
        except:
            RET_INFO['ret'] = '-97'
            return json.dumps(RET_INFO)
        delete_emp_fc(temp_pin)
        RET_INFO['ret'] = '0'
        RET_INFO['id'] = temp_emp.id
        return json.dumps(RET_INFO)
    
    @ladonize(str,rtype=str)
    def sprFace(self,pin):
        """
        重新分发人脸
        @param pin: 参数一 人员工号
        @rtype: 返回 执行结果信息
             0    成功
            -91    人员编号只支持数字
            -92    人员编号只支持数字或字母
            -93    人员编号不能为0
            -94    人员编号的长度不能大于指定长度
            -97    人员编号不存在
        """
        from mysite.personnel.models.emp_extend import send_dev_face
        RET_INFO={}
        RET_INFO['option'] = 'sprFace'
        RET_INFO['ret'] = format_valid(pin,'',check_cardno = False)#人员编号验证
        if RET_INFO['ret'] != '-1' :
            return json.dumps(RET_INFO)
        temp_pin = format_pin(pin)
        try:
            temp_emp = model_Employee.objects.get(PIN = temp_pin)
        except:
            RET_INFO['ret'] = '-97'
            return json.dumps(RET_INFO)
        send_dev_face(temp_emp)
        RET_INFO['ret'] = '0'
        RET_INFO['id'] = temp_emp.id
        return json.dumps(RET_INFO)
    @ladonize(str,rtype=[str])
    def GetFaceCount(self,pin):
        """
        获取人脸模板信息
        @param pin: 参数一 人员工号
        @rtype: 返回 人员的人脸模板有无情况(例: 返回[5,7]表示有5.0和7.0版本的人脸模板)
        """
        ret = get_face_count(pin)
        if ret==0:
            return 'RPC200'
        else:
            return ret
       
class EmployeePicService(object):
    u"""
    【人员照片操作】包含更新人员照片、删除照片、重新分发照片等操作
    """
    @ladonize(str,str,str,rtype=str)
    def setPic(self, pin, data,format):
        """
        更新人员照片
        @param pin: 参数一 人员工号
        @param data: 参数二 用户照片数据
        @rtype: 返回值 执行结果信息
             0    成功
            -91    人员编号只支持数字
            -92    人员编号只支持数字或字母
            -93    人员编号不能为0
            -94    人员编号的长度不能大于指定长度
            -97    人员编号不存在
            -121    图片格式不正确(只支持'jpg','gif','png','bmp')
            -122    人员照片大小不能超过16Kb
            -123    图片内容为空
        """
        from base.sync_api import update_emp_pic
        RET_INFO={}
        RET_INFO['option'] = 'setPic'
        RET_INFO['ret'] = format_valid(pin,'',check_cardno = False)#人员编号验证
        if RET_INFO['ret'] != '-1' :
            return json.dumps(RET_INFO)
        if format not in ['jpg','gif','png','bmp']:
            RET_INFO['ret'] = '-121'
            return json.dumps(RET_INFO)
        if len(data)>16*1024:
            RET_INFO['ret'] = '-122'
            return json.dumps(RET_INFO)
        if not data:
            RET_INFO['ret'] = '-123'
            return json.dumps(RET_INFO)
        temp_pin = format_pin(pin)
        try:
            temp_emp = model_Employee.objects.get(PIN = temp_pin)
        except:
            RET_INFO['ret'] = '-97'
            return json.dumps(RET_INFO)
        update_emp_pic(temp_pin, data)
        RET_INFO['ret'] = '0'
        RET_INFO['id'] = temp_emp.id
        return json.dumps(RET_INFO)
        
    @ladonize(str,rtype=str)
    def delPic(self,pin):
        """
        删除人员照片
        @param pin: 参数一 人员工号
        @rtype: 返回 执行结果信息
             0    成功
            -91    人员编号只支持数字
            -92    人员编号只支持数字或字母
            -93    人员编号不能为0
            -94    人员编号的长度不能大于指定长度
            -97    人员编号不存在
        """
        from mysite.personnel.models.emp_extend import delete_dev_user_photo
        RET_INFO={}
        RET_INFO['option'] = 'delPic'
        RET_INFO['ret'] = format_valid(pin,'',check_cardno = False)#人员编号验证
        if RET_INFO['ret'] != '-1' :
            return json.dumps(RET_INFO)
        temp_pin = format_pin(pin)
        try:
            temp_emp = model_Employee.objects.get(PIN = temp_pin)
        except:
            RET_INFO['ret'] = '-97'
            return json.dumps(RET_INFO)
        delete_dev_user_photo(temp_emp)
        RET_INFO['ret'] = '0'
        RET_INFO['id'] = temp_emp.id
        return json.dumps(RET_INFO)
       
        
    @ladonize(str,rtype=str)
    def sprPic(self,pin):
        """
        重新分发人员照片
        @param pin: 参数一 人员工号
        @rtype: 返回 执行结果信息
             0    成功
            -91    人员编号只支持数字
            -92    人员编号只支持数字或字母
            -93    人员编号不能为0
            -94    人员编号的长度不能大于指定长度
            -97    人员编号不存在
            -124    该人员未上传照片
        """
        from mysite.personnel.models.emp_extend import sendphoto_deive
        RET_INFO={}
        RET_INFO['option'] = 'sprPic'
        RET_INFO['ret'] = format_valid(pin,'',check_cardno = False)#人员编号验证
        if RET_INFO['ret'] != '-1' :
            return json.dumps(RET_INFO)
        temp_pin = format_pin(pin)
        try:
            temp_emp = model_Employee.objects.get(PIN = temp_pin)
        except:
            RET_INFO['ret'] = '-97'
            return json.dumps(RET_INFO)
        msg = sendphoto_deive(temp_emp)
        if msg:
            RET_INFO['ret'] = '-124'
            return json.dumps(RET_INFO)
        else:
            RET_INFO['ret'] = '0'
            RET_INFO['id'] = temp_emp.id
            return json.dumps(RET_INFO)
       
class DeviceService(object):
    u"""
    【设备操作】包含更新或注册设备信息、删除设备、重新分发人员、重新收集人员、重新收集考勤记录、获取在线状态、获取任务数、清除考勤照片、清除考勤记录、清除数据、重新获取信息、重启等操作
    """
    @ladonize(str,Device,rtype=str)
    def SetDevice(self,sn,dev_info):
        """
        更新或注册设备信息
        @param sn: 参数一 设备序列号
        @param dev_info: 参数二 设备基本信息
        @rtype: 返回 执行结果信息
        """
        arg = {}
        for key in dir(dev_info):
            if not key.startswith('__'):
                val = getattr(dev_info,key)
                if key in ('area', 'alias', 'push_status', 'update_db', 'trans_times', 'trans_interval', 'tz_adj') and val!=None:
                    arg[key] = val
        ret = set_device(sn,arg)
        if ret==0:
            return 'RPC200'
        else:
            return ret
    
    @ladonize(str,rtype=str)
    def delDevice(self,sn):
        """
        删除设备
        @param sn: 参数一 设备序列号
        @rtype: 返回 执行结果信息
            0    成功
            -171    查无此设备序列号
        """
        RET_INFO={}
        RET_INFO['option'] = 'delDevice'
        from mysite.iclock.models.model_device import Device
        try:
            dev = Device.objects.get(sn=sn)
        except:
            RET_INFO['ret'] = '-171'
            return json.dumps(RET_INFO)
        RET_INFO['id'] = dev.id
        dev.delete()
        RET_INFO['ret'] = '0'
        return json.dumps(RET_INFO)
        
    @ladonize(str,rtype=str)
    def SprDevice(self,sn):
        """
        重新分发设备
        @param sn: 参数一 设备序列号
        @rtype: 返回 执行结果信息
        """
        ret = spread_device_employee(sn)
        if ret==0:
            return 'RPC200'
        else:
            return ret

    @ladonize(str,rtype=str)
    def CollectEmp(self,sn):
        """
        重新收集人员(基本信息、指纹、面部、人员照片)
        @param sn: 参数一 设备序列号
        @rtype: 返回 执行结果信息
        """
        ret = collect_device_employee(sn)
        if ret==0:
            return 'RPC200'
        else:
            return ret
        
    @ladonize(str,rtype=str)
    def CollectAtt(self,sn):
        """
        重新收集考勤记录
        @param sn: 参数一 设备序列号
        @rtype: 返回 执行结果信息
        """
        ret = collect_device_att(sn)
        if ret==0:
            return 'RPC200'
        else:
            return ret
        
    @ladonize(str,rtype=str)
    def CollectData(self,sn):
        """
        重新收集数据(人员基本信息、指纹、面部、照片, 考勤记录, 考勤照片)
        @param sn: 参数一 设备序列号
        @rtype: 返回 执行结果信息
        """
        ret = collect_device_data(sn)
        if ret==0:
            return 'RPC200'
        else:
            return ret
        
    @ladonize(str,rtype=bool)
    def GetStatus(self,sn):
        """
        获取设备在线状态(在线True 离线 False)
        @param sn: 参数一 设备序列号
        @rtype: 返回 在线状态(True or False)
        """
        ret = get_device_status(sn)
        return ret
        
    @ladonize(str,rtype=int)
    def GetCmdCount(self,sn):
        """
        获取设备任务数
        @param sn: 参数一 设备序列号
        @rtype: 返回 设备任务命令数
        """
        ret = get_count_cmd(sn)
        return ret
    
    @ladonize(str,rtype=str)
    def CleanAttPic(self,sn):
        """
        清除考勤照片
        @param sn: 参数一 设备序列号
        @rtype: 返回 执行结果信息
        """
        ret = clean_attpic(sn)
        if ret==0:
            return 'RPC200'
        else:
            return ret
        
    @ladonize(str,rtype=str)
    def CleanAtt(self,sn):
        """
        清除考勤记录
        @param sn: 参数一 设备序列号
        @rtype: 返回 执行结果信息
        """
        ret = clean_att(sn)
        if ret==0:
            return 'RPC200'
        else:
            return ret
        
    @ladonize(str,rtype=str)
    def CleanData(self,sn):
        """
        清除所有数据
        @param sn: 参数一 设备序列号
        @rtype: 返回 执行结果信息
        """
        ret = clean_data(sn)
        if ret==0:
            return 'RPC200'
        else:
            return ret
        
    @ladonize(str,rtype=str)
    def Reboot(self,sn):
        """
        重启设备
        @param sn: 参数一 设备序列号
        @rtype: 返回 执行结果信息
        """
        ret = reboot_device(sn)
        if ret==0:
            return 'RPC200'
        else:
            return ret
        
    @ladonize(str,rtype=str)
    def GetInfo(self,sn):
        """
        获取设备信息
        @param sn: 参数一 设备序列号
        @rtype: 返回 执行结果信息
        """
        ret = get_info(sn)
        if ret==0:
            return 'RPC200'
        else:
            return ret
        
    @ladonize(str,rtype=[str])
    def GetSnList(self,key):
        """
        获取设备序列号列表
        @param key: 参数一 查询关键字
        @rtype: 返回 设备序列号列表
        """
        ret = get_device_sn_list(key)
        return ret
    
    @ladonize(str,rtype=str)
    def GetTopN(self,key):
        """
        获取考勤批次数据
        @param key: 参数一 批次ID
        @rtype: 返回 考勤数据
        """
        from mole.mole import json_dumps
        ret = get_att_record_topN()
        return key+":"+ json_dumps(ret)
    
