main.py 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. import requests
  2. import json
  3. from datetime import datetime
  4. from alien_contract.infrastructure.esign.esign_config import Config
  5. from alien_contract.infrastructure.esign.esign_algorithm import buildSignJsonHeader
  6. cfg = Config()
  7. SIGN_FLOW_TITLES = {
  8. "store_agreement": "商家入驻U店平台协议签署",
  9. "lawyer_agreement": "律所入驻U店平台协议签署",
  10. "alipay_auth": "支付宝授权函签署",
  11. "wechat_pay_commitment": "微信支付承诺函签署",
  12. }
  13. SIGN_POSITIONS = {
  14. "store_agreement": {"alien":{"page": 7, "x": 294, "y": 668}, "org": {"page": 7, "x": 114, "y": 666}},
  15. "lawyer_agreement": {"alien": {"page": 6, "x": 336, "y": 418}, "org": {"page": 6, "x": 145, "y": 418}},
  16. "alipay_auth": {"alien": {"page": 1, "x": 535, "y": 555}, "org": {"page": 1, "x": 535, "y": 431}},
  17. "wechat_pay_commitment": {"org": {"page": 1, "x": 535, "y": 515}},
  18. }
  19. TEMPLATE_COMPONENT_VALUES = {
  20. "store_agreement": lambda store_name: [
  21. {"componentKey": "store_name", "componentValue": store_name},
  22. {"componentKey": "one_name", "componentValue": store_name},
  23. {"componentKey": "date", "componentValue": datetime.now().strftime("%Y年%m月%d日")},
  24. {"componentKey": "alien_name", "componentValue": "爱丽恩严(大连)商务科技有限公司"},
  25. ],
  26. "lawyer_agreement": lambda store_name: [
  27. {"componentKey": "alien_name", "componentValue": "爱丽恩严(大连)商务科技有限公司"},
  28. {"componentKey": "alien_name_2", "componentValue": "爱丽恩严(大连)商务科技有限公司"},
  29. {"componentKey": "law_firm_name", "componentValue": store_name},
  30. {"componentKey": "law_firm_name_2", "componentValue": store_name},
  31. {"componentKey": "signing_date", "componentValue": datetime.now().strftime("%Y年%m月%d日")},
  32. ],
  33. "alipay_auth": lambda store_name: [],
  34. "wechat_pay_commitment": lambda store_name: [],
  35. }
  36. def _request(method: str, url: str, body: dict | None = None) -> str:
  37. if not url.startswith("http"):
  38. url = f"{cfg.host}{url}"
  39. headers = buildSignJsonHeader(cfg.appId, cfg.scert, method, url, body)
  40. if body is None:
  41. response = requests.request(method, url, headers=headers)
  42. else:
  43. payload = json.dumps(body, separators=(",", ":"), ensure_ascii=False).encode("utf-8")
  44. response = requests.request(method, url, data=payload, headers=headers)
  45. if response.text:
  46. return response.text
  47. fallback = {"success": False, "http_status": response.status_code, "message": "EMPTY_RESPONSE", "request_id": response.headers.get("x-ts-request-id")}
  48. return json.dumps(fallback, ensure_ascii=False)
  49. def apply_platform_seal(sign_flow_id):
  50. sign_url = "/v3/sign-flow/{}/sign-fields/auto-sign".format(sign_flow_id)
  51. return _request("POST", sign_url, {})
  52. def _build_alien_signer(file_id: str, position: dict) -> dict:
  53. """构建平台方(爱丽恩严)签署人配置"""
  54. return {
  55. "signConfig": {"signOrder": 1},
  56. "signerType": 1,
  57. "signFields": [{
  58. "customBizNum": "9527",
  59. "fileId": file_id,
  60. "normalSignFieldConfig": {
  61. "autoSign": True,
  62. "signFieldStyle": 1,
  63. "signFieldPosition": {
  64. "positionPage": str(position["page"]),
  65. "positionX": position["x"],
  66. "positionY": position["y"]
  67. }
  68. }
  69. }]
  70. }
  71. def _build_org_signer(file_id: str, position: dict, signer_name: str, signer_id_num: str, psn_account: str, psn_name: str) -> dict:
  72. return {
  73. "signConfig": {"signOrder": 2, "forcedReadingTime": 10},
  74. "signerType": 1,
  75. "orgSignerInfo": {
  76. "orgName": signer_name,
  77. "orgInfo": {
  78. "orgIDCardNum": signer_id_num,
  79. "orgIDCardType": "CRED_ORG_USCC"
  80. },
  81. "transactorInfo": {
  82. "psnAccount": psn_account,
  83. "psnInfo": {"psnName": psn_name}
  84. }
  85. },
  86. "signFields": [
  87. {
  88. "customBizNum": "自定义编码001",
  89. "fileId": file_id,
  90. "normalSignFieldConfig": {
  91. "signFieldStyle": 1,
  92. "signFieldPosition": {
  93. "positionPage": str(position["page"]),
  94. "positionX": position["x"],
  95. "positionY": position["y"],
  96. },
  97. },
  98. }
  99. ],
  100. }
  101. def get_auth_flow_id(org_name: str, org_id_card_num: str, legal_rep_name: str, legal_rep_id_card_num: str):
  102. body = {
  103. "orgAuthConfig": {
  104. "orgName": org_name,
  105. "orgInfo": {
  106. "orgIDCardNum": org_id_card_num,
  107. "legalRepName": legal_rep_name,
  108. "legalRepIDCardNum": legal_rep_id_card_num,
  109. },
  110. },
  111. "transactorUseSeal": True,
  112. }
  113. return _request("POST", "/v3/org-auth-url", body)
  114. def get_template_detail():
  115. return _request("GET", f"/v3/doc-templates/{cfg.templates_id}")
  116. def create_by_file(
  117. file_id,
  118. file_name,
  119. signer_name,
  120. signer_id_num,
  121. psn_account,
  122. psn_name,
  123. contract_type: str = "store_agreement",
  124. ):
  125. sign_flow_url = "/v3/sign-flow/create-by-file"
  126. title = SIGN_FLOW_TITLES.get(contract_type, SIGN_FLOW_TITLES["store_agreement"])
  127. positions = SIGN_POSITIONS.get(contract_type, SIGN_POSITIONS["store_agreement"])
  128. signers = []
  129. if positions.get("alien"):
  130. signers.append(_build_alien_signer(file_id, positions["alien"]))
  131. if positions.get("org"):
  132. signers.append(_build_org_signer(file_id, positions["org"], signer_name, signer_id_num, psn_account, psn_name))
  133. body = {
  134. "docs": [{"fileId": file_id, "fileName": f"{file_name}.pdf"}],
  135. "signFlowConfig": {
  136. "signFlowTitle": title,
  137. "autoFinish": True,
  138. "noticeConfig": {"noticeTypes": "1,2"},
  139. "notifyUrl": cfg.callback_url,
  140. "noticeDeveloperUrl": cfg.developer_callback_url,
  141. "redirectConfig": {"redirectUrl": cfg.redirect_url},
  142. },
  143. "signers": signers,
  144. }
  145. return _request("POST", sign_flow_url, body)
  146. def sign_url(sign_flow_id, account):
  147. sign_url_info = "/v3/sign-flow/{}/sign-url".format(sign_flow_id)
  148. body = {
  149. "signFlowId": sign_flow_id,
  150. "operator": {"psnAccount": account},
  151. "needLogin": False,
  152. "urlType": 2,
  153. "clientType": "ALL",
  154. }
  155. return _request("POST", sign_url_info, body)
  156. def file_download_url(sign_flow_id):
  157. sign_download = "/v3/sign-flow/{}/file-download-url".format(sign_flow_id)
  158. return _request("POST", sign_download, {"urlAvailableDate": "3600"})
  159. def fill_in_template(store_name: str, contract_type: str = "store_agreement"):
  160. template_id = cfg.templates_map.get(contract_type, cfg.templates_map["store_agreement"])
  161. template_file_name = cfg.template_file_names.get(contract_type, cfg.template_file_names["store_agreement"])
  162. fill_in_data = "/v3/files/create-by-doc-template"
  163. component_builder = TEMPLATE_COMPONENT_VALUES.get(contract_type, TEMPLATE_COMPONENT_VALUES["store_agreement"])
  164. body = {
  165. "docTemplateId": template_id,
  166. "fileName": template_file_name,
  167. "components": component_builder(store_name),
  168. }
  169. return _request("POST", fill_in_data, body)
  170. def get_contract_detail(file_id: str):
  171. detail_url = f"/v3/files/{file_id}"
  172. return _request("GET", detail_url)