Files
tyapi-server/internal/shared/esign/signflow_service.go
2025-07-28 01:46:39 +08:00

218 lines
5.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package esign
import (
"fmt"
)
// SignFlowService 签署流程服务
// 处理签署流程创建、链接获取等操作
type SignFlowService struct {
httpClient *HTTPClient
config *Config
}
// NewSignFlowService 创建签署流程服务
func NewSignFlowService(httpClient *HTTPClient, config *Config) *SignFlowService {
return &SignFlowService{
httpClient: httpClient,
config: config,
}
}
// UpdateConfig 更新配置
func (s *SignFlowService) UpdateConfig(config *Config) {
s.config = config
}
// Create 创建签署流程
// 创建包含多个签署人的签署流程,支持自动盖章和手动签署
func (s *SignFlowService) Create(req *CreateSignFlowRequest) (string, error) {
fmt.Println("开始创建签署流程...")
fmt.Println("(将创建包含甲方自动盖章和乙方手动签署的流程)")
// 构建甲方签署人信息(自动盖章)
partyASigner := s.buildPartyASigner(req.FileID)
// 构建乙方签署人信息(手动签署)
partyBSigner := s.buildPartyBSigner(req.FileID, req.SignerAccount, req.SignerName, req.TransactorPhone, req.TransactorName, req.TransactorIDCardNum)
signers := []SignerInfo{partyASigner, partyBSigner}
// 构建请求数据
requestData := CreateSignFlowByFileRequest{
Docs: []DocInfo{
{
FileId: req.FileID,
FileName: s.config.Contract.Name,
},
},
SignFlowConfig: s.buildSignFlowConfig(),
Signers: signers,
}
// 序列化请求数据
jsonData, err := MarshalRequest(requestData)
if err != nil {
return "", err
}
fmt.Printf("发起签署请求数据: %s\n", string(jsonData))
// 发送API请求
responseBody, err := s.httpClient.Request("POST", "/v3/sign-flow/create-by-file", jsonData)
if err != nil {
return "", fmt.Errorf("发起签署失败: %v", err)
}
// 解析响应
var response CreateSignFlowByFileResponse
if err := UnmarshalResponse(responseBody, &response); err != nil {
return "", err
}
if err := CheckResponseCode(response.Code, response.Message); err != nil {
return "", err
}
fmt.Printf("签署流程创建成功流程ID: %s\n", response.Data.SignFlowId)
return response.Data.SignFlowId, nil
}
// GetSignURL 获取签署页面链接
// 为指定的签署人获取签署页面链接
func (s *SignFlowService) GetSignURL(signFlowID, psnAccount, orgName string) (string, string, error) {
fmt.Println("开始获取签署页面链接...")
// 构建请求数据
requestData := GetSignUrlRequest{
NeedLogin: false,
UrlType: UrlTypeSign,
Operator: &Operator{
PsnAccount: psnAccount,
},
Organization: &Organization{
OrgName: orgName,
},
ClientType: ClientTypeAll,
}
// 序列化请求数据
jsonData, err := MarshalRequest(requestData)
if err != nil {
return "", "", err
}
fmt.Printf("获取签署页面链接请求数据: %s\n", string(jsonData))
// 发送API请求
urlPath := fmt.Sprintf("/v3/sign-flow/%s/sign-url", signFlowID)
responseBody, err := s.httpClient.Request("POST", urlPath, jsonData)
if err != nil {
return "", "", fmt.Errorf("获取签署页面链接失败: %v", err)
}
// 解析响应
var response GetSignUrlResponse
if err := UnmarshalResponse(responseBody, &response); err != nil {
return "", "", err
}
if err := CheckResponseCode(response.Code, response.Message); err != nil {
return "", "", err
}
fmt.Printf("签署页面链接获取成功!\n")
fmt.Printf("完整链接: %s\n", response.Data.Url)
fmt.Printf("短链接: %s\n", response.Data.ShortUrl)
return response.Data.Url, response.Data.ShortUrl, nil
}
// buildPartyASigner 构建甲方签署人信息(自动盖章)
func (s *SignFlowService) buildPartyASigner(fileID string) SignerInfo {
return SignerInfo{
SignConfig: &SignConfig{SignOrder: 1},
SignerType: SignerTypeOrg,
SignFields: []SignField{
{
CustomBizNum: "甲方签章",
FileId: fileID,
NormalSignFieldConfig: &NormalSignFieldConfig{
AutoSign: true,
SignFieldStyle: SignFieldStyleNormal,
SignFieldPosition: &SignFieldPosition{
PositionPage: "8",
PositionX: 200,
PositionY: 430,
},
},
},
},
}
}
// buildPartyBSigner 构建乙方签署人信息(手动签署)
func (s *SignFlowService) buildPartyBSigner(fileID, signerAccount, signerName, transactorPhone, transactorName, transactorIDCardNum string) SignerInfo {
return SignerInfo{
SignConfig: &SignConfig{
SignOrder: 2,
},
AuthConfig: &AuthConfig{
PsnAvailableAuthModes: []string{AuthModeMobile3},
WillingnessAuthModes: []string{WillingnessAuthSMS},
},
SignerType: SignerTypeOrg,
OrgSignerInfo: &OrgSignerInfo{
OrgName: signerName,
OrgInfo: &OrgInfo{
LegalRepName: transactorName,
LegalRepIDCardNum: transactorIDCardNum,
LegalRepIDCardType: IDCardTypeChina,
OrgIDCardNum: signerAccount,
OrgIDCardType: OrgCardTypeUSCC,
},
TransactorInfo: &TransactorInfo{
PsnAccount: transactorPhone,
PsnInfo: &PsnInfo{
PsnName: transactorName,
PsnIDCardNum: transactorIDCardNum,
PsnIDCardType: IDCardTypeChina,
},
},
},
SignFields: []SignField{
{
CustomBizNum: "乙方签章",
FileId: fileID,
NormalSignFieldConfig: &NormalSignFieldConfig{
AutoSign: false,
SignFieldStyle: SignFieldStyleNormal,
SignFieldPosition: &SignFieldPosition{
PositionPage: "8",
PositionX: 450,
PositionY: 430,
},
},
},
},
}
}
// buildSignFlowConfig 构建签署流程配置
func (s *SignFlowService) buildSignFlowConfig() SignFlowConfig {
return SignFlowConfig{
SignFlowTitle: s.config.Contract.Name,
SignFlowExpireTime: calculateExpireTime(s.config.Contract.ExpireDays),
AutoFinish: s.config.Sign.AutoFinish,
AuthConfig: &AuthConfig{
PsnAvailableAuthModes: []string{AuthModeMobile3},
WillingnessAuthModes: []string{WillingnessAuthSMS},
},
ContractConfig: &ContractConfig{
AllowToRescind: false,
},
RedirectConfig: &RedirectConfig{
RedirectUrl: s.config.Sign.RedirectUrl,
},
}
}