205 lines
5.9 KiB
Go
205 lines
5.9 KiB
Go
|
|
package esign
|
|||
|
|
|
|||
|
|
import (
|
|||
|
|
"context"
|
|||
|
|
"encoding/json"
|
|||
|
|
"fmt"
|
|||
|
|
"strings"
|
|||
|
|
|
|||
|
|
"hyapi-server/internal/domains/certification/enums"
|
|||
|
|
"hyapi-server/internal/domains/certification/ports"
|
|||
|
|
sharedesign "hyapi-server/internal/shared/esign"
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
type Provider struct {
|
|||
|
|
client *sharedesign.Client
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func NewProvider(client *sharedesign.Client) *Provider {
|
|||
|
|
return &Provider{client: client}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (p *Provider) Platform() enums.SignPlatform {
|
|||
|
|
return enums.SignPlatformEsign
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (p *Provider) GenerateEnterpriseAuth(ctx context.Context, req *ports.EnterpriseAuthRequest) (*ports.AuthLinkResult, error) {
|
|||
|
|
_ = ctx
|
|||
|
|
res, err := p.client.GenerateEnterpriseAuth(&sharedesign.EnterpriseAuthRequest{
|
|||
|
|
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
|
|||
|
|
identity, err := p.client.QueryOrgIdentityInfo(&sharedesign.QueryOrgIdentityRequest{
|
|||
|
|
OrgName: req.OrgName,
|
|||
|
|
OrgIDCardNum: req.OrgIdentNo,
|
|||
|
|
})
|
|||
|
|
if err != nil {
|
|||
|
|
return false, err
|
|||
|
|
}
|
|||
|
|
return identity != nil && identity.Data.RealnameStatus == 1, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (p *Provider) GenerateContractFile(ctx context.Context, req *ports.ContractGenerateRequest) (*ports.ContractFileResult, error) {
|
|||
|
|
_ = ctx
|
|||
|
|
components := map[string]string{
|
|||
|
|
"jfqym": req.CompanyName,
|
|||
|
|
"jfqym2": req.CompanyName,
|
|||
|
|
"jfsqdb": req.AuthorizedRepName,
|
|||
|
|
"jftyshxydm": req.UnifiedSocialCode,
|
|||
|
|
"jflxdz": req.EnterpriseAddress,
|
|||
|
|
"xybh": req.AgreementNo,
|
|||
|
|
"qsrq1": req.SignDate,
|
|||
|
|
"qsrq3": req.SignDate,
|
|||
|
|
"qsrq2": req.SignDate,
|
|||
|
|
}
|
|||
|
|
res, err := p.client.FillTemplate(components)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
return &ports.ContractFileResult{
|
|||
|
|
FileID: res.FileID,
|
|||
|
|
FileDownloadURL: res.FileDownloadUrl,
|
|||
|
|
}, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (p *Provider) CreateSignFlow(ctx context.Context, req *ports.SignFlowCreateRequest) (*ports.SignFlowResult, error) {
|
|||
|
|
_ = ctx
|
|||
|
|
flowID, err := p.client.CreateSignFlow(&sharedesign.CreateSignFlowRequest{
|
|||
|
|
FileID: req.FileID,
|
|||
|
|
SignerAccount: req.PartyAUSCC,
|
|||
|
|
SignerName: req.PartyAName,
|
|||
|
|
TransactorPhone: req.TransactorMobile,
|
|||
|
|
TransactorName: req.TransactorName,
|
|||
|
|
TransactorIDCardNum: req.TransactorID,
|
|||
|
|
})
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
if req.SkipActorURL {
|
|||
|
|
return &ports.SignFlowResult{SignFlowID: flowID}, nil
|
|||
|
|
}
|
|||
|
|
longURL, shortURL, err := p.client.GetSignURL(flowID, req.TransactorMobile, req.PartyAName)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
return &ports.SignFlowResult{
|
|||
|
|
SignFlowID: flowID,
|
|||
|
|
SignURL: firstNonEmpty(longURL, shortURL),
|
|||
|
|
ShortURL: shortURL,
|
|||
|
|
}, 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 不能为空")
|
|||
|
|
}
|
|||
|
|
longURL, shortURL, err := p.client.GetSignURL(req.SignFlowID, req.TransactorMobile, req.PartyAName)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
return &ports.ActorSignURLResult{
|
|||
|
|
SignFlowID: req.SignFlowID,
|
|||
|
|
EmbedURL: firstNonEmpty(longURL, shortURL),
|
|||
|
|
ShortURL: shortURL,
|
|||
|
|
}, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (p *Provider) GetSignTaskPreviewURL(ctx context.Context, signFlowID string) (*ports.SignTaskPreviewURLResult, error) {
|
|||
|
|
_ = ctx
|
|||
|
|
// e签宝无独立预览接口:用已签/合同文件下载链作为预览源(前端用 PDF 打开)
|
|||
|
|
files, err := p.DownloadSignedFiles(ctx, signFlowID)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
if len(files) == 0 || strings.TrimSpace(files[0].DownloadURL) == "" {
|
|||
|
|
return nil, fmt.Errorf("未获取到可预览的合同文件")
|
|||
|
|
}
|
|||
|
|
return &ports.SignTaskPreviewURLResult{
|
|||
|
|
SignFlowID: signFlowID,
|
|||
|
|
PreviewURL: files[0].DownloadURL,
|
|||
|
|
}, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (p *Provider) QuerySignStatus(ctx context.Context, flowID string) (*ports.SignStatusResult, error) {
|
|||
|
|
_ = ctx
|
|||
|
|
detail, err := p.client.QuerySignFlowDetail(flowID)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
status := detail.Data.SignFlowStatus
|
|||
|
|
return &ports.SignStatusResult{
|
|||
|
|
SignFlowID: flowID,
|
|||
|
|
Status: fmt.Sprintf("%d", status),
|
|||
|
|
Completed: status == 2,
|
|||
|
|
Rejected: status == 7,
|
|||
|
|
Expired: status == 5,
|
|||
|
|
Message: detail.Data.SignFlowDescription,
|
|||
|
|
}, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (p *Provider) DownloadSignedFiles(ctx context.Context, flowID string) ([]*ports.SignedFile, error) {
|
|||
|
|
_ = ctx
|
|||
|
|
res, err := p.client.DownloadSignedFile(flowID)
|
|||
|
|
if err != nil {
|
|||
|
|
return nil, err
|
|||
|
|
}
|
|||
|
|
files := make([]*ports.SignedFile, 0, len(res.Data.Files))
|
|||
|
|
for _, f := range res.Data.Files {
|
|||
|
|
files = append(files, &ports.SignedFile{DownloadURL: f.DownloadUrl})
|
|||
|
|
}
|
|||
|
|
return files, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (p *Provider) VerifyCallback(ctx context.Context, headers map[string]string, body []byte) error {
|
|||
|
|
_ = ctx
|
|||
|
|
_ = headers
|
|||
|
|
_ = body
|
|||
|
|
// e签宝现有回调走独立验签逻辑,此处保持兼容(由原 HandleEsignCallback 处理)
|
|||
|
|
return nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func (p *Provider) ParseCallback(ctx context.Context, headers map[string]string, body []byte) (*ports.CallbackEvent, error) {
|
|||
|
|
_ = ctx
|
|||
|
|
_ = headers
|
|||
|
|
var raw map[string]interface{}
|
|||
|
|
_ = json.Unmarshal(body, &raw)
|
|||
|
|
action, _ := raw["action"].(string)
|
|||
|
|
ev := &ports.CallbackEvent{Event: action, Raw: raw}
|
|||
|
|
if action == "AUTH_PASS" {
|
|||
|
|
ev.AuthPassed = true
|
|||
|
|
}
|
|||
|
|
if action == "SIGN_FLOW_COMPLETE" || action == "SIGN_MISSON_COMPLETE" {
|
|||
|
|
ev.SignCompleted = true
|
|||
|
|
}
|
|||
|
|
return ev, nil
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
func firstNonEmpty(values ...string) string {
|
|||
|
|
for _, v := range values {
|
|||
|
|
if strings.TrimSpace(v) != "" {
|
|||
|
|
return v
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return ""
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
var _ ports.SignPlatformProvider = (*Provider)(nil)
|