python/Django对接dingtalk-sdk企业内部开发对接钉钉过程手记

前提

需要拥有管理员账号或获得开发者权限


准备

钉钉方面

1. 创建钉钉应用

钉钉开放平台——应用开发——钉钉应用——创建应用

2. 记录应用凭证

记录应用的AgentId、AppKey、AppSecret

3. 打开应用权限

打开需要获取数据的接口权限


开发环境方面

1.安装依赖库

dingtalk-sdk 消息加解密同时兼容 cryptography 和 PyCrypto, 优先使用 cryptography 库。 需先自行安装 cryptography 或者 PyCrypto 库:

# 安装 cryptography
pip install cryptography>=0.8.2# 或者安装 PyCrypto
pip install pycrypto>=2.6.1

2.安装 dingtalk-sdk

pip install dingtalk-sdk# with cryptography
pip install dingtalk-sdk[cryptography]# with pycrypto
pip install dingtalk-sdk[pycrypto]

升级 dingtalk-sdk 到新版本

pip install -U dingtalk-sdk

ding_talk-sdk 使用文档https://dingtalk-sdk.readthedocs.io/zh_CN/latest/index.html


基础接口

1. 获得access_token

dingtalk-sdk方法

from dingtalk import SecretClient, AppKeyClientclient = SecretClient('corp_id', 'secret')  # 旧 access_token 获取方式
client = AppKeyClient('corp_id', 'app_key', 'app_secret')  # 新 access_token 获取方式

自建接口方法

# 获得access_token
def access_token():response = requests.get("https://oapi.dingtalk.com/gettoken?appkey=%s&appsecret=%s" % (AppKey, AppSecret))if response.status_code == 200:str_res = response.texttoken = (json.loads(str_res)).get('access_token')return token

2. 获得部门列表

dingtalk-sdk方法

departments = client.department.list()

自建接口方法

# 获得部门列表
def get_department_list(dept_id=1):"""查询部门列表:param dept_id: 部门id,默认为1(根部门),可输入任意部门id"""post_url = "https://oapi.dingtalk.com/topapi/v2/department/listsub?access_token=%s" % (access_token())data = {"dept_id": dept_id,}response = requests.post(post_url, data)str_res = response.textresult = (json.loads(str_res)).get('result')return result

注意,无论是 dingtalk-sdk 方法还是自建接口方法,都只能获取一层部门的列表,比如总公司下面有市场部和技术部,市场部下面有研究部和发展部,技术部下面有研究部和开发部,当我们调用接口的时候,只能获取到市场部和技术部,无法获取下面的子部门。想全部获取则需要做循环。

 3. 获得部门员工

dingtalk-sdk方法

from dingtalk.client.api import Userobject = User(client=client) # 传入上文的token,实例化对象
data = object.listbypage(department_id, offset=0, size=100, order='custom', lang='zh_CN')

自建接口方法

我懒得分别调用每个部门,直接找了个获取全部在职员工的接口,写成了生成器,在外面直接遍历获取就行

# 获得在职员工列表
def get_user_list():post_url = "https://oapi.dingtalk.com/topapi/smartwork/hrm/employee/queryonjob?access_token=%s" % (access_token())# 初始化offsetoffset = 0while True:# 请求参数data = {"status_list": "2,3,5,-1","offset": offset,"size": 50}# 发送post请求response = requests.post(post_url, data)str_res = response.text# json解析result = (json.loads(str_res)).get('result')# 返回当前页列表yield result["data_list"]try:# 下一页(下50条)offset = result["next_cursor"]continue# 退出条件except KeyError:break

4. 获得用户详情 

dingtalk-sdk方法

from dingtalk.client.api import Userobject = User(client=client) # 传入上文的token,实例化对象
data = object.get(userid, lang='zh_CN')

自建接口方法

# 获得员工详情(user_id)
def get_user_info(user_id):""":param user_id::return :"""post_url = "https://oapi.dingtalk.com/topapi/v2/user/get?access_token=%s" % (access_token())data = {"userid": user_id,}response = requests.post(post_url, data)str_res = response.textresult = (json.loads(str_res)).get('result')return result["name"], result["mobile"], result["userid"]

