Yimaru-BackEnd/internal/services/report/company.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

112 lines
3.6 KiB
Go

package report
import (
"context"
"fmt"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"go.uber.org/zap"
)
type CompanyIntervalRow struct {
Period string `csv:"Period"`
CompanyName string `csv:"CompanyName"`
TotalBets int64 `csv:"Total Bets"`
TotalStake float32 `csv:"Total Stake"`
DeductedStake float32 `csv:"Deducted Stake"`
TotalCashOut float32 `csv:"Total CashOut"`
TotalCashBacks float32 `csv:"Total CashBacks"`
NumberOfUnsettled int64 `csv:"Number Of Unsettled"`
TotalUnsettledAmount float32 `csv:"Total Unsettled Amount"`
TotalAdmins int64 `csv:"Total Admins"`
TotalManagers int64 `csv:"Total Managers"`
TotalCashiers int64 `csv:"Total Cashiers"`
TotalCustomers int64 `csv:"Total Customers"`
TotalApprovers int64 `csv:"Total Approvers"`
TotalBranches int64 `csv:"Total Branches"`
}
func (s *Service) GenerateCompanyIntervalReport(ctx context.Context, request domain.ReportRequestDetail) (string, error) {
// Only a super-admin is allowed to generate this type of report
if request.RequesterRole.Valid && request.RequesterRole.Value != domain.RoleSuperAdmin {
s.mongoLogger.Error("[GenerateCompanyIntervalReport] Unauthorized user report")
return "", ErrUnauthorizedUserReport
}
if request.Metadata.Interval == nil {
s.mongoLogger.Error("[GenerateCompanyIntervalReport] Metadata interval is empty")
return "", domain.ErrInvalidInterval
}
interval, err := domain.ParseDateInterval(*request.Metadata.Interval)
if err != nil {
s.mongoLogger.Error("[GenerateCompanyIntervalReport] Failed to parse date interval",
zap.String("interval", *request.Metadata.Interval),
zap.Error(err),
)
return "", domain.ErrInvalidInterval
}
stats, err := s.statService.GetCompanyStatsByInterval(ctx, domain.CompanyStatFilter{
Interval: domain.ValidDateInterval{
Value: interval,
Valid: true,
},
})
if err != nil {
s.mongoLogger.Error("[GenerateCompanyIntervalReport] Failed to fetch company stats",
zap.String("interval", string(interval)),
zap.Error(err),
)
return "", fmt.Errorf("fetching company stats: %w", err)
}
var rows [][]string
var headers []string
for _, stat := range stats {
endDate, err := domain.GetEndDateFromInterval(interval, stat.IntervalStart)
if err != nil {
s.mongoLogger.Error("[GenerateCompanyIntervalReport] Failed to get end date from interval",
zap.String("interval", string(interval)),
zap.Error(err),
)
return "", fmt.Errorf("invalid interval end date: %w", err)
}
period := fmt.Sprintf("%s to %s",
stat.IntervalStart.Format("2006-01-02"),
endDate.Format("2006-01-02"),
)
r := CompanyIntervalRow{
Period: period,
CompanyName: stat.CompanyName,
TotalBets: stat.TotalBets,
TotalStake: stat.TotalStake.Float32(),
DeductedStake: stat.DeductedStake.Float32(),
TotalCashOut: stat.TotalCashOut.Float32(),
TotalCashBacks: stat.TotalCashBacks.Float32(),
NumberOfUnsettled: stat.NumberOfUnsettled,
TotalUnsettledAmount: stat.TotalUnsettledAmount.Float32(),
TotalAdmins: stat.TotalAdmins,
TotalManagers: stat.TotalManagers,
TotalCashiers: stat.TotalCashiers,
TotalCustomers: stat.TotalCustomers,
TotalApprovers: stat.TotalApprovers,
TotalBranches: stat.TotalBranches,
}
if headers == nil {
headers, _ = StructToCSVRow(r)
rows = append(rows, headers)
}
_, row := StructToCSVRow(r)
rows = append(rows, row)
}
return s.WriteCSV(rows, "company_interval")
}