Просмотр исходного кода

合同签署改成机构与商家模式,TODO:短信发送

mengqiankang 2 месяцев назад
Родитель
Сommit
20f703a035

+ 8 - 7
alien_store/api/router.py

@@ -54,9 +54,10 @@ async def create_esign_templates(
     templates_data: TemplatesCreate, 
     templates_server: ContractServer = Depends(get_contract_service)
 ) -> Union[TemplatesCreateResponse, ErrorResponse]:
-    # AI审核完调用 e签宝生成文件
+    """AI审核完调用 e签宝生成文件"""
     logger.info(f"get_esign_templates request: {templates_data}")
-    res_text = fill_in_template(templates_data.merchant_name)
+    # res_text = fill_in_template(templates_data.merchant_name)
+    res_text = fill_in_template(templates_data.store_name)
     try:
         res_data = json.loads(res_text)
     except json.JSONDecodeError:
@@ -74,7 +75,8 @@ async def create_esign_templates(
         logger.error(f"fill_in_template missing fileDownloadUrl: {res_data}")
         return ErrorResponse(success=False, message="e签宝返回缺少 fileDownloadUrl", raw=res_data)
 
-    sign_data = create_by_file(file_id, file_name, templates_data.contact_phone, templates_data.merchant_name)
+    # sign_data = create_by_file(file_id, file_name, templates_data.contact_phone, templates_data.merchant_name)
+    sign_data = create_by_file(file_id, file_name, templates_data.contact_phone, templates_data.store_name, templates_data.merchant_name, templates_data.ord_id)
     try:
         sign_json = json.loads(sign_data)
     except json.JSONDecodeError:
@@ -194,17 +196,16 @@ async def esign_callback(
         except Exception:
             signing_dt = None
 
-    if sign_result == 2 and contact_phone and sign_flow_id:
+    if sign_result == 2:
         # 获取合同下载链接
         contract_download_url = None
         try:
             download_resp = file_download_url(sign_flow_id)
             download_json = json.loads(download_resp)
-            if download_json.get("data") and download_json["data"].get("url"):
-                contract_download_url = download_json["data"]["url"]
+            contract_download_url = download_json["data"]["files"][0]["downloadUrl"]
         except Exception as e:
             logger.error(f"file_download_url failed for sign_flow_id={sign_flow_id}: {e}")
-        
+        print(contract_download_url,666666666666666666666666666666)
         updated = await templates_server.mark_signed_by_phone(contact_phone, sign_flow_id, signing_dt, contract_download_url)
         logger.info(f"esign_callback success phone={contact_phone}, sign_flow_id={sign_flow_id}, updated={updated}")
         return SuccessResponse(code="200", msg="success")

+ 1 - 0
alien_store/db/models/contract_store.py

@@ -12,6 +12,7 @@ class ContractStore(Base, AuditMixin):
     __tablename__ = "store_contract"
     id: Mapped[int] = mapped_column(BigInteger, primary_key=True, autoincrement=True, comment="主键")
     store_id: Mapped[int] = mapped_column(BigInteger, comment="店铺id")
+    store_name: Mapped[str] = mapped_column(String(100), comment="商家店铺名称")
     business_segment: Mapped[str] = mapped_column(String(100), comment="经营板块")
     merchant_name: Mapped[str] = mapped_column(String(100), comment="商家姓名")
     contact_phone: Mapped[str] = mapped_column(String(20), comment="联系电话")

+ 7 - 1
alien_store/repositories/contract_repo.py

@@ -43,6 +43,7 @@ class ContractRepository:
         """创建未签署合同模板"""
         db_templates = ContractStore(
             store_id=user_data.store_id,
+            store_name=getattr(user_data, "store_name", None),
             merchant_name=user_data.merchant_name,
             business_segment=user_data.business_segment,
             contact_phone=user_data.contact_phone,
@@ -175,6 +176,7 @@ class ContractRepository:
         )
         rows = result.mappings().all()
         updated = False
+        store_name = getattr(templates_data, "store_name", None)
         if rows:
             for row in rows:
                 contract_url_raw = row.get("contract_url")
@@ -185,10 +187,13 @@ class ContractRepository:
                 if not isinstance(items, list):
                     items = []
                 items.append(contract_item)
+                update_values = {"contract_url": json.dumps(items, ensure_ascii=False)}
+                if store_name:
+                    update_values["store_name"] = store_name
                 await self.db.execute(
                     ContractStore.__table__.update()
                     .where(ContractStore.id == row["id"])
-                    .values(contract_url=json.dumps(items, ensure_ascii=False))
+                    .values(**update_values)
                 )
                 updated = True
             if updated:
@@ -197,6 +202,7 @@ class ContractRepository:
         # 未找到则创建新记录
         new_record = ContractStore(
             store_id=getattr(templates_data, "store_id", None),
+            store_name=store_name,
             business_segment=getattr(templates_data, "business_segment", None),
             merchant_name=getattr(templates_data, "merchant_name", None),
             contact_phone=contact_phone,

+ 2 - 0
alien_store/schemas/request/contract_store.py

@@ -5,11 +5,13 @@ from pydantic import BaseModel, EmailStr, Field, field_validator
 class TemplatesCreate(BaseModel):
     """模板创建请求模型"""
     store_id: int = Field(description="入驻店铺ID")
+    store_name: str = Field(description="商家店铺名称")
     business_segment: str = Field(description="入驻店铺经营板块")
     merchant_name: str = Field(description="商家姓名")
     contact_phone: str = Field(description="联系电话")
     contract_url: str | None = Field(default=None, description="合同下载地址,合同文件id,以及签署状态")
     seal_url: str | None = Field(default=None, description="印章文件地址")
+    ord_id: str = Field(description="企业用户的统一社会信用代码")
 
 class SignUrl(BaseModel):
     """签署合同页面请求模型"""

+ 5 - 0
alien_store/schemas/response/contract_store.py

@@ -22,6 +22,7 @@ class ContractStoreResponse(BaseModel):
     """合同记录响应模型"""
     id: int = Field(description="主键")
     store_id: int = Field(description="店铺id")
+    store_name: str = Field(description="商家店铺名称")
     business_segment: str = Field(description="经营板块")
     merchant_name: str = Field(description="商家姓名")
     contact_phone: str = Field(description="联系电话")
@@ -42,6 +43,7 @@ class ContractStoreDetailResponse(BaseModel):
     """合同记录详情响应模型(包含解析后的 contract_url)"""
     id: int = Field(description="主键")
     store_id: int = Field(description="店铺id")
+    store_name: str = Field(description="商家店铺名称")
     business_segment: str = Field(description="经营板块")
     merchant_name: str = Field(description="商家姓名")
     contact_phone: str = Field(description="联系电话")
@@ -107,3 +109,6 @@ class ModuleStatusResponse(BaseModel):
     module: str = Field(description="模块名称")
     status: str = Field(description="状态")
 
+
+
+

+ 3 - 0
alien_util/celery_app.py

@@ -32,3 +32,6 @@ celery_app.conf.update(
     },
 )
 
+
+
+

+ 167 - 81
common/esigntool/main.py

@@ -97,99 +97,185 @@ def fill_in_template(name):
     print(resp.text)
     return resp.text
 
-def create_by_file(file_id, file_name,  contact_phone, merchant_name):
+# def create_by_file(file_id, file_name,  contact_phone, merchant_name):
+#     """基于文件发起签署"""
+#     api_path = "/v3/sign-flow/create-by-file"
+#     method = "POST"
+#     body = {
+#         "docs": [
+#             {
+#                 "fileId": file_id,
+#                 "fileName": f"{file_name}.pdf"
+#             }
+#         ],
+#         "signFlowConfig": {
+#             "signFlowTitle": "商家入驻U店的签署协议", # 请设置当前签署任务的主题
+#             "autoFinish": True,
+#             "noticeConfig": {
+#                 "noticeTypes": "" #
+#                 # """通知类型,通知发起方、签署方、抄送方,默认不通知(值为""空字符串),允许多种通知方式,请使用英文逗号分隔
+#                 #
+#                 # "" - 不通知(默认值)
+#                 #
+#                 # 1 - 短信通知(如果套餐内带“分项”字样,请确保开通【电子签名流量费(分项)认证】中的子项:【短信服务】,否则短信通知收不到)
+#                 #
+#                 # 2 - 邮件通知
+#                 #
+#                 # 3 - 钉钉工作通知(需使用e签宝钉签产品)
+#                 #
+#                 # 5 - 微信通知(用户需关注“e签宝电子签名”微信公众号且使用过e签宝微信小程序)
+#                 #
+#                 # 6 - 企业微信通知(需要使用e签宝企微版产品)
+#                 #
+#                 # 7 - 飞书通知(需要使用e签宝飞书版产品)
+#                 #
+#                 # 补充说明:
+#                 #
+#                 # 1、2:个人账号中需要绑定短信/邮件才有对应的通知方式;
+#                 # 3、5、6、7:仅限e签宝正式环境调用才会有。"""
+#             },
+#             "notifyUrl": "http://120.26.186.130:33333:/api/store/esign/callback", # 接收相关回调通知的Web地址,
+#             "redirectConfig": {
+#                 "redirectUrl": "https://www.esign.cn/"
+#             }
+#         },
+#         "signers": [
+#             {
+#                 "signConfig": {
+#                     "signOrder": 1
+#                 },
+#                 "signerType": 1,
+#                 "signFields": [
+#                     {
+#                         "customBizNum": "9527", # 开发者自定义业务编号
+#                         "fileId": file_id,  #签署区所在待签署文件ID 【注】这里的fileId需先添加在docs数组中,否则会报错“参数错误: 文件id不在签署流程中”。
+#                         "normalSignFieldConfig": {
+#                             "autoSign": True,
+#                             "signFieldStyle": 1,
+#                             "signFieldPosition": {
+#                                 "positionPage": "7",
+#                                 "positionX": 294, # 获取需要盖章的位置: https://open.esign.cn/tools/seal-position
+#                                 "positionY": 668
+#                             }
+#                         }
+#                     }
+#                 ]
+#             },
+#             {
+#                 "psnSignerInfo": {
+#                     "psnAccount": contact_phone,
+#                     "psnInfo": {
+#                         "psnName": merchant_name
+#                     }
+#                 },
+#                 "signConfig": {
+#                     "forcedReadingTime": 10,
+#                     "signOrder": 2
+#                 },
+#                 "signerType": 0,
+#                 "signFields": [
+#                     {
+#                         "customBizNum": "9527",
+#                         "fileId": file_id,
+#                         "normalSignFieldConfig": {
+#                             "signFieldStyle": 1,
+#                             "signFieldPosition": {
+#                                 "positionPage": "7",
+#                                 "positionX": 114,  # 获取需要盖章的位置: https://open.esign.cn/tools/seal-position
+#                                 "positionY": 666
+#                             }
+#                         }
+#                     }
+#                 ]
+#             }
+#         ]
+#     }
+#     json_headers = buildSignJsonHeader(config.appId, config.scert, method, api_path, body=body)
+#     body_json = json.dumps(body, separators=(",", ":"), ensure_ascii=False)
+#     resp = requests.request(method, config.host + api_path, data=body_json, headers=json_headers)
+#     print(resp.text)
+#     return resp.text
+
+def create_by_file(file_id, file_name,  contact_phone, store_name, merchant_name, ord_id):
     """基于文件发起签署"""
     api_path = "/v3/sign-flow/create-by-file"
     method = "POST"
     body = {
-        "docs": [
-            {
-                "fileId": file_id,
-                "fileName": f"{file_name}.pdf"
-            }
-        ],
-        "signFlowConfig": {
-            "signFlowTitle": "商家入驻U店的签署协议", # 请设置当前签署任务的主题
-            "autoFinish": True,
-            "noticeConfig": {
-                "noticeTypes": "" #
-                # """通知类型,通知发起方、签署方、抄送方,默认不通知(值为""空字符串),允许多种通知方式,请使用英文逗号分隔
-                #
-                # "" - 不通知(默认值)
-                #
-                # 1 - 短信通知(如果套餐内带“分项”字样,请确保开通【电子签名流量费(分项)认证】中的子项:【短信服务】,否则短信通知收不到)
-                #
-                # 2 - 邮件通知
-                #
-                # 3 - 钉钉工作通知(需使用e签宝钉签产品)
-                #
-                # 5 - 微信通知(用户需关注“e签宝电子签名”微信公众号且使用过e签宝微信小程序)
-                #
-                # 6 - 企业微信通知(需要使用e签宝企微版产品)
-                #
-                # 7 - 飞书通知(需要使用e签宝飞书版产品)
-                #
-                # 补充说明:
-                #
-                # 1、2:个人账号中需要绑定短信/邮件才有对应的通知方式;
-                # 3、5、6、7:仅限e签宝正式环境调用才会有。"""
-            },
-            "notifyUrl": "http://120.26.186.130:33333:/api/store/esign/callback", # 接收相关回调通知的Web地址,
-            "redirectConfig": {
-                "redirectUrl": "https://www.esign.cn/"
-            }
+    "docs": [
+        {
+            "fileId": file_id,
+            "fileName": f"{file_name}.pdf"
+        }
+    ],
+    "signFlowConfig": {
+        "signFlowTitle": "商家入驻U店平台协议签署",
+        "autoFinish": True,
+        "noticeConfig": {
+            "noticeTypes": "1,2"
         },
-        "signers": [
-            {
-                "signConfig": {
-                    "signOrder": 1
-                },
-                "signerType": 1,
-                "signFields": [
-                    {
-                        "customBizNum": "9527", # 开发者自定义业务编号
-                        "fileId": file_id,  #签署区所在待签署文件ID 【注】这里的fileId需先添加在docs数组中,否则会报错“参数错误: 文件id不在签署流程中”。
-                        "normalSignFieldConfig": {
-                            "autoSign": True,
-                            "signFieldStyle": 1,
-                            "signFieldPosition": {
-                                "positionPage": "7",
-                                "positionX": 294, # 获取需要盖章的位置: https://open.esign.cn/tools/seal-position
-                                "positionY": 668
-                            }
+        "notifyUrl": "http://120.26.186.130:33333:/api/store/esign/callback",
+        "redirectConfig": {
+            "redirectUrl": "https://www.esign.cn/"
+        }
+    },
+    "signers": [
+        {
+            "signConfig": {
+                "signOrder": 1
+            },
+            "signerType": 1,
+            "signFields": [
+                {
+                    "customBizNum": "9527",
+                    "fileId": file_id,
+                    "normalSignFieldConfig": {
+                        "autoSign": True,
+                        "signFieldStyle": 1,
+                        "signFieldPosition": {
+                            "positionPage": "7",
+                            "positionX": 294,
+                            "positionY": 668
                         }
                     }
-                ]
-            },
-            {
-                "psnSignerInfo": {
+                }
+            ]
+        },
+        {
+            "orgSignerInfo": {
+                "orgName": store_name,
+                "orgInfo": {
+                    "orgIDCardNum": ord_id, # "91440300MADDW7XC4C"
+                    "orgIDCardType": "CRED_ORG_USCC"
+                },
+                "transactorInfo": {
                     "psnAccount": contact_phone,
                     "psnInfo": {
                         "psnName": merchant_name
                     }
-                },
-                "signConfig": {
-                    "forcedReadingTime": 10,
-                    "signOrder": 2
-                },
-                "signerType": 0,
-                "signFields": [
-                    {
-                        "customBizNum": "9527",
-                        "fileId": file_id,
-                        "normalSignFieldConfig": {
-                            "signFieldStyle": 1,
-                            "signFieldPosition": {
-                                "positionPage": "7",
-                                "positionX": 114,  # 获取需要盖章的位置: https://open.esign.cn/tools/seal-position
-                                "positionY": 666
-                            }
+                }
+            },
+            "signConfig": {
+                "forcedReadingTime": 10,
+                "signOrder": 2
+            },
+            "signerType": 1,
+            "signFields": [
+                {
+                    "customBizNum": "自定义编码001",
+                    "fileId": file_id,
+                    "normalSignFieldConfig": {
+                        "signFieldStyle": 1,
+                        "signFieldPosition": {
+                            "positionPage": "7",
+                            "positionX": 114,
+                            "positionY": 666
                         }
                     }
-                ]
-            }
-        ]
-    }
+                }
+            ]
+        }
+    ]
+}
     json_headers = buildSignJsonHeader(config.appId, config.scert, method, api_path, body=body)
     body_json = json.dumps(body, separators=(",", ":"), ensure_ascii=False)
     resp = requests.request(method, config.host + api_path, data=body_json, headers=json_headers)
@@ -232,4 +318,4 @@ def file_download_url(sign_flow_id):
 # sign_json  = json.loads(sing_data)
 # sing_id = sign_json["data"]["signFlowId"]
 # sign_url("", "13503301290")
-# file_download_url("56245b135f5546f39329cb2aea47a7d0")
+file_download_url("15156afb603e4145b112ad6eab0815d5")