import pandas as pd import pandas as pd import numpy as np import requests import json import time import re from datetime import datetime from dateutil.relativedelta import relativedelta from pathlib import Path from urllib.parse import quote from io import BytesIO ROOT = Path('.').absolute() # 当前工作目录 def generateToken() -> str: """ 生成 token """ token_api = 'https://api.dingtalk.com/v1.0/oauth2/accessToken' # 该信息在钉钉开放应用中 data = { "appKey": "ding5kqocon5s9oph5uq", "appSecret": 'HL1jgsIIfLAC0eTH0A1m4mwxUDqbgsiPeCCGGE3ocM6qJBTIW7Ivt9drxF_Z4Kb_' } res = requests.post(token_api, json=data) token = res.json()['accessToken'] return token def read_processes_instances(token, formUuid, createFromTimeGMT, createToTimeGMT, page, n): """ 函数功能:读取流程表单的所有数据 """ api = f'https://api.dingtalk.com/v1.0/yida/processes/instances?pageNumber={page}&pageSize={n}' headers = { "Content-Type": "application/json", "x-acs-dingtalk-access-token": token } formData = { "appType": "APP_TNVBVZ3K8G56HG03Z45Q", "systemToken": "CH7669818R0WN18TYTYJ42PE6GY22WZN0BYWKD1", "userId": "yida_pub_account", # 超级管理员账号 "language": "zh_CN", "formUuid": formUuid, "createFromTimeGMT": createFromTimeGMT, "createToTimeGMT": createToTimeGMT, # "searchFieldJson": json.dumps(searchField), # 如果增加上这一项会要求升级宜搭存储 "instanceStatus": "RUNNING" } res = requests.post(api, headers=headers, json=formData) return res.json() def read_instances(token, formUuid, page, n): """ 函数功能:读取流程表单的所有数据 """ api = f'https://api.dingtalk.com//v1.0/yida/forms/instances/search?pageNumber={page}&pageSize={n}' headers = { "Content-Type": "application/json", "x-acs-dingtalk-access-token": token } formData = { "appType": "APP_TNVBVZ3K8G56HG03Z45Q", "systemToken": "CH7669818R0WN18TYTYJ42PE6GY22WZN0BYWKD1", "userId": "yida_pub_account", # 超级管理员账号 "language": "zh_CN", "formUuid": formUuid, # "searchFieldJson": json.dumps(searchField), # 如果增加上这一项会要求升级宜搭存储 "instanceStatus": "RUNNING" } res = requests.post(api, headers=headers, json=formData) return res.json() def timeStamp(timeNum): """ 函数功能:将时间戳(毫秒) 转化为时间日期格式""" timeStamp = float(timeNum/1000) timeArray = time.localtime(timeStamp) otherStyleTime = time.strftime("%Y-%m-%d %H:%M:%S", timeArray) return otherStyleTime def get_time_range_minute(n): """ 获取近n分钟的时间戳(单位是毫秒)""" def delay_time(time_str, years=0, months=0, days=0, hours=0, minutes=0, seconds=0): if type(time_str) == str: time_str = datetime.strptime(time_str, '%Y-%m-%d %H:%M:%S') ret = time_str + relativedelta(years=years, months=months, days=days, hours=hours, minutes=minutes, seconds=seconds) return ret # 获得当前时间 now_time = datetime.now() endTime = int(time.mktime(time.strptime(now_time.strftime('%Y/%m/%d %H:%M:%S'), '%Y/%m/%d %H:%M:%S'))) * 1000 - 1000 # n小时前的时间 ret2 = delay_time(now_time, minutes=-n) startTime = int(time.mktime(time.strptime(ret2.strftime('%Y/%m/%d %H:%M:%S'), '%Y/%m/%d %H:%M:%S'))) * 1000 # print(f'时间区间:[{startTime}-{endTime}]') return startTime, endTime def get_approval_records(token: str, processInstanceId: str): """ 函数功能:获取流程表单的审批记录 --F6客户服务 应用 """ appType = "APP_TNVBVZ3K8G56HG03Z45Q" systemToken = "CH7669818R0WN18TYTYJ42PE6GY22WZN0BYWKD1" userId = "yida_pub_account" api = f'https://api.dingtalk.com/v1.0/yida/processes/operationRecords?appType={appType}&systemToken={systemToken}&userId={userId}&language=zh_CN&processInstanceId={processInstanceId}' headers = { "Content-Type": "application/json", "x-acs-dingtalk-access-token": token } res = requests.get(api, headers=headers) print('获取流程表单的审批记录') return res.json() def forms_isDone(TOKEN: str, FORMID: str, CREATE_FROM, CREATE_TO,PAGES,processInstanceId,isDone_id): ''' 返回isDone_id 对应的控件内容 ''' for i in range(1, PAGES+1): form_data = read_processes_instances(token=TOKEN, formUuid=FORMID, page=i, n=100) for data in form_data.get('data'): processInstanceId_1 = data.get('processInstanceId') if processInstanceId_1 == processInstanceId: isDone = data.get('data').get(isDone_id) return isDone def aggree_approval(token: str, taskId: str, processInstanceId: str, formData: dict): """ 函数功能:同意审批节点 --F6客户服务 应用 """ api = f'https://api.dingtalk.com/v1.0/yida/tasks/execute' headers = { "Content-Type": "application/json", "x-acs-dingtalk-access-token": token } payload = { "outResult": "AGREE", "appType": "APP_TNVBVZ3K8G56HG03Z45Q", "systemToken": "CH7669818R0WN18TYTYJ42PE6GY22WZN0BYWKD1", "remark": "同意(接口自动)", "formDataJson": json.dumps(formData, cls=NpEncoder), "processInstanceId": processInstanceId, # "userId": "yida_pub_account", "userId": "2268275546837446", "language": "zh_CN", "taskId": int(taskId) } res = requests.post(api, headers=headers, json=payload) print('同意审批节点') return res def switch(token: str, processInstanceId: str, formData: dict): """ 函数说明: 开关 程序调用时避免 重复进行(执行间隔 小于 单次执行时间时 发送 重复处理) """ api = f'https://api.dingtalk.com//v1.0/yida/forms/instances' headers = { "Content-Type": "application/json", "x-acs-dingtalk-access-token": token } payload = { "appType" : "APP_TNVBVZ3K8G56HG03Z45Q", "systemToken" : "CH7669818R0WN18TYTYJ42PE6GY22WZN0BYWKD1", "userId" : "yida_pub_account", # 管理员 "language" : "zh_CN", "useLatestVersion" : "false", "formInstanceId" : processInstanceId, "updateFormDataJson" : json.dumps(formData, cls=NpEncoder), } res = requests.put(api, headers=headers, json=payload) print('开关 程序调用时避免 重复进行(执行间隔 小于 单次执行时间时 发送 重复处理)') def update_form_staff(TOKEN: str,processInstanceId,staff_id,ModifiedField_value): """ 函数功能:员工更新表单内容 """ api = f'https://api.dingtalk.com//v1.0/yida/forms/instances' headers = { "Content-Type": "application/json", "x-acs-dingtalk-access-token": TOKEN } data_new = { ModifiedField_value:[staff_id] } payload = { "appType" : "APP_TNVBVZ3K8G56HG03Z45Q", "systemToken" : "CH7669818R0WN18TYTYJ42PE6GY22WZN0BYWKD1", "userId" : "yida_pub_account", # 曹伟 id "language" : "zh_CN", "useLatestVersion" : "false", "formInstanceId" : processInstanceId, "updateFormDataJson" : json.dumps(data_new, cls=NpEncoder), } res = requests.put(api, headers=headers, json=payload) print('员工更新表单内容') return res def get_staffID(TOKEN: str,staff_name): """ 函数功能:通过员工名称获取员工id""" # 读取员工对应关系:宜搭员工-ID对应表 TOKEN = generateToken() FORMID = "FORM-EA866E715PF9YA7ECCAGSABX91Q72PVA3WRFL6" # 宜搭员工-ID对应表 FORM-EA866E715PF9YA7ECCAGSABX91Q72PVA3WRFL6 # 读取流程表单数据 form_data = read_instances(token=TOKEN, formUuid=FORMID, page=1, n=100) PAGES = form_data.get('totalCount')//100 + 1 ALL_DATA_staff = [] """ 获取全量数据 """ for i in range(1, PAGES+1): # form_data = read_processes_instances(token=TOKEN, formUuid=FORMID, createFromTimeGMT=CREATE_FROM, createToTimeGMT=CREATE_TO, page=i, n=100, searchField={'textField_l7if5ff9': '否'}) form_data = read_instances(token=TOKEN, formUuid=FORMID, page=i, n=100) for data in form_data.get('data'): ALL_DATA_staff.append(data) res_new = [v['formData']['textField_lfrw3u59'] for v in ALL_DATA_staff if v['formData']['textField_lfrw3u58']== staff_name] print('通过员工名称获取员工id') return res_new def get_type(TOKEN: str,ModifiedField_value,Form_id): """ 函数功能:通过唯一标识获取控件类型""" api = f'https://api.dingtalk.com/v1.0/yida/forms/formFields?appType=APP_TNVBVZ3K8G56HG03Z45Q&systemToken=CH7669818R0WN18TYTYJ42PE6GY22WZN0BYWKD1&formUuid='+Form_id+'&userId=yida_pub_account' headers = { "Content-Type": "application/json", "x-acs-dingtalk-access-token": TOKEN } res = requests.get(api, headers=headers) cnew = res.json().get('result') componentName = [i.get('componentName') for i in cnew if i.get('fieldId')== ModifiedField_value ] print('通过唯一标识获取控件类型') return componentName def update_text(TOKEN: str, processInstanceId, formData): """ 函数说明:更新单行文本控件内容 """ api = f'https://api.dingtalk.com//v1.0/yida/forms/instances' headers = { "Content-Type": "application/json", "x-acs-dingtalk-access-token": TOKEN } payload = { "appType" : "APP_TNVBVZ3K8G56HG03Z45Q", "systemToken" : "CH7669818R0WN18TYTYJ42PE6GY22WZN0BYWKD1", "userId" : "yida_pub_account", # 管理员 "language" : "zh_CN", "useLatestVersion" : "false", "formInstanceId" : processInstanceId, "updateFormDataJson" : json.dumps(formData, cls=NpEncoder), } res = requests.put(api, headers=headers, json=payload) print('更新单行文本控件内容') return res def read_instances_V2(token, formUuid, createFromTimeGMT, createToTimeGMT, page, n): """ 函数功能:读取流程表单的所有数据 """ api = f'https://api.dingtalk.com//v1.0/yida/forms/instances/search' headers = { "Content-Type": "application/json", "x-acs-dingtalk-access-token": token } formData = { "appType": "APP_TNVBVZ3K8G56HG03Z45Q", "systemToken": "CH7669818R0WN18TYTYJ42PE6GY22WZN0BYWKD1", "userId": "yida_pub_account", # 超级管理员账号 "language": "zh_CN", "formUuid": formUuid, 'pageNumber':page, 'pageSize':n, # "searchFieldJson": json.dumps(searchField), # 如果增加上这一项会要求升级宜搭存储 "instanceStatus": "RUNNING" } res = requests.post(api, headers=headers, json=formData) return res.json() def pass_on(TOKEN: str,taskId, processInstanceId, staffid): """ 函数功能:转交审批节点 """ api = f'https://api.dingtalk.com//v1.0/yida/tasks/redirect' headers = { "Content-Type": "application/json", "x-acs-dingtalk-access-token": TOKEN } payload = { "processInstanceId" : processInstanceId, "byManager" : "y", "appType" : "APP_TNVBVZ3K8G56HG03Z45Q", "systemToken" : "CH7669818R0WN18TYTYJ42PE6GY22WZN0BYWKD1", "language": "zh_CN", "remark" : "转交(接口自动)", "nowActionExecutorId" : staffid, "userId" : "2268275546837446", "taskId" : int(taskId) } res = requests.post(api, headers=headers, json=payload) print('转交审批节点') return res def read_instances_new(token, formUuid, createFromTimeGMT, createToTimeGMT, page, n): """ 函数功能:读取流程表单的所有数据 """ api = f'https://api.dingtalk.com/v1.0/yida/forms/instances/search' headers = { "Content-Type": "application/json", "x-acs-dingtalk-access-token": token } formData = { "appType": "APP_TNVBVZ3K8G56HG03Z45Q", "systemToken": "CH7669818R0WN18TYTYJ42PE6GY22WZN0BYWKD1", "userId": "yida_pub_account", # 超级管理员账号 "language": "zh_CN", "formUuid": formUuid, # "searchFieldJson": json.dumps(searchField), # 如果增加上这一项会要求升级宜搭存储 'currentPage':page, 'pageSize':n } res = requests.post(api, headers=headers, json=formData) return res.json() class NpEncoder(json.JSONEncoder): def default(self, obj): if isinstance(obj, np.integer): return int(obj) elif isinstance(obj, np.floating): return float(obj) elif isinstance(obj, np.ndarray): return obj.tolist() else: return super(NpEncoder, self).default(obj) """ 处理流程开始 """ TOKEN = generateToken() FORMID2 = "FORM-W46663A1DNH4EKZI6WCEZCQNPZXQ2ZZB92I9LZ" # 10分钟时间间隔 CREATE_FROM, CREATE_TO = [timeStamp(t) for t in get_time_range_minute(100000)] # 读取修改明细表全量数据 form_data = read_instances_V2(token=TOKEN, formUuid=FORMID2, createFromTimeGMT=CREATE_FROM, createToTimeGMT=CREATE_TO, page=1, n=100) PAGES = form_data.get('totalCount')//100 + 1 LIST_DATA = [] """ 获取全量数据 """ for i in range(1, PAGES+1): # form_data = read_processes_instances(token=TOKEN, formUuid=FORMID, createFromTimeGMT=CREATE_FROM, createToTimeGMT=CREATE_TO, page=i, n=100, searchField={'textField_l7if5ff9': '否'}) form_data = read_instances_new(token=TOKEN, formUuid=FORMID2, createFromTimeGMT=CREATE_FROM, createToTimeGMT=CREATE_TO, page=i, n=100) for v in range(0,len(form_data.get('data'))): pass if form_data.get('data')[v]['formData']['textField_l2zx3p5q'] =="0" and form_data.get('data')[v]['formData']['textField_l90wwpsz'] !="v423(auto_update)": formData = {'textField_l90wwpsz':'v423(auto_update)'} formInstanceId = form_data.get('data')[v]['formInstanceId'] update_text(TOKEN, formInstanceId, formData)