Yimaru-BackEnd/internal/services/report/process.go
Samuel Tariku 485cba3c9c feat: Add new stat stores and reporting functionalities for bets, branches, and wallets
- Introduced BetStatStore, BranchStatStore, and WalletStatStore interfaces for handling statistics.
- Implemented repository methods for fetching and updating bet, branch, and wallet statistics.
- Created reporting services for generating interval reports for bets, branches, companies, and wallets.
- Enhanced CSV writing functionality to support dynamic struct to CSV conversion.
- Added cron jobs for periodic updates of branch and wallet statistics.
- Updated wallet handler to include transaction statistics in the response.
2025-10-29 07:14:38 +03:00

109 lines
2.7 KiB
Go

package report
import (
"context"
"errors"
"fmt"
"time"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"go.uber.org/zap"
)
var (
ErrUnauthorizedUserReport = errors.New("unauthorized user report")
)
func (s *Service) ProcessReportRequests(ctx context.Context) error {
requests, total, err := s.GetAllReportRequests(ctx, domain.ReportRequestFilter{
Status: domain.ValidReportRequestStatus{
Value: domain.PendingReportRequest,
Valid: true,
},
})
if err != nil {
s.mongoLogger.Error("failed to get pending report requests", zap.Error(err))
return err
}
for i, req := range requests {
if err := s.processSingleReportRequest(ctx, req); err != nil {
s.mongoLogger.Error("failed to process report request",
zap.Int64("id", req.ID),
zap.Int("index", i),
zap.Int64("total", total),
zap.String("type", string(req.Type)),
zap.Error(err),
)
}
}
return nil
}
func (s *Service) processSingleReportRequest(ctx context.Context, req domain.ReportRequestDetail) error {
var (
filePath string
rejectReason string
status = domain.SuccessReportRequest
)
start := time.Now()
defer func() {
s.mongoLogger.Info("report request processed",
zap.Int64("id", req.ID),
zap.String("type", string(req.Type)),
zap.String("status", string(status)),
zap.Duration("duration", time.Since(start)),
)
}()
gen, ok := s.generators[req.Type]
if !ok {
status = domain.RejectReportRequest
rejectReason = fmt.Sprintf("unsupported report type: %s", req.Type)
s.mongoLogger.Warn("unsupported report type", zap.String("type", string(req.Type)))
} else {
fp, err := gen(ctx, req)
if err != nil {
status = domain.RejectReportRequest
rejectReason = fmt.Sprintf("failed to generate report: %v", err)
} else {
filePath = fp
}
}
update := domain.UpdateRequestRequest{
ID: req.ID,
Status: domain.ValidReportRequestStatus{
Value: status,
Valid: true,
},
FilePath: domain.ValidString{
Value: filePath,
Valid: filePath != "",
},
RejectReason: domain.ValidString{
Value: rejectReason,
Valid: rejectReason != "",
},
}
if err := s.UpdateReportRequest(ctx, update); err != nil {
s.mongoLogger.Error("failed to update report request", zap.Int64("id", req.ID), zap.Error(err))
return fmt.Errorf("failed to update report request: %w", err)
}
// Prepare updated object for notification
updatedReq := req
updatedReq.FilePath = update.FilePath
updatedReq.Status = update.Status.Value
updatedReq.RejectReason = update.RejectReason
if err := s.SendReportRequestNotification(ctx, updatedReq); err != nil {
s.mongoLogger.Warn("failed to send notification", zap.Int64("id", req.ID), zap.Error(err))
}
return nil
}