263 lines
7.1 KiB
Go
263 lines
7.1 KiB
Go
package fadada
|
||
|
||
import (
|
||
"fmt"
|
||
"strings"
|
||
"time"
|
||
)
|
||
|
||
// FillTemplate 填写文档模板并生成合同文件(POST /doc-template/fill-values)
|
||
func (c *Client) FillTemplate(req *ContractFillRequest) (*ContractFileResult, error) {
|
||
if err := c.config.ValidateTemplateFields(); err != nil {
|
||
return nil, err
|
||
}
|
||
if err := validateContractFillRequest(req); err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
accessToken, err := c.ensureAccessToken()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
signDate := strings.TrimSpace(req.SignDate)
|
||
if signDate == "" {
|
||
signDate = time.Now().Format("2006年01月02日")
|
||
}
|
||
|
||
fileName := strings.TrimSpace(req.FileName)
|
||
if fileName == "" {
|
||
if c.config.Contract != nil && c.config.Contract.Name != "" {
|
||
fileName = c.config.Contract.Name
|
||
} else {
|
||
fileName = "海宇数据-合作协议"
|
||
}
|
||
fileName = fmt.Sprintf("%s-%s", fileName, strings.TrimSpace(req.AgreementNo))
|
||
}
|
||
|
||
fieldValues := c.BuildTemplateFieldValues(&ContractFillRequest{
|
||
AgreementNo: req.AgreementNo,
|
||
CompanyName: req.CompanyName,
|
||
UnifiedSocialCode: req.UnifiedSocialCode,
|
||
EnterpriseAddress: req.EnterpriseAddress,
|
||
AuthorizedRepName: req.AuthorizedRepName,
|
||
SignDate: signDate,
|
||
})
|
||
|
||
docFieldValues := make([]docFieldValue, 0, len(fieldValues))
|
||
for _, fv := range fieldValues {
|
||
docFieldValues = append(docFieldValues, docFieldValue{
|
||
FieldID: fv.FieldID,
|
||
FieldValue: fv.FieldValue,
|
||
})
|
||
}
|
||
|
||
res, err := c.http.PostBiz(pathFillDocTemplateValues, accessToken, &fillDocTemplateReq{
|
||
OwnerID: &openID{IDType: "corp", OpenID: c.config.OpenCorpID},
|
||
DocTemplateID: c.config.TemplateID,
|
||
FileName: fileName,
|
||
DocFieldValues: docFieldValues,
|
||
})
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
if res.Code != successCode {
|
||
return nil, fmt.Errorf("法大大填写模板失败: code=%s msg=%s requestId=%s", res.Code, res.Msg, res.RequestID)
|
||
}
|
||
|
||
var data fillDocTemplateData
|
||
if err := decodeData(res.Data, &data); err != nil {
|
||
return nil, fmt.Errorf("解析模板填单响应失败: %w", err)
|
||
}
|
||
if data.FileID == "" {
|
||
return nil, fmt.Errorf("法大大填写模板失败: fileId 为空 requestId=%s", res.RequestID)
|
||
}
|
||
|
||
return &ContractFileResult{
|
||
FileID: data.FileID,
|
||
FileDownloadURL: data.FileDownloadURL,
|
||
}, nil
|
||
}
|
||
|
||
// FillSignTaskFields 向已创建的签署任务填写控件(POST /sign-task/field/fill-values)
|
||
func (c *Client) FillSignTaskFields(signTaskID string, req *ContractFillRequest) error {
|
||
if strings.TrimSpace(signTaskID) == "" {
|
||
return fmt.Errorf("signTaskId 不能为空")
|
||
}
|
||
if err := c.config.ValidateTemplateFields(); err != nil {
|
||
return err
|
||
}
|
||
if err := validateContractFillRequest(req); err != nil {
|
||
return err
|
||
}
|
||
|
||
accessToken, err := c.ensureAccessToken()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
docID, err := c.resolveSignTaskDocID(signTaskID, accessToken)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
signDate := strings.TrimSpace(req.SignDate)
|
||
if signDate == "" {
|
||
signDate = time.Now().Format("2006年01月02日")
|
||
}
|
||
|
||
fieldValues := c.BuildTemplateFieldValues(&ContractFillRequest{
|
||
AgreementNo: req.AgreementNo,
|
||
CompanyName: req.CompanyName,
|
||
UnifiedSocialCode: req.UnifiedSocialCode,
|
||
EnterpriseAddress: req.EnterpriseAddress,
|
||
AuthorizedRepName: req.AuthorizedRepName,
|
||
SignDate: signDate,
|
||
})
|
||
|
||
docFieldValues := make([]docFieldValue, 0, len(fieldValues))
|
||
for _, fv := range fieldValues {
|
||
docFieldValues = append(docFieldValues, docFieldValue{
|
||
DocID: docID,
|
||
FieldDocID: docID,
|
||
FieldID: fv.FieldID,
|
||
FieldValue: fv.FieldValue,
|
||
})
|
||
}
|
||
|
||
res, err := c.http.PostBiz(pathFillSignTaskFieldValues, accessToken, &fillSignTaskFieldsReq{
|
||
SignTaskID: signTaskID,
|
||
DocFieldValues: docFieldValues,
|
||
})
|
||
if err != nil {
|
||
return err
|
||
}
|
||
if res.Code != successCode {
|
||
return fmt.Errorf("法大大签署任务填单失败: code=%s msg=%s requestId=%s", res.Code, res.Msg, res.RequestID)
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// resolveSignTaskDocID 解析签署任务文档 docId(填单必填)
|
||
func (c *Client) resolveSignTaskDocID(signTaskID, accessToken string) (string, error) {
|
||
if c.config != nil {
|
||
if id := strings.TrimSpace(c.config.TemplateDocID); id != "" {
|
||
return id, nil
|
||
}
|
||
}
|
||
|
||
res, err := c.http.PostBiz(pathGetSignTaskDetail, accessToken, &getSignTaskDetailReq{
|
||
SignTaskID: signTaskID,
|
||
})
|
||
if err != nil {
|
||
return "", fmt.Errorf("查询签署任务文档失败: %w", err)
|
||
}
|
||
if res.Code != successCode {
|
||
return "", fmt.Errorf("查询签署任务文档失败: code=%s msg=%s requestId=%s", res.Code, res.Msg, res.RequestID)
|
||
}
|
||
|
||
var data getSignTaskDetailData
|
||
if err := decodeData(res.Data, &data); err != nil {
|
||
return "", fmt.Errorf("解析签署任务文档失败: %w", err)
|
||
}
|
||
for _, d := range data.Docs {
|
||
if id := strings.TrimSpace(d.DocID); id != "" {
|
||
return id, nil
|
||
}
|
||
}
|
||
return "", fmt.Errorf("签署任务未返回 docId,请在配置 fadada.template_doc_id 中填写模板文档ID")
|
||
}
|
||
|
||
// BuildTemplateFieldValues 将业务字段映射为法大大控件编码/值
|
||
func (c *Client) BuildTemplateFieldValues(req *ContractFillRequest) []TemplateFieldValue {
|
||
fields := c.config.TemplateFields
|
||
if fields == nil || req == nil {
|
||
return nil
|
||
}
|
||
signDate := strings.TrimSpace(req.SignDate)
|
||
agreementNo := strings.TrimSpace(req.AgreementNo)
|
||
companyName := strings.TrimSpace(req.CompanyName)
|
||
|
||
pairs := make([]struct {
|
||
fieldID string
|
||
value string
|
||
}, 0, len(fields.AgreementNo)+len(fields.PartyAName)+6)
|
||
for _, id := range fields.AgreementNo {
|
||
id = strings.TrimSpace(id)
|
||
if id == "" {
|
||
continue
|
||
}
|
||
pairs = append(pairs, struct {
|
||
fieldID string
|
||
value string
|
||
}{id, agreementNo})
|
||
}
|
||
for _, id := range fields.PartyAName {
|
||
id = strings.TrimSpace(id)
|
||
if id == "" {
|
||
continue
|
||
}
|
||
pairs = append(pairs, struct {
|
||
fieldID string
|
||
value string
|
||
}{id, companyName})
|
||
}
|
||
pairs = append(pairs,
|
||
struct {
|
||
fieldID string
|
||
value string
|
||
}{fields.ContractDate, signDate},
|
||
struct {
|
||
fieldID string
|
||
value string
|
||
}{fields.PartyAUSCC, strings.TrimSpace(req.UnifiedSocialCode)},
|
||
struct {
|
||
fieldID string
|
||
value string
|
||
}{fields.PartyAAddress, strings.TrimSpace(req.EnterpriseAddress)},
|
||
struct {
|
||
fieldID string
|
||
value string
|
||
}{fields.PartyARep, strings.TrimSpace(req.AuthorizedRepName)},
|
||
struct {
|
||
fieldID string
|
||
value string
|
||
}{fields.PartyASignDate, signDate},
|
||
struct {
|
||
fieldID string
|
||
value string
|
||
}{fields.PartyBSignDate, signDate},
|
||
)
|
||
|
||
out := make([]TemplateFieldValue, 0, len(pairs))
|
||
for _, p := range pairs {
|
||
if p.fieldID == "" {
|
||
continue
|
||
}
|
||
out = append(out, TemplateFieldValue{
|
||
FieldID: p.fieldID,
|
||
FieldValue: p.value,
|
||
})
|
||
}
|
||
return out
|
||
}
|
||
|
||
func validateContractFillRequest(req *ContractFillRequest) error {
|
||
if req == nil {
|
||
return fmt.Errorf("合同填单请求不能为空")
|
||
}
|
||
if strings.TrimSpace(req.AgreementNo) == "" {
|
||
return fmt.Errorf("协议编号不能为空")
|
||
}
|
||
if strings.TrimSpace(req.CompanyName) == "" {
|
||
return fmt.Errorf("甲方企业名不能为空")
|
||
}
|
||
if strings.TrimSpace(req.UnifiedSocialCode) == "" {
|
||
return fmt.Errorf("甲方统一信用代码不能为空")
|
||
}
|
||
if strings.TrimSpace(req.AuthorizedRepName) == "" {
|
||
return fmt.Errorf("甲方授权代表不能为空")
|
||
}
|
||
return nil
|
||
}
|