This commit is contained in:
2026-07-22 12:16:27 +08:00
parent 5a56491740
commit ec2e336310
22 changed files with 955 additions and 28 deletions

View File

@@ -110,7 +110,7 @@ type signConfigInfo struct {
OrderNo int `json:"orderNo"`
JoinByLink bool `json:"joinByLink"`
RequestVerifyFree bool `json:"requestVerifyFree"`
FreeSignType string `json:"freeSignType,omitempty"` // template=按模板免验证签business=按场景码(需 businessId
FreeSignType string `json:"freeSignType,omitempty"` // template=按模板business=按场景码
FreeLogin bool `json:"freeLogin"`
BlockHere bool `json:"blockHere"`
}
@@ -125,7 +125,7 @@ type createSignTaskWithTemplateReq struct {
SignInOrder bool `json:"signInOrder,omitempty"`
ExpiresTime string `json:"expiresTime,omitempty"`
FreeSignType string `json:"freeSignType,omitempty"` // template按模板business按场景码
BusinessID string `json:"businessId,omitempty"` // 仅 freeSignType=business 时传场景码
BusinessID string `json:"businessId,omitempty"` // 免验证签场景码requestVerifyFree=true 时必传
TransReferenceID string `json:"transReferenceId,omitempty"`
Actors []signTaskActor `json:"actors"`
}

View File

@@ -47,7 +47,7 @@ type Config struct {
AppSecret string `json:"appSecret" yaml:"app_secret"`
ServerURL string `json:"serverUrl" yaml:"server_url"`
OpenCorpID string `json:"openCorpId" yaml:"open_corp_id"`
// NoAuthSceneCode 免验证签场景码;仅 freeSignType=business 时需要。当前按模板免验证签,可留空
// NoAuthSceneCode 免验证签场景码businessIdrequestVerifyFree=true 时必传
NoAuthSceneCode string `json:"noAuthSceneCode" yaml:"no_auth_scene_code"`
TemplateID string `json:"templateId" yaml:"template_id"`
// PartyAActorID / PartyBActorID 签署模板中的参与方标识actorId须与模板角色名一致

View File

@@ -10,7 +10,7 @@ import (
// CreateSignFlow 基于签署任务模板创建签署任务POST /sign-task/create-with-template
// - autoStart无填单时创建即自动提交有填单时创建后填控件再 Start完成自动提交
// - 签署顺序:甲方 orderNo=1 先签(短信/验证);乙方 orderNo=2 后签,由系统按模板免验证签自动盖章
// - 乙方参与方开启免验证签requestVerifyFree + freeSignType=template
// - 乙方参与方开启免验证签requestVerifyFree=true + freeSignType=templaterequestVerifyFree 时 businessId 必传
func (c *Client) CreateSignFlow(req *CreateSignFlowRequest) (*CreateSignFlowResult, error) {
if err := validateCreateSignFlowRequest(req); err != nil {
return nil, err
@@ -31,6 +31,11 @@ func (c *Client) CreateSignFlow(req *CreateSignFlowRequest) (*CreateSignFlowResu
// 有填单须先填再提交,创建时不能 autoStart无填单则创建时自动提交
autoStart := !needFill
businessID, err := c.resolveBusinessID()
if err != nil {
return nil, err
}
subject := strings.TrimSpace(req.Subject)
if subject == "" {
if c.config.Contract != nil && c.config.Contract.Name != "" {
@@ -55,7 +60,8 @@ func (c *Client) CreateSignFlow(req *CreateSignFlowRequest) (*CreateSignFlowResu
AutoFinish: true,
SignInOrder: true,
ExpiresTime: expiresTime,
FreeSignType: freeSignTypeTemplate, // 按模板免验证签,无需 businessId
FreeSignType: freeSignTypeTemplate, // 按模板免验证签
BusinessID: businessID, // requestVerifyFree=true 时必传场景码
TransReferenceID: strings.TrimSpace(req.TransReferenceID),
Actors: actors,
})
@@ -338,7 +344,19 @@ func (c *Client) GenerateContractSigning(req *ContractSigningRequest) (*Contract
}, nil
}
const freeSignTypeTemplate = "template" // 根据模板免验证签(无需 businessId
const freeSignTypeTemplate = "template" // 根据模板免验证签requestVerifyFree 时仍须传 businessId
// resolveBusinessID 免验证签场景码requestVerifyFree=true 时 businessId 必传)
func (c *Client) resolveBusinessID() (string, error) {
if c.config == nil {
return "", fmt.Errorf("法大大配置为空")
}
businessID := strings.TrimSpace(c.config.NoAuthSceneCode)
if businessID == "" {
return "", fmt.Errorf("法大大 no_auth_scene_code免验证签场景码不能为空requestVerifyFree 时 businessId 必传")
}
return businessID, nil
}
func (c *Client) buildSignActors(req *CreateSignFlowRequest) []signTaskActor {
partyAActorID := c.config.ResolvePartyAActorID()
@@ -366,7 +384,7 @@ func (c *Client) buildSignActors(req *CreateSignFlowRequest) []signTaskActor {
},
}
// 乙方(平台)后签 OrderNo=2甲方签完后由系统按模板免验证签自动盖章
// 乙方(平台)后签 OrderNo=2甲方签完后由系统按模板免验证签自动盖章(任务级传 businessId
partyB := signTaskActor{
Actor: &actor{
ActorType: "corp",

View File

@@ -19,11 +19,12 @@ func TestIsSignTaskCompletedStatus(t *testing.T) {
func TestBuildSignActors(t *testing.T) {
c := NewClient(&Config{
AppID: "app",
AppSecret: "secret",
ServerURL: "https://uat-api.fadada.com/api/v5/",
OpenCorpID: "haiyu-open-corp",
TemplateID: "tpl",
AppID: "app",
AppSecret: "secret",
ServerURL: "https://uat-api.fadada.com/api/v5/",
OpenCorpID: "haiyu-open-corp",
NoAuthSceneCode: "scene-code",
TemplateID: "tpl",
})
actors := c.buildSignActors(&CreateSignFlowRequest{
PartyAOpenCorpID: "client-open-corp",
@@ -45,6 +46,10 @@ func TestBuildSignActors(t *testing.T) {
if actors[1].SignConfigInfo.FreeSignType != freeSignTypeTemplate {
t.Fatalf("party B freeSignType=%q, want %s", actors[1].SignConfigInfo.FreeSignType, freeSignTypeTemplate)
}
businessID, err := c.resolveBusinessID()
if err != nil || businessID != "scene-code" {
t.Fatalf("businessId=%q err=%v, want scene-code", businessID, err)
}
if actors[0].Actor.ActorID == "party_a" || actors[1].Actor.ActorID == "party_b" {
t.Fatal("actorId must match sign-template role names, not party_a/party_b")
}