Files
hyapi-server/internal/shared/fadada/corp_service.go

181 lines
5.4 KiB
Go
Raw Normal View History

2026-07-21 15:53:29 +08:00
package fadada
import (
"fmt"
"net/url"
"strings"
)
// 默认授权范围:认证信息 + 后续签署所需能力
var defaultAuthScopes = []string{
"ident_info",
"seal_info",
"signtask_info",
"signtask_init",
"signtask_file",
"organization",
"template",
}
// GenerateEnterpriseAuth 获取企业认证/授权链接POST /corp/get-auth-url
// 文档见 1.mdcorpIdentType 置空由用户在页面选择组织类型。
func (c *Client) GenerateEnterpriseAuth(req *EnterpriseAuthRequest) (*EnterpriseAuthResult, error) {
if err := validateEnterpriseAuthRequest(req); err != nil {
return nil, err
}
accessToken, err := c.ensureAccessToken()
if err != nil {
return nil, err
}
clientCorpID := strings.TrimSpace(req.ClientCorpID)
if clientCorpID == "" {
clientCorpID = strings.TrimSpace(req.UnifiedSocialCode)
}
clientUserID := strings.TrimSpace(req.ClientUserID)
if clientUserID == "" {
clientUserID = strings.TrimSpace(req.TransactorID)
}
redirectURL := ""
if c.config.Auth != nil {
redirectURL = c.config.Auth.RedirectURL
}
apiReq := &getCorpAuthURLReq{
ClientCorpID: clientCorpID,
ClientUserID: clientUserID,
AccountName: strings.TrimSpace(req.TransactorMobile),
CorpIdentInfo: &corpIdentInfo{
CorpName: strings.TrimSpace(req.CompanyName),
// 按官方文档:不传默认为企业;置空让用户在页面选择组织类型
// CorpIdentType: "",
CorpIdentNo: strings.TrimSpace(req.UnifiedSocialCode),
LegalRepName: strings.TrimSpace(req.LegalPersonName),
CorpIdentMethod: []string{CorpIdentMethodLegalRep},
},
// 文档合法值仅 corpName/corpIdentType/corpIdentNo不传表示都可修改
// CorpNonEditableInfo: ,
OprIdentInfo: &oprIdentInfo{
UserName: strings.TrimSpace(req.TransactorName),
UserIdentType: UserIdentTypeIDCard,
UserIdentNo: strings.TrimSpace(req.TransactorID),
Mobile: strings.TrimSpace(req.TransactorMobile),
OprIdentMethod: []string{OprIdentMethodMobile},
},
OprNonEditableInfo: nil,
AuthScopes: append([]string{}, defaultAuthScopes...),
RedirectURL: encodeRedirectURL(redirectURL),
}
res, err := c.http.PostBiz(pathGetCorpAuthURL, accessToken, apiReq)
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 getCorpAuthURLData
if err := decodeData(res.Data, &data); err != nil {
return nil, fmt.Errorf("解析企业认证链接响应失败: %w", err)
}
if data.AuthURL == "" {
return nil, fmt.Errorf("获取法大大企业认证链接失败: authUrl 为空 requestId=%s", res.RequestID)
}
return &EnterpriseAuthResult{
AuthFlowID: clientCorpID,
AuthURL: data.AuthURL,
AuthShortURL: data.AuthURL,
}, nil
}
// QueryOrgVerified 查询企业是否已在法大大完成实名POST /corp/get-identified-status
func (c *Client) QueryOrgVerified(req *QueryOrgIdentityRequest) (bool, error) {
result, err := c.QueryOrgIdentity(req)
if err != nil {
return false, err
}
return result.Identified, nil
}
// QueryOrgIdentity 查询企业实名认证状态详情
func (c *Client) QueryOrgIdentity(req *QueryOrgIdentityRequest) (*QueryOrgIdentityResult, error) {
if req == nil {
return nil, fmt.Errorf("查询请求不能为空")
}
corpName := strings.TrimSpace(req.CorpName)
corpIdentNo := strings.TrimSpace(req.CorpIdentNo)
if corpName == "" && corpIdentNo == "" {
return nil, fmt.Errorf("企业名称与统一社会信用代码不能同时为空")
}
accessToken, err := c.ensureAccessToken()
if err != nil {
return nil, err
}
res, err := c.http.PostBiz(pathGetCorpIdentifiedStatus, accessToken, &getIdentifiedStatusReq{
CorpName: corpName,
CorpIdentNo: corpIdentNo,
})
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 getIdentifiedStatusData
if err := decodeData(res.Data, &data); err != nil {
return nil, fmt.Errorf("解析企业实名状态失败: %w", err)
}
return &QueryOrgIdentityResult{
Identified: data.IdentStatus,
CorpName: corpName,
CorpIdentNo: corpIdentNo,
}, nil
}
func validateEnterpriseAuthRequest(req *EnterpriseAuthRequest) error {
if req == nil {
return fmt.Errorf("认证请求不能为空")
}
if strings.TrimSpace(req.CompanyName) == "" {
return fmt.Errorf("企业名称不能为空")
}
if strings.TrimSpace(req.UnifiedSocialCode) == "" {
return fmt.Errorf("统一社会信用代码不能为空")
}
if strings.TrimSpace(req.LegalPersonName) == "" {
return fmt.Errorf("法人姓名不能为空")
}
if strings.TrimSpace(req.TransactorName) == "" {
return fmt.Errorf("经办人姓名不能为空")
}
if strings.TrimSpace(req.TransactorMobile) == "" {
return fmt.Errorf("经办人手机号不能为空")
}
if strings.TrimSpace(req.TransactorID) == "" {
return fmt.Errorf("经办人身份证号不能为空")
}
return nil
}
// encodeRedirectURL 按官方文档对 redirectUrl 做 URL encode已编码则原样返回
func encodeRedirectURL(raw string) string {
raw = strings.TrimSpace(raw)
if raw == "" {
return ""
}
if strings.Contains(raw, "%") {
if decoded, err := url.QueryUnescape(raw); err == nil && decoded != raw {
return raw
}
}
return url.QueryEscape(raw)
}