考勤统计接口

SDK方法已经没有啦~开始手撸~~~

1. 获取考勤报表列名称

我这里是把我需要的列的名称和id返回了,各位各取所需哈

def get_attcolumns():post_url = "https://oapi.dingtalk.com/topapi/attendance/getattcolumns?access_token=%s" % (access_token())response = requests.post(post_url)str_res = response.textresult = (json.loads(str_res)).get('result')name_list = ["应出勤天数", "出勤天数", "休息天数", "迟到次数", "迟到时长", "早退次数", "早退时长", "上班缺卡次数", "下班缺卡次数", "补卡次数", "旷工天数","加班-审批单统计", "加班总时长", "休息日加班", "工作日加班", "节假日加班"]response_data = {}for i in result["columns"]:try:print(i["name"] + ":" + str(i["id"]))except:print(i["name"] + ":NONE")if i["name"] in name_list:response_data[i["name"]] = i["id"]print(response_data)return response_data

2. 获取考勤报表列值

各取所需各取所需

def get_columnval(userid: str, name: str, column_id: str, from_date: str, to_date: str):"""from_date和to_date格式为:'2022-01-01 00:00:00'这样式的column_id为列名称id"""post_url = "https://oapi.dingtalk.com/topapi/attendance/getcolumnval?access_token=%s" % (access_token())data = {"userid": userid,"column_id_list": column_id,"from_date": from_date,"to_date": to_date}response = requests.post(post_url, data)str_res = response.textnum = 0try:result = (json.loads(str_res)).get('result').get("column_vals")for value in result[0]["column_vals"]:num += int(float(value["value"]))except:passreturn {name: num}

3. 获取员工考勤详情

这个接口有个问题,它两个时间的间隔不能超过七天..我就顺手也给时间搞定了。

还有个小建议,当你在外面调用接口的时候,肯定会有同时获取好多人考勤详情的情况,可以在调用的时候使用多线程,然后一次只传一个人的userid,效率会很高,不会搞线程的可以找我哈

# 查询员工考勤情况
def attendance_information(workDateFrom, workDateTo, userIdList):"""查询员工考勤情况:param workDateFrom: 查询开始时间 格式:"2022-03-10 00:00:00":param workDateTo: 查询结束时间 格式:"2022-03-10 00:00:00":param userIdList: 员工id列表:return: 员工考勤情况 type:dict"""num1 = int(time.mktime(time.strptime(workDateFrom, "%Y-%m-%d %H:%M:%S")))num2 = int(time.mktime(time.strptime(workDateTo, "%Y-%m-%d %H:%M:%S")))if num2 - num1 >= 604800:# 604800为七天的秒数response_data = []while True:if num1 >= num2:breakif num2 - num1 < 604800:end_num = num2else:end_num = num1 + 604799startTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(num1))endTime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(end_num))data = attendance_info(startTime, endTime, userIdList)response_data += datanum1 = end_num + 1else:response_data = attendance_info(workDateFrom, workDateTo, userIdList)return response_data# 获取员工打卡结果
def attendance_info(workDateFrom, workDateTo, userIdList):post_url = "https://oapi.dingtalk.com/attendance/list?access_token=%s" % (access_token())data = {"workDateFrom": workDateFrom,"workDateTo": workDateTo,"userIdList": userIdList,"offset": 0,"limit": 50}response = requests.post(post_url, json.dumps(data))str_res = response.textrecordresult = (json.loads(str_res)).get('recordresult')return recordresult

4. 审批接口(请假、加班等)

总共分为两个步骤:

1. 获取审批实例ID列表

2. 获取审批实例详情

在调用第一个接口的时候,需要传入一个process_code参数,这个参数要在钉钉管理后台的审批模板编辑页面的URL中获取,这需要拿到OA审批的权限:

 比如这个请假,点击最右侧的编辑,进入页面后,process_code就在上面这个位置,记录下来

有了这个code,就可以写接口调用了,这边我封装了一个类:

