This commit is contained in:
2025-07-21 15:13:26 +08:00
parent 8ad1d7288e
commit b03129667a
41 changed files with 8497 additions and 3968 deletions

View File

@@ -9,25 +9,49 @@ import (
)
// CertificationApplicationService 认证应用服务接口
// 负责用例协调,提供精简的应用层接口
type CertificationApplicationService interface {
// 认证状态查询
GetCertificationStatus(ctx context.Context, query *queries.GetCertificationStatusQuery) (*responses.CertificationResponse, error)
GetCertificationDetails(ctx context.Context, query *queries.GetCertificationDetailsQuery) (*responses.CertificationResponse, error)
GetCertificationProgress(ctx context.Context, userID string) (map[string]interface{}, error)
// ================ 用户操作用例 ================
// 企业信息管理
// 创建认证申请
CreateCertification(ctx context.Context, cmd *commands.CreateCertificationCommand) (*responses.CertificationResponse, error)
// 提交企业信息
SubmitEnterpriseInfo(ctx context.Context, cmd *commands.SubmitEnterpriseInfoCommand) (*responses.CertificationResponse, error)
// 企业认证
GetEnterpriseAuthURL(ctx context.Context, userID string) (*responses.EnterpriseAuthURLResponse, error)
// 申请合同签署
ApplyContract(ctx context.Context, cmd *commands.ApplyContractCommand) (*responses.ContractSignUrlResponse, error)
// 合同管理
ApplyContract(ctx context.Context, userID string) (*responses.CertificationResponse, error)
GetContractSignURL(ctx context.Context, cmd *commands.GetContractSignURLCommand) (*responses.ContractSignURLResponse, error)
}
// 重试失败操作
RetryOperation(ctx context.Context, cmd *commands.RetryOperationCommand) (*responses.CertificationResponse, error)
// ================ 查询用例 ================
// 获取认证详情
GetCertification(ctx context.Context, query *queries.GetCertificationQuery) (*responses.CertificationResponse, error)
// 获取用户认证列表
GetUserCertifications(ctx context.Context, query *queries.GetUserCertificationsQuery) (*responses.CertificationListResponse, error)
// 获取认证列表(管理员)
ListCertifications(ctx context.Context, query *queries.ListCertificationsQuery) (*responses.CertificationListResponse, error)
// 搜索认证
SearchCertifications(ctx context.Context, query *queries.SearchCertificationsQuery) (*responses.CertificationListResponse, error)
// 获取认证统计
GetCertificationStatistics(ctx context.Context, query *queries.GetCertificationStatisticsQuery) (*responses.CertificationStatisticsResponse, error)
// ================ e签宝回调处理 ================
// EsignCallbackApplicationService e签宝回调应用服务接口
type EsignCallbackApplicationService interface {
// 处理e签宝回调
HandleCallback(ctx context.Context, callbackData map[string]interface{}, headers map[string]string, queryParams map[string]string) error
HandleEsignCallback(ctx context.Context, cmd *commands.EsignCallbackCommand) (*responses.CallbackResponse, error)
// ================ 管理员操作 ================
// 手动状态转换(管理员)
ForceTransitionStatus(ctx context.Context, cmd *commands.ForceTransitionStatusCommand) (*responses.CertificationResponse, error)
// 获取系统监控数据
GetSystemMonitoring(ctx context.Context, query *queries.GetSystemMonitoringQuery) (*responses.SystemMonitoringResponse, error)
}

View File

