Files
hyapi-server/internal/infrastructure/external/fadada/fadada_provider.go
2026-07-21 15:53:29 +08:00

248 lines
7.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package fadada
import (
"context"
"fmt"
"net/url"
"strings"
"hyapi-server/internal/domains/certification/enums"
"hyapi-server/internal/domains/certification/ports"
sharedfadada "hyapi-server/internal/shared/fadada"
)
type Provider struct {
client *sharedfadada.Client
}
func NewProvider(client *sharedfadada.Client) *Provider {
return &Provider{client: client}
}
func (p *Provider) Platform() enums.SignPlatform {
return enums.SignPlatformFadada
}
func (p *Provider) GenerateEnterpriseAuth(ctx context.Context, req *ports.EnterpriseAuthRequest) (*ports.AuthLinkResult, error) {
_ = ctx
res, err := p.client.GenerateEnterpriseAuth(&sharedfadada.EnterpriseAuthRequest{
ClientCorpID: req.ClientCorpID,
ClientUserID: req.ClientUserID,
CompanyName: req.CompanyName,
UnifiedSocialCode: req.UnifiedSocialCode,
LegalPersonName: req.LegalPersonName,
LegalPersonID: req.LegalPersonID,
TransactorName: req.TransactorName,
TransactorMobile: req.TransactorMobile,
TransactorID: req.TransactorID,
})
if err != nil {
return nil, err
}
return &ports.AuthLinkResult{
AuthFlowID: res.AuthFlowID,
AuthURL: res.AuthURL,
AuthShortURL: firstNonEmpty(res.AuthShortURL, res.AuthURL),
}, nil
}
func (p *Provider) QueryOrgVerified(ctx context.Context, req *ports.OrgIdentityQuery) (bool, error) {
_ = ctx
return p.client.QueryOrgVerified(&sharedfadada.QueryOrgIdentityRequest{
CorpName: req.OrgName,
CorpIdentNo: req.OrgIdentNo,
})
}
// GenerateContractFile 法大大走签署任务模板(/sign-task/create-with-template
// 此处返回空结果,实际填单由 CreateSignFlow 通过 /sign-task/field/fill-values 完成。
func (p *Provider) GenerateContractFile(ctx context.Context, req *ports.ContractGenerateRequest) (*ports.ContractFileResult, error) {
_ = ctx
_ = req
return &ports.ContractFileResult{FileID: "", FileDownloadURL: ""}, nil
}
func (p *Provider) CreateSignFlow(ctx context.Context, req *ports.SignFlowCreateRequest) (*ports.SignFlowResult, error) {
_ = ctx
createReq := &sharedfadada.CreateSignFlowRequest{
Subject: req.Subject,
PartyAOpenCorpID: req.PartyAOpenCorpID,
PartyAName: req.PartyAName,
PartyAUSCC: req.PartyAUSCC,
TransactorName: req.TransactorName,
TransactorMobile: req.TransactorMobile,
TransactorID: req.TransactorID,
TransReferenceID: req.TransReferenceID,
}
if req.Fill != nil {
createReq.Fill = &sharedfadada.ContractFillRequest{
AgreementNo: req.Fill.AgreementNo,
CompanyName: req.Fill.CompanyName,
UnifiedSocialCode: req.Fill.UnifiedSocialCode,
EnterpriseAddress: req.Fill.EnterpriseAddress,
AuthorizedRepName: req.Fill.AuthorizedRepName,
SignDate: req.Fill.SignDate,
FileName: req.Fill.FileName,
}
} else {
// 签署模板创建必须填控件
createReq.Fill = &sharedfadada.ContractFillRequest{
CompanyName: req.PartyAName,
UnifiedSocialCode: req.PartyAUSCC,
AuthorizedRepName: req.TransactorName,
}
}
createRes, err := p.client.CreateSignFlow(createReq)
if err != nil {
return nil, err
}
if req.SkipActorURL {
return &ports.SignFlowResult{
SignFlowID: createRes.SignTaskID,
}, nil
}
urlRes, err := p.client.GetSignURL(createRes.SignTaskID, sharedfadada.ActorIDPartyA)
if err != nil {
return nil, err
}
embedURL := strings.TrimSpace(urlRes.EmbedURL)
if embedURL == "" {
return nil, fmt.Errorf("法大大未返回可嵌入签署链接 actorSignTaskEmbedUrl")
}
return &ports.SignFlowResult{
SignFlowID: createRes.SignTaskID,
SignURL: embedURL,
ShortURL: strings.TrimSpace(urlRes.SignURL),
}, nil
}
func (p *Provider) GetActorSignURL(ctx context.Context, req *ports.GetActorSignURLRequest) (*ports.ActorSignURLResult, error) {
_ = ctx
if req == nil || strings.TrimSpace(req.SignFlowID) == "" {
return nil, fmt.Errorf("signFlowId 不能为空")
}
urlRes, err := p.client.GetSignURL(strings.TrimSpace(req.SignFlowID), sharedfadada.ActorIDPartyA)
if err != nil {
return nil, err
}
embedURL := strings.TrimSpace(urlRes.EmbedURL)
if embedURL == "" {
return nil, fmt.Errorf("法大大未返回可嵌入签署链接 actorSignTaskEmbedUrl")
}
return &ports.ActorSignURLResult{
SignFlowID: req.SignFlowID,
EmbedURL: embedURL,
ShortURL: strings.TrimSpace(urlRes.SignURL),
}, nil
}
func (p *Provider) GetSignTaskPreviewURL(ctx context.Context, signFlowID string) (*ports.SignTaskPreviewURLResult, error) {
_ = ctx
signFlowID = strings.TrimSpace(signFlowID)
if signFlowID == "" {
return nil, fmt.Errorf("signFlowId 不能为空")
}
res, err := p.client.GetSignTaskPreviewURL(signFlowID)
if err != nil {
return nil, err
}
return &ports.SignTaskPreviewURLResult{
SignFlowID: signFlowID,
PreviewURL: res.PreviewURL,
}, nil
}
func (p *Provider) QuerySignStatus(ctx context.Context, flowID string) (*ports.SignStatusResult, error) {
_ = ctx
st, err := p.client.QuerySignStatus(flowID)
if err != nil {
return nil, err
}
return &ports.SignStatusResult{
SignFlowID: flowID,
Status: st.SignTaskStatus,
Completed: st.Completed,
Rejected: st.Terminated,
Expired: false,
Message: firstNonEmpty(st.TerminationNote, st.RevokeReason),
}, nil
}
func (p *Provider) DownloadSignedFiles(ctx context.Context, flowID string) ([]*ports.SignedFile, error) {
_ = ctx
res, err := p.client.DownloadSignedFiles(flowID)
if err != nil {
return nil, err
}
files := make([]*ports.SignedFile, 0, len(res.Files))
for _, f := range res.Files {
files = append(files, &ports.SignedFile{
DownloadURL: f.DownloadURL,
DownloadID: f.DownloadID,
})
}
return files, nil
}
func (p *Provider) VerifyCallback(ctx context.Context, headers map[string]string, body []byte) error {
_ = ctx
bizContent := extractBizContent(body)
return p.client.VerifyCallback(headers, bizContent)
}
func (p *Provider) ParseCallback(ctx context.Context, headers map[string]string, body []byte) (*ports.CallbackEvent, error) {
_ = ctx
bizContent := extractBizContent(body)
ev, err := p.client.ParseCallback(headers, bizContent)
if err != nil {
return nil, err
}
out := &ports.CallbackEvent{
Event: ev.Event,
SignFlowID: ev.SignTaskID,
AuthFlowID: firstNonEmpty(ev.ClientCorpID, ev.OpenCorpID),
Raw: ev.Raw,
}
if ev.IsSignCompletedCallback() {
out.SignCompleted = true
}
// 企业授权/认证成功事件
switch strings.ToLower(ev.Event) {
case "corp-authorize", "corp-authorize-success", "corporation_authorize", "auth-pass":
out.AuthPassed = true
}
if strings.EqualFold(ev.AuthResult, "success") || strings.EqualFold(ev.AuthResult, "pass") {
out.AuthPassed = true
}
return out, nil
}
func extractBizContent(body []byte) string {
raw := strings.TrimSpace(string(body))
if raw == "" {
return ""
}
if strings.HasPrefix(raw, "{") {
return raw
}
values, err := url.ParseQuery(raw)
if err == nil {
if v := values.Get("bizContent"); v != "" {
return v
}
}
return raw
}
func firstNonEmpty(values ...string) string {
for _, v := range values {
if strings.TrimSpace(v) != "" {
return v
}
}
return ""
}
var _ ports.SignPlatformProvider = (*Provider)(nil)