f
This commit is contained in:
@@ -2,7 +2,10 @@ package certification
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"hyapi-server/internal/shared/fadada"
|
||||
)
|
||||
|
||||
func TestIsEnterpriseAlreadyAuthorizedErr(t *testing.T) {
|
||||
@@ -12,18 +15,38 @@ func TestIsEnterpriseAlreadyAuthorizedErr(t *testing.T) {
|
||||
want bool
|
||||
}{
|
||||
{
|
||||
name: "fadada 210002",
|
||||
name: "structured 210002",
|
||||
err: fadada.NewAPIError("获取法大大企业认证链接失败", fadada.CodeAuthScopeDuplicate, "授权范围重复获取", "abc"),
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "structured 210013",
|
||||
err: fadada.NewAPIError("获取法大大企业认证链接失败", fadada.CodeAuthScopeDuplicateCorp, "授权范围重复获取", "def"),
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "legacy string 210002",
|
||||
err: errors.New("获取法大大企业认证链接失败: code=210002 msg=该企业已授权,无需重复操作 requestId=abc"),
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "exist authorize wording",
|
||||
err: errors.New("当前应用已存在授权"),
|
||||
name: "legacy string 210013",
|
||||
err: errors.New("获取法大大企业认证链接失败: code=210013 msg=授权范围重复获取 requestId=xyz"),
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "other error",
|
||||
err: errors.New("获取法大大企业认证链接失败: code=100011 msg=参数错误"),
|
||||
name: "wrapped structured 210002",
|
||||
err: fmt.Errorf("生成企业认证链接失败: %w", fadada.NewAPIError("获取法大大企业认证链接失败", fadada.CodeAuthScopeDuplicate, "授权范围重复获取", "rid")),
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "msg only should not match",
|
||||
err: errors.New("当前应用已存在授权"),
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "other error 100011",
|
||||
err: fadada.NewAPIError("获取法大大企业认证链接失败", fadada.CodeParamIllegal, "请求参数非法", "rid"),
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -27,6 +27,7 @@ import (
|
||||
"hyapi-server/internal/infrastructure/external/storage"
|
||||
"hyapi-server/internal/shared/database"
|
||||
"hyapi-server/internal/shared/esign"
|
||||
"hyapi-server/internal/shared/fadada"
|
||||
sharedOCR "hyapi-server/internal/shared/ocr"
|
||||
|
||||
"go.uber.org/zap"
|
||||
@@ -51,6 +52,7 @@ type CertificationApplicationServiceImpl struct {
|
||||
// 仓储依赖
|
||||
queryRepository repositories.CertificationQueryRepository
|
||||
enterpriseInfoSubmitRecordRepo repositories.EnterpriseInfoSubmitRecordRepository
|
||||
fadadaCorpAuthRecordRepo repositories.FadadaCorpAuthRecordRepository
|
||||
txManager *database.TransactionManager
|
||||
|
||||
wechatWorkService *notification.WeChatWorkService
|
||||
@@ -64,6 +66,7 @@ func NewCertificationApplicationService(
|
||||
userAggregateService user_service.UserAggregateService,
|
||||
queryRepository repositories.CertificationQueryRepository,
|
||||
enterpriseInfoSubmitRecordRepo repositories.EnterpriseInfoSubmitRecordRepository,
|
||||
fadadaCorpAuthRecordRepo repositories.FadadaCorpAuthRecordRepository,
|
||||
smsCodeService *user_service.SMSCodeService,
|
||||
esignClient *esign.Client,
|
||||
esignConfig *esign.Config,
|
||||
@@ -87,6 +90,7 @@ func NewCertificationApplicationService(
|
||||
userAggregateService: userAggregateService,
|
||||
queryRepository: queryRepository,
|
||||
enterpriseInfoSubmitRecordRepo: enterpriseInfoSubmitRecordRepo,
|
||||
fadadaCorpAuthRecordRepo: fadadaCorpAuthRecordRepo,
|
||||
smsCodeService: smsCodeService,
|
||||
esignClient: esignClient,
|
||||
esignConfig: esignConfig,
|
||||
@@ -160,6 +164,9 @@ func (s *CertificationApplicationServiceImpl) SubmitEnterpriseInfo(
|
||||
}
|
||||
}
|
||||
|
||||
// 企业名半角括号统一为全角,避免与工商登记不一致
|
||||
cmd.CompanyName = normalizeCompanyNameParentheses(cmd.CompanyName)
|
||||
|
||||
// 1.5 插入企业信息提交记录(包含扩展字段)
|
||||
record := entities.NewEnterpriseInfoSubmitRecord(
|
||||
cmd.UserID,
|
||||
@@ -445,7 +452,7 @@ func (s *CertificationApplicationServiceImpl) ConfirmAuth(
|
||||
s.logger.Info("确认状态-步骤2-获取最近提交记录成功",
|
||||
zap.String("user_id", cmd.UserID),
|
||||
zap.String("record_id", record.ID))
|
||||
s.logger.Info("确认状态-步骤3-开始查询三方实名状态",
|
||||
s.logger.Info("确认状态-步骤3-开始查询三方实名/授权状态",
|
||||
zap.String("user_id", cmd.UserID),
|
||||
zap.String("company_name", record.CompanyName),
|
||||
zap.String("sign_platform", string(cert.ResolvedSignPlatform())))
|
||||
@@ -453,6 +460,19 @@ func (s *CertificationApplicationServiceImpl) ConfirmAuth(
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 法大大:ConfirmAuth 时再查一次授权状态并落库 openCorpId
|
||||
authorizedByCorpGet := false
|
||||
if cert.ResolvedSignPlatform() == enums.SignPlatformFadada {
|
||||
authQuery := s.resolveCorpAuthQueryForGet(ctx, cert.UserID, record.UnifiedSocialCode, record.UnifiedSocialCode)
|
||||
if authStatus, qErr := provider.QueryCorpAuthStatus(ctx, authQuery); qErr != nil {
|
||||
s.logger.Warn("确认认证时查询企业授权状态失败", zap.Error(qErr), zap.String("user_id", cmd.UserID))
|
||||
} else if authStatus != nil && authStatus.Supported {
|
||||
s.persistFadadaCorpAuthStatus(ctx, cert, record, authStatus, "corp_get_confirm_auth")
|
||||
authorizedByCorpGet = authStatus.Authorized
|
||||
}
|
||||
}
|
||||
|
||||
verified, err := provider.QueryOrgVerified(ctx, &ports.OrgIdentityQuery{
|
||||
OrgName: record.CompanyName,
|
||||
OrgIdentNo: record.UnifiedSocialCode,
|
||||
@@ -461,6 +481,9 @@ func (s *CertificationApplicationServiceImpl) ConfirmAuth(
|
||||
s.logger.Error("查询企业认证信息失败", zap.Error(err))
|
||||
return nil, fmt.Errorf("查询企业认证信息失败: %w", err)
|
||||
}
|
||||
if authorizedByCorpGet {
|
||||
verified = true
|
||||
}
|
||||
reason := ""
|
||||
if verified {
|
||||
s.logger.Info("确认状态-步骤3-三方实名状态已完成,准备事务内推进认证",
|
||||
@@ -547,9 +570,14 @@ func (s *CertificationApplicationServiceImpl) ApplyContract(
|
||||
return nil, err
|
||||
}
|
||||
ei := enterpriseInfo.EnterpriseInfo
|
||||
submitRec, _ := s.enterpriseInfoSubmitRecordRepo.FindLatestByUserID(ctx, cmd.UserID)
|
||||
_, transactorMobile, _ := pickTransactorFromRecord(submitRec)
|
||||
if transactorMobile == "" {
|
||||
transactorMobile = ei.LegalPersonPhone
|
||||
}
|
||||
urlRes, err := provider.GetActorSignURL(ctx, &ports.GetActorSignURLRequest{
|
||||
SignFlowID: flowID,
|
||||
TransactorMobile: ei.LegalPersonPhone,
|
||||
TransactorMobile: transactorMobile,
|
||||
PartyAName: ei.CompanyName,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -625,9 +653,14 @@ func (s *CertificationApplicationServiceImpl) RefreshContractSignURL(
|
||||
return nil, fmt.Errorf("获取企业信息失败: %w", err)
|
||||
}
|
||||
ei := enterpriseInfo.EnterpriseInfo
|
||||
submitRec, _ := s.enterpriseInfoSubmitRecordRepo.FindLatestByUserID(ctx, userID)
|
||||
_, transactorMobile, _ := pickTransactorFromRecord(submitRec)
|
||||
if transactorMobile == "" {
|
||||
transactorMobile = ei.LegalPersonPhone
|
||||
}
|
||||
urlRes, err := provider.GetActorSignURL(ctx, &ports.GetActorSignURLRequest{
|
||||
SignFlowID: cert.EsignFlowID,
|
||||
TransactorMobile: ei.LegalPersonPhone,
|
||||
TransactorMobile: transactorMobile,
|
||||
PartyAName: ei.CompanyName,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -1349,16 +1382,11 @@ func isEnterpriseAlreadyRealnamedErr(err error) bool {
|
||||
return strings.Contains(msg, "企业用户已实名") || strings.Contains(msg, "已实名")
|
||||
}
|
||||
|
||||
// isEnterpriseAlreadyAuthorizedErr 法大大等平台:企业已对本应用授权,无需再获取授权链接(如 code=210002)
|
||||
// isEnterpriseAlreadyAuthorizedErr 法大大:授权范围重复获取,无需再获取授权链接。
|
||||
// 官方错误码说明要求按 code 判断(210002 / 210013),勿依赖 msg 文案。
|
||||
// 文档:https://dev.fadada.com/api-doc/JOQQIJXLFL/H4F0HSKMHQ3HPIIM/5-1
|
||||
func isEnterpriseAlreadyAuthorizedErr(err error) bool {
|
||||
if err == nil {
|
||||
return false
|
||||
}
|
||||
msg := err.Error()
|
||||
return strings.Contains(msg, "210002") ||
|
||||
strings.Contains(msg, "该企业已授权") ||
|
||||
strings.Contains(msg, "无需重复操作") ||
|
||||
strings.Contains(msg, "已存在授权")
|
||||
return fadada.IsAuthAlreadyGranted(err)
|
||||
}
|
||||
|
||||
// validateApplyContractCommand 验证申请合同命令
|
||||
@@ -1380,6 +1408,44 @@ func (s *CertificationApplicationServiceImpl) validateContractApplicationPrecond
|
||||
return nil
|
||||
}
|
||||
|
||||
// pickAuthorizedRepName 合同模板「客户授权代表」: 优先企业提交记录中的授权代表, 否则为法定代表人
|
||||
func pickAuthorizedRepName(record *entities.EnterpriseInfoSubmitRecord, legalPersonName string) string {
|
||||
if record != nil && strings.TrimSpace(record.AuthorizedRepName) != "" {
|
||||
return strings.TrimSpace(record.AuthorizedRepName)
|
||||
}
|
||||
return legalPersonName
|
||||
}
|
||||
|
||||
// normalizeCompanyNameParentheses 将企业名中的半角括号 () 转为全角 ()
|
||||
func normalizeCompanyNameParentheses(name string) string {
|
||||
name = strings.TrimSpace(name)
|
||||
if name == "" {
|
||||
return name
|
||||
}
|
||||
replacer := strings.NewReplacer("(", "(", ")", ")")
|
||||
return replacer.Replace(name)
|
||||
}
|
||||
|
||||
// pickTransactorFromRecord 法大大经办人:优先授权代表,缺省回退法定代表人
|
||||
func pickTransactorFromRecord(record *entities.EnterpriseInfoSubmitRecord) (name, mobile, idNo string) {
|
||||
if record == nil {
|
||||
return "", "", ""
|
||||
}
|
||||
name = strings.TrimSpace(record.AuthorizedRepName)
|
||||
mobile = strings.TrimSpace(record.AuthorizedRepPhone)
|
||||
idNo = strings.TrimSpace(record.AuthorizedRepID)
|
||||
if name == "" {
|
||||
name = strings.TrimSpace(record.LegalPersonName)
|
||||
}
|
||||
if mobile == "" {
|
||||
mobile = strings.TrimSpace(record.LegalPersonPhone)
|
||||
}
|
||||
if idNo == "" {
|
||||
idNo = strings.TrimSpace(record.LegalPersonID)
|
||||
}
|
||||
return name, mobile, idNo
|
||||
}
|
||||
|
||||
// generateContractAndSignURL 生成合同和签署链接
|
||||
func (s *CertificationApplicationServiceImpl) generateContractAndSignURL(ctx context.Context, cert *entities.Certification, enterpriseInfo *user_entities.EnterpriseInfo) (*certification_value_objects.ContractInfo, error) {
|
||||
provider, err := s.resolveProvider(cert)
|
||||
@@ -1395,14 +1461,25 @@ func (s *CertificationApplicationServiceImpl) generateContractAndSignURL(ctx con
|
||||
address = record.EnterpriseAddress
|
||||
}
|
||||
}
|
||||
transactorName, transactorMobile, transactorID := pickTransactorFromRecord(record)
|
||||
if transactorName == "" {
|
||||
transactorName = enterpriseInfo.LegalPersonName
|
||||
}
|
||||
if transactorMobile == "" {
|
||||
transactorMobile = enterpriseInfo.LegalPersonPhone
|
||||
}
|
||||
if transactorID == "" {
|
||||
transactorID = enterpriseInfo.LegalPersonID
|
||||
}
|
||||
req := &ports.SignFlowCreateRequest{
|
||||
Subject: "海宇数据-合作协议-" + enterpriseInfo.CompanyName,
|
||||
FileID: cert.ContractFileID,
|
||||
PartyAOpenCorpID: s.partyAOpenCorpIDFromStore(ctx, cert.UserID, enterpriseInfo.UnifiedSocialCode),
|
||||
PartyAName: enterpriseInfo.CompanyName,
|
||||
PartyAUSCC: enterpriseInfo.UnifiedSocialCode,
|
||||
TransactorName: enterpriseInfo.LegalPersonName,
|
||||
TransactorMobile: enterpriseInfo.LegalPersonPhone,
|
||||
TransactorID: enterpriseInfo.LegalPersonID,
|
||||
TransactorName: transactorName,
|
||||
TransactorMobile: transactorMobile,
|
||||
TransactorID: transactorID,
|
||||
TransReferenceID: cert.ID,
|
||||
Fill: ensureContractFill(cert, enterpriseInfo.CompanyName, enterpriseInfo.UnifiedSocialCode, address, repName),
|
||||
}
|
||||
@@ -1450,6 +1527,7 @@ func (s *CertificationApplicationServiceImpl) completeEnterpriseVerification(
|
||||
zap.String("user_id", userID),
|
||||
zap.String("record_id", record.ID))
|
||||
|
||||
// 新用户:创建企业信息;重新认证:更新已有企业信息(CreateOrUpdateEnterpriseInfo 内部分流)
|
||||
err = s.userAggregateService.CreateOrUpdateEnterpriseInfo(
|
||||
ctx,
|
||||
userID,
|
||||
@@ -1464,7 +1542,7 @@ func (s *CertificationApplicationServiceImpl) completeEnterpriseVerification(
|
||||
s.logger.Error("保存企业信息到用户域失败", zap.Error(err))
|
||||
return fmt.Errorf("保存企业信息失败: %s", err.Error())
|
||||
}
|
||||
s.logger.Info("企业信息已写入用户域(创建或更新)", zap.String("user_id", userID))
|
||||
s.logger.Info("企业信息已写入用户域(新用户创建/重新认证更新)", zap.String("user_id", userID))
|
||||
|
||||
// 生成合同(填单/文件)
|
||||
err = s.generateAndAddContractFile(ctx, cert, record.CompanyName, record.UnifiedSocialCode, record.EnterpriseAddress, pickAuthorizedRepName(record, record.LegalPersonName))
|
||||
@@ -1512,14 +1590,16 @@ func (s *CertificationApplicationServiceImpl) createSignTaskAfterEnterpriseVerif
|
||||
}
|
||||
repName := pickAuthorizedRepName(record, record.LegalPersonName)
|
||||
address := record.EnterpriseAddress
|
||||
transactorName, transactorMobile, transactorID := pickTransactorFromRecord(record)
|
||||
req := &ports.SignFlowCreateRequest{
|
||||
Subject: "海宇数据-合作协议-" + record.CompanyName,
|
||||
FileID: cert.ContractFileID,
|
||||
PartyAOpenCorpID: s.partyAOpenCorpIDFromStore(ctx, cert.UserID, record.UnifiedSocialCode),
|
||||
PartyAName: record.CompanyName,
|
||||
PartyAUSCC: record.UnifiedSocialCode,
|
||||
TransactorName: record.LegalPersonName,
|
||||
TransactorMobile: record.LegalPersonPhone,
|
||||
TransactorID: record.LegalPersonID,
|
||||
TransactorName: transactorName,
|
||||
TransactorMobile: transactorMobile,
|
||||
TransactorID: transactorID,
|
||||
TransReferenceID: cert.ID,
|
||||
Fill: ensureContractFill(cert, record.CompanyName, record.UnifiedSocialCode, address, repName),
|
||||
SkipActorURL: true, // 预创建不取甲方链接,避免消耗单次 EmbedURL
|
||||
@@ -1534,14 +1614,6 @@ func (s *CertificationApplicationServiceImpl) createSignTaskAfterEnterpriseVerif
|
||||
return nil
|
||||
}
|
||||
|
||||
// pickAuthorizedRepName 合同模板「客户授权代表」: 优先企业提交记录中的授权代表, 否则为法定代表人
|
||||
func pickAuthorizedRepName(record *entities.EnterpriseInfoSubmitRecord, legalPersonName string) string {
|
||||
if record != nil && strings.TrimSpace(record.AuthorizedRepName) != "" {
|
||||
return strings.TrimSpace(record.AuthorizedRepName)
|
||||
}
|
||||
return legalPersonName
|
||||
}
|
||||
|
||||
// generateAndAddContractFile 生成并添加合同文件的公共方法
|
||||
func (s *CertificationApplicationServiceImpl) generateAndAddContractFile(
|
||||
ctx context.Context,
|
||||
|
||||
151
internal/application/certification/fadada_corp_auth.go
Normal file
151
internal/application/certification/fadada_corp_auth.go
Normal file
@@ -0,0 +1,151 @@
|
||||
package certification
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strings"
|
||||
|
||||
"hyapi-server/internal/domains/certification/entities"
|
||||
"hyapi-server/internal/domains/certification/ports"
|
||||
|
||||
"go.uber.org/zap"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// resolveCorpAuthQueryForGet 构造 /corp/get 入参(三选一)。
|
||||
// 优先级:库中 openCorpId > corpIdentNo(USCC) > 库中 clientCorpId
|
||||
func (s *CertificationApplicationServiceImpl) resolveCorpAuthQueryForGet(
|
||||
ctx context.Context,
|
||||
userID, uscc, fallbackClientCorpID string,
|
||||
) *ports.CorpAuthStatusQuery {
|
||||
uscc = strings.TrimSpace(uscc)
|
||||
fallbackClientCorpID = strings.TrimSpace(fallbackClientCorpID)
|
||||
rec := s.loadFadadaCorpAuthRecord(ctx, userID, uscc, fallbackClientCorpID)
|
||||
|
||||
q := &ports.CorpAuthStatusQuery{}
|
||||
if rec != nil && strings.TrimSpace(rec.OpenCorpID) != "" {
|
||||
q.OpenCorpID = strings.TrimSpace(rec.OpenCorpID)
|
||||
return q
|
||||
}
|
||||
if uscc != "" {
|
||||
q.CorpIdentNo = uscc
|
||||
return q
|
||||
}
|
||||
if rec != nil && strings.TrimSpace(rec.ClientCorpID) != "" {
|
||||
q.ClientCorpID = strings.TrimSpace(rec.ClientCorpID)
|
||||
return q
|
||||
}
|
||||
if fallbackClientCorpID != "" {
|
||||
q.ClientCorpID = fallbackClientCorpID
|
||||
}
|
||||
return q
|
||||
}
|
||||
|
||||
func (s *CertificationApplicationServiceImpl) loadFadadaCorpAuthRecord(
|
||||
ctx context.Context,
|
||||
userID, uscc, clientCorpID string,
|
||||
) *entities.FadadaCorpAuthRecord {
|
||||
if s.fadadaCorpAuthRecordRepo == nil {
|
||||
return nil
|
||||
}
|
||||
if userID != "" {
|
||||
if rec, err := s.fadadaCorpAuthRecordRepo.FindLatestByUserID(ctx, userID); err == nil && rec != nil {
|
||||
return rec
|
||||
} else if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
s.logger.Warn("按用户查询法大大授权记录失败", zap.String("user_id", userID), zap.Error(err))
|
||||
}
|
||||
}
|
||||
if uscc != "" {
|
||||
if rec, err := s.fadadaCorpAuthRecordRepo.FindByUnifiedSocialCode(ctx, uscc); err == nil && rec != nil {
|
||||
return rec
|
||||
} else if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
s.logger.Warn("按信用代码查询法大大授权记录失败", zap.String("uscc", uscc), zap.Error(err))
|
||||
}
|
||||
}
|
||||
if clientCorpID != "" {
|
||||
if rec, err := s.fadadaCorpAuthRecordRepo.FindByClientCorpID(ctx, clientCorpID); err == nil && rec != nil {
|
||||
return rec
|
||||
} else if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
s.logger.Warn("按clientCorpId查询法大大授权记录失败", zap.String("client_corp_id", clientCorpID), zap.Error(err))
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *CertificationApplicationServiceImpl) fadadaAppID() string {
|
||||
if s.config != nil {
|
||||
return strings.TrimSpace(s.config.Fadada.AppID)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (s *CertificationApplicationServiceImpl) ensureFadadaCorpAuthSeed(
|
||||
ctx context.Context,
|
||||
cert *entities.Certification,
|
||||
record *entities.EnterpriseInfoSubmitRecord,
|
||||
clientCorpID string,
|
||||
) {
|
||||
if s.fadadaCorpAuthRecordRepo == nil || cert == nil || record == nil {
|
||||
return
|
||||
}
|
||||
seed := entities.NewFadadaCorpAuthRecord(
|
||||
cert.UserID,
|
||||
cert.ID,
|
||||
s.fadadaAppID(),
|
||||
record.CompanyName,
|
||||
record.UnifiedSocialCode,
|
||||
clientCorpID,
|
||||
)
|
||||
seed.Source = "select_sign_platform"
|
||||
if err := s.fadadaCorpAuthRecordRepo.UpsertByBizKey(ctx, seed); err != nil {
|
||||
s.logger.Warn("初始化法大大授权记录失败", zap.Error(err), zap.String("user_id", cert.UserID))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *CertificationApplicationServiceImpl) persistFadadaCorpAuthStatus(
|
||||
ctx context.Context,
|
||||
cert *entities.Certification,
|
||||
record *entities.EnterpriseInfoSubmitRecord,
|
||||
status *ports.CorpAuthStatusResult,
|
||||
source string,
|
||||
) {
|
||||
if s.fadadaCorpAuthRecordRepo == nil || status == nil || !status.Found {
|
||||
return
|
||||
}
|
||||
userID, certID, company, uscc := "", "", "", ""
|
||||
if cert != nil {
|
||||
userID = cert.UserID
|
||||
certID = cert.ID
|
||||
}
|
||||
if record != nil {
|
||||
company = record.CompanyName
|
||||
uscc = record.UnifiedSocialCode
|
||||
if userID == "" {
|
||||
userID = record.UserID
|
||||
}
|
||||
}
|
||||
rec := entities.NewFadadaCorpAuthRecord(userID, certID, s.fadadaAppID(), company, uscc, status.ClientCorpID)
|
||||
rec.ApplyAuthStatus(
|
||||
status.OpenCorpID,
|
||||
status.ClientCorpID,
|
||||
status.BindingStatus,
|
||||
status.IdentStatus,
|
||||
"",
|
||||
nil,
|
||||
source,
|
||||
)
|
||||
if err := s.fadadaCorpAuthRecordRepo.UpsertByBizKey(ctx, rec); err != nil {
|
||||
s.logger.Warn("保存法大大授权状态失败", zap.Error(err), zap.String("user_id", userID), zap.String("source", source))
|
||||
}
|
||||
}
|
||||
|
||||
func (s *CertificationApplicationServiceImpl) partyAOpenCorpIDFromStore(
|
||||
ctx context.Context,
|
||||
userID, uscc string,
|
||||
) string {
|
||||
rec := s.loadFadadaCorpAuthRecord(ctx, userID, uscc, uscc)
|
||||
if rec == nil {
|
||||
return ""
|
||||
}
|
||||
return strings.TrimSpace(rec.OpenCorpID)
|
||||
}
|
||||
@@ -88,19 +88,23 @@ func (s *CertificationApplicationServiceImpl) SelectSignPlatform(
|
||||
return nil, err
|
||||
}
|
||||
|
||||
transactorName, transactorMobile, transactorID := pickTransactorFromRecord(record)
|
||||
clientCorpID := strings.TrimSpace(record.UnifiedSocialCode)
|
||||
authReq := &ports.EnterpriseAuthRequest{
|
||||
ClientCorpID: record.UnifiedSocialCode,
|
||||
ClientUserID: record.LegalPersonID,
|
||||
ClientCorpID: clientCorpID,
|
||||
ClientUserID: transactorID,
|
||||
CompanyName: record.CompanyName,
|
||||
UnifiedSocialCode: record.UnifiedSocialCode,
|
||||
LegalPersonName: record.LegalPersonName,
|
||||
LegalPersonID: record.LegalPersonID,
|
||||
TransactorName: record.LegalPersonName,
|
||||
TransactorMobile: record.LegalPersonPhone,
|
||||
TransactorID: record.LegalPersonID,
|
||||
TransactorName: transactorName,
|
||||
TransactorMobile: transactorMobile,
|
||||
TransactorID: transactorID,
|
||||
}
|
||||
// 选平台时先落库种子数据(clientCorpId/USCC),供后续 /corp/get 与签署复用
|
||||
s.ensureFadadaCorpAuthSeed(ctx, cert, record, clientCorpID)
|
||||
|
||||
authRes, alreadyVerified, err := s.generateEnterpriseAuthOrDetectVerifiedWithProvider(ctx, provider, authReq)
|
||||
authRes, alreadyVerified, err := s.generateEnterpriseAuthOrDetectVerifiedWithProvider(ctx, provider, authReq, cert, record)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("生成企业认证链接失败: %w", err)
|
||||
}
|
||||
@@ -166,7 +170,20 @@ func (s *CertificationApplicationServiceImpl) HandleFadadaCallback(ctx context.C
|
||||
zap.String("event", ev.Event),
|
||||
zap.Bool("auth_passed", ev.AuthPassed),
|
||||
zap.Bool("sign_completed", ev.SignCompleted),
|
||||
zap.String("sign_flow_id", ev.SignFlowID))
|
||||
zap.String("sign_flow_id", ev.SignFlowID),
|
||||
zap.String("open_corp_id", ev.OpenCorpID),
|
||||
zap.String("client_corp_id", ev.ClientCorpID))
|
||||
|
||||
// 授权成功:落库 openCorpId / clientCorpId
|
||||
if ev.AuthPassed && (strings.TrimSpace(ev.OpenCorpID) != "" || strings.TrimSpace(ev.ClientCorpID) != "") {
|
||||
rec := entities.NewFadadaCorpAuthRecord("", "", s.fadadaAppID(), ev.OrgName, "", ev.ClientCorpID)
|
||||
rec.ApplyAuthStatus(ev.OpenCorpID, ev.ClientCorpID, "authorized", "", "", nil, "callback_auth_passed")
|
||||
if s.fadadaCorpAuthRecordRepo != nil {
|
||||
if err := s.fadadaCorpAuthRecordRepo.UpsertByBizKey(ctx, rec); err != nil {
|
||||
s.logger.Warn("回调落库法大大授权信息失败", zap.Error(err))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 认证完成主要依赖 ConfirmAuth / details 轮询;签署完成按任务 ID 兜底推进
|
||||
if ev.SignCompleted && ev.SignFlowID != "" {
|
||||
@@ -186,19 +203,59 @@ func (s *CertificationApplicationServiceImpl) generateEnterpriseAuthOrDetectVeri
|
||||
ctx context.Context,
|
||||
provider ports.SignPlatformProvider,
|
||||
authReq *ports.EnterpriseAuthRequest,
|
||||
cert *entities.Certification,
|
||||
record *entities.EnterpriseInfoSubmitRecord,
|
||||
) (*ports.AuthLinkResult, bool, error) {
|
||||
userID := ""
|
||||
if cert != nil {
|
||||
userID = cert.UserID
|
||||
}
|
||||
// 1) 正式查授权:POST /corp/get(三选一:库 openCorpId > USCC corpIdentNo > 库 clientCorpId)
|
||||
authQuery := s.resolveCorpAuthQueryForGet(ctx, userID, authReq.UnifiedSocialCode, authReq.ClientCorpID)
|
||||
s.logger.Info("查询企业授权状态入参",
|
||||
zap.String("company_name", authReq.CompanyName),
|
||||
zap.String("open_corp_id", authQuery.OpenCorpID),
|
||||
zap.String("corp_ident_no", authQuery.CorpIdentNo),
|
||||
zap.String("client_corp_id", authQuery.ClientCorpID),
|
||||
zap.String("platform", string(provider.Platform())))
|
||||
authStatus, qErr := provider.QueryCorpAuthStatus(ctx, authQuery)
|
||||
if qErr != nil {
|
||||
s.logger.Warn("查询企业授权状态失败,将继续尝试获取授权链接",
|
||||
zap.String("company_name", authReq.CompanyName),
|
||||
zap.String("uscc", authReq.UnifiedSocialCode),
|
||||
zap.String("platform", string(provider.Platform())),
|
||||
zap.Error(qErr))
|
||||
} else if authStatus != nil && authStatus.Supported {
|
||||
s.persistFadadaCorpAuthStatus(ctx, cert, record, authStatus, "corp_get_select_platform")
|
||||
if authStatus.Authorized {
|
||||
s.logger.Info("查询企业授权状态为已授权,跳过认证链接并视为认证完成",
|
||||
zap.String("company_name", authReq.CompanyName),
|
||||
zap.String("uscc", authReq.UnifiedSocialCode),
|
||||
zap.String("platform", string(provider.Platform())),
|
||||
zap.String("binding_status", authStatus.BindingStatus),
|
||||
zap.String("open_corp_id", authStatus.OpenCorpID),
|
||||
zap.String("ident_status", authStatus.IdentStatus))
|
||||
return nil, true, nil
|
||||
}
|
||||
}
|
||||
|
||||
// 2) 未授权或不支持查询:走获取授权链接
|
||||
authRes, err := provider.GenerateEnterpriseAuth(ctx, authReq)
|
||||
if err == nil {
|
||||
return authRes, false, nil
|
||||
}
|
||||
|
||||
// 法大大:企业已对本应用授权(210002)= 授权已完成,直接跳过授权页
|
||||
// 3) 兜底:get-auth-url 返回授权范围重复获取(210002/210013)
|
||||
if isEnterpriseAlreadyAuthorizedErr(err) {
|
||||
s.logger.Info("第三方返回企业已授权,跳过认证链接并视为认证完成",
|
||||
s.logger.Info("获取授权链接返回重复授权错误码,跳过认证链接并视为认证完成",
|
||||
zap.String("company_name", authReq.CompanyName),
|
||||
zap.String("uscc", authReq.UnifiedSocialCode),
|
||||
zap.String("platform", string(provider.Platform())),
|
||||
zap.Error(err))
|
||||
// 再查一次 /corp/get,尽量把 openCorpId 落库
|
||||
if authStatus2, qErr2 := provider.QueryCorpAuthStatus(ctx, authQuery); qErr2 == nil && authStatus2 != nil {
|
||||
s.persistFadadaCorpAuthStatus(ctx, cert, record, authStatus2, "corp_get_after_duplicate_auth")
|
||||
}
|
||||
return nil, true, nil
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user