import json import logging import requests from common.esigntool.esign_config import Config from common.esigntool.esign_algorithm import buildSignJsonHeader from datetime import datetime logger = logging.getLogger(__name__) config = Config() def _request(method: str, api_path: str, body: dict = None) -> str: """统一的e签宝API请求方法 Args: method: HTTP方法 (GET/POST) api_path: API路径 body: 请求体字典 Returns: 响应文本 """ headers = buildSignJsonHeader(config.appId, config.scert, method, api_path, body=body) url = config.host + api_path if body is not None: data = json.dumps(body, separators=(",", ":"), ensure_ascii=False) resp = requests.request(method, url, data=data, headers=headers) else: resp = requests.request(method, url, headers=headers) logger.debug("请求 %s %s, 响应: %s", method, api_path, resp.text) return resp.text # ==================== 签署流程标题映射 ==================== SIGN_FLOW_TITLES = { "store_agreement": "商家入驻U店平台协议签署", "alipay_auth": "支付宝授权函签署", "wechat_pay_commitment": "微信支付承诺函签署", "lawyer_agreement": "律所入驻U店平台协议签署", } # ==================== 签署位置配置 ==================== SIGN_POSITIONS = { "store_agreement": { "alien": {"page": 7, "x": 294, "y": 668}, "signer": {"page": 7, "x": 114, "y": 666}, }, "alipay_auth": { "alien": {"page": 1, "x": 535, "y": 555}, "signer": {"page": 1, "x": 535, "y": 431}, }, "wechat_pay_commitment": { "signer": {"page": 1, "x": 535, "y": 515}, }, "lawyer_agreement": { "alien": {"page": 6, "x": 336, "y": 418}, "signer": {"page": 6, "x": 145, "y": 418}, }, } # ==================== 模板填充配置 ==================== TEMPLATE_COMPONENT_VALUES = { "store_agreement": { "alien_name": "爱丽恩严(大连)商务科技有限公司", "date": None, # 运行时填充 "one_name": None, # 运行时填充 "store_name": None, # 运行时填充 }, "lawyer_agreement": { "alien_name": "爱丽恩严(大连)商务科技有限公司", "alien_name_2": "爱丽恩严(大连)商务科技有限公司", "law_firm_name": None, # 运行时填充 "law_firm_name_2": None, # 运行时填充 "signing_date": None, # 运行时填充 }, "alipay_auth": {}, "wechat_pay_commitment": {}, } def get_auth_flow_id(org_name, org_id, legal_rep_name, legal_rep_id): """获取机构认证&授权页面链接""" body = { "clientType": "ALL", "redirectConfig": { "redirectUrl": "https://www.baidu.com" }, "orgAuthConfig": { "orgName": org_name, "orgInfo": { "orgIDCardNum": org_id, "orgIDCardType": "CRED_ORG_USCC", "legalRepName": legal_rep_name, "legalRepIDCardNum": legal_rep_id, "legalRepIDCardType": "CRED_PSN_CH_IDCARD" }, "transactorInfo": { "psnAccount": "17337039317", "psnInfo": { "psnName": "孟骞康", "psnIDCardNum": "411426200308121212", "psnIDCardType": "CRED_PSN_CH_IDCARD", "psnMobile": "17337039317" } } }, "notifyUrl": "http://120.26.186.130:33333/api/store/esign/callback_auth", "transactorUseSeal": True } return _request("POST", "/v3/org-auth-url", body) def get_template_detail(): """查询合同模板中控件详情""" return _request("GET", f"/v3/doc-templates/{config.templates_id}") def fill_in_template(name, contract_type="store_agreement"): """填写模板生成文件 Args: name: 商家/律所名称 contract_type: 合同类型 (store_agreement/lawyer_agreement/alipay_auth/wechat_pay_commitment) """ today = datetime.now().strftime("%Y年%m月%d日") base_values = TEMPLATE_COMPONENT_VALUES.get(contract_type, {}) # 根据合同类型填充动态字段 dynamic_values = { "store_agreement": {"store_name": name, "one_name": name, "date": today}, "lawyer_agreement": {"law_firm_name": name, "law_firm_name_2": name, "signing_date": today}, }.get(contract_type, {}) components = [ {"componentKey": key, "componentValue": value} for key, value in {**base_values, **dynamic_values}.items() ] body = { "docTemplateId": config.templates_map.get(contract_type, ""), "fileName": config.template_file_names.get(contract_type, ""), "components": components } return _request("POST", "/v3/files/create-by-doc-template", body) def get_contract_detail(file_id): """查询PDF模板填写后文件""" return _request("GET", f"/v3/files/{file_id}") def _build_alien_signer(file_id, position): """构建平台方(爱丽恩严)签署人配置""" return { "signConfig": {"signOrder": 1}, "signerType": 1, "signFields": [{ "customBizNum": "9527", "fileId": file_id, "normalSignFieldConfig": { "autoSign": True, "signFieldStyle": 1, "signFieldPosition": { "positionPage": str(position["page"]), "positionX": position["x"], "positionY": position["y"] } } }] } def _build_org_signer(file_id, position, signer_name, signer_id_num, psn_account, psn_name): """构建签署方(商家/律所)签署人配置""" return { "signConfig": {"forcedReadingTime": 10, "signOrder": 2}, "signerType": 1, "orgSignerInfo": { "orgName": signer_name, "orgInfo": { "orgIDCardNum": signer_id_num, "orgIDCardType": "CRED_ORG_USCC" }, "transactorInfo": { "psnAccount": psn_account, "psnInfo": {"psnName": psn_name} } }, "signFields": [{ "customBizNum": "自定义编码001", "fileId": file_id, "normalSignFieldConfig": { "signFieldStyle": 1, "signFieldPosition": { "positionPage": str(position["page"]), "positionX": position["x"], "positionY": position["y"] } } }] } def create_by_file(file_id, file_name, signer_name, signer_id_num, psn_account, psn_name, contract_type="store_agreement"): """基于文件发起签署 Args: file_id: 文件ID file_name: 文件名 signer_name: 签署方名称 signer_id_num: 签署方证件号 psn_account: 经办人账号标识(手机号/邮箱) psn_name: 经办人姓名 contract_type: 合同类型 (store_agreement/alipay_auth/wechat_pay_commitment/lawyer_agreement) """ positions = SIGN_POSITIONS.get(contract_type, SIGN_POSITIONS["store_agreement"]) signers = [] if positions.get("alien"): signers.append(_build_alien_signer(file_id, positions["alien"])) if positions.get("signer"): signers.append(_build_org_signer(file_id, positions["signer"], signer_name, signer_id_num, psn_account, psn_name)) body = { "docs": [{"fileId": file_id, "fileName": f"{file_name}.pdf"}], "signFlowConfig": { "signFlowTitle": SIGN_FLOW_TITLES.get(contract_type, "合同签署"), "autoFinish": True, "noticeConfig": {"noticeTypes": "1,2"}, "notifyUrl": "http://120.26.186.130:33333:/api/store/esign/callback", "redirectConfig": {"redirectUrl": "https://www.esign.cn/"}, }, "signers": signers } return _request("POST", "/v3/sign-flow/create-by-file", body) def sign_url(sign_flow_id, psn_account): """获取签署页面链接""" body = { "signFlowId": sign_flow_id, "clientType": "ALL", "needLogin": False, "operator": {"psnAccount": psn_account}, "urlType": 2 } return _request("POST", f"/v3/sign-flow/{sign_flow_id}/sign-url", body) def file_download_url(sign_flow_id): """下载已签署文件及附属材料""" body = {"urlAvailableDate": "3600"} return _request("POST", f"/v3/sign-flow/{sign_flow_id}/file-download-url", body)