@@ -1,21 +1,50 @@
package commands
// SubmitEnterpriseInfoCommand 提交企业信息命令
// 用于用户提交企业四要素信息,完成企业信息验证
// 如果用户没有认证申请,系统会自动创建
type SubmitEnterpriseInfoCommand struct {
UserID string `json:"-" comment:"用户唯一标识从JWT token获取不在JSON中暴露"`
CompanyName string `json:"company_name" binding:"required,min=2,max=100" comment:"企业名称,如:北京科技有限公司"`
UnifiedSocialCode string `json:"unified_social_code" binding:"required,social_credit_code" comment:"统一社会信用代码18位企业唯一标识91110000123456789X"`
LegalPersonName string `json:"legal_person_name" binding:"required,min=2,max=20" comment:"法定代表人姓名,如:张三"`
LegalPersonID string `json:"legal_person_id" binding:"required,id_card" comment:"法定代表人身份证号码18位110101199001011234"`
LegalPersonPhone string `json:"legal_person_phone" binding:"required,phone" comment:"法定代表人手机号11位13800138000"`
VerificationCode string `json:"verification_code" binding:"required,len=6" comment:"验证码"`
import (
"tyapi-server/internal/domains/certification/entities/value_objects"
"tyapi-server/internal/domains/certification/enums"
)
// CreateCertificationCommand 创建认证申请命令
type CreateCertificationCommand struct {
UserID string `json:"-"`
}
// CompleteContractSignCommand 完成合同签署命令
// 用于用户完成合同签署提交合同URL
type CompleteContractSignCommand struct {
UserID string `json:"-" comment:"用户唯一标识从JWT token获取不在JSON中暴露"`
ContractURL string `json:"contract_url" binding:"required,url,min=10,max=500" comment:"合同签署后的URL地址"`
// ApplyContractCommand 申请合同命令
type ApplyContractCommand struct {
CertificationID string `json:"certification_id" validate:"required"`
UserID string `json:"user_id" validate:"required"`
}
// RetryOperationCommand 重试操作命令
type RetryOperationCommand struct {
CertificationID string `json:"certification_id" validate:"required"`
UserID string `json:"user_id" validate:"required"`
Operation string `json:"operation" validate:"required,oneof=enterprise_verification contract_application"`
Reason string `json:"reason,omitempty"`
}
// EsignCallbackCommand e签宝回调命令
type EsignCallbackCommand struct {
CertificationID string `json:"certification_id" validate:"required"`
CallbackType string `json:"callback_type" validate:"required,oneof=auth_result sign_result flow_status"`
RawData string `json:"raw_data" validate:"required"`
Headers map[string]string `json:"headers,omitempty"`
QueryParams map[string]string `json:"query_params,omitempty"`
}
// ForceTransitionStatusCommand 强制状态转换命令(管理员)
type ForceTransitionStatusCommand struct {
CertificationID string `json:"certification_id" validate:"required"`
AdminID string `json:"admin_id" validate:"required"`
TargetStatus enums.CertificationStatus `json:"target_status" validate:"required"`
Reason string `json:"reason" validate:"required"`
Force bool `json:"force,omitempty"` // 是否强制执行,跳过业务规则验证
}
// SubmitEnterpriseInfoCommand 提交企业信息命令
type SubmitEnterpriseInfoCommand struct {
CertificationID string `json:"certification_id" validate:"required"`
UserID string `json:"-" validate:"required"`
EnterpriseInfo *value_objects.EnterpriseInfo `json:"enterprise_info" validate:"required"`
}

View File

@@ -1,13 +1,185 @@
package queries
// GetCertificationStatusQuery 获取认证状态查询
// 用于查询用户当前认证申请的进度状态
type GetCertificationStatusQuery struct {
UserID string `json:"user_id" binding:"required,uuid" comment:"用户唯一标识,用于查询该用户的认证申请状态"`
import (
"time"
"tyapi-server/internal/domains/certification/enums"
domainQueries "tyapi-server/internal/domains/certification/repositories/queries"
)
// GetCertificationQuery 获取认证详情查询
type GetCertificationQuery struct {
CertificationID string `json:"certification_id" validate:"required"`
UserID string `json:"user_id,omitempty"` // 用于权限验证
}
// GetCertificationDetailsQuery 获取认证详情查询
// 用于查询用户认证申请的详细信息,包括所有相关记录
type GetCertificationDetailsQuery struct {
UserID string `json:"user_id" binding:"required,uuid" comment:"用户唯一标识,用于查询该用户的认证申请详细信息"`
// GetUserCertificationsQuery 获取用户认证列表查询
type GetUserCertificationsQuery struct {
UserID string `json:"user_id" validate:"required"`
Status enums.CertificationStatus `json:"status,omitempty"`
IncludeCompleted bool `json:"include_completed,omitempty"`
IncludeFailed bool `json:"include_failed,omitempty"`
Page int `json:"page"`
PageSize int `json:"page_size"`
}
// ToDomainQuery 转换为领域查询对象
func (q *GetUserCertificationsQuery) ToDomainQuery() *domainQueries.UserCertificationsQuery {
domainQuery := &domainQueries.UserCertificationsQuery{
UserID: q.UserID,
Status: q.Status,
IncludeCompleted: q.IncludeCompleted,
IncludeFailed: q.IncludeFailed,
Page: q.Page,
PageSize: q.PageSize,
}
domainQuery.DefaultValues()
return domainQuery
}
// ListCertificationsQuery 认证列表查询(管理员)
type ListCertificationsQuery struct {
Page int `json:"page"`
PageSize int `json:"page_size"`
SortBy string `json:"sort_by"`
SortOrder string `json:"sort_order"`
UserID string `json:"user_id,omitempty"`
Status enums.CertificationStatus `json:"status,omitempty"`
Statuses []enums.CertificationStatus `json:"statuses,omitempty"`
FailureReason enums.FailureReason `json:"failure_reason,omitempty"`
CreatedAfter *time.Time `json:"created_after,omitempty"`
CreatedBefore *time.Time `json:"created_before,omitempty"`
CompanyName string `json:"company_name,omitempty"`
LegalPersonName string `json:"legal_person_name,omitempty"`
SearchKeyword string `json:"search_keyword,omitempty"`
}
// ToDomainQuery 转换为领域查询对象
func (q *ListCertificationsQuery) ToDomainQuery() *domainQueries.ListCertificationsQuery {
domainQuery := &domainQueries.ListCertificationsQuery{
Page: q.Page,
PageSize: q.PageSize,
SortBy: q.SortBy,
SortOrder: q.SortOrder,
UserID: q.UserID,
Status: q.Status,
Statuses: q.Statuses,
FailureReason: q.FailureReason,
CreatedAfter: q.CreatedAfter,
CreatedBefore: q.CreatedBefore,
CompanyName: q.CompanyName,
LegalPersonName: q.LegalPersonName,
SearchKeyword: q.SearchKeyword,
}
domainQuery.DefaultValues()
return domainQuery
}
// SearchCertificationsQuery 搜索认证查询
type SearchCertificationsQuery struct {
Keyword string `json:"keyword" validate:"required,min=2"`
SearchFields []string `json:"search_fields,omitempty"`
Statuses []enums.CertificationStatus `json:"statuses,omitempty"`
UserID string `json:"user_id,omitempty"`
Page int `json:"page"`
PageSize int `json:"page_size"`
SortBy string `json:"sort_by"`
SortOrder string `json:"sort_order"`
ExactMatch bool `json:"exact_match,omitempty"`
}
// ToDomainQuery 转换为领域查询对象
func (q *SearchCertificationsQuery) ToDomainQuery() *domainQueries.SearchCertificationsQuery {
domainQuery := &domainQueries.SearchCertificationsQuery{
Keyword: q.Keyword,
SearchFields: q.SearchFields,
Statuses: q.Statuses,
UserID: q.UserID,
Page: q.Page,
PageSize: q.PageSize,
SortBy: q.SortBy,
SortOrder: q.SortOrder,
ExactMatch: q.ExactMatch,
}
domainQuery.DefaultValues()
return domainQuery
}
// GetCertificationStatisticsQuery 认证统计查询
type GetCertificationStatisticsQuery struct {
StartDate time.Time `json:"start_date" validate:"required"`
EndDate time.Time `json:"end_date" validate:"required"`
Period string `json:"period" validate:"oneof=daily weekly monthly yearly"`
GroupBy []string `json:"group_by,omitempty"`
UserIDs []string `json:"user_ids,omitempty"`
Statuses []enums.CertificationStatus `json:"statuses,omitempty"`
IncludeProgressStats bool `json:"include_progress_stats,omitempty"`
IncludeRetryStats bool `json:"include_retry_stats,omitempty"`
IncludeTimeStats bool `json:"include_time_stats,omitempty"`
}
// ToDomainQuery 转换为领域查询对象
func (q *GetCertificationStatisticsQuery) ToDomainQuery() *domainQueries.CertificationStatisticsQuery {
return &domainQueries.CertificationStatisticsQuery{
StartDate: q.StartDate,
EndDate: q.EndDate,
Period: q.Period,
GroupBy: q.GroupBy,
UserIDs: q.UserIDs,
Statuses: q.Statuses,
IncludeProgressStats: q.IncludeProgressStats,
IncludeRetryStats: q.IncludeRetryStats,
IncludeTimeStats: q.IncludeTimeStats,
}
}
// GetSystemMonitoringQuery 系统监控查询
type GetSystemMonitoringQuery struct {
TimeRange string `json:"time_range" validate:"oneof=1h 6h 24h 7d 30d"`
Metrics []string `json:"metrics,omitempty"` // 指定要获取的指标类型
}
// GetAvailableMetrics 获取可用的监控指标
func (q *GetSystemMonitoringQuery) GetAvailableMetrics() []string {
return []string{
"certification_count",
"success_rate",
"failure_rate",
"avg_processing_time",
"status_distribution",
"retry_count",
"esign_callback_success_rate",
}
}
// GetTimeRangeDuration 获取时间范围对应的持续时间
func (q *GetSystemMonitoringQuery) GetTimeRangeDuration() time.Duration {
switch q.TimeRange {
case "1h":
return time.Hour
case "6h":
return 6 * time.Hour
case "24h":
return 24 * time.Hour
case "7d":
return 7 * 24 * time.Hour
case "30d":
return 30 * 24 * time.Hour
default:
return 24 * time.Hour // 默认24小时
}
}
// ShouldIncludeMetric 检查是否应该包含指定指标
func (q *GetSystemMonitoringQuery) ShouldIncludeMetric(metric string) bool {
if len(q.Metrics) == 0 {
return true // 如果没有指定,包含所有指标
}
for _, m := range q.Metrics {
if m == metric {
return true
}
}
return false
}

View File

@@ -1,45 +1,235 @@
package responses
import (
"fmt"
"time"
"tyapi-server/internal/domains/certification/entities/value_objects"
"tyapi-server/internal/domains/certification/enums"
"tyapi-server/internal/domains/certification/repositories"
"tyapi-server/internal/domains/certification/services/state_machine"
)
// CertificationResponse 认证响应
type CertificationResponse struct {
ID string `json:"id"`
UserID string `json:"user_id"`
Status enums.CertificationStatus `json:"status"`
StatusName string `json:"status_name"`
Progress int `json:"progress"`
IsUserActionRequired bool `json:"is_user_action_required"`
InfoSubmittedAt *time.Time `json:"info_submitted_at,omitempty"`
EnterpriseVerifiedAt *time.Time `json:"enterprise_verified_at,omitempty"`
ContractAppliedAt *time.Time `json:"contract_applied_at,omitempty"`
ContractSignedAt *time.Time `json:"contract_signed_at,omitempty"`
CompletedAt *time.Time `json:"completed_at,omitempty"`
Enterprise *EnterpriseInfoResponse `json:"enterprise,omitempty"`
ContractURL string `json:"contract_url,omitempty"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
ID string `json:"id"`
UserID string `json:"user_id"`
Status enums.CertificationStatus `json:"status"`
StatusName string `json:"status_name"`
Progress int `json:"progress"`
// 企业信息
EnterpriseInfo *value_objects.EnterpriseInfo `json:"enterprise_info,omitempty"`
// 合同信息
ContractInfo *value_objects.ContractInfo `json:"contract_info,omitempty"`
// 时间戳
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
InfoSubmittedAt *time.Time `json:"info_submitted_at,omitempty"`
EnterpriseVerifiedAt *time.Time `json:"enterprise_verified_at,omitempty"`
ContractAppliedAt *time.Time `json:"contract_applied_at,omitempty"`
ContractSignedAt *time.Time `json:"contract_signed_at,omitempty"`
// 业务状态
IsCompleted bool `json:"is_completed"`
IsFailed bool `json:"is_failed"`
IsUserActionRequired bool `json:"is_user_action_required"`
// 失败信息
FailureReason enums.FailureReason `json:"failure_reason,omitempty"`
FailureReasonName string `json:"failure_reason_name,omitempty"`
FailureMessage string `json:"failure_message,omitempty"`
CanRetry bool `json:"can_retry,omitempty"`
RetryCount int `json:"retry_count,omitempty"`
// 用户操作提示
NextAction string `json:"next_action,omitempty"`
AvailableActions []string `json:"available_actions,omitempty"`
// 元数据
Metadata map[string]interface{} `json:"metadata,omitempty"`
}
// EnterpriseInfoResponse 企业信息响应
type EnterpriseInfoResponse struct {
ID string `json:"id"`
CompanyName string `json:"company_name"`
UnifiedSocialCode string `json:"unified_social_code"`
LegalPersonName string `json:"legal_person_name"`
LegalPersonID string `json:"legal_person_id"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
// CertificationListResponse 认证列表响应
type CertificationListResponse struct {
Items []*CertificationResponse `json:"items"`
Total int64 `json:"total"`
Page int `json:"page"`
PageSize int `json:"page_size"`
TotalPages int `json:"total_pages"`
}
// EnterpriseAuthURLResponse 企业认证链接响应
type EnterpriseAuthURLResponse struct {
EsignFlowID string `json:"esign_flow_id"` // e签宝认证流程ID
AuthURL string `json:"auth_url"` // 认证链接
ShortURL string `json:"short_url"` // 短链接
ExpireAt string `json:"expire_at"` // 过期时间
// ContractSignUrlResponse 合同签署URL响应
type ContractSignUrlResponse struct {
CertificationID string `json:"certification_id"`
ContractSignURL string `json:"contract_sign_url"`
ContractURL string `json:"contract_url,omitempty"`
ExpireAt *time.Time `json:"expire_at,omitempty"`
NextAction string `json:"next_action"`
Message string `json:"message"`
}
// CallbackResponse 回调响应
type CallbackResponse struct {
Success bool `json:"success"`
CertificationID string `json:"certification_id"`
CallbackType string `json:"callback_type"`
ProcessedAt time.Time `json:"processed_at"`
OldStatus enums.CertificationStatus `json:"old_status,omitempty"`
NewStatus enums.CertificationStatus `json:"new_status,omitempty"`
Message string `json:"message"`
StateTransition *state_machine.StateTransitionResult `json:"state_transition,omitempty"`
}
// CertificationStatisticsResponse 认证统计响应
type CertificationStatisticsResponse struct {
Period string `json:"period"`
TimeRange string `json:"time_range"`
Statistics *repositories.CertificationStatistics `json:"statistics"`
ProgressStats *repositories.CertificationProgressStats `json:"progress_stats,omitempty"`
Charts map[string]interface{} `json:"charts,omitempty"`
GeneratedAt time.Time `json:"generated_at"`
}
// SystemMonitoringResponse 系统监控响应
type SystemMonitoringResponse struct {
TimeRange string `json:"time_range"`
Metrics map[string]interface{} `json:"metrics"`
Alerts []SystemAlert `json:"alerts,omitempty"`
SystemHealth SystemHealthStatus `json:"system_health"`
LastUpdatedAt time.Time `json:"last_updated_at"`
}
// SystemAlert 系统警告
type SystemAlert struct {
Level string `json:"level"` // info, warning, error, critical
Type string `json:"type"` // 警告类型
Message string `json:"message"` // 警告消息
Metric string `json:"metric"` // 相关指标
Value interface{} `json:"value"` // 当前值
Threshold interface{} `json:"threshold"` // 阈值
CreatedAt time.Time `json:"created_at"`
Metadata map[string]interface{} `json:"metadata,omitempty"`
}
// SystemHealthStatus 系统健康状态
type SystemHealthStatus struct {
Overall string `json:"overall"` // healthy, warning, critical
Components map[string]string `json:"components"` // 各组件状态
LastCheck time.Time `json:"last_check"`
Details map[string]interface{} `json:"details,omitempty"`
}
// ================ 响应构建辅助方法 ================
// NewCertificationListResponse 创建认证列表响应
func NewCertificationListResponse(items []*CertificationResponse, total int64, page, pageSize int) *CertificationListResponse {
totalPages := int((total + int64(pageSize) - 1) / int64(pageSize))
if totalPages == 0 {
totalPages = 1
}
return &CertificationListResponse{
Items: items,
Total: total,
Page: page,
PageSize: pageSize,
TotalPages: totalPages,
}
}
// NewContractSignUrlResponse 创建合同签署URL响应
func NewContractSignUrlResponse(certificationID, signURL, contractURL, nextAction, message string) *ContractSignUrlResponse {
response := &ContractSignUrlResponse{
CertificationID: certificationID,
ContractSignURL: signURL,
ContractURL: contractURL,
NextAction: nextAction,
Message: message,
}
// 设置过期时间默认24小时
expireAt := time.Now().Add(24 * time.Hour)
response.ExpireAt = &expireAt
return response
}
// NewCallbackResponse 创建回调响应
func NewCallbackResponse(success bool, certificationID, callbackType, message string) *CallbackResponse {
return &CallbackResponse{
Success: success,
CertificationID: certificationID,
CallbackType: callbackType,
ProcessedAt: time.Now(),
Message: message,
}
}
// NewSystemAlert 创建系统警告
func NewSystemAlert(level, alertType, message, metric string, value, threshold interface{}) *SystemAlert {
return &SystemAlert{
Level: level,
Type: alertType,
Message: message,
Metric: metric,
Value: value,
Threshold: threshold,
CreatedAt: time.Now(),
Metadata: make(map[string]interface{}),
}
}
// IsSuccess 检查响应是否成功
func (r *CallbackResponse) IsSuccess() bool {
return r.Success
}
// HasStateTransition 检查是否有状态转换
func (r *CallbackResponse) HasStateTransition() bool {
return r.StateTransition != nil
}
// GetStatusChange 获取状态变更描述
func (r *CallbackResponse) GetStatusChange() string {
if !r.HasStateTransition() {
return ""
}
if r.OldStatus == r.NewStatus {
return "状态无变化"
}
return fmt.Sprintf("从 %s 转换为 %s",
enums.GetStatusName(r.OldStatus),
enums.GetStatusName(r.NewStatus))
}
// IsHealthy 检查系统是否健康
func (r *SystemMonitoringResponse) IsHealthy() bool {
return r.SystemHealth.Overall == "healthy"
}
// GetCriticalAlerts 获取严重警告
func (r *SystemMonitoringResponse) GetCriticalAlerts() []*SystemAlert {
var criticalAlerts []*SystemAlert
for i := range r.Alerts {
if r.Alerts[i].Level == "critical" {
criticalAlerts = append(criticalAlerts, &r.Alerts[i])
}
}
return criticalAlerts
}
// HasAlerts 检查是否有警告
func (r *SystemMonitoringResponse) HasAlerts() bool {
return len(r.Alerts) > 0
}
// GetMetricValue 获取指标值
func (r *SystemMonitoringResponse) GetMetricValue(metric string) (interface{}, bool) {
value, exists := r.Metrics[metric]
return value, exists
}

View File

@@ -1,385 +0,0 @@
package certification
import (
"context"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"sort"
"strings"
"go.uber.org/zap"
"tyapi-server/internal/domains/certification/entities"
"tyapi-server/internal/domains/certification/enums"
"tyapi-server/internal/domains/certification/services"
user_services "tyapi-server/internal/domains/user/services"
"tyapi-server/internal/shared/database"
esign_service "tyapi-server/internal/shared/esign"
)
// EsignCallbackData e签宝回调数据结构
type EsignCallbackData struct {
Action string `json:"action"`
Timestamp int64 `json:"timestamp"`
AuthFlowId string `json:"authFlowId,omitempty"`
SignFlowId string `json:"signFlowId,omitempty"`
CustomBizNum string `json:"customBizNum,omitempty"`
SignOrder int `json:"signOrder,omitempty"`
OperateTime int64 `json:"operateTime,omitempty"`
SignResult int `json:"signResult,omitempty"`
ResultDescription string `json:"resultDescription,omitempty"`
AuthType string `json:"authType,omitempty"`
SignFlowStatus string `json:"signFlowStatus,omitempty"`
Operator *EsignOperator `json:"operator,omitempty"`
PsnInfo *EsignPsnInfo `json:"psnInfo,omitempty"`
Organization *EsignOrganization `json:"organization,omitempty"`
}
// EsignOperator 签署人信息
type EsignOperator struct {
PsnId string `json:"psnId"`
PsnAccount *EsignPsnAccount `json:"psnAccount"`
}
// EsignPsnInfo 个人认证信息
type EsignPsnInfo struct {
PsnId string `json:"psnId"`
PsnAccount *EsignPsnAccount `json:"psnAccount"`
}
// EsignPsnAccount 个人账户信息
type EsignPsnAccount struct {
AccountMobile string `json:"accountMobile"`
AccountEmail string `json:"accountEmail"`
}
// EsignOrganization 企业信息
type EsignOrganization struct {
OrgName string `json:"orgName"`
// 可以根据需要添加更多企业信息字段
}
// EsignCallbackApplicationServiceImpl e签宝回调应用服务实现
type EsignCallbackApplicationServiceImpl struct {
certManagementService *services.CertificationManagementService
certWorkflowService *services.CertificationWorkflowService
certificationEsignService *services.CertificationEsignService
enterpriseService *user_services.EnterpriseService
esignService *esign_service.Client
enterpriseRecordService *services.EnterpriseInfoSubmitRecordService
txManager *database.TransactionManager
logger *zap.Logger
}
// NewEsignCallbackApplicationService 创建e签宝回调应用服务
func NewEsignCallbackApplicationService(
certManagementService *services.CertificationManagementService,
certWorkflowService *services.CertificationWorkflowService,
certificationEsignService *services.CertificationEsignService,
enterpriseService *user_services.EnterpriseService,
esignService *esign_service.Client,
enterpriseRecordService *services.EnterpriseInfoSubmitRecordService,
txManager *database.TransactionManager,
logger *zap.Logger,
) EsignCallbackApplicationService {
return &EsignCallbackApplicationServiceImpl{
certManagementService: certManagementService,
certWorkflowService: certWorkflowService,
certificationEsignService: certificationEsignService,
enterpriseService: enterpriseService,
esignService: esignService,
enterpriseRecordService: enterpriseRecordService,
txManager: txManager,
logger: logger,
}
}
// HandleCallback 处理e签宝回调
func (s *EsignCallbackApplicationServiceImpl) HandleCallback(ctx context.Context, callbackData map[string]interface{}, headers map[string]string, queryParams map[string]string) error {
s.logger.Info("开始处理e签宝回调", zap.Any("callback_data", callbackData))
// 1. 验签
if err := s.verifySignature(callbackData, headers, queryParams); err != nil {
s.logger.Error("e签宝回调验签失败", zap.Error(err))
return fmt.Errorf("验签失败: %w", err)
}
// 2. 解析回调数据为结构体
var callback EsignCallbackData
jsonBytes, err := json.Marshal(callbackData)
if err != nil {
return fmt.Errorf("序列化回调数据失败: %w", err)
}
if err := json.Unmarshal(jsonBytes, &callback); err != nil {
return fmt.Errorf("解析回调数据失败: %w", err)
}
// 3. 记录回调信息
s.logger.Info("e签宝回调信息解析",
zap.String("action", callback.Action),
zap.String("auth_flow_id", callback.AuthFlowId),
zap.String("sign_flow_id", callback.SignFlowId),
zap.String("auth_type", callback.AuthType),
zap.String("sign_flow_status", callback.SignFlowStatus),
zap.Int64("timestamp", callback.Timestamp),
)
// 4. 根据回调类型处理业务逻辑
switch callback.Action {
case "AUTH_PASS":
// 只处理企业认证通过
if callback.AuthType == "ORG" {
return s.handleEnterpriseAuthPass(ctx, &callback)
}
s.logger.Info("忽略非企业认证通过回调", zap.String("auth_type", callback.AuthType))
return nil
case "AUTH_FAIL":
// 只处理企业认证失败
if callback.AuthType == "ORG" {
return s.handleEnterpriseAuthFail(ctx, &callback)
}
s.logger.Info("忽略非企业认证失败回调", zap.String("auth_type", callback.AuthType))
return nil
case "SIGN_FLOW_COMPLETE":
// 合同签署流程完成
return s.handleContractSignFlowComplete(ctx, &callback)
default:
s.logger.Info("忽略未知的回调动作", zap.String("action", callback.Action))
return nil
}
}
// verifySignature 验证e签宝回调签名
func (s *EsignCallbackApplicationServiceImpl) verifySignature(callbackData map[string]interface{}, headers map[string]string, queryParams map[string]string) error {
// 1. 获取签名相关参数
signature, ok := headers["X-Tsign-Open-Signature"]
if !ok {
return fmt.Errorf("缺少签名头: X-Tsign-Open-Signature")
}
timestamp, ok := headers["X-Tsign-Open-Timestamp"]
if !ok {
return fmt.Errorf("缺少时间戳头: X-Tsign-Open-Timestamp")
}
// 2. 构建查询参数字符串
var queryKeys []string
for key := range queryParams {
queryKeys = append(queryKeys, key)
}
sort.Strings(queryKeys) // 按ASCII码升序排序
var queryValues []string
for _, key := range queryKeys {
queryValues = append(queryValues, queryParams[key])
}
queryString := strings.Join(queryValues, "")
// 3. 获取请求体数据
bodyData, err := s.getRequestBodyString(callbackData)
if err != nil {
return fmt.Errorf("获取请求体数据失败: %w", err)
}
// 4. 构建验签数据
data := timestamp + queryString + bodyData
// 5. 计算签名
expectedSignature := s.calculateSignature(data, s.esignService.GetConfig().AppSecret)
// 6. 比较签名
if strings.ToLower(expectedSignature) != strings.ToLower(signature) {
s.logger.Error("签名验证失败",
zap.String("expected", strings.ToLower(expectedSignature)),
zap.String("received", strings.ToLower(signature)),
zap.String("data", data),
)
return fmt.Errorf("签名验证失败")
}
s.logger.Info("e签宝回调验签成功")
return nil
}
// calculateSignature 计算HMAC-SHA256签名
func (s *EsignCallbackApplicationServiceImpl) calculateSignature(data, secret string) string {
h := hmac.New(sha256.New, []byte(secret))
h.Write([]byte(data))
return strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
}
// getRequestBodyString 获取请求体字符串
func (s *EsignCallbackApplicationServiceImpl) getRequestBodyString(callbackData map[string]interface{}) (string, error) {
// 将map转换为JSON字符串
jsonBytes, err := json.Marshal(callbackData)
if err != nil {
return "", fmt.Errorf("JSON序列化失败: %w", err)
}
return string(jsonBytes), nil
}
// handleEnterpriseAuthPass 处理企业认证通过回调
func (s *EsignCallbackApplicationServiceImpl) handleEnterpriseAuthPass(ctx context.Context, callback *EsignCallbackData) error {
s.logger.Info("处理企业认证通过回调")
if callback.Organization == nil {
return fmt.Errorf("回调数据中缺少organization字段")
}
if callback.AuthFlowId == "" {
return fmt.Errorf("回调数据中缺少authFlowId字段")
}
// 查找对应的认证申请
certification, err := s.certManagementService.GetCertificationByAuthFlowID(ctx, callback.AuthFlowId)
if err != nil {
return fmt.Errorf("查找认证申请失败: %w", err)
}
if certification.Status != enums.StatusInfoSubmitted {
s.logger.Warn("当前状态不允许完成企业认证", zap.String("status", string(certification.Status)))
return nil
}
if err := s.completeEnterpriseAuth(ctx, certification); err != nil {
return fmt.Errorf("完成企业认证失败: %w", err)
}
s.logger.Info("企业认证通过处理完成",
zap.String("user_id", certification.UserID),
zap.String("certification_id", certification.ID),
zap.String("org_name", callback.Organization.OrgName),
)
return nil
}
// handleEnterpriseAuthFail 处理企业认证失败回调
func (s *EsignCallbackApplicationServiceImpl) handleEnterpriseAuthFail(ctx context.Context, callback *EsignCallbackData) error {
s.logger.Info("处理企业认证失败回调")
if callback.Organization == nil {
return fmt.Errorf("回调数据中缺少organization字段")
}
// 暂时忽略
return nil
}
// handleContractSignFlowComplete 处理合同签署流程完成回调
func (s *EsignCallbackApplicationServiceImpl) handleContractSignFlowComplete(ctx context.Context, callback *EsignCallbackData) error {
s.logger.Info("处理合同签署流程完成回调")
if callback.SignFlowId == "" {
return fmt.Errorf("回调数据中缺少signFlowId字段")
}
if callback.SignFlowStatus == "" {
return fmt.Errorf("回调数据中缺少signFlowStatus字段")
}
// 查找对应的认证申请
certification, err := s.certManagementService.GetCertificationByEsignFlowID(ctx, callback.SignFlowId)
if err != nil {
return fmt.Errorf("查找认证申请失败: %w", err)
}
// 根据签署流程状态处理
switch callback.SignFlowStatus {
case "2": // 已完成(所有签署方完成签署)
s.logger.Info("合同签署流程已完成,所有签署方完成签署")
// 完成合同签署
if err := s.certWorkflowService.CompleteContractSign(ctx, certification.ID, "所有签署方完成签署"); err != nil {
return fmt.Errorf("完成合同签署失败: %w", err)
}
// 自动完成认证
if err := s.certWorkflowService.CompleteCertification(ctx, certification.ID); err != nil {
return fmt.Errorf("完成认证失败: %w", err)
}
s.logger.Info("合同签署流程完成处理成功",
zap.String("user_id", certification.UserID),
zap.String("certification_id", certification.ID),
zap.String("sign_flow_id", callback.SignFlowId),
zap.String("sign_flow_status", callback.SignFlowStatus),
)
case "3": // 已撤销(发起方撤销签署任务)
s.logger.Info("合同签署流程已撤销")
// 可以在这里添加撤销处理逻辑
s.logger.Info("合同签署流程撤销处理完成",
zap.String("user_id", certification.UserID),
zap.String("certification_id", certification.ID),
zap.String("sign_flow_id", callback.SignFlowId),
zap.String("sign_flow_status", callback.SignFlowStatus),
)
// 暂无撤销业务逻辑
case "5": // 已过期(签署截止日到期后触发)
s.logger.Info("合同签署流程已过期")
// 可以在这里添加过期处理逻辑
s.logger.Info("合同签署流程过期处理完成",
zap.String("user_id", certification.UserID),
zap.String("certification_id", certification.ID),
zap.String("sign_flow_id", callback.SignFlowId),
zap.String("sign_flow_status", callback.SignFlowStatus),
)
// 暂无过期业务逻辑
case "7": // 已拒签(签署方拒绝签署)
s.logger.Info("合同签署流程已拒签")
// 可以在这里添加拒签处理逻辑
s.logger.Info("合同签署流程拒签处理完成",
zap.String("user_id", certification.UserID),
zap.String("certification_id", certification.ID),
zap.String("sign_flow_id", callback.SignFlowId),
zap.String("sign_flow_status", callback.SignFlowStatus),
)
default:
s.logger.Warn("未知的签署流程状态",
zap.String("sign_flow_status", callback.SignFlowStatus),
zap.String("sign_flow_id", callback.SignFlowId),
)
// 暂无拒签业务逻辑
}
return nil
}
// 企业认证成功后操作
func (s *EsignCallbackApplicationServiceImpl) completeEnterpriseAuth(ctx context.Context, certification *entities.Certification) error {
err := s.txManager.ExecuteInTx(ctx, func(txCtx context.Context) error {
// 1. 获取企业信息提交记录
enterpriseRecord, err := s.enterpriseRecordService.GetLatestByUserID(txCtx, certification.UserID)
if err != nil {
return fmt.Errorf("获取企业信息失败: %w", err)
}
// 2. 转换状态
if err := s.certWorkflowService.CompleteEnterpriseVerification(txCtx, certification.ID); err != nil {
return err
}
// 3. 创建企业信息
_, err = s.enterpriseService.CreateEnterpriseInfo(txCtx, certification.UserID, enterpriseRecord.CompanyName, enterpriseRecord.UnifiedSocialCode, enterpriseRecord.LegalPersonName, enterpriseRecord.LegalPersonID)
if err != nil {
s.logger.Warn("创建用户企业信息失败", zap.Error(err))
return err
}
return nil
})
if err != nil {
return fmt.Errorf("完成企业认证失败: %w", err)
}
return nil
}