Files
tyapi-server/internal/shared/esign/signflow_service.go

219 lines
6.0 KiB
Go
Raw Normal View History

2025-07-20 20:53:26 +08:00
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,
2025-07-28 01:46:39 +08:00
FileName: s.config.Contract.Name,
2025-07-20 20:53:26 +08:00
},
},
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{
2025-07-28 01:46:39 +08:00
PositionPage: "8",
2025-07-20 20:53:26 +08:00
PositionX: 200,
2025-07-28 01:46:39 +08:00
PositionY: 430,
2025-07-20 20:53:26 +08:00
},
},
},
},
}
}
// 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{
2025-07-28 01:46:39 +08:00
PositionPage: "8",
PositionX: 450,
PositionY: 430,
2025-07-20 20:53:26 +08:00
},
2025-07-28 22:35:13 +08:00
OrgSealBizTypes: "PUBLIC",
2025-07-20 20:53:26 +08:00
},
},
},
}
}
// buildSignFlowConfig 构建签署流程配置
func (s *SignFlowService) buildSignFlowConfig() SignFlowConfig {
return SignFlowConfig{
2025-07-28 01:46:39 +08:00
SignFlowTitle: s.config.Contract.Name,
SignFlowExpireTime: calculateExpireTime(s.config.Contract.ExpireDays),
AutoFinish: s.config.Sign.AutoFinish,
2025-07-20 20:53:26 +08:00
AuthConfig: &AuthConfig{
PsnAvailableAuthModes: []string{AuthModeMobile3},
WillingnessAuthModes: []string{WillingnessAuthSMS},
},
ContractConfig: &ContractConfig{
AllowToRescind: false,
},
2025-07-28 01:46:39 +08:00
RedirectConfig: &RedirectConfig{
RedirectUrl: s.config.Sign.RedirectUrl,
},
2025-07-20 20:53:26 +08:00
}
}