|
|
@@ -34,6 +34,17 @@ def _init_logger():
|
|
|
|
|
|
logger = _init_logger()
|
|
|
|
|
|
+SIGN_SUCCESS_ACTIONS = {
|
|
|
+ "OPERATOR_COMPLETE_SIGN",
|
|
|
+ "SIGN_FLOW_FINISH",
|
|
|
+ "SIGN_FLOW_COMPLETE",
|
|
|
+}
|
|
|
+
|
|
|
+NON_SIGNING_ACTIONS = {
|
|
|
+ "OPERATOR_READ",
|
|
|
+ "OPERATOR_VIEW",
|
|
|
+}
|
|
|
+
|
|
|
BUNDLE_CONFIGS = {
|
|
|
"STORE_STANDARD": [
|
|
|
("store_agreement", "店铺入驻协议", 1),
|
|
|
@@ -84,10 +95,32 @@ class ContractCenterService:
|
|
|
"contact_phone": req.contact_phone,
|
|
|
"ord_id": req.ord_id,
|
|
|
"bundle_type": bundle_type,
|
|
|
- "status": "pending",
|
|
|
+ "status": "未签署",
|
|
|
}
|
|
|
)
|
|
|
documents = await self.repo.create_documents(bundle.id, items)
|
|
|
+ for document in documents:
|
|
|
+ try:
|
|
|
+ sign_resp = sign_url(document.sign_flow_id, req.contact_phone)
|
|
|
+ sign_json = json.loads(sign_resp)
|
|
|
+ sign_data = sign_json.get("data") if isinstance(sign_json, dict) else None
|
|
|
+ result_sign_url = sign_data.get("url") if isinstance(sign_data, dict) else None
|
|
|
+ except Exception:
|
|
|
+ await self.repo.rollback()
|
|
|
+ return {
|
|
|
+ "success": False,
|
|
|
+ "message": f"{document.contract_name}创建成功但签署链接获取失败",
|
|
|
+ "raw": {"contract_type": document.contract_type, "sign_flow_id": document.sign_flow_id},
|
|
|
+ }
|
|
|
+ if not result_sign_url:
|
|
|
+ await self.repo.rollback()
|
|
|
+ return {
|
|
|
+ "success": False,
|
|
|
+ "message": f"{document.contract_name}创建成功但签署链接缺失",
|
|
|
+ "raw": {"contract_type": document.contract_type, "sign_flow_id": document.sign_flow_id, "resp": sign_json},
|
|
|
+ }
|
|
|
+ await self.repo.update_document_urls(document.id, sign_url=result_sign_url)
|
|
|
+ document.sign_url = result_sign_url
|
|
|
primary_doc = next((doc for doc in documents if doc.is_primary == 1), documents[0])
|
|
|
await self.repo.set_primary_document(bundle.id, primary_doc.id)
|
|
|
await self.repo.commit()
|
|
|
@@ -103,6 +136,7 @@ class ContractCenterService:
|
|
|
"sign_flow_id": d.sign_flow_id,
|
|
|
"file_id": d.file_id,
|
|
|
"contract_url": d.template_url,
|
|
|
+ "sign_url": d.sign_url,
|
|
|
}
|
|
|
for d in documents
|
|
|
],
|
|
|
@@ -211,16 +245,69 @@ class ContractCenterService:
|
|
|
async def process_esign_callback(self, payload: dict) -> dict:
|
|
|
sign_result = payload.get("signResult")
|
|
|
sign_flow_id = payload.get("signFlowId")
|
|
|
+ action = payload.get("action")
|
|
|
+ operator_mobile = (
|
|
|
+ payload.get("operator", {})
|
|
|
+ .get("psnAccount", {})
|
|
|
+ .get("accountMobile")
|
|
|
+ )
|
|
|
if not sign_flow_id:
|
|
|
+ logger.info(
|
|
|
+ "esign_callback_event %s",
|
|
|
+ json.dumps(
|
|
|
+ {
|
|
|
+ "result": "ignored",
|
|
|
+ "reason": "missing_signFlowId",
|
|
|
+ "action": action,
|
|
|
+ "sign_result": sign_result,
|
|
|
+ "operator_mobile": operator_mobile,
|
|
|
+ },
|
|
|
+ ensure_ascii=False,
|
|
|
+ ),
|
|
|
+ )
|
|
|
return {"success": True, "code": "200", "msg": "ignored_missing_signFlowId"}
|
|
|
|
|
|
document, bundle = await self.repo.get_document_and_bundle(sign_flow_id)
|
|
|
if not document:
|
|
|
+ logger.info(
|
|
|
+ "esign_callback_event %s",
|
|
|
+ json.dumps(
|
|
|
+ {
|
|
|
+ "result": "ignored",
|
|
|
+ "reason": "unknown_signFlowId",
|
|
|
+ "sign_flow_id": sign_flow_id,
|
|
|
+ "action": action,
|
|
|
+ "sign_result": sign_result,
|
|
|
+ "operator_mobile": operator_mobile,
|
|
|
+ },
|
|
|
+ ensure_ascii=False,
|
|
|
+ ),
|
|
|
+ )
|
|
|
return {"success": True, "code": "200", "msg": "ignored_unknown_signFlowId"}
|
|
|
|
|
|
- await self.repo.create_event(bundle.id, document.id, sign_flow_id, "esign_callback", payload)
|
|
|
+ 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))
|
|
|
+
|
|
|
+ logger.info(
|
|
|
+ "esign_callback_event %s",
|
|
|
+ json.dumps(
|
|
|
+ {
|
|
|
+ "result": "mark_signed" if mark_signed else "ignored",
|
|
|
+ "sign_flow_id": sign_flow_id,
|
|
|
+ "bundle_id": bundle.id,
|
|
|
+ "document_id": document.id,
|
|
|
+ "contract_type": document.contract_type,
|
|
|
+ "action": action,
|
|
|
+ "sign_result": sign_result,
|
|
|
+ "operator_mobile": operator_mobile,
|
|
|
+ },
|
|
|
+ ensure_ascii=False,
|
|
|
+ ),
|
|
|
+ )
|
|
|
|
|
|
- if sign_result == 2:
|
|
|
+ if mark_signed:
|
|
|
ts_ms = payload.get("operateTime") or payload.get("timestamp")
|
|
|
signing_dt = None
|
|
|
if ts_ms:
|
|
|
@@ -245,4 +332,6 @@ class ContractCenterService:
|
|
|
return {"success": True, "code": "200", "msg": "success"}
|
|
|
|
|
|
await self.repo.commit()
|
|
|
+ if action:
|
|
|
+ return {"success": True, "code": "200", "msg": f"ignored_action_{action}"}
|
|
|
return {"success": True, "code": "200", "msg": f"ignored_signResult_{sign_result}"}
|