219 lines
		
	
	
		
			6.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			219 lines
		
	
	
		
			6.0 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,
 | ||
| 					},
 | ||
| 					OrgSealBizTypes: "PUBLIC",
 | ||
| 				},
 | ||
| 			},
 | ||
| 		},
 | ||
| 	}
 | ||
| }
 | ||
| 
 | ||
| // 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,
 | ||
| 		},
 | ||
| 	}
 | ||
| }  |