2026-07-27 00:03:07 +08:00
|
|
|
|
package fadada
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"errors"
|
|
|
|
|
|
"fmt"
|
|
|
|
|
|
"regexp"
|
|
|
|
|
|
"strings"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// 法大大 FASC OpenAPI 错误码(以官方「错误码说明」文档 code 为准,勿依赖 msg 文案)。
|
|
|
|
|
|
// 文档:https://dev.fadada.com/api-doc/JOQQIJXLFL/H4F0HSKMHQ3HPIIM/5-1
|
|
|
|
|
|
const (
|
|
|
|
|
|
CodeSuccess = "100000" // 请求成功
|
|
|
|
|
|
|
|
|
|
|
|
// 公共
|
|
|
|
|
|
CodeUnknownException = "100001" // 不可预知异常
|
|
|
|
|
|
CodeAccessTokenInvalid = "100002" // 访问凭证失效
|
|
|
|
|
|
CodeSignInvalid = "100003" // 接口签名错误
|
|
|
|
|
|
CodeTooFrequent = "100004" // 请求频繁
|
|
|
|
|
|
CodeParamIllegal = "100011" // 请求参数非法
|
|
|
|
|
|
CodeParamEmpty = "100012" // 请求参数为空
|
|
|
|
|
|
CodeBusinessIDNotFound = "212007" // 业务场景标识不存在
|
|
|
|
|
|
|
2026-07-27 00:18:02 +08:00
|
|
|
|
// get-auth-url 返回「授权范围重复获取」时可用作兜底(非正式查授权接口)
|
|
|
|
|
|
// 正式查授权请用 POST /corp/get 的 bindingStatus
|
2026-07-27 00:03:07 +08:00
|
|
|
|
CodeAuthScopeDuplicate = "210002" // 授权范围重复获取
|
|
|
|
|
|
CodeAuthScopeDuplicateCorp = "210013" // 授权范围重复获取(无须重复获取授权申请链接)
|
2026-07-27 00:18:02 +08:00
|
|
|
|
CodeCorpNotFound = "210032" // 企业用户不存在
|
2026-07-27 00:03:07 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// APIError 法大大业务错误(按 code 判断,不依赖 msg)
|
|
|
|
|
|
type APIError struct {
|
|
|
|
|
|
Op string // 调用场景说明
|
|
|
|
|
|
Code string
|
|
|
|
|
|
Msg string
|
|
|
|
|
|
RequestID string
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (e *APIError) Error() string {
|
|
|
|
|
|
if e == nil {
|
|
|
|
|
|
return ""
|
|
|
|
|
|
}
|
|
|
|
|
|
op := strings.TrimSpace(e.Op)
|
|
|
|
|
|
if op == "" {
|
|
|
|
|
|
op = "法大大接口调用失败"
|
|
|
|
|
|
}
|
|
|
|
|
|
return fmt.Sprintf("%s: code=%s msg=%s requestId=%s", op, e.Code, e.Msg, e.RequestID)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// NewAPIError 构造结构化业务错误
|
|
|
|
|
|
func NewAPIError(op, code, msg, requestID string) *APIError {
|
|
|
|
|
|
return &APIError{
|
|
|
|
|
|
Op: strings.TrimSpace(op),
|
|
|
|
|
|
Code: strings.TrimSpace(code),
|
|
|
|
|
|
Msg: strings.TrimSpace(msg),
|
|
|
|
|
|
RequestID: strings.TrimSpace(requestID),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-07-27 00:18:02 +08:00
|
|
|
|
// IsAuthAlreadyGranted 是否为 get-auth-url「授权范围重复获取」错误码(210002/210013)。
|
|
|
|
|
|
// 注意:正式判断是否已授权应调用 POST /corp/get(bindingStatus=authorized);
|
|
|
|
|
|
// 本函数仅作取链失败时的兜底。
|
2026-07-27 00:03:07 +08:00
|
|
|
|
func IsAuthAlreadyGranted(err error) bool {
|
|
|
|
|
|
if err == nil {
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
var apiErr *APIError
|
|
|
|
|
|
if errors.As(err, &apiErr) && apiErr != nil {
|
|
|
|
|
|
return isAuthAlreadyGrantedCode(apiErr.Code)
|
|
|
|
|
|
}
|
|
|
|
|
|
return isAuthAlreadyGrantedCode(extractFadadaCode(err.Error()))
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func isAuthAlreadyGrantedCode(code string) bool {
|
|
|
|
|
|
switch strings.TrimSpace(code) {
|
|
|
|
|
|
case CodeAuthScopeDuplicate, CodeAuthScopeDuplicateCorp:
|
|
|
|
|
|
return true
|
|
|
|
|
|
default:
|
|
|
|
|
|
return false
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var fadadaCodeRe = regexp.MustCompile(`(?i)(?:^|[^\d])code\s*=\s*(\d{6})(?:[^\d]|$)`)
|
|
|
|
|
|
|
|
|
|
|
|
func extractFadadaCode(msg string) string {
|
|
|
|
|
|
m := fadadaCodeRe.FindStringSubmatch(msg)
|
|
|
|
|
|
if len(m) < 2 {
|
|
|
|
|
|
return ""
|
|
|
|
|
|
}
|
|
|
|
|
|
return m[1]
|
|
|
|
|
|
}
|