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 }