221 lines
6.6 KiB
Go
221 lines
6.6 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, companyID int64) (float64, error)
|
|
GetTotalCashMadeInRange(ctx context.Context, from, to time.Time, companyID int64) (float64, error)
|
|
GetTotalCashBacksInRange(ctx context.Context, from, to time.Time, companyID int64) (float64, error)
|
|
GetTotalBetsMadeInRange(ctx context.Context, from, to time.Time, companyID int64) (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)
|
|
}
|
|
|
|
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, companyID int64) (int64, error) {
|
|
params := dbgen.GetTotalBetsMadeInRangeParams{
|
|
From: ToPgTimestamp(from),
|
|
To: ToPgTimestamp(to),
|
|
CompanyID: ToPgInt8(companyID),
|
|
}
|
|
return r.store.queries.GetTotalBetsMadeInRange(ctx, params)
|
|
}
|
|
|
|
func (r *ReportRepo) GetTotalCashBacksInRange(ctx context.Context, from, to time.Time, companyID int64) (float64, error) {
|
|
params := dbgen.GetTotalCashBacksInRangeParams{
|
|
From: ToPgTimestamp(from),
|
|
To: ToPgTimestamp(to),
|
|
CompanyID: ToPgInt8(companyID),
|
|
}
|
|
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, companyID int64) (float64, error) {
|
|
params := dbgen.GetTotalCashMadeInRangeParams{
|
|
From: ToPgTimestamp(from),
|
|
To: ToPgTimestamp(to),
|
|
CompanyID: ToPgInt8(companyID),
|
|
}
|
|
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, companyID int64) (float64, error) {
|
|
params := dbgen.GetTotalCashOutInRangeParams{
|
|
From: ToPgTimestamp(from),
|
|
To: ToPgTimestamp(to),
|
|
CompanyID: ToPgInt8(companyID),
|
|
}
|
|
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: ToPgTimestamp(from),
|
|
CreatedAt_2: ToPgTimestamp(to),
|
|
}
|
|
return r.store.queries.GetVirtualGameSummaryInRange(ctx, params)
|
|
}
|
|
|
|
func ToPgTimestamp(t time.Time) pgtype.Timestamp {
|
|
return pgtype.Timestamp{Time: t, Valid: true}
|
|
}
|
|
|
|
func ToPgInt8(i int64) pgtype.Int8 {
|
|
return pgtype.Int8{Int64: i, 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)
|
|
}
|
|
}
|