|
|
@@ -2,6 +2,7 @@ import datetime
|
|
|
import json
|
|
|
import logging
|
|
|
import os
|
|
|
+from typing import Any
|
|
|
|
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
|
|
@@ -34,13 +35,13 @@ def _init_logger():
|
|
|
|
|
|
logger = _init_logger()
|
|
|
|
|
|
-SIGN_SUCCESS_ACTIONS = {
|
|
|
- "OPERATOR_COMPLETE_SIGN",
|
|
|
+SIGN_FLOW_FINISH_ACTIONS = {
|
|
|
"SIGN_FLOW_FINISH",
|
|
|
"SIGN_FLOW_COMPLETE",
|
|
|
}
|
|
|
|
|
|
-NON_SIGNING_ACTIONS = {
|
|
|
+NON_FINAL_SIGN_ACTIONS = {
|
|
|
+ "OPERATOR_COMPLETE_SIGN",
|
|
|
"OPERATOR_READ",
|
|
|
"OPERATOR_VIEW",
|
|
|
}
|
|
|
@@ -64,6 +65,23 @@ DEFAULT_BUNDLE_BY_SUBJECT = {
|
|
|
}
|
|
|
|
|
|
|
|
|
+def _extract_download_url(download_resp: str) -> tuple[str | None, Any]:
|
|
|
+ try:
|
|
|
+ download_json = json.loads(download_resp)
|
|
|
+ except json.JSONDecodeError as exc:
|
|
|
+ return None, {"error": f"e签宝返回非 JSON: {exc}", "resp": download_resp}
|
|
|
+
|
|
|
+ data = download_json.get("data") if isinstance(download_json, dict) else None
|
|
|
+ files = data.get("files") if isinstance(data, dict) else None
|
|
|
+ if isinstance(files, list) and files:
|
|
|
+ first_file = files[0]
|
|
|
+ if isinstance(first_file, dict):
|
|
|
+ download_url = first_file.get("downloadUrl")
|
|
|
+ if download_url:
|
|
|
+ return download_url, download_json
|
|
|
+ return None, download_json
|
|
|
+
|
|
|
+
|
|
|
class ContractCenterService:
|
|
|
def __init__(self, db: AsyncSession):
|
|
|
self.repo = ContractRepository(db)
|
|
|
@@ -229,10 +247,32 @@ class ContractCenterService:
|
|
|
async def _get_signed_detail(self, document, _bundle):
|
|
|
try:
|
|
|
download_resp = file_download_url(document.sign_flow_id)
|
|
|
- download_json = json.loads(download_resp)
|
|
|
- contract_download_url = download_json["data"]["files"][0]["downloadUrl"]
|
|
|
except Exception as exc:
|
|
|
+ cached_url = document.download_url or None
|
|
|
+ if cached_url:
|
|
|
+ return {
|
|
|
+ "status": 1,
|
|
|
+ "contract_url": cached_url,
|
|
|
+ "contract_download_url": cached_url,
|
|
|
+ "sign_flow_id": document.sign_flow_id,
|
|
|
+ }
|
|
|
return {"success": False, "message": "获取合同下载链接失败", "raw": str(exc)}
|
|
|
+ contract_download_url, raw = _extract_download_url(download_resp)
|
|
|
+ if not contract_download_url:
|
|
|
+ cached_url = document.download_url or None
|
|
|
+ if cached_url:
|
|
|
+ return {
|
|
|
+ "status": 1,
|
|
|
+ "contract_url": cached_url,
|
|
|
+ "contract_download_url": cached_url,
|
|
|
+ "sign_flow_id": document.sign_flow_id,
|
|
|
+ }
|
|
|
+ logger.error(
|
|
|
+ "file_download_url missing downloadUrl sign_flow_id=%s resp=%s",
|
|
|
+ document.sign_flow_id,
|
|
|
+ download_resp,
|
|
|
+ )
|
|
|
+ return {"success": False, "message": "合同已签署,下载文件生成中,请稍后重试", "raw": raw}
|
|
|
await self.repo.update_document_urls(document.id, template_url=contract_download_url, download_url=contract_download_url)
|
|
|
await self.repo.commit()
|
|
|
return {
|
|
|
@@ -288,7 +328,7 @@ class ContractCenterService:
|
|
|
event_type = f"esign_callback:{action or 'UNKNOWN'}"
|
|
|
await self.repo.create_event(bundle.id, document.id, sign_flow_id, event_type[:50], payload)
|
|
|
|
|
|
- mark_signed = bool(sign_result == 2 or (action in SIGN_SUCCESS_ACTIONS and action not in NON_SIGNING_ACTIONS))
|
|
|
+ mark_signed = bool(action in SIGN_FLOW_FINISH_ACTIONS or (sign_result == 2 and action not in NON_FINAL_SIGN_ACTIONS))
|
|
|
|
|
|
logger.info(
|
|
|
"esign_callback_event %s",
|
|
|
@@ -322,10 +362,15 @@ class ContractCenterService:
|
|
|
contract_download_url = None
|
|
|
try:
|
|
|
download_resp = file_download_url(sign_flow_id)
|
|
|
- download_json = json.loads(download_resp)
|
|
|
- contract_download_url = download_json["data"]["files"][0]["downloadUrl"]
|
|
|
- except Exception:
|
|
|
- contract_download_url = None
|
|
|
+ contract_download_url, raw_download_resp = _extract_download_url(download_resp)
|
|
|
+ except Exception as exc:
|
|
|
+ raw_download_resp = str(exc)
|
|
|
+ if not contract_download_url:
|
|
|
+ logger.error(
|
|
|
+ "file_download_url missing downloadUrl on callback sign_flow_id=%s resp=%s",
|
|
|
+ sign_flow_id,
|
|
|
+ raw_download_resp,
|
|
|
+ )
|
|
|
await self.repo.mark_document_signed(document.id, signing_dt, effective_dt, expiry_dt, contract_download_url)
|
|
|
await self.repo.recalc_bundle_status(bundle.id)
|
|
|
await self.repo.commit()
|