package events import ( "context" "encoding/json" "fmt" "time" "go.uber.org/zap" "tyapi-server/internal/domains/finance/events" "tyapi-server/internal/infrastructure/external/email" "tyapi-server/internal/shared/interfaces" ) // InvoiceEventHandler 发票事件处理器 type InvoiceEventHandler struct { logger *zap.Logger emailService *email.QQEmailService name string eventTypes []string isAsync bool } // NewInvoiceEventHandler 创建发票事件处理器 func NewInvoiceEventHandler(logger *zap.Logger, emailService *email.QQEmailService) *InvoiceEventHandler { return &InvoiceEventHandler{ logger: logger, emailService: emailService, name: "invoice-event-handler", eventTypes: []string{ "InvoiceApplicationCreated", "InvoiceApplicationApproved", "InvoiceApplicationRejected", "InvoiceFileUploaded", }, isAsync: true, } } // GetName 获取处理器名称 func (h *InvoiceEventHandler) GetName() string { return h.name } // GetEventTypes 获取支持的事件类型 func (h *InvoiceEventHandler) GetEventTypes() []string { return h.eventTypes } // IsAsync 是否为异步处理器 func (h *InvoiceEventHandler) IsAsync() bool { return h.isAsync } // GetRetryConfig 获取重试配置 func (h *InvoiceEventHandler) GetRetryConfig() interfaces.RetryConfig { return interfaces.RetryConfig{ MaxRetries: 3, RetryDelay: 5 * time.Second, BackoffFactor: 2.0, MaxDelay: 30 * time.Second, } } // Handle 处理事件 func (h *InvoiceEventHandler) Handle(ctx context.Context, event interfaces.Event) error { h.logger.Info("🔄 开始处理发票事件", zap.String("event_type", event.GetType()), zap.String("event_id", event.GetID()), zap.String("aggregate_id", event.GetAggregateID()), zap.String("handler_name", h.GetName()), zap.Time("event_timestamp", event.GetTimestamp()), ) switch event.GetType() { case "InvoiceApplicationCreated": h.logger.Info("📝 处理发票申请创建事件") return h.handleInvoiceApplicationCreated(ctx, event) case "InvoiceApplicationApproved": h.logger.Info("✅ 处理发票申请通过事件") return h.handleInvoiceApplicationApproved(ctx, event) case "InvoiceApplicationRejected": h.logger.Info("❌ 处理发票申请拒绝事件") return h.handleInvoiceApplicationRejected(ctx, event) case "InvoiceFileUploaded": h.logger.Info("📎 处理发票文件上传事件") return h.handleInvoiceFileUploaded(ctx, event) default: h.logger.Warn("⚠️ 未知的发票事件类型", zap.String("event_type", event.GetType())) return nil } } // handleInvoiceApplicationCreated 处理发票申请创建事件 func (h *InvoiceEventHandler) handleInvoiceApplicationCreated(ctx context.Context, event interfaces.Event) error { h.logger.Info("发票申请已创建", zap.String("application_id", event.GetAggregateID()), ) // 这里可以发送通知给管理员,告知有新的发票申请 // 暂时只记录日志 return nil } // handleInvoiceApplicationApproved 处理发票申请通过事件 func (h *InvoiceEventHandler) handleInvoiceApplicationApproved(ctx context.Context, event interfaces.Event) error { h.logger.Info("发票申请已通过", zap.String("application_id", event.GetAggregateID()), ) // 这里可以发送通知给用户,告知发票申请已通过 // 暂时只记录日志 return nil } // handleInvoiceApplicationRejected 处理发票申请拒绝事件 func (h *InvoiceEventHandler) handleInvoiceApplicationRejected(ctx context.Context, event interfaces.Event) error { h.logger.Info("发票申请被拒绝", zap.String("application_id", event.GetAggregateID()), ) // 这里可以发送邮件通知用户,告知发票申请被拒绝 // 暂时只记录日志 return nil } // handleInvoiceFileUploaded 处理发票文件上传事件 func (h *InvoiceEventHandler) handleInvoiceFileUploaded(ctx context.Context, event interfaces.Event) error { h.logger.Info("📎 发票文件已上传事件开始处理", zap.String("invoice_id", event.GetAggregateID()), zap.String("event_id", event.GetID()), ) // 解析事件数据 payload := event.GetPayload() if payload == nil { h.logger.Error("❌ 事件数据为空") return fmt.Errorf("事件数据为空") } h.logger.Info("📋 事件数据解析开始", zap.Any("payload_type", fmt.Sprintf("%T", payload)), ) // 将payload转换为JSON,然后解析为InvoiceFileUploadedEvent payloadBytes, err := json.Marshal(payload) if err != nil { h.logger.Error("❌ 序列化事件数据失败", zap.Error(err)) return fmt.Errorf("序列化事件数据失败: %w", err) } h.logger.Info("📄 事件数据序列化成功", zap.String("payload_json", string(payloadBytes)), ) var fileUploadedEvent events.InvoiceFileUploadedEvent err = json.Unmarshal(payloadBytes, &fileUploadedEvent) if err != nil { h.logger.Error("❌ 解析发票文件上传事件失败", zap.Error(err)) return fmt.Errorf("解析发票文件上传事件失败: %w", err) } h.logger.Info("✅ 事件数据解析成功", zap.String("invoice_id", fileUploadedEvent.InvoiceID), zap.String("user_id", fileUploadedEvent.UserID), zap.String("receiving_email", fileUploadedEvent.ReceivingEmail), zap.String("file_name", fileUploadedEvent.FileName), zap.String("file_url", fileUploadedEvent.FileURL), zap.String("company_name", fileUploadedEvent.CompanyName), zap.String("amount", fileUploadedEvent.Amount.String()), zap.String("invoice_type", string(fileUploadedEvent.InvoiceType)), ) // 发送发票邮件给用户 return h.sendInvoiceEmail(ctx, &fileUploadedEvent) } // sendInvoiceEmail 发送发票邮件 func (h *InvoiceEventHandler) sendInvoiceEmail(ctx context.Context, event *events.InvoiceFileUploadedEvent) error { h.logger.Info("📧 开始发送发票邮件", zap.String("invoice_id", event.InvoiceID), zap.String("user_id", event.UserID), zap.String("receiving_email", event.ReceivingEmail), zap.String("file_name", event.FileName), zap.String("file_url", event.FileURL), ) // 构建邮件数据 emailData := &email.InvoiceEmailData{ CompanyName: event.CompanyName, Amount: event.Amount.String(), InvoiceType: event.InvoiceType.GetDisplayName(), FileURL: event.FileURL, FileName: event.FileName, ReceivingEmail: event.ReceivingEmail, ApprovedAt: event.UploadedAt.Format("2006-01-02 15:04:05"), } h.logger.Info("📋 邮件数据构建完成", zap.String("company_name", emailData.CompanyName), zap.String("amount", emailData.Amount), zap.String("invoice_type", emailData.InvoiceType), zap.String("file_url", emailData.FileURL), zap.String("file_name", emailData.FileName), zap.String("receiving_email", emailData.ReceivingEmail), zap.String("approved_at", emailData.ApprovedAt), ) // 发送邮件 h.logger.Info("🚀 开始调用邮件服务发送邮件") err := h.emailService.SendInvoiceEmail(ctx, emailData) if err != nil { h.logger.Error("❌ 发送发票邮件失败", zap.String("invoice_id", event.InvoiceID), zap.String("receiving_email", event.ReceivingEmail), zap.Error(err), ) return fmt.Errorf("发送发票邮件失败: %w", err) } h.logger.Info("✅ 发票邮件发送成功", zap.String("invoice_id", event.InvoiceID), zap.String("receiving_email", event.ReceivingEmail), ) return nil }