b2c_handsign_demo.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. # -*- coding: UTF-8 -*-
  2. import esigntool
  3. import requests
  4. from esigntool import esign_run_print_outer
  5. from esigntool.esign_file import fileHelp
  6. # 签署场景:平台方自动签署(签署方1)+个人用户手动签署流程(签署方2)
  7. # 平台方(签署方1):appId所属企业为平台方,默认平台方已完成实名认证,通过获取企业签署帐号来实现平台方自动签署。
  8. # 个人用户手动签署(签署方2):通过传入个人信息,来实现个人用户手动签署。
  9. config = esigntool.config() # 初始化配置类
  10. @esign_run_print_outer
  11. def findOrgIdentityInfo(orgName):
  12. """
  13. 查询机构认证信息
  14. :return:
  15. """
  16. api_path = "/v3/organizations/identity-info?orgName={}".format(orgName)
  17. method = esigntool.httpMethodEnum.GET
  18. if orgName == "":
  19. print("请设置实名企业名称")
  20. exit()
  21. # 签名并构造签名鉴权json请求头
  22. json_headers = esigntool.buildSignJsonHeader(config.appId, config.scert, method, esigntool.apiPathSort(api_path))
  23. # 发起请求
  24. resp = requests.request(method, config.host + api_path, json=None, headers=json_headers)
  25. print(resp.text)
  26. orgId = resp.json()['data']['orgId']
  27. return orgId
  28. @esign_run_print_outer
  29. def getFileUploadUrl(file):
  30. """
  31. 获取文件上传地址
  32. :return:
  33. """
  34. contentType = "application/pdf" # 声明请求变量
  35. body = {
  36. "contentMd5": file.contentMd5,
  37. "contentType": contentType,
  38. "convert2Pdf": False,
  39. "fileName": file.fileName,
  40. "fileSize": file.fileSize
  41. } # 构建请求参数body体
  42. api_path = "/v3/files/file-upload-url"
  43. method = esigntool.httpMethodEnum.POST
  44. json_headers = esigntool.buildSignJsonHeader(config.appId, config.scert,
  45. method, api_path, body) # 签名并构造签名鉴权json请求头
  46. resp = requests.request(method, config.host + api_path, json=body, headers=json_headers) # 发送请求
  47. fileUploadUrl = resp.json()['data']['fileUploadUrl'] # 获取文件上传路径
  48. fileId = resp.json()['data']['fileId']
  49. print(resp.text)
  50. return fileUploadUrl, fileId
  51. @esign_run_print_outer
  52. def fileStreamUpload(binfile, fileUploadUrl):
  53. """
  54. 文件流上传服务器
  55. :return:
  56. """
  57. contentMd5 = file.contentMd5 # 声明请求变量
  58. contentType = "application/pdf" # 声明请求变量
  59. method = esigntool.httpMethodEnum.PUT # 声明请求方法
  60. json_headers = esigntool.buildFileUploadHeader(contentType, contentMd5) # 构建请求头
  61. resp = requests.request(method, fileUploadUrl, data=binfile, headers=json_headers) # 发送请求
  62. print(resp.text)
  63. return resp
  64. @esign_run_print_outer
  65. def signFlowCreateByFile(fileId, orgId, psnAccount):
  66. """
  67. 基于文件发起签署
  68. :return:
  69. """
  70. body = {
  71. "docs": [{
  72. "fileId": fileId,
  73. "fileName": "xx企业劳动合同.pdf"
  74. }],
  75. "attachments": [{
  76. "fileId": fileId,
  77. "fileName": "入职材料.pdf"
  78. }],
  79. "signers": [{
  80. "psnSignerInfo": {
  81. "psnAccount": psnAccount
  82. },
  83. "signConfig": {
  84. "forcedReadingTime": "10",
  85. "signOrder": 2
  86. },
  87. "signFields": [{
  88. "customBizNum": "自定义编码",
  89. "fileId": fileId,
  90. "normalSignFieldConfig": {
  91. "freeMode": False,
  92. "movableSignField": False,
  93. "psnSealStyles": "0,1",
  94. "signFieldPosition": {
  95. "positionPage": "1",
  96. "positionX": 100,
  97. "positionY": 100
  98. },
  99. "signFieldStyle": 1
  100. }
  101. }],
  102. "signerType": 0
  103. }, {
  104. "orgSignerInfo": {
  105. "orgId": orgId
  106. },
  107. "signConfig": {
  108. "signOrder": 1
  109. },
  110. "signFields": [{
  111. "customBizNum": "自定义编码",
  112. "fileId": fileId,
  113. "normalSignFieldConfig": {
  114. "autoSign": True,
  115. "signFieldPosition": {
  116. "positionPage": "1",
  117. "positionX": 100,
  118. "positionY": 200
  119. },
  120. "signFieldStyle": 1
  121. }
  122. }],
  123. "signerType": 1
  124. }],
  125. "signFlowConfig": {
  126. "autoFinish": False,
  127. "autoStart": True,
  128. "noticeConfig": {
  129. "noticeTypes": "1"
  130. },
  131. "notifyUrl": "http://xx.xx.86.172:8081/asyn/notify",
  132. "redirectConfig": {
  133. "redirectDelayTime": "3",
  134. "redirectUrl": "http://www.esign.cn"
  135. },
  136. "signConfig": {
  137. "availableSignClientTypes": "1",
  138. "showBatchDropSealButton": True
  139. },
  140. "signFlowTitle": "企业员工劳动合同签署"
  141. }
  142. } # 构建请求body体
  143. api_path = "/v3/sign-flow/create-by-file" # 拼接请求路径
  144. method = esigntool.httpMethodEnum.POST # 声明请求方法
  145. json_headers = esigntool.buildSignJsonHeader(config.appId, config.scert,
  146. method, api_path, body) # 签名并构造签名鉴权json请求头
  147. resp = requests.request(method, config.host + api_path, json=body, headers=json_headers) # 发送请求
  148. print(resp.text)
  149. sign_flowId = resp.json()['data']['signFlowId']
  150. return sign_flowId
  151. @esign_run_print_outer
  152. def signUrl(sign_flowId, psnAccount):
  153. """
  154. 获取合同文件签署链接
  155. :return:
  156. """
  157. body = {
  158. "clientType": "ALL",
  159. "needLogin": True,
  160. "operator": {
  161. "psnAccount": psnAccount
  162. },
  163. "urlType": 2
  164. } # 构建请求body体
  165. api_path = "/v3/sign-flow/{}/sign-url".format(sign_flowId) # 拼接请求路径
  166. method = esigntool.httpMethodEnum.POST # 请求方法
  167. json_headers = esigntool.buildSignJsonHeader(config.appId, config.scert,
  168. method, api_path, body) # 签名并构造签名鉴权json请求头
  169. resp = requests.request(method, config.host + api_path, json=body, headers=json_headers) # 发送http请求
  170. print(resp.text)
  171. return resp
  172. @esign_run_print_outer
  173. def fileDownloadUrl(sign_flowId):
  174. """
  175. 下载已签署文件及附属材料
  176. :return:
  177. """
  178. api_path = "/v3/sign-flow/{}/file-download-url".format(sign_flowId) # 拼接请求路径
  179. method = esigntool.httpMethodEnum.GET # 声明请求方法
  180. json_headers = esigntool.buildSignJsonHeader(config.appId, config.scert,
  181. method, api_path) # 签名并构造签名鉴权json请求头
  182. resp = requests.request(method, config.host + api_path, json=None, headers=json_headers) # 发送请求
  183. print(resp.text)
  184. return resp
  185. if __name__ == '__main__':
  186. if config.appId == "" or config.scert == "":
  187. print("请设置应用Appid和应用Secret")
  188. exit()
  189. fileUrl = "D:\\**文件\\1.pdf" # 本地文件路径
  190. orgName = "***企业" # 平台自身企业名称,即appid所属的企业名称
  191. psnAccount = "1*****" # 个人用户手机号
  192. orgId = findOrgIdentityInfo(orgName) # 查询平台自身实名帐号ID
  193. file = fileHelp(fileUrl) # 初始化文件辅助类
  194. fileUploadUrl, fileId = getFileUploadUrl(file) # 获取文件ID&文件上传路径
  195. fileStreamUpload(file.getBinFile(), fileUploadUrl) # 上传文件流
  196. sign_flowId = signFlowCreateByFile(fileId, orgId, psnAccount) # 发起一步签署:主动发送签署短信给签署用户
  197. signUrl(sign_flowId, psnAccount) # 手动获取当前签署任务中,个人的签署链接
  198. fileDownloadUrl(sign_flowId) # 合同结束后(个人用户签署完成后),下载签署后合同