package notification import ( "context" "errors" "tm/internal/customer" "tm/internal/user" "tm/pkg/logger" "tm/pkg/notification" "tm/pkg/response" ) // NotificationService defines the interface for notification business logic type Service interface { Send(ctx context.Context, req *NotificationRequest) error getUsers(ctx context.Context, userIDs []string) ([]notificationRecipient, error) getCustomers(ctx context.Context, values []string, target string) ([]notificationRecipient, error) } // notificationService implements NotificationService interface type notificationService struct { sdk notification.SDK userService user.Service customerService customer.Service logger logger.Logger } // NewNotificationService creates a new notification service func NewNotificationService( sdk notification.SDK, userService user.Service, customerService customer.Service, logger logger.Logger, ) Service { return ¬ificationService{ sdk: sdk, userService: userService, customerService: customerService, logger: logger, } } // Send sends a multiple notification func (s *notificationService) Send(ctx context.Context, req *NotificationRequest) error { s.logger.Info("Sending notification", map[string]interface{}{ "recipient": req.Recipient, "type": req.Type, "priority": req.Priority, }) if req.Target == TargetAudienceAllUsers || req.Target == TargetAudienceSpecificUsers { recipients, err := s.getUsers(ctx, req.Recipient) if err != nil { return err } for _, recipient := range recipients { for _, v := range recipient.DeviceTokens { s.sdk.SendNotification(ctx, ¬ification.NotificationRequest{ UserID: recipient.UserID, Title: req.Title, Message: req.Description, Type: string(req.Type), Priority: string(req.Priority), EventType: notification.EventTypePush, Metadata: map[string]any{ "tender": req.Tender, }, Methods: notification.NotificationMethods{ Push: v, }, ScheduledAt: req.ScheduleAt, }) } if recipient.Email != "" { s.sdk.SendNotification(ctx, ¬ification.NotificationRequest{ UserID: recipient.UserID, Title: req.Title, Message: req.Description, Type: string(req.Type), Priority: string(req.Priority), EventType: notification.EventTypeEmail, Metadata: map[string]any{ "tender": req.Tender, }, Methods: notification.NotificationMethods{ Email: recipient.Email, }, ScheduledAt: req.ScheduleAt, }) } } } else { recipients, err := s.getCustomers(ctx, req.Recipient, string(req.Target)) if err != nil { return err } for _, recipient := range recipients { for _, v := range recipient.DeviceTokens { s.sdk.SendNotification(ctx, ¬ification.NotificationRequest{ UserID: recipient.UserID, Title: req.Title, Message: req.Description, Type: string(req.Type), Priority: string(req.Priority), EventType: notification.EventTypePush, Methods: notification.NotificationMethods{ Push: v, }, ScheduledAt: req.ScheduleAt, }) } if recipient.Email != "" { s.sdk.SendNotification(ctx, ¬ification.NotificationRequest{ UserID: recipient.UserID, Title: req.Title, Message: req.Description, Type: string(req.Type), Priority: string(req.Priority), EventType: notification.EventTypeEmail, Methods: notification.NotificationMethods{ Email: recipient.Email, }, ScheduledAt: req.ScheduleAt, }) } } s.logger.Info("Notification sent", map[string]interface{}{ "recipient": req.Recipient, "channels": req.Channels, }) return nil } return nil } func (s *notificationService) getUsers(ctx context.Context, userIDs []string) ([]notificationRecipient, error) { recipients := make([]notificationRecipient, 0) offset := 0 for { var users *user.UserListResponse var err error if len(userIDs) > 0 { users, err = s.userService.GetUsersByIDs(ctx, userIDs) if err != nil { return nil, err } } else { users, err = s.userService.Search(ctx, &user.SearchUsersForm{}, &response.Pagination{Limit: 100, Offset: offset}) if err != nil { return nil, err } offset += 100 if len(users.Users) == 0 { break } } for _, user := range users.Users { recipients = append(recipients, notificationRecipient{ UserID: user.ID, Email: user.Email, DeviceTokens: user.DeviceToken, }) } if len(recipients) == 0 { return nil, errors.New("no users found") } } return recipients, nil } func (s *notificationService) getCustomers(ctx context.Context, values []string, target string) ([]notificationRecipient, error) { recipients := make([]notificationRecipient, 0) if target == string(TargetAudienceSpecificRole) { customers, err := s.customerService.GetCustomersByRole(ctx, values[0]) if err != nil { return nil, err } for _, customer := range customers.Customers { recipients = append(recipients, notificationRecipient{ UserID: customer.ID, Email: customer.Email, DeviceTokens: customer.DeviceToken, }) } } else if target == string(TargetAudienceSpecificCompany) { customers, err := s.customerService.GetCustomersByCompanies(ctx, values) if err != nil { return nil, err } for _, customer := range customers.Customers { recipients = append(recipients, notificationRecipient{ UserID: customer.ID, Email: customer.Email, DeviceTokens: customer.DeviceToken, }) } } else if target == string(TargetAudienceSpecificCustomer) { customers, err := s.customerService.GetCustomersByIDs(ctx, values) if err != nil { return nil, err } for _, customer := range customers.Customers { recipients = append(recipients, notificationRecipient{ UserID: customer.ID, Email: customer.Email, DeviceTokens: customer.DeviceToken, }) } } else { offset := 0 for { customers, err := s.customerService.Search(ctx, &customer.SearchCustomersForm{}, &response.Pagination{Limit: 100, Offset: offset}) if err != nil { return nil, err } for _, customer := range customers.Customers { recipients = append(recipients, notificationRecipient{ UserID: customer.ID, Email: customer.Email, DeviceTokens: customer.DeviceToken, }) } offset += 100 if len(customers.Customers) == 0 { break } } } if len(recipients) == 0 { return nil, errors.New("no customers found") } return recipients, nil }