"""
请假processCode=PROC-EF6YNNYRN2-CRQI0Q3ZSC7L2TDQEKQO1-25SLJQZI-ST
加班processCode=PROC-EF6YNNYRN2-CRQI0Q3ZSC7L2TDQEKQO1-XZRLJQZI-GT
补卡processCode=PROC-EF6YNNYRN2-CRQI0Q3ZSC7L2TDQEKQO1-V2SLJQZI-NT
"""# 获取审批信息
class ProcessInstance:def __init__(self, process_code: str, start_time: int, end_time: int, userid: str):self.process_code = process_codeself.start_time = start_timeself.end_time = end_timeself.userid = userid# 获取审批实例id列表def processinstance_list(self):post_url = "https://oapi.dingtalk.com/topapi/processinstance/listids?access_token=%s" % (access_token())data = {"process_code": self.process_code,"start_time": self.start_time - 2678400000,"end_time": self.end_time + 2678400000,"userid_list": self.userid,"size": 20,"cursor": 0,}response = requests.post(post_url, data)str_res = response.textresult = (json.loads(str_res)).get('result').get("list")return result# 获取审批实例详情def getprocessinstance_details(self):lists = self.processinstance_list()response_list = []for i in lists:post_url = "https://oapi.dingtalk.com/topapi/processinstance/get?access_token=%s" % (access_token())data = {"process_instance_id": i,}response = requests.post(post_url, data)str_res = response.textresult = (json.loads(str_res)).get('process_instance')status = self.status_CN(result.get("status"))form_component_values = result.get("form_component_values")types = [x.get('value') for x in form_component_values if x.get("component_type") == "DDSelectField"][0]s_times = [(json.loads(x.get('value')))for x in form_component_values if x.get("component_type") == "DDDateRangeField"][0][0]if self.start_time <= self.date_to_UNIX(s_times) <= self.end_time:e_times = [(json.loads(x.get('value')))for x in form_component_values if x.get("component_type") == "DDDateRangeField"][0][1]days = [(json.loads(x.get('value')))for x in form_component_values if x.get("component_type") == "DDDateRangeField"][0][2]text = [x.get('value') for x in form_component_values if x.get("component_type") == "TextareaField"][0]response_list.append({"status": status, "types": types, "s_times": s_times, "e_times": e_times, "days": days,"text": text})print(response_list)return response_list# 获取天数def getprocessinstance_days(self):lists = self.processinstance_list()days = 0for i in lists:post_url = "https://oapi.dingtalk.com/topapi/processinstance/get?access_token=%s" % (access_token())data = {"process_instance_id": i,}response = requests.post(post_url, data)str_res = response.texttry:form_component_values = (json.loads(str_res)).get('process_instance').get("form_component_values")num = self.date_to_UNIX([(json.loads(x.get('value')))for x in form_component_values ifx.get("component_type") == "DDDateRangeField"][0][0])if self.start_time <= num <= self.end_time:days += float([(json.loads(x.get('value')))for x in form_component_values if x.get("component_type") == "DDDateRangeField"][0][2])except AttributeError:passreturn days@staticmethoddef date_to_UNIX(date: str):return int(time.mktime(time.strptime(date, "%Y-%m-%d"))) * 1000@staticmethoddef status_CN(status: str):if status == "NEW":return "新创建"elif status == "RUNNING":return "审批中"elif status == "COMPLETED":return "已完成"elif status == "CANCELED":return "已取消"

因为审批单发起的时间可能与审批单实际的时间不符,比如我明天要请假,我今天发起了请假审批,那我们传入明天的时间就会导致查不到这条审批,于是我就把传入的时间扩大了31天,等查到这个人在这个时间段内发起的审批单后,再根据审批单实际的时间把不符合查询时间筛选出去,这样就能最大程度的保证不遗漏。但是这样也有一个缺点,就是代码处理的时间变长了。


目前我用到的接口就是这些,然后就把数据处理成自己想要的样子,再放到前端页面上显示就可以啦。如果以后用到别的借口,还会继续在这个文章更新。可以简单看一下目前实现的效果

 


Everything is going smoothly.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/37328.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

钉钉发送消息 java

