218 lines
5.9 KiB
Go
218 lines
5.9 KiB
Go
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,
|
||
},
|
||
}
|
||
} |