contract_builder.py 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. import json
  2. import logging
  3. import re
  4. import urllib.parse
  5. from typing import Any
  6. from alien_contract.infrastructure.esign.main import fill_in_template, create_by_file
  7. from alien_contract.infrastructure.esign.esign_config import Config
  8. logger = logging.getLogger(__name__)
  9. cfg = Config()
  10. class ContractBuildError(Exception):
  11. def __init__(self, message: str, raw: Any):
  12. super().__init__(message)
  13. self.message = message
  14. self.raw = raw
  15. def build_contract_items(
  16. configs: list[tuple[str, str, int]],
  17. template_name: str,
  18. signer_name: str,
  19. signer_id_num: str,
  20. psn_account: str,
  21. psn_name: str,
  22. ) -> list[dict[str, Any]]:
  23. items: list[dict[str, Any]] = []
  24. for contract_type, contract_name, is_master in configs:
  25. res_text = fill_in_template(template_name, contract_type=contract_type)
  26. try:
  27. res_data = json.loads(res_text)
  28. except json.JSONDecodeError:
  29. logger.error("fill_in_template non-json resp contract_type=%s: %s", contract_type, res_text)
  30. raise ContractBuildError(
  31. message=f"{contract_name}生成失败:e签宝返回非 JSON",
  32. raw={"contract_type": contract_type, "resp": res_text},
  33. )
  34. try:
  35. contract_url = res_data["data"]["fileDownloadUrl"]
  36. file_id = res_data["data"]["fileId"]
  37. m = re.search(r"/([^/]+)\.pdf", contract_url)
  38. if m:
  39. encoded_name = m.group(1)
  40. file_name = urllib.parse.unquote(encoded_name)
  41. else:
  42. file_name = f"{contract_type}.pdf"
  43. except Exception:
  44. logger.error("fill_in_template missing fileDownloadUrl contract_type=%s: %s", contract_type, res_data)
  45. template_id = cfg.templates_map.get(contract_type)
  46. code = res_data.get("code") if isinstance(res_data, dict) else None
  47. if code == 404:
  48. message = f"{contract_name}生成失败:模板不存在或无权限(template_id={template_id})"
  49. elif code == 401:
  50. message = f"{contract_name}生成失败:签名校验失败(template_id={template_id})"
  51. else:
  52. message = f"{contract_name}生成失败:e签宝返回缺少 fileDownloadUrl"
  53. raise ContractBuildError(
  54. message=message,
  55. raw={"contract_type": contract_type, "template_id": template_id, "resp": res_data},
  56. )
  57. sign_data = create_by_file(
  58. file_id,
  59. file_name,
  60. signer_name,
  61. signer_id_num,
  62. psn_account,
  63. psn_name,
  64. contract_type=contract_type,
  65. )
  66. try:
  67. sign_json = json.loads(sign_data)
  68. except json.JSONDecodeError:
  69. logger.error("create_by_file non-json resp contract_type=%s: %s", contract_type, sign_data)
  70. raise ContractBuildError(
  71. message=f"{contract_name}发起签署失败:e签宝返回非 JSON",
  72. raw={"contract_type": contract_type, "resp": sign_data},
  73. )
  74. if not sign_json.get("data"):
  75. logger.error("create_by_file failed or missing data contract_type=%s: %s", contract_type, sign_json)
  76. resp_code = sign_json.get("code") if isinstance(sign_json, dict) else None
  77. resp_msg = sign_json.get("message") if isinstance(sign_json, dict) else None
  78. if resp_code == 1437328:
  79. message = f"{contract_name}发起签署失败:手机号与真实姓名不匹配,请确认联系人实名信息"
  80. elif resp_code == 1435002:
  81. message = f"{contract_name}发起签署失败:签署参数不合法({resp_msg})"
  82. elif resp_code == 1437306:
  83. message = f"{contract_name}发起签署失败:签章定位页超出文档页数,请检查模板页码配置"
  84. elif resp_code == 1435011:
  85. message = f"{contract_name}发起签署失败:签署文件或签署人为空,请检查签章坐标与签署方配置"
  86. elif resp_msg == "EMPTY_RESPONSE":
  87. message = f"{contract_name}发起签署失败:e签宝返回空响应,请检查签署参数与账号配置"
  88. else:
  89. message = f"{contract_name}发起签署失败"
  90. raise ContractBuildError(
  91. message=message,
  92. raw={"contract_type": contract_type, "resp": sign_json},
  93. )
  94. sign_id = sign_json["data"].get("signFlowId")
  95. if not sign_id:
  96. logger.error("create_by_file missing signFlowId contract_type=%s: %s", contract_type, sign_json)
  97. raise ContractBuildError(
  98. message=f"{contract_name}发起签署失败:e签宝返回缺少 signFlowId",
  99. raw={"contract_type": contract_type, "resp": sign_json},
  100. )
  101. items.append(
  102. {
  103. "contract_type": contract_type,
  104. "contract_name": contract_name,
  105. "contract_url": contract_url,
  106. "file_name": file_name,
  107. "file_id": file_id,
  108. "status": 0,
  109. "sign_flow_id": sign_id,
  110. "sign_url": "",
  111. "signing_time": "",
  112. "effective_time": "",
  113. "expiry_time": "",
  114. "contract_download_url": "",
  115. "is_master": is_master,
  116. }
  117. )
  118. return items