1、完成钉钉认证才能使用此功能 2、需要登录控制台进行创建应用操作 https://open-dev.dingtalk.com/fe/app 3、需要设置 权限范围及通讯录权限设置 参考 https://www.ngui.cc/el/778161.html?actiononClick pom <dependency><groupId>com.aliyun</groupId&g…

PHP 通过钉钉API向员工推送消息(以工作通知的形式)

通过钉钉 API 向员工推送消息分为多种形式, 今天只以工作通知的形式讲述。 第一步: 进入 钉钉开放平台 注册账号按照流程操作即可 进入开发者后台后需要进行创建应用(之所以创建应用, 是因为以应用为一个 demo) 第二步:创建应用(今天以创建小程序为例) 第三步: 获取企业内部…

LzDingTalk-免费的钉钉机器人框架

LzDingTalk-是一款免费的钉钉机器人框架 1.异常处理规则 2.稳定不易掉线 3.哈希多线程处理 再多消息也能轻松应对 4.框架完全免费&#xff0c;用爱发电&#xff01; 5.多样式API支持二次开发插件&#xff01; 蓝奏下载地址&#xff1a;DingTalk 密码&#xff1a;6jbd界面展示&a…

禅道接入钉钉工作通知与钉钉群机器人二次开发代码详解

目录 禅道接入钉钉工作通知与钉钉群机器人 一、钉钉工作通知使用步骤 1.进入钉钉管理后台工作台添加自建应用进入开发者平台 2.禅道中得操作 3.接收到消息 二、钉钉群机器人使用步骤 1.钉钉群进行设置群机器人 2.禅道设置 三、禅道二次开发添加新功能进行工作通知和群机…

推送Markdown格式信息到钉钉机器人

1.自定义机器人设置 根据钉钉官方开放文档进行自定义机器人的配置&#xff0c;文档地址为&#xff1a;自定义机器人接入 - 钉钉开放平台 (dingtalk.com) 2.Markdown推送形式 Markdown类型 参数说明 3.Markdown图片格式 Markdown中可以使用url连接的图片进行推送&#xff0c…

Java项目如何接入钉钉群机器人

创建群机器人&#xff1a;对于任意我们所在的群&#xff0c;我们都可以创建自己的机器人&#xff0c;不需要群主权限&#xff0c;每个机器人信息只能自己看到。 我们项目通过对应的链接调用机器人发送消息。 创建对应的鉴权方式&#xff0c; 关键字只要消息内容携带即可&…

雷军入局ChatGPT大战/ AutoGPT星标超PyTorch/ 马斯克星舰今晚发射…今日更多新鲜事在此...

h日报君 发自 凹非寺量子位 | 公众号 QbitAI 大家好&#xff0c;今天是4月17日星期一&#xff0c;新的一周要元气满满哦~ 今天科技圈有哪些新鲜事儿&#xff0c;和日报君一起来看看~ 马斯克星舰今晚发射&#xff1a;将进行直播&#xff0c;此前曾延期 SpaceX官网发布通告称&…

[论文阅读] Collaborative and Adversarial Learning of Focused and Dispersive Representation

[论文地址] [代码] [ICCV 21] Abstract 从结肠镜图像中自动分割息肉是计算机辅助诊断结直肠癌的一个重要步骤。近年来报道的大多数息肉分割方法都是基于完全监督的深度学习。然而&#xff0c;医生在诊断过程中对息肉图像的注释是非常耗时和昂贵的。在本文中&#xff0c;我们提…

2000元训练比肩ChatGPT的开源大模型!GPT-4亲自盖章认证,模型权重均可下载

鱼羊 编辑整理量子位 | 公众号 QbitAI 2000块&#xff0c;调教出一个达到ChatGPT九成功力的开源大模型。 还是被GPT-4亲自盖章认证实力的那种。 这事儿&#xff0c;一群主要来自加州大学伯克利分校的研究人员做到了。 如图中所见&#xff0c;这个模型名叫Vicuna &#xff08;小…

chatgpt赋能python:Python处理雷达基数据:从入门到实践

