Yimaru-BackEnd/internal/repository/report.go

235 lines
7.1 KiB
Go

package repository
import (
"context"
"fmt"
"time"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/jackc/pgx/v5/pgtype"
)
type ReportRepository interface {
GenerateReport(timeFrame domain.TimeFrame, start, end time.Time) (*domain.Report, error)
SaveReport(report *domain.Report) error
FindReportsByTimeFrame(timeFrame domain.TimeFrame, limit int) ([]*domain.Report, error)
GetTotalCashOutInRange(ctx context.Context, from, to time.Time) (float64, error)
GetTotalCashMadeInRange(ctx context.Context, from, to time.Time) (float64, error)
GetTotalCashBacksInRange(ctx context.Context, from, to time.Time) (float64, error)
GetTotalBetsMadeInRange(ctx context.Context, from, to time.Time) (int64, error)
GetVirtualGameSummaryInRange(ctx context.Context, from, to time.Time) ([]dbgen.GetVirtualGameSummaryInRangeRow, error)
GetAllTicketsInRange(ctx context.Context, from, to time.Time) (dbgen.GetAllTicketsInRangeRow, error)
GetWalletTransactionsInRange(ctx context.Context, from, to time.Time) ([]dbgen.GetWalletTransactionsInRangeRow, error)
GetCompanyWiseReport(ctx context.Context, from, to time.Time) ([]dbgen.GetCompanyWiseReportRow, error)
GetBranchWiseReport(ctx context.Context, from, to time.Time) ([]dbgen.GetBranchWiseReportRow, error)
}
type ReportRepo struct {
store *Store
}
func NewReportRepo(store *Store) ReportRepository {
return &ReportRepo{store: store}
}
func (r *ReportRepo) GenerateReport(timeFrame domain.TimeFrame, start, end time.Time) (*domain.Report, error) {
// Implement SQL queries to calculate metrics
var report domain.Report
// Total Bets
err := r.store.conn.QueryRow(
context.Background(),
`SELECT COUNT(*) FROM bets
WHERE created_at BETWEEN $1 AND $2`, start, end).Scan(&report.TotalBets)
if err != nil {
return nil, err
}
// Total Cash In
err = r.store.conn.QueryRow(
context.Background(),
`SELECT COALESCE(SUM(amount), 0) FROM transactions
WHERE type = 'stake' AND created_at BETWEEN $1 AND $2`, start, end).Scan(&report.TotalCashIn)
if err != nil {
return nil, err
}
// Similar queries for Cash Out and Cash Back...
report.TimeFrame = timeFrame
report.PeriodStart = start
report.PeriodEnd = end
report.GeneratedAt = time.Now()
return &report, nil
}
func (r *ReportRepo) SaveReport(report *domain.Report) error {
_, err := r.store.conn.Exec(
context.Background(),
`INSERT INTO reports
(id, time_frame, period_start, period_end, total_bets, total_cash_in, total_cash_out, total_cash_back, generated_at)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
report.ID, report.TimeFrame, report.PeriodStart, report.PeriodEnd,
report.TotalBets, report.TotalCashIn, report.TotalCashOut, report.TotalCashBack, report.GeneratedAt)
return err
}
func (r *ReportRepo) FindReportsByTimeFrame(timeFrame domain.TimeFrame, limit int) ([]*domain.Report, error) {
rows, err := r.store.conn.Query(
context.Background(),
`SELECT id, time_frame, period_start, period_end, total_bets,
total_cash_in, total_cash_out, total_cash_back, generated_at
FROM reports
WHERE time_frame = $1
ORDER BY generated_at DESC
LIMIT $2`,
timeFrame, limit)
if err != nil {
return nil, err
}
defer rows.Close()
var reports []*domain.Report
for rows.Next() {
var report domain.Report
err := rows.Scan(
&report.ID,
&report.TimeFrame,
&report.PeriodStart,
&report.PeriodEnd,
&report.TotalBets,
&report.TotalCashIn,
&report.TotalCashOut,
&report.TotalCashBack,
&report.GeneratedAt,
)
if err != nil {
return nil, err
}
reports = append(reports, &report)
}
if err := rows.Err(); err != nil {
return nil, err
}
return reports, nil
}
func (r *ReportRepo) GetTotalBetsMadeInRange(ctx context.Context, from, to time.Time) (int64, error) {
params := dbgen.GetTotalBetsMadeInRangeParams{
From: ToPgTimestamp(from),
To: ToPgTimestamp(to),
}
return r.store.queries.GetTotalBetsMadeInRange(ctx, params)
}
func (r *ReportRepo) GetTotalCashBacksInRange(ctx context.Context, from, to time.Time) (float64, error) {
params := dbgen.GetTotalCashBacksInRangeParams{
From: ToPgTimestamp(from),
To: ToPgTimestamp(to),
}
value, err := r.store.queries.GetTotalCashBacksInRange(ctx, params)
if err != nil {
return 0, err
}
return parseFloat(value)
}
func (r *ReportRepo) GetTotalCashMadeInRange(ctx context.Context, from, to time.Time) (float64, error) {
params := dbgen.GetTotalCashMadeInRangeParams{
From: ToPgTimestamp(from),
To: ToPgTimestamp(to),
}
value, err := r.store.queries.GetTotalCashMadeInRange(ctx, params)
if err != nil {
return 0, err
}
return parseFloat(value)
}
func (r *ReportRepo) GetTotalCashOutInRange(ctx context.Context, from, to time.Time) (float64, error) {
params := dbgen.GetTotalCashOutInRangeParams{
From: ToPgTimestamp(from),
To: ToPgTimestamp(to),
}
value, err := r.store.queries.GetTotalCashOutInRange(ctx, params)
if err != nil {
return 0, err
}
return parseFloat(value)
}
func (r *ReportRepo) GetWalletTransactionsInRange(ctx context.Context, from, to time.Time) ([]dbgen.GetWalletTransactionsInRangeRow, error) {
params := dbgen.GetWalletTransactionsInRangeParams{
CreatedAt: ToPgTimestamp(from),
CreatedAt_2: ToPgTimestamp(to),
}
return r.store.queries.GetWalletTransactionsInRange(ctx, params)
}
func (r *ReportRepo) GetAllTicketsInRange(ctx context.Context, from, to time.Time) (dbgen.GetAllTicketsInRangeRow, error) {
params := dbgen.GetAllTicketsInRangeParams{
CreatedAt: ToPgTimestamp(from),
CreatedAt_2: ToPgTimestamp(to),
}
return r.store.queries.GetAllTicketsInRange(ctx, params)
}
func (r *ReportRepo) GetVirtualGameSummaryInRange(ctx context.Context, from, to time.Time) ([]dbgen.GetVirtualGameSummaryInRangeRow, error) {
params := dbgen.GetVirtualGameSummaryInRangeParams{
CreatedAt: ToPgTimestamptz(from),
CreatedAt_2: ToPgTimestamptz(to),
}
return r.store.queries.GetVirtualGameSummaryInRange(ctx, params)
}
func ToPgTimestamp(t time.Time) pgtype.Timestamp {
return pgtype.Timestamp{Time: t, Valid: true}
}
func ToPgTimestamptz(t time.Time) pgtype.Timestamptz {
return pgtype.Timestamptz{Time: t, Valid: true}
}
func parseFloat(value interface{}) (float64, error) {
switch v := value.(type) {
case float64:
return v, nil
case int64:
return float64(v), nil
case pgtype.Numeric:
if !v.Valid {
return 0, nil
}
f, err := v.Float64Value()
if err != nil {
return 0, fmt.Errorf("failed to convert pgtype.Numeric to float64: %w", err)
}
return f.Float64, nil
case nil:
return 0, nil
default:
return 0, fmt.Errorf("unexpected type %T for value: %+v", v, v)
}
}
func (r *ReportRepo) GetCompanyWiseReport(ctx context.Context, from, to time.Time) ([]dbgen.GetCompanyWiseReportRow, error) {
params := dbgen.GetCompanyWiseReportParams{
From: ToPgTimestamp(from),
To: ToPgTimestamp(to),
}
return r.store.queries.GetCompanyWiseReport(ctx, params)
}
func (r *ReportRepo) GetBranchWiseReport(ctx context.Context, from, to time.Time) ([]dbgen.GetBranchWiseReportRow, error) {
params := dbgen.GetBranchWiseReportParams{
From: ToPgTimestamp(from),
To: ToPgTimestamp(to),
}
return r.store.queries.GetBranchWiseReport(ctx, params)
}