# -*- coding: UTF-8 -*- import esigntool import requests from esigntool import esign_run_print_outer from esigntool.esign_file import fileHelp # 签署场景:平台方自动签署(签署方1)+企业用户手动签署流程(签署方2) # 平台方(签署方1):appId所属企业为平台方,默认平台方已完成实名认证,通过获取企业签署帐号来实现平台方自动签署。 # 企业用户手动签署(签署方2):通过传入企业名称和经办人信息,来实现企业用户手动签署。 config = esigntool.Config() # 初始化配置类 @esign_run_print_outer def findOrgIdentityInfo(orgName): """ :param orgName 查询机构认证信息 :return: 企业实名主体帐号ID """ api_path = "/v3/organizations/identity-info?orgName={}".format(orgName) method = esigntool.httpMethodEnum.GET if orgName == "": print("请设置实名企业名称") exit() # 签名并构造签名鉴权json请求头 json_headers = esigntool.buildSignJsonHeader(config.appId, config.scert, method, esigntool.apiPathSort(api_path)) # 发起请求 resp = requests.request(method, config.host + api_path, json=None, headers=json_headers) print(resp.text) orgId = resp.json()['data']['orgId'] return orgId @esign_run_print_outer def getFileUploadUrl(file): """ 获取文件上传地址 :param file 文件辅助类初始化 :return: fileUploadUrl, fileId 文件流上传路径,文件ID """ contentType = "application/pdf" # 声明请求变量 body = { "contentMd5": file.contentMd5, "contentType": contentType, "convert2Pdf": False, "fileName": file.fileName, "fileSize": file.fileSize } # 构建请求参数body体 api_path = "/v3/files/file-upload-url" method = esigntool.httpMethodEnum.POST json_headers = esigntool.buildSignJsonHeader(config.appId, config.scert, method, api_path, body) # 签名并构造签名鉴权json请求头 resp = requests.request(method, config.host + api_path, json=body, headers=json_headers) # 发送请求 fileUploadUrl = resp.json()['data']['fileUploadUrl'] # 获取文件上传路径 fileId = resp.json()['data']['fileId'] print(resp.text) return fileUploadUrl, fileId @esign_run_print_outer def fileStreamUpload(binfile, fileUploadUrl): """ :param binfile 文件流 :param fileUploadUrl 文件流上传路径 方法名:文件流上传服务器 :return: 文件上传结果 """ contentMd5 = file.contentMd5 # 声明请求变量 contentType = "application/pdf" # 声明请求变量 method = esigntool.httpMethodEnum.PUT # 声明请求方法 json_headers = esigntool.buildFileUploadHeader(contentType, contentMd5) # 构建请求头 resp = requests.request(method, fileUploadUrl, data=binfile, headers=json_headers) # 发送请求 print(resp.text) return resp @esign_run_print_outer def signFlowCreateByFile(fileId, orgId,psnAccount): """ :param fileId 文件ID :param orgId 企业实名主体帐号ID,用于实现自动平台放自动签署 基于文件发起签署 :return: 签署流程ID """ body = { "docs": [{ "fileId": fileId, "fileName": "xx企业劳动合同.pdf" }], "attachments": [{ "fileId": fileId, "fileName": "入职材料.pdf" }], "signers": [{ "orgSignerInfo": { "orgName": orgName, # 签署方1:平台自动签署 "transactorInfo": { "psnAccount": psnAccount } }, "signConfig": { "forcedReadingTime": "10", "signOrder": 2 }, "signFields": [{ "customBizNum": "202200001111", "fileId": fileId, "normalSignFieldConfig": { "autoSign": False, "freeMode": False, "movableSignField": False, "signFieldPosition": { "positionPage": "1", "positionX": 100, "positionY": 200 }, "signFieldSize": 200, "signFieldStyle": 1 }, "signFieldType": 0 }], "signerType": 1 }, { "orgSignerInfo": { "orgId": orgId # 签署方2:企业用户手动签署 }, "signConfig": { "forcedReadingTime": "10", "signOrder": 1 }, "signFields": [{ "customBizNum": "202200001111", "fileId": fileId, "normalSignFieldConfig": { "autoSign": True, "freeMode": False, "movableSignField": False, "signFieldPosition": { "positionPage": "1", "positionX": 300, "positionY": 200 }, "signFieldSize": 200, "signFieldStyle": 1 }, "signFieldType": 0 }], "signerType": 1 }], "signFlowConfig": { "autoFinish": False, "autoStart": True, "chargeConfig": { "chargeMode": 0 }, "noticeConfig": { "noticeTypes": "1" }, "notifyUrl": "http://xx.xx.86.172:8081/asyn/notify", "redirectConfig": { "redirectDelayTime": "3", "redirectUrl": "http://www.xx.cn/" }, "signConfig": { "availableSignClientTypes": "1", "showBatchDropSealButton": True }, "authConfig": { "psnAvailableAuthModes": ["PSN_BANK4_AUTHCODE"], "willingnessAuthModes": ["FACE_TECENT_CLOUD_H5"], "orgAvailableAuthModes": ["ORG_BANK_TRANSFER"] }, "signFlowTitle": "企业员工劳动合同签署" } } # 构建请求body体 api_path = "/v3/sign-flow/create-by-file" # 拼接请求路径 method = esigntool.httpMethodEnum.POST # 声明请求方法 json_headers = esigntool.buildSignJsonHeader(config.appId, config.scert, method, api_path, body) # 签名并构造签名鉴权json请求头 resp = requests.request(method, config.host + api_path, json=body, headers=json_headers) # 发送请求 print(resp.text) sign_flowId = resp.json()['data']['signFlowId'] return sign_flowId @esign_run_print_outer def signUrl(sign_flowId): """ 获取合同文件签署链接 :param 签署流程ID :return: """ body = { "clientType": "ALL", "needLogin": True, "operator": { "psnAccount": psnAccount }, "urlType": 2 } # 构建请求body体 api_path = "/v3/sign-flow/{}/sign-url".format(sign_flowId) # 拼接请求路径 method = esigntool.httpMethodEnum.POST # 请求方法 json_headers = esigntool.buildSignJsonHeader(config.appId, config.scert, method, api_path, body) # 签名并构造签名鉴权json请求头 resp = requests.request(method, config.host + api_path, json=body, headers=json_headers) # 发送http请求 print(resp.text) return resp @esign_run_print_outer def fileDownloadUrl(sign_flowId): """ :param 签署流程ID 下载已签署文件及附属材料 :return: """ api_path = "/v3/sign-flow/{}/file-download-url".format(sign_flowId) # 拼接请求路径 method = esigntool.httpMethodEnum.GET # 声明请求方法 json_headers = esigntool.buildSignJsonHeader(config.appId, config.scert, method, api_path) # 签名并构造签名鉴权json请求头 resp = requests.request(method, config.host + api_path, json=None, headers=json_headers) # 发送请求 print(resp.text) return resp if __name__ == '__main__': fileUrl = "D:\\**文件\\*.pdf" # 本地文件路径 orgName = "**企业" # 签署方企业名称 psnAccount = "1******" # 签署人手机号或者邮箱地址 orgId = findOrgIdentityInfo(orgName) # 查询平台方实名帐号ID file = fileHelp(fileUrl) # 初始化文件辅助类 fileUploadUrl, fileId = getFileUploadUrl(file) # 获取文件ID&文件上传路径 fileStreamUpload(file.getBinFile(), fileUploadUrl) # 上传文件流 sign_flowId = signFlowCreateByFile(fileId, orgId, psnAccount) # 发起一步签署:主动发送签署短信给签署用户 signUrl(sign_flowId) # 获取签署链接 fileDownloadUrl(sign_flowId) # 合同结束后,下载签署后合同