Python处理雷达基数据&#xff1a;从入门到实践 随着气象技术的不断发展&#xff0c;雷达探测技术已成为当今天气预报和气象研究的主要手段之一。雷达基数据是气象雷达接收到的未经加工的原始数据&#xff0c;因其包含大量天气信息&#xff0c;不仅在天气预报、天气预警等方面…

推演语言模型的大小与计算开销

2020年&#xff0c;OpenAI提出了在增加模型尺寸与提高模型性能之间的扩展定律&#xff0c;指出人们应该将大部分预算用于扩大模型规模。这篇论文直接推动了增大模型规模的浪潮。然而&#xff0c;在预算和内存有限的情况下&#xff0c;盲目扩大模型规模并不是提升模型性能的最佳…

codesblocks头文件的正确使用

之前对头文件如何引用一直百思不得其解&#xff0c;现在弄懂了&#xff0c;来复盘一下。关键点在于要建立工程文件。 下面以一个长度转换的程序来简单说明。 第一步&#xff0c;建立C语言项目。 在新建项目点击Console applicaton&#xff0c;接着打上名称&#xff0c;默认设置…

jdbc工具类的定义和使用

DBUtils的定义 导入3个jar包 代码实现 public class DBUtils {//1.配置数据库连接信息&#xff08;MySQL&#xff09;//数据库驱动private static final String DRIVER "com.mysql.jdbc.Driver";//数据库名private static final String DATABASE "test_db&q…

Servlet的介绍与使用

Servlet简介 servlet是运行在服务器上的应用程序&#xff0c; 它的作用是实现前端与后台的数据交互。 Servlet生命周期 三个方法 init()&#xff1a;初始化 service()&#xff1a;处理客户端请求 destroy()&#xff1a;终止 工作原理 客户端向服务器发送一个http请求服务器…

python破解md5_python怎么使用md5加密解密

python采用hashlib这个标准库实现MD5加密解密。方法是:1、updata传数据;2、利用hexdigest进行16进制转换; update(arg)传入arg对象来更新hash的对象。必须注意的是,该方法只接受byte类型,否则会报错。这就是要在参数前添加b来转换类型的原因。 同时要注意,重复调用update…

分布式任务调度平台XXL-JOB的简单使用

推荐使用xxl2.2.0版本 参考地址: 分布式任务调度平台XXL-JOB xxl-job安装到本地打开项目工程对yml配置文件进行修改 主要修改数据库地址和告警邮件地址 将服务注册到xxl-job -如果在xxl里配置了accessToken 服务里就需要使用同样的Token 注册到xxl-job-admin之后打开xxl可视…

selenium获取页面数据入数据库

Selenium是一个用于Web应用程序测试的工具&#xff0c;但是也可以爬取页面中的数据。 开发环境是内网&#xff08;局域网&#xff09;&#xff0c;项目工程是web项目&#xff0c;jdk使用的1.8&#xff0c;tomcat使用的 8。 web项目&#xff1a; 启动时使用tomcat&#xff0c;…

ChatGPT 教我用 200 行代码写一个简版 Vue 框架 - OpenTiny

AI 是未来最好的老师 最近&#xff0c;我正在准备一份关于 Vue 基础的学习材料。期间我突发奇想&#xff1a;能否利用现在热门的 ChatGPT 帮我创建学习内容&#xff1f;其实 Vue 本身不难学&#xff0c;特别是基础用法&#xff0c;但是&#xff0c;如果你想深入掌握 Vue&#…

阿里云AliGenie开发天猫语音功能-入门篇

文章目录结构如下 登录应用开发平台 创建语音技能 云开发部署后端技能服务 语音技能测试 下线不必要的应用 一、登录应用开发平台 1.登录云开发平台。打开网址 https://workbench.aliyun.com/&#xff0c;使用阿里云账号登录&#xff0c;按照提示创建团队&#xff0c;点…

ESP8266对接天猫精灵-多路继电器控制

上面是我的微信和QQ群&#xff0c;欢迎新朋友的加入。 资源和烧录我就不管了&#xff0c;和https://blog.csdn.net/Jun626/article/details/109150006一模一样 把那个kaiguan的lua改一下代码 DEVICEID "19539" APIKEY "17aaa8a16" INPUTID "…