293 lines
9.6 KiB
Go
293 lines
9.6 KiB
Go
package result
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
func (s *Service) CheckAndSendResultNotifications(ctx context.Context, createdAfter time.Time) error {
|
|
|
|
resultLog, err := s.resultLogStore.GetAllResultLog(ctx, domain.ResultLogFilter{
|
|
CreatedAfter: domain.ValidTime{
|
|
Value: createdAfter,
|
|
Valid: true,
|
|
},
|
|
})
|
|
|
|
if err != nil {
|
|
s.mongoLogger.Error(
|
|
"Failed to get result log",
|
|
zap.Time("CreatedAfter", createdAfter),
|
|
zap.Error(err),
|
|
)
|
|
return err
|
|
}
|
|
|
|
if len(resultLog) == 0 {
|
|
s.mongoLogger.Info(
|
|
"No results found for check and send result notification",
|
|
zap.Time("CreatedAfter", createdAfter),
|
|
)
|
|
return nil
|
|
}
|
|
|
|
totalResultLog := domain.ResultLog{
|
|
StatusNotFinishedCount: resultLog[0].StatusNotFinishedCount,
|
|
StatusPostponedCount: resultLog[0].StatusPostponedCount,
|
|
}
|
|
for _, log := range resultLog {
|
|
// Add all the bets
|
|
totalResultLog.StatusNotFinishedBets += log.StatusNotFinishedBets
|
|
totalResultLog.StatusPostponedBets += log.StatusPostponedBets
|
|
totalResultLog.StatusToBeFixedBets += log.StatusToBeFixedBets
|
|
totalResultLog.StatusRemovedBets += log.StatusRemovedBets
|
|
totalResultLog.StatusEndedBets += log.StatusEndedBets
|
|
|
|
totalResultLog.StatusToBeFixedCount += log.StatusToBeFixedCount
|
|
totalResultLog.StatusRemovedCount += log.StatusRemovedCount
|
|
totalResultLog.StatusEndedCount += log.StatusEndedCount
|
|
totalResultLog.RemovedCount += log.RemovedCount
|
|
}
|
|
|
|
err = s.SendAdminResultStatusErrorNotification(ctx, totalResultLog, createdAfter, time.Now())
|
|
if err != nil {
|
|
s.mongoLogger.Error(
|
|
"Failed to send admin result status notification",
|
|
zap.Time("CreatedAfter", createdAfter),
|
|
zap.Error(err),
|
|
)
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func buildHeadlineAndMessage(counts domain.ResultLog, createdAfter time.Time, endTime time.Time) (string, string) {
|
|
period := fmt.Sprintf("%s - %s", createdAfter.Format("02 Jan 2006"), endTime.Format("02 Jan 2006"))
|
|
|
|
totalIssues := counts.StatusNotFinishedCount + counts.StatusToBeFixedCount + counts.StatusPostponedCount + counts.StatusRemovedCount
|
|
totalBets := counts.StatusEndedBets + counts.StatusNotFinishedBets + counts.StatusPostponedBets + counts.StatusRemovedBets + counts.StatusToBeFixedBets
|
|
if totalIssues == 0 {
|
|
return "✅ Successfully Processed Event Results", fmt.Sprintf(
|
|
"%d total ended events with %d total bets. No issues detected", counts.StatusEndedCount, totalBets,
|
|
)
|
|
}
|
|
|
|
parts := []string{}
|
|
if counts.StatusNotFinishedCount > 0 {
|
|
parts = append(parts, fmt.Sprintf("%d unfinished with %d bets", counts.StatusNotFinishedCount, counts.StatusNotFinishedBets))
|
|
}
|
|
if counts.StatusToBeFixedCount > 0 {
|
|
parts = append(parts, fmt.Sprintf("%d to-fix with %d bets", counts.StatusToBeFixedCount, counts.StatusToBeFixedBets))
|
|
}
|
|
if counts.StatusPostponedCount > 0 {
|
|
parts = append(parts, fmt.Sprintf("%d postponed with %d bets", counts.StatusPostponedCount, counts.StatusPostponedBets))
|
|
}
|
|
if counts.StatusRemovedCount > 0 {
|
|
parts = append(parts, fmt.Sprintf("%d removed with %d bets", counts.StatusRemovedCount, counts.StatusRemovedBets))
|
|
}
|
|
if counts.StatusEndedCount > 0 {
|
|
parts = append(parts, fmt.Sprintf("%d ended with %d bets", counts.StatusEndedCount, counts.StatusEndedBets))
|
|
}
|
|
|
|
headline := "⚠️ Issues Found Processing Event Results"
|
|
message := fmt.Sprintf("Processed expired event results (%s): %s. Please review pending entries.",
|
|
period, strings.Join(parts, ", "))
|
|
return headline, message
|
|
}
|
|
|
|
func buildHeadlineAndMessageEmail(counts domain.ResultLog, user domain.User, createdAfter time.Time, endTime time.Time) (string, string, string) {
|
|
period := fmt.Sprintf("%s - %s", createdAfter.Format("02 Jan 2006"), endTime.Format("02 Jan 2006"))
|
|
|
|
totalIssues := counts.StatusNotFinishedCount + counts.StatusToBeFixedCount +
|
|
counts.StatusPostponedCount + counts.StatusRemovedCount
|
|
totalEvents := counts.StatusEndedCount + counts.StatusNotFinishedCount +
|
|
counts.StatusToBeFixedCount + counts.StatusPostponedCount + counts.StatusRemovedCount
|
|
totalBets := counts.StatusEndedBets + counts.StatusNotFinishedBets +
|
|
counts.StatusPostponedBets + counts.StatusRemovedBets + counts.StatusToBeFixedBets
|
|
|
|
greeting := fmt.Sprintf("Hi %s %s,", user.FirstName, user.LastName)
|
|
|
|
if totalIssues == 0 {
|
|
headline := "✅ Weekly Results Report — All Events Processed Successfully"
|
|
plain := fmt.Sprintf(`%s
|
|
|
|
Weekly Results Summary (%s):
|
|
- %d Ended Events
|
|
- %d Total Bets
|
|
|
|
All events were processed successfully, and no issues were detected.
|
|
|
|
Best regards,
|
|
The System`, greeting, period, counts.StatusEndedCount, totalBets)
|
|
|
|
html := fmt.Sprintf(`<p>%s</p>
|
|
<h2>Weekly Results Summary</h2>
|
|
<p><em>Period: %s</em></p>
|
|
<ul>
|
|
<li><strong>%d Ended Events</strong></li>
|
|
<li><strong>%d Total Bets</strong></li>
|
|
</ul>
|
|
<p>All events were processed successfully, and no issues were detected.</p>
|
|
<p>Best regards,<br>The System</p>`,
|
|
greeting, period, counts.StatusEndedCount, totalBets)
|
|
|
|
return headline, plain, html
|
|
}
|
|
|
|
partsPlain := []string{}
|
|
partsHTML := []string{}
|
|
|
|
if counts.StatusNotFinishedCount > 0 {
|
|
partsPlain = append(partsPlain,
|
|
fmt.Sprintf("- %d Incomplete Events (%d Bets)", counts.StatusNotFinishedCount, counts.StatusNotFinishedBets))
|
|
partsHTML = append(partsHTML,
|
|
fmt.Sprintf("<li><strong>%d Incomplete Events</strong> (%d Bets)</li>", counts.StatusNotFinishedCount, counts.StatusNotFinishedBets))
|
|
}
|
|
if counts.StatusToBeFixedCount > 0 {
|
|
partsPlain = append(partsPlain,
|
|
fmt.Sprintf("- %d Requires Review (%d Bets)", counts.StatusToBeFixedCount, counts.StatusToBeFixedBets))
|
|
partsHTML = append(partsHTML,
|
|
fmt.Sprintf("<li><strong>%d Requires Review</strong> (%d Bets)</li>", counts.StatusToBeFixedCount, counts.StatusToBeFixedBets))
|
|
}
|
|
if counts.StatusPostponedCount > 0 {
|
|
partsPlain = append(partsPlain,
|
|
fmt.Sprintf("- %d Postponed Events (%d Bets)", counts.StatusPostponedCount, counts.StatusPostponedBets))
|
|
partsHTML = append(partsHTML,
|
|
fmt.Sprintf("<li><strong>%d Postponed Events</strong> (%d Bets)</li>", counts.StatusPostponedCount, counts.StatusPostponedBets))
|
|
}
|
|
if counts.StatusRemovedCount > 0 {
|
|
partsPlain = append(partsPlain,
|
|
fmt.Sprintf("- %d Discarded Events (%d Bets)", counts.StatusRemovedCount, counts.StatusRemovedBets))
|
|
partsHTML = append(partsHTML,
|
|
fmt.Sprintf("<li><strong>%d Discarded Events</strong> (%d Bets)</li>", counts.StatusRemovedCount, counts.StatusRemovedBets))
|
|
}
|
|
if counts.StatusEndedCount > 0 {
|
|
partsPlain = append(partsPlain,
|
|
fmt.Sprintf("- %d Successfully Ended Events (%d Bets)", counts.StatusEndedCount, counts.StatusEndedBets))
|
|
partsHTML = append(partsHTML,
|
|
fmt.Sprintf("<li><strong>%d Successfully Ended Events</strong> (%d Bets)</li>", counts.StatusEndedCount, counts.StatusEndedBets))
|
|
}
|
|
|
|
headline := "⚠️ Weekly Results Report — Review Required"
|
|
|
|
plain := fmt.Sprintf(`%s
|
|
|
|
Weekly Results Summary (%s):
|
|
%s
|
|
|
|
Totals:
|
|
- %d Events Processed
|
|
- %d Total Bets
|
|
|
|
Next Steps:
|
|
Some events require your attention. Please log into the admin dashboard to review pending issues.
|
|
|
|
Best regards,
|
|
The System`,
|
|
greeting,
|
|
period,
|
|
strings.Join(partsPlain, "\n"),
|
|
totalEvents,
|
|
totalBets,
|
|
)
|
|
|
|
html := fmt.Sprintf(`<p>%s</p>
|
|
<h2>Weekly Results Summary</h2>
|
|
<p><em>Period: %s</em></p>
|
|
<ul>
|
|
%s
|
|
</ul>
|
|
<h3>Totals</h3>
|
|
<ul>
|
|
<li><strong>%d Events Processed</strong></li>
|
|
<li><strong>%d Total Bets</strong></li>
|
|
</ul>
|
|
<p><strong>Next Steps:</strong><br>Some events require your attention. Please <a href="https://admin.fortunebets.net">log into the admin dashboard</a> to review pending issues.</p>
|
|
<p>Best regards,<br>The System</p>`,
|
|
greeting,
|
|
period,
|
|
strings.Join(partsHTML, "\n"),
|
|
totalEvents,
|
|
totalBets,
|
|
)
|
|
|
|
return headline, plain, html
|
|
}
|
|
|
|
func (s *Service) SendAdminResultStatusErrorNotification(
|
|
ctx context.Context,
|
|
counts domain.ResultLog,
|
|
createdAfter time.Time,
|
|
endTime time.Time,
|
|
) error {
|
|
|
|
superAdmins, _, err := s.userSvc.GetAllUsers(ctx, domain.UserFilter{
|
|
Role: string(domain.RoleSuperAdmin),
|
|
})
|
|
if err != nil {
|
|
s.mongoLogger.Error("failed to get super_admin recipients", zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
metaBytes, err := json.Marshal(counts)
|
|
if err != nil {
|
|
s.mongoLogger.Error("failed to marshal metadata", zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
headline, message := buildHeadlineAndMessage(counts, createdAfter, endTime)
|
|
|
|
notification := &domain.Notification{
|
|
ErrorSeverity: domain.NotificationErrorSeverityHigh,
|
|
DeliveryStatus: domain.DeliveryStatusPending,
|
|
IsRead: false,
|
|
Type: domain.NOTIFICATION_TYPE_BET_RESULT,
|
|
Level: domain.NotificationLevelWarning,
|
|
Reciever: domain.NotificationRecieverSideAdmin,
|
|
DeliveryChannel: domain.DeliveryChannelInApp,
|
|
Payload: domain.NotificationPayload{
|
|
Headline: headline,
|
|
Message: message,
|
|
},
|
|
Priority: 2,
|
|
Metadata: metaBytes,
|
|
}
|
|
|
|
var sendErrors []error
|
|
for _, user := range superAdmins {
|
|
notification.RecipientID = user.ID
|
|
if err := s.notificationSvc.SendNotification(ctx, notification); err != nil {
|
|
s.mongoLogger.Error("failed to send admin notification",
|
|
zap.Int64("admin_id", user.ID),
|
|
zap.Error(err),
|
|
)
|
|
sendErrors = append(sendErrors, err)
|
|
}
|
|
// notification.DeliveryChannel = domain.DeliveryChannelEmail
|
|
if user.Email == "" {
|
|
continue
|
|
}
|
|
|
|
subject, plain, html := buildHeadlineAndMessageEmail(counts, user, createdAfter, endTime)
|
|
if err := s.messengerSvc.SendEmail(ctx, user.Email, plain, html, subject); err != nil {
|
|
s.mongoLogger.Error("failed to send admin result report email",
|
|
zap.Int64("admin_id", user.ID),
|
|
zap.Error(err),
|
|
)
|
|
sendErrors = append(sendErrors, err)
|
|
}
|
|
}
|
|
|
|
if len(sendErrors) > 0 {
|
|
return fmt.Errorf("sent with partial failure: %d errors", len(sendErrors))
|
|
}
|
|
return nil
|
|
}
|