230 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			230 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
|  | 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 | |||
|  | } | |||
|  | 
 | |||
|  |   |