diff --git a/cmd/main.go b/cmd/main.go index 051cff2..af32dba 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -49,7 +49,6 @@ import ( "github.com/SamuelTariku/FortuneBet-Backend/internal/services/raffle" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/recommendation" referralservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/referal" - "github.com/SamuelTariku/FortuneBet-Backend/internal/services/report" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/result" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/santimpay" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/settings" @@ -286,23 +285,23 @@ func main() { *userSvc, ) - reportSvc := report.NewService( - repository.NewReportStore(store), - repository.NewBetStore(store), - repository.NewWalletStore(store), - repository.NewTransactionStore(store), - repository.NewBranchStore(store), - repository.NewUserStore(store), - repository.NewOldRepositoryStore(store), - repository.NewCompanyStore(store), - repository.NewVirtualGameRepository(store), - repository.NewNotificationStore(store), - notificationSvc, - statSvc, - logger, - domain.MongoDBLogger, - cfg, - ) + // reportSvc := report.NewService( + // repository.NewVirtualGameReportStore(store), + // repository.NewBetStore(store), + // repository.NewWalletStore(store), + // repository.NewTransactionStore(store), + // repository.NewBranchStore(store), + // repository.NewUserStore(store), + // repository.NewOldRepositoryStore(store), + // repository.NewCompanyStore(store), + // repository.NewVirtualGameRepository(store), + // repository.NewNotificationStore(store), + // notificationSvc, + // statSvc, + // logger, + // domain.MongoDBLogger, + // cfg, + // ) enePulseSvc := enetpulse.New( *cfg, @@ -310,7 +309,7 @@ func main() { ) go httpserver.StartEnetPulseCron(enePulseSvc, domain.MongoDBLogger) - go httpserver.SetupReportandVirtualGameCronJobs(context.Background(), reportSvc, orchestrationSvc, "C:/Users/User/Desktop") + // go httpserver.SetupReportandVirtualGameCronJobs(context.Background(), reportSvc, orchestrationSvc, "C:/Users/User/Desktop") go httpserver.ProcessBetCashback(context.TODO(), betSvc) bankRepository := repository.NewBankRepository(store) @@ -363,7 +362,7 @@ func main() { httpserver.StartBetAPIDataFetchingCrons(eventSvc, *oddsSvc, resultSvc, domain.MongoDBLogger) httpserver.StartCleanupCrons(*ticketSvc, notificationSvc, domain.MongoDBLogger) httpserver.StartStatCrons(statSvc, domain.MongoDBLogger) - httpserver.StartReportCrons(reportSvc, domain.MongoDBLogger) + // httpserver.StartReportCrons(reportSvc, domain.MongoDBLogger) issueReportingRepo := repository.NewReportedIssueRepository(store) @@ -405,7 +404,7 @@ func main() { userSvc, ticketSvc, betSvc, - reportSvc, // Make sure httpserver.NewApp accepts this parameter + // reportSvc, // Make sure httpserver.NewApp accepts this parameter chapaSvc, walletSvc, transactionSvc, diff --git a/db/migrations/000001_fortune.up.sql b/db/migrations/000001_fortune.up.sql index e24d0b5..90f5219 100644 --- a/db/migrations/000001_fortune.up.sql +++ b/db/migrations/000001_fortune.up.sql @@ -37,7 +37,7 @@ CREATE TABLE IF NOT EXISTS virtual_game_providers ( CREATE TABLE IF NOT EXISTS virtual_game_provider_reports ( id BIGSERIAL PRIMARY KEY, - provider_id VARCHAR(100) NOT NULL REFERENCES virtual_game_providers(provider_id) ON DELETE CASCADE, + provider_id BIGINT NOT NULL REFERENCES virtual_game_providers(id) ON DELETE CASCADE, report_date DATE NOT NULL, total_games_played BIGINT DEFAULT 0, total_bets NUMERIC(18,2) DEFAULT 0, @@ -55,7 +55,7 @@ ON virtual_game_provider_reports (provider_id, report_date, report_type); CREATE TABLE IF NOT EXISTS virtual_games ( id BIGSERIAL PRIMARY KEY, game_id VARCHAR(150) UNIQUE NOT NULL, - provider_id VARCHAR(100) NOT NULL REFERENCES virtual_game_providers(provider_id) ON DELETE CASCADE, + provider_id BIGINT NOT NULL REFERENCES virtual_game_providers(id) ON DELETE CASCADE, name VARCHAR(255) NOT NULL, category VARCHAR(100), device_type VARCHAR(100), @@ -75,7 +75,7 @@ CREATE TABLE IF NOT EXISTS virtual_game_favourites ( id BIGSERIAL PRIMARY KEY, game_id BIGINT NOT NULL REFERENCES virtual_games(id) ON DELETE CASCADE, user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE, - provider_id VARCHAR(100) NOT NULL REFERENCES virtual_game_providers(id) ON DELETE CASCADE, + provider_id BIGINT NOT NULL REFERENCES virtual_game_providers(id) ON DELETE CASCADE, created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, UNIQUE (game_id, user_id) ); @@ -83,7 +83,7 @@ CREATE TABLE IF NOT EXISTS virtual_game_favourites ( CREATE TABLE IF NOT EXISTS virtual_game_reports ( id BIGSERIAL PRIMARY KEY, game_id VARCHAR(150) NOT NULL REFERENCES virtual_games(game_id) ON DELETE CASCADE, - provider_id VARCHAR(100) NOT NULL REFERENCES virtual_game_providers(provider_id) ON DELETE CASCADE, + provider_id BIGINT NOT NULL REFERENCES virtual_game_providers(id) ON DELETE CASCADE, report_date DATE NOT NULL, total_rounds BIGINT DEFAULT 0, total_bets NUMERIC(18,2) DEFAULT 0, diff --git a/db/migrations/00009_virtual_reports.down.sql b/db/migrations/00009_virtual_reports.down.sql new file mode 100644 index 0000000..fa7e51e --- /dev/null +++ b/db/migrations/00009_virtual_reports.down.sql @@ -0,0 +1,4 @@ +DROP TABLE IF EXISTS virtual_game_financial_reports; +DROP TABLE IF EXISTS virtual_game_company_reports; +DROP TABLE IF EXISTS virtual_game_player_cashflow_reports; +DROP TABLE IF EXISTS virtual_game_player_session_reports; \ No newline at end of file diff --git a/db/migrations/00009_virtual_reports.up.sql b/db/migrations/00009_virtual_reports.up.sql new file mode 100644 index 0000000..f72ebcb --- /dev/null +++ b/db/migrations/00009_virtual_reports.up.sql @@ -0,0 +1,73 @@ +CREATE TABLE IF NOT EXISTS virtual_game_financial_reports ( + id BIGSERIAL PRIMARY KEY, + game_id VARCHAR(150) NOT NULL REFERENCES virtual_games(game_id) ON DELETE CASCADE, + provider_id VARCHAR(100) NOT NULL REFERENCES virtual_game_providers(provider_id) ON DELETE CASCADE, + + report_date DATE NOT NULL, + report_type VARCHAR(50) NOT NULL DEFAULT 'daily', + + total_bets NUMERIC(18,2) DEFAULT 0, + total_wins NUMERIC(18,2) DEFAULT 0, + + ggr NUMERIC(18,2) GENERATED ALWAYS AS (total_bets - total_wins) STORED, + rtp NUMERIC(5,2) GENERATED ALWAYS AS ( + CASE WHEN total_bets > 0 THEN (total_wins / total_bets) * 100 ELSE 0 END + ) STORED, + + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ +); + +CREATE TABLE IF NOT EXISTS virtual_game_company_reports ( + id BIGSERIAL PRIMARY KEY, + + company_id BIGINT NOT NULL REFERENCES companies(id) ON DELETE CASCADE, + provider_id VARCHAR(100) NOT NULL REFERENCES virtual_game_providers(provider_id) ON DELETE CASCADE, + + report_date DATE NOT NULL, + report_type VARCHAR(50) NOT NULL DEFAULT 'daily', + + total_bet_amount NUMERIC(18,2) DEFAULT 0, + total_win_amount NUMERIC(18,2) DEFAULT 0, + + net_profit NUMERIC(18,2) GENERATED ALWAYS AS (total_bet_amount - total_win_amount) STORED, + profit_margin NUMERIC(6,3) GENERATED ALWAYS AS ( + CASE WHEN total_bet_amount > 0 THEN (total_bet_amount - total_win_amount) / total_bet_amount ELSE 0 END + ) STORED, + + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ +); + +CREATE TABLE IF NOT EXISTS virtual_game_player_activity_reports ( + id BIGSERIAL PRIMARY KEY, + + user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE, + + -- Reporting scope + report_date DATE NOT NULL, + report_type VARCHAR(50) NOT NULL DEFAULT 'daily', + + -- Cashflow information + total_deposits NUMERIC(18,2) DEFAULT 0, + total_withdrawals NUMERIC(18,2) DEFAULT 0, + net_contribution NUMERIC(18,2) GENERATED ALWAYS AS ( + total_deposits - total_withdrawals + ) STORED, + + -- Betting and win/loss analytics + total_bet_amount NUMERIC(18,2) DEFAULT 0, + total_win_amount NUMERIC(18,2) DEFAULT 0, + net_result NUMERIC(18,2) GENERATED ALWAYS AS ( + total_bet_amount - total_win_amount + ) STORED, + + rounds_played BIGINT DEFAULT 0, + avg_bet_size NUMERIC(18,4) GENERATED ALWAYS AS ( + CASE WHEN rounds_played > 0 THEN total_bet_amount / rounds_played ELSE 0 END + ) STORED, + + created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMPTZ +); + diff --git a/db/query/report.sql b/db/query/report.sql deleted file mode 100644 index 263f310..0000000 --- a/db/query/report.sql +++ /dev/null @@ -1,74 +0,0 @@ --- name: CreateReportRequest :one -INSERT INTO report_requests ( - company_id, - requested_by, - type, - metadata - ) -VALUES ($1, $2, $3, $4) -RETURNING *; --- name: GetAllReportRequests :many -SELECT * -FROM report_request_detail -WHERE ( - company_id = sqlc.narg('company_id') - OR sqlc.narg('company_id') IS NULL - ) - AND ( - type = sqlc.narg('type') - OR sqlc.narg('type') IS NULL - ) - AND ( - status = sqlc.narg('status') - OR sqlc.narg('status') IS NULL - ) - AND ( - requested_by = sqlc.narg('requested_by') - OR sqlc.narg('requested_by') IS NULL - ) -ORDER BY id DESC -LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); --- name: GetTotalReportRequests :one -SELECT COUNT(id) -FROM report_request_detail -WHERE ( - company_id = sqlc.narg('company_id') - OR sqlc.narg('company_id') IS NULL - ) - AND ( - type = sqlc.narg('type') - OR sqlc.narg('type') IS NULL - ) - AND ( - status = sqlc.narg('status') - OR sqlc.narg('status') IS NULL - ) - AND ( - requested_by = sqlc.narg('requested_by') - OR sqlc.narg('requested_by') IS NULL - ); --- name: GetReportRequestByID :one -SELECT * -FROM report_request_detail -WHERE id = $1; --- name: GetReportRequestByRequestedByID :many -SELECT * -FROM report_request_detail -WHERE requested_by = $1 - AND ( - type = sqlc.narg('type') - OR sqlc.narg('type') IS NULL - ) - AND ( - status = sqlc.narg('status') - OR sqlc.narg('status') IS NULL - ) -ORDER BY id DESC -LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset'); --- name: UpdateReportRequest :exec -UPDATE report_requests -SET file_path = COALESCE(sqlc.narg(file_path), file_path), - reject_reason = COALESCE(sqlc.narg(reject_reason), reject_reason), - status = COALESCE(sqlc.narg(status), status), - completed_at = now() -WHERE id = $1; \ No newline at end of file diff --git a/db/query/virtual_report.sql b/db/query/virtual_report.sql new file mode 100644 index 0000000..0bd4868 --- /dev/null +++ b/db/query/virtual_report.sql @@ -0,0 +1,139 @@ +-- name: CreateFinancialReport :one +INSERT INTO virtual_game_financial_reports ( + game_id, provider_id, report_date, report_type, + total_bets, total_wins, created_at +) VALUES ($1, $2, $3, $4, $5, $6, NOW()) +RETURNING *; + +-- name: UpsertFinancialReport :one +INSERT INTO virtual_game_financial_reports ( + game_id, provider_id, report_date, report_type, + total_bets, total_wins, created_at, updated_at +) +VALUES ($1, $2, $3, $4, $5, $6, NOW(), NOW()) +ON CONFLICT (game_id, provider_id, report_date, report_type) +DO UPDATE SET + total_bets = EXCLUDED.total_bets, + total_wins = EXCLUDED.total_wins, + updated_at = NOW() +RETURNING *; + +-- name: GetFinancialReportByID :one +SELECT * FROM virtual_game_financial_reports +WHERE id = $1; + +-- name: GetFinancialReportsForGame :many +SELECT * FROM virtual_game_financial_reports +WHERE game_id = $1 + AND provider_id = $2 + AND report_date BETWEEN $3 AND $4 +ORDER BY report_date; + +-- name: GetDailyFinancialReports :many +SELECT * FROM virtual_game_financial_reports +WHERE report_date = $1 + AND report_type = 'daily'; + +-- name: DeleteFinancialReport :exec +DELETE FROM virtual_game_financial_reports +WHERE id = $1; + +-- name: CreateCompanyReport :one +INSERT INTO virtual_game_company_reports ( + company_id, provider_id, + report_date, report_type, + total_bet_amount, total_win_amount, created_at +) +VALUES ($1, $2, $3, $4, $5, $6, NOW()) +RETURNING *; + +-- name: UpsertCompanyReport :one +INSERT INTO virtual_game_company_reports ( + company_id, provider_id, + report_date, report_type, + total_bet_amount, total_win_amount, + created_at, updated_at +) +VALUES ($1, $2, $3, $4, $5, $6, NOW(), NOW()) +ON CONFLICT (company_id, provider_id, report_date, report_type) +DO UPDATE SET + total_bet_amount = EXCLUDED.total_bet_amount, + total_win_amount = EXCLUDED.total_win_amount, + updated_at = NOW() +RETURNING *; + +-- name: GetCompanyReportByID :one +SELECT * FROM virtual_game_company_reports +WHERE id = $1; + +-- name: GetCompanyReportsInRange :many +SELECT * FROM virtual_game_company_reports +WHERE company_id = $1 + AND provider_id = $2 + AND report_date BETWEEN $3 AND $4 +ORDER BY report_date; + +-- name: GetCompanyProfitTrend :many +SELECT report_date, SUM(net_profit) AS total_profit +FROM virtual_game_company_reports +WHERE company_id = $1 + AND provider_id = $2 + AND report_date BETWEEN $3 AND $4 +GROUP BY report_date +ORDER BY report_date; + +-- name: CreatePlayerActivityReport :one +INSERT INTO virtual_game_player_activity_reports ( + user_id, report_date, report_type, + total_deposits, total_withdrawals, + total_bet_amount, total_win_amount, + rounds_played, created_at +) +VALUES ($1, $2, $3, $4, $5, $6, $7, $8, NOW()) +RETURNING *; + +-- name: UpsertPlayerActivityReport :one +INSERT INTO virtual_game_player_activity_reports ( + user_id, report_date, report_type, + total_deposits, total_withdrawals, + total_bet_amount, total_win_amount, + rounds_played, created_at, updated_at +) +VALUES ($1, $2, $3, $4, $5, $6, $7, $8, NOW(), NOW()) +ON CONFLICT (user_id, report_date, report_type) +DO UPDATE SET + total_deposits = EXCLUDED.total_deposits, + total_withdrawals = EXCLUDED.total_withdrawals, + total_bet_amount = EXCLUDED.total_bet_amount, + total_win_amount = EXCLUDED.total_win_amount, + rounds_played = EXCLUDED.rounds_played, + updated_at = NOW() +RETURNING *; + +-- name: GetPlayerActivityByID :one +SELECT * FROM virtual_game_player_activity_reports +WHERE id = $1; + +-- name: GetPlayerActivityByDate :one +SELECT * FROM virtual_game_player_activity_reports +WHERE user_id = $1 + AND report_date = $2 + AND report_type = $3; + +-- name: GetPlayerActivityRange :many +SELECT * FROM virtual_game_player_activity_reports +WHERE user_id = $1 + AND report_date BETWEEN $2 AND $3 +ORDER BY report_date; + +-- name: GetTopPlayersByNetResult :many +SELECT user_id, SUM(net_result) AS total_net +FROM virtual_game_player_activity_reports +WHERE report_date BETWEEN $1 AND $2 +GROUP BY user_id +ORDER BY total_net DESC +LIMIT $3; + +-- name: DeletePlayerActivityReport :exec +DELETE FROM virtual_game_player_activity_reports +WHERE id = $1; diff --git a/gen/db/models.go b/gen/db/models.go index 644370c..60d03dd 100644 --- a/gen/db/models.go +++ b/gen/db/models.go @@ -1157,6 +1157,20 @@ type VirtualGame struct { UpdatedAt pgtype.Timestamptz `json:"updated_at"` } +type VirtualGameCompanyReport struct { + ID int64 `json:"id"` + CompanyID int64 `json:"company_id"` + ProviderID string `json:"provider_id"` + ReportDate pgtype.Date `json:"report_date"` + ReportType string `json:"report_type"` + TotalBetAmount pgtype.Numeric `json:"total_bet_amount"` + TotalWinAmount pgtype.Numeric `json:"total_win_amount"` + NetProfit pgtype.Numeric `json:"net_profit"` + ProfitMargin pgtype.Numeric `json:"profit_margin"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + type VirtualGameFavourite struct { ID int64 `json:"id"` GameID int64 `json:"game_id"` @@ -1165,6 +1179,20 @@ type VirtualGameFavourite struct { CreatedAt pgtype.Timestamptz `json:"created_at"` } +type VirtualGameFinancialReport struct { + ID int64 `json:"id"` + GameID string `json:"game_id"` + ProviderID string `json:"provider_id"` + ReportDate pgtype.Date `json:"report_date"` + ReportType string `json:"report_type"` + TotalBets pgtype.Numeric `json:"total_bets"` + TotalWins pgtype.Numeric `json:"total_wins"` + Ggr pgtype.Numeric `json:"ggr"` + Rtp pgtype.Numeric `json:"rtp"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + type VirtualGameHistory struct { ID int64 `json:"id"` UserID int64 `json:"user_id"` @@ -1182,6 +1210,23 @@ type VirtualGameHistory struct { UpdatedAt pgtype.Timestamp `json:"updated_at"` } +type VirtualGamePlayerActivityReport struct { + ID int64 `json:"id"` + UserID int64 `json:"user_id"` + ReportDate pgtype.Date `json:"report_date"` + ReportType string `json:"report_type"` + TotalDeposits pgtype.Numeric `json:"total_deposits"` + TotalWithdrawals pgtype.Numeric `json:"total_withdrawals"` + NetContribution pgtype.Numeric `json:"net_contribution"` + TotalBetAmount pgtype.Numeric `json:"total_bet_amount"` + TotalWinAmount pgtype.Numeric `json:"total_win_amount"` + NetResult pgtype.Numeric `json:"net_result"` + RoundsPlayed pgtype.Int8 `json:"rounds_played"` + AvgBetSize pgtype.Numeric `json:"avg_bet_size"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + type VirtualGameProvider struct { ID int64 `json:"id"` ProviderID string `json:"provider_id"` diff --git a/gen/db/virtual_report.sql.go b/gen/db/virtual_report.sql.go new file mode 100644 index 0000000..104b4c5 --- /dev/null +++ b/gen/db/virtual_report.sql.go @@ -0,0 +1,721 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.29.0 +// source: virtual_report.sql + +package dbgen + +import ( + "context" + + "github.com/jackc/pgx/v5/pgtype" +) + +const CreateCompanyReport = `-- name: CreateCompanyReport :one +INSERT INTO virtual_game_company_reports ( + company_id, provider_id, + report_date, report_type, + total_bet_amount, total_win_amount, created_at +) +VALUES ($1, $2, $3, $4, $5, $6, NOW()) +RETURNING id, company_id, provider_id, report_date, report_type, total_bet_amount, total_win_amount, net_profit, profit_margin, created_at, updated_at +` + +type CreateCompanyReportParams struct { + CompanyID int64 `json:"company_id"` + ProviderID string `json:"provider_id"` + ReportDate pgtype.Date `json:"report_date"` + ReportType string `json:"report_type"` + TotalBetAmount pgtype.Numeric `json:"total_bet_amount"` + TotalWinAmount pgtype.Numeric `json:"total_win_amount"` +} + +func (q *Queries) CreateCompanyReport(ctx context.Context, arg CreateCompanyReportParams) (VirtualGameCompanyReport, error) { + row := q.db.QueryRow(ctx, CreateCompanyReport, + arg.CompanyID, + arg.ProviderID, + arg.ReportDate, + arg.ReportType, + arg.TotalBetAmount, + arg.TotalWinAmount, + ) + var i VirtualGameCompanyReport + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.ProviderID, + &i.ReportDate, + &i.ReportType, + &i.TotalBetAmount, + &i.TotalWinAmount, + &i.NetProfit, + &i.ProfitMargin, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const CreateFinancialReport = `-- name: CreateFinancialReport :one +INSERT INTO virtual_game_financial_reports ( + game_id, provider_id, report_date, report_type, + total_bets, total_wins, created_at +) VALUES ($1, $2, $3, $4, $5, $6, NOW()) +RETURNING id, game_id, provider_id, report_date, report_type, total_bets, total_wins, ggr, rtp, created_at, updated_at +` + +type CreateFinancialReportParams struct { + GameID string `json:"game_id"` + ProviderID string `json:"provider_id"` + ReportDate pgtype.Date `json:"report_date"` + ReportType string `json:"report_type"` + TotalBets pgtype.Numeric `json:"total_bets"` + TotalWins pgtype.Numeric `json:"total_wins"` +} + +func (q *Queries) CreateFinancialReport(ctx context.Context, arg CreateFinancialReportParams) (VirtualGameFinancialReport, error) { + row := q.db.QueryRow(ctx, CreateFinancialReport, + arg.GameID, + arg.ProviderID, + arg.ReportDate, + arg.ReportType, + arg.TotalBets, + arg.TotalWins, + ) + var i VirtualGameFinancialReport + err := row.Scan( + &i.ID, + &i.GameID, + &i.ProviderID, + &i.ReportDate, + &i.ReportType, + &i.TotalBets, + &i.TotalWins, + &i.Ggr, + &i.Rtp, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const CreatePlayerActivityReport = `-- name: CreatePlayerActivityReport :one +INSERT INTO virtual_game_player_activity_reports ( + user_id, report_date, report_type, + total_deposits, total_withdrawals, + total_bet_amount, total_win_amount, + rounds_played, created_at +) +VALUES ($1, $2, $3, $4, $5, $6, $7, $8, NOW()) +RETURNING id, user_id, report_date, report_type, total_deposits, total_withdrawals, net_contribution, total_bet_amount, total_win_amount, net_result, rounds_played, avg_bet_size, created_at, updated_at +` + +type CreatePlayerActivityReportParams struct { + UserID int64 `json:"user_id"` + ReportDate pgtype.Date `json:"report_date"` + ReportType string `json:"report_type"` + TotalDeposits pgtype.Numeric `json:"total_deposits"` + TotalWithdrawals pgtype.Numeric `json:"total_withdrawals"` + TotalBetAmount pgtype.Numeric `json:"total_bet_amount"` + TotalWinAmount pgtype.Numeric `json:"total_win_amount"` + RoundsPlayed pgtype.Int8 `json:"rounds_played"` +} + +func (q *Queries) CreatePlayerActivityReport(ctx context.Context, arg CreatePlayerActivityReportParams) (VirtualGamePlayerActivityReport, error) { + row := q.db.QueryRow(ctx, CreatePlayerActivityReport, + arg.UserID, + arg.ReportDate, + arg.ReportType, + arg.TotalDeposits, + arg.TotalWithdrawals, + arg.TotalBetAmount, + arg.TotalWinAmount, + arg.RoundsPlayed, + ) + var i VirtualGamePlayerActivityReport + err := row.Scan( + &i.ID, + &i.UserID, + &i.ReportDate, + &i.ReportType, + &i.TotalDeposits, + &i.TotalWithdrawals, + &i.NetContribution, + &i.TotalBetAmount, + &i.TotalWinAmount, + &i.NetResult, + &i.RoundsPlayed, + &i.AvgBetSize, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const DeleteFinancialReport = `-- name: DeleteFinancialReport :exec +DELETE FROM virtual_game_financial_reports +WHERE id = $1 +` + +func (q *Queries) DeleteFinancialReport(ctx context.Context, id int64) error { + _, err := q.db.Exec(ctx, DeleteFinancialReport, id) + return err +} + +const DeletePlayerActivityReport = `-- name: DeletePlayerActivityReport :exec +DELETE FROM virtual_game_player_activity_reports +WHERE id = $1 +` + +func (q *Queries) DeletePlayerActivityReport(ctx context.Context, id int64) error { + _, err := q.db.Exec(ctx, DeletePlayerActivityReport, id) + return err +} + +const GetCompanyProfitTrend = `-- name: GetCompanyProfitTrend :many +SELECT report_date, SUM(net_profit) AS total_profit +FROM virtual_game_company_reports +WHERE company_id = $1 + AND provider_id = $2 + AND report_date BETWEEN $3 AND $4 +GROUP BY report_date +ORDER BY report_date +` + +type GetCompanyProfitTrendParams struct { + CompanyID int64 `json:"company_id"` + ProviderID string `json:"provider_id"` + ReportDate pgtype.Date `json:"report_date"` + ReportDate_2 pgtype.Date `json:"report_date_2"` +} + +type GetCompanyProfitTrendRow struct { + ReportDate pgtype.Date `json:"report_date"` + TotalProfit int64 `json:"total_profit"` +} + +func (q *Queries) GetCompanyProfitTrend(ctx context.Context, arg GetCompanyProfitTrendParams) ([]GetCompanyProfitTrendRow, error) { + rows, err := q.db.Query(ctx, GetCompanyProfitTrend, + arg.CompanyID, + arg.ProviderID, + arg.ReportDate, + arg.ReportDate_2, + ) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetCompanyProfitTrendRow + for rows.Next() { + var i GetCompanyProfitTrendRow + if err := rows.Scan(&i.ReportDate, &i.TotalProfit); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const GetCompanyReportByID = `-- name: GetCompanyReportByID :one +SELECT id, company_id, provider_id, report_date, report_type, total_bet_amount, total_win_amount, net_profit, profit_margin, created_at, updated_at FROM virtual_game_company_reports +WHERE id = $1 +` + +func (q *Queries) GetCompanyReportByID(ctx context.Context, id int64) (VirtualGameCompanyReport, error) { + row := q.db.QueryRow(ctx, GetCompanyReportByID, id) + var i VirtualGameCompanyReport + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.ProviderID, + &i.ReportDate, + &i.ReportType, + &i.TotalBetAmount, + &i.TotalWinAmount, + &i.NetProfit, + &i.ProfitMargin, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const GetCompanyReportsInRange = `-- name: GetCompanyReportsInRange :many +SELECT id, company_id, provider_id, report_date, report_type, total_bet_amount, total_win_amount, net_profit, profit_margin, created_at, updated_at FROM virtual_game_company_reports +WHERE company_id = $1 + AND provider_id = $2 + AND report_date BETWEEN $3 AND $4 +ORDER BY report_date +` + +type GetCompanyReportsInRangeParams struct { + CompanyID int64 `json:"company_id"` + ProviderID string `json:"provider_id"` + ReportDate pgtype.Date `json:"report_date"` + ReportDate_2 pgtype.Date `json:"report_date_2"` +} + +func (q *Queries) GetCompanyReportsInRange(ctx context.Context, arg GetCompanyReportsInRangeParams) ([]VirtualGameCompanyReport, error) { + rows, err := q.db.Query(ctx, GetCompanyReportsInRange, + arg.CompanyID, + arg.ProviderID, + arg.ReportDate, + arg.ReportDate_2, + ) + if err != nil { + return nil, err + } + defer rows.Close() + var items []VirtualGameCompanyReport + for rows.Next() { + var i VirtualGameCompanyReport + if err := rows.Scan( + &i.ID, + &i.CompanyID, + &i.ProviderID, + &i.ReportDate, + &i.ReportType, + &i.TotalBetAmount, + &i.TotalWinAmount, + &i.NetProfit, + &i.ProfitMargin, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const GetDailyFinancialReports = `-- name: GetDailyFinancialReports :many +SELECT id, game_id, provider_id, report_date, report_type, total_bets, total_wins, ggr, rtp, created_at, updated_at FROM virtual_game_financial_reports +WHERE report_date = $1 + AND report_type = 'daily' +` + +func (q *Queries) GetDailyFinancialReports(ctx context.Context, reportDate pgtype.Date) ([]VirtualGameFinancialReport, error) { + rows, err := q.db.Query(ctx, GetDailyFinancialReports, reportDate) + if err != nil { + return nil, err + } + defer rows.Close() + var items []VirtualGameFinancialReport + for rows.Next() { + var i VirtualGameFinancialReport + if err := rows.Scan( + &i.ID, + &i.GameID, + &i.ProviderID, + &i.ReportDate, + &i.ReportType, + &i.TotalBets, + &i.TotalWins, + &i.Ggr, + &i.Rtp, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const GetFinancialReportByID = `-- name: GetFinancialReportByID :one +SELECT id, game_id, provider_id, report_date, report_type, total_bets, total_wins, ggr, rtp, created_at, updated_at FROM virtual_game_financial_reports +WHERE id = $1 +` + +func (q *Queries) GetFinancialReportByID(ctx context.Context, id int64) (VirtualGameFinancialReport, error) { + row := q.db.QueryRow(ctx, GetFinancialReportByID, id) + var i VirtualGameFinancialReport + err := row.Scan( + &i.ID, + &i.GameID, + &i.ProviderID, + &i.ReportDate, + &i.ReportType, + &i.TotalBets, + &i.TotalWins, + &i.Ggr, + &i.Rtp, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const GetFinancialReportsForGame = `-- name: GetFinancialReportsForGame :many +SELECT id, game_id, provider_id, report_date, report_type, total_bets, total_wins, ggr, rtp, created_at, updated_at FROM virtual_game_financial_reports +WHERE game_id = $1 + AND provider_id = $2 + AND report_date BETWEEN $3 AND $4 +ORDER BY report_date +` + +type GetFinancialReportsForGameParams struct { + GameID string `json:"game_id"` + ProviderID string `json:"provider_id"` + ReportDate pgtype.Date `json:"report_date"` + ReportDate_2 pgtype.Date `json:"report_date_2"` +} + +func (q *Queries) GetFinancialReportsForGame(ctx context.Context, arg GetFinancialReportsForGameParams) ([]VirtualGameFinancialReport, error) { + rows, err := q.db.Query(ctx, GetFinancialReportsForGame, + arg.GameID, + arg.ProviderID, + arg.ReportDate, + arg.ReportDate_2, + ) + if err != nil { + return nil, err + } + defer rows.Close() + var items []VirtualGameFinancialReport + for rows.Next() { + var i VirtualGameFinancialReport + if err := rows.Scan( + &i.ID, + &i.GameID, + &i.ProviderID, + &i.ReportDate, + &i.ReportType, + &i.TotalBets, + &i.TotalWins, + &i.Ggr, + &i.Rtp, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const GetPlayerActivityByDate = `-- name: GetPlayerActivityByDate :one +SELECT id, user_id, report_date, report_type, total_deposits, total_withdrawals, net_contribution, total_bet_amount, total_win_amount, net_result, rounds_played, avg_bet_size, created_at, updated_at FROM virtual_game_player_activity_reports +WHERE user_id = $1 + AND report_date = $2 + AND report_type = $3 +` + +type GetPlayerActivityByDateParams struct { + UserID int64 `json:"user_id"` + ReportDate pgtype.Date `json:"report_date"` + ReportType string `json:"report_type"` +} + +func (q *Queries) GetPlayerActivityByDate(ctx context.Context, arg GetPlayerActivityByDateParams) (VirtualGamePlayerActivityReport, error) { + row := q.db.QueryRow(ctx, GetPlayerActivityByDate, arg.UserID, arg.ReportDate, arg.ReportType) + var i VirtualGamePlayerActivityReport + err := row.Scan( + &i.ID, + &i.UserID, + &i.ReportDate, + &i.ReportType, + &i.TotalDeposits, + &i.TotalWithdrawals, + &i.NetContribution, + &i.TotalBetAmount, + &i.TotalWinAmount, + &i.NetResult, + &i.RoundsPlayed, + &i.AvgBetSize, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const GetPlayerActivityByID = `-- name: GetPlayerActivityByID :one +SELECT id, user_id, report_date, report_type, total_deposits, total_withdrawals, net_contribution, total_bet_amount, total_win_amount, net_result, rounds_played, avg_bet_size, created_at, updated_at FROM virtual_game_player_activity_reports +WHERE id = $1 +` + +func (q *Queries) GetPlayerActivityByID(ctx context.Context, id int64) (VirtualGamePlayerActivityReport, error) { + row := q.db.QueryRow(ctx, GetPlayerActivityByID, id) + var i VirtualGamePlayerActivityReport + err := row.Scan( + &i.ID, + &i.UserID, + &i.ReportDate, + &i.ReportType, + &i.TotalDeposits, + &i.TotalWithdrawals, + &i.NetContribution, + &i.TotalBetAmount, + &i.TotalWinAmount, + &i.NetResult, + &i.RoundsPlayed, + &i.AvgBetSize, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const GetPlayerActivityRange = `-- name: GetPlayerActivityRange :many +SELECT id, user_id, report_date, report_type, total_deposits, total_withdrawals, net_contribution, total_bet_amount, total_win_amount, net_result, rounds_played, avg_bet_size, created_at, updated_at FROM virtual_game_player_activity_reports +WHERE user_id = $1 + AND report_date BETWEEN $2 AND $3 +ORDER BY report_date +` + +type GetPlayerActivityRangeParams struct { + UserID int64 `json:"user_id"` + ReportDate pgtype.Date `json:"report_date"` + ReportDate_2 pgtype.Date `json:"report_date_2"` +} + +func (q *Queries) GetPlayerActivityRange(ctx context.Context, arg GetPlayerActivityRangeParams) ([]VirtualGamePlayerActivityReport, error) { + rows, err := q.db.Query(ctx, GetPlayerActivityRange, arg.UserID, arg.ReportDate, arg.ReportDate_2) + if err != nil { + return nil, err + } + defer rows.Close() + var items []VirtualGamePlayerActivityReport + for rows.Next() { + var i VirtualGamePlayerActivityReport + if err := rows.Scan( + &i.ID, + &i.UserID, + &i.ReportDate, + &i.ReportType, + &i.TotalDeposits, + &i.TotalWithdrawals, + &i.NetContribution, + &i.TotalBetAmount, + &i.TotalWinAmount, + &i.NetResult, + &i.RoundsPlayed, + &i.AvgBetSize, + &i.CreatedAt, + &i.UpdatedAt, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const GetTopPlayersByNetResult = `-- name: GetTopPlayersByNetResult :many +SELECT user_id, SUM(net_result) AS total_net +FROM virtual_game_player_activity_reports +WHERE report_date BETWEEN $1 AND $2 +GROUP BY user_id +ORDER BY total_net DESC +LIMIT $3 +` + +type GetTopPlayersByNetResultParams struct { + ReportDate pgtype.Date `json:"report_date"` + ReportDate_2 pgtype.Date `json:"report_date_2"` + Limit int32 `json:"limit"` +} + +type GetTopPlayersByNetResultRow struct { + UserID int64 `json:"user_id"` + TotalNet int64 `json:"total_net"` +} + +func (q *Queries) GetTopPlayersByNetResult(ctx context.Context, arg GetTopPlayersByNetResultParams) ([]GetTopPlayersByNetResultRow, error) { + rows, err := q.db.Query(ctx, GetTopPlayersByNetResult, arg.ReportDate, arg.ReportDate_2, arg.Limit) + if err != nil { + return nil, err + } + defer rows.Close() + var items []GetTopPlayersByNetResultRow + for rows.Next() { + var i GetTopPlayersByNetResultRow + if err := rows.Scan(&i.UserID, &i.TotalNet); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const UpsertCompanyReport = `-- name: UpsertCompanyReport :one +INSERT INTO virtual_game_company_reports ( + company_id, provider_id, + report_date, report_type, + total_bet_amount, total_win_amount, + created_at, updated_at +) +VALUES ($1, $2, $3, $4, $5, $6, NOW(), NOW()) +ON CONFLICT (company_id, provider_id, report_date, report_type) +DO UPDATE SET + total_bet_amount = EXCLUDED.total_bet_amount, + total_win_amount = EXCLUDED.total_win_amount, + updated_at = NOW() +RETURNING id, company_id, provider_id, report_date, report_type, total_bet_amount, total_win_amount, net_profit, profit_margin, created_at, updated_at +` + +type UpsertCompanyReportParams struct { + CompanyID int64 `json:"company_id"` + ProviderID string `json:"provider_id"` + ReportDate pgtype.Date `json:"report_date"` + ReportType string `json:"report_type"` + TotalBetAmount pgtype.Numeric `json:"total_bet_amount"` + TotalWinAmount pgtype.Numeric `json:"total_win_amount"` +} + +func (q *Queries) UpsertCompanyReport(ctx context.Context, arg UpsertCompanyReportParams) (VirtualGameCompanyReport, error) { + row := q.db.QueryRow(ctx, UpsertCompanyReport, + arg.CompanyID, + arg.ProviderID, + arg.ReportDate, + arg.ReportType, + arg.TotalBetAmount, + arg.TotalWinAmount, + ) + var i VirtualGameCompanyReport + err := row.Scan( + &i.ID, + &i.CompanyID, + &i.ProviderID, + &i.ReportDate, + &i.ReportType, + &i.TotalBetAmount, + &i.TotalWinAmount, + &i.NetProfit, + &i.ProfitMargin, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const UpsertFinancialReport = `-- name: UpsertFinancialReport :one +INSERT INTO virtual_game_financial_reports ( + game_id, provider_id, report_date, report_type, + total_bets, total_wins, created_at, updated_at +) +VALUES ($1, $2, $3, $4, $5, $6, NOW(), NOW()) +ON CONFLICT (game_id, provider_id, report_date, report_type) +DO UPDATE SET + total_bets = EXCLUDED.total_bets, + total_wins = EXCLUDED.total_wins, + updated_at = NOW() +RETURNING id, game_id, provider_id, report_date, report_type, total_bets, total_wins, ggr, rtp, created_at, updated_at +` + +type UpsertFinancialReportParams struct { + GameID string `json:"game_id"` + ProviderID string `json:"provider_id"` + ReportDate pgtype.Date `json:"report_date"` + ReportType string `json:"report_type"` + TotalBets pgtype.Numeric `json:"total_bets"` + TotalWins pgtype.Numeric `json:"total_wins"` +} + +func (q *Queries) UpsertFinancialReport(ctx context.Context, arg UpsertFinancialReportParams) (VirtualGameFinancialReport, error) { + row := q.db.QueryRow(ctx, UpsertFinancialReport, + arg.GameID, + arg.ProviderID, + arg.ReportDate, + arg.ReportType, + arg.TotalBets, + arg.TotalWins, + ) + var i VirtualGameFinancialReport + err := row.Scan( + &i.ID, + &i.GameID, + &i.ProviderID, + &i.ReportDate, + &i.ReportType, + &i.TotalBets, + &i.TotalWins, + &i.Ggr, + &i.Rtp, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} + +const UpsertPlayerActivityReport = `-- name: UpsertPlayerActivityReport :one +INSERT INTO virtual_game_player_activity_reports ( + user_id, report_date, report_type, + total_deposits, total_withdrawals, + total_bet_amount, total_win_amount, + rounds_played, created_at, updated_at +) +VALUES ($1, $2, $3, $4, $5, $6, $7, $8, NOW(), NOW()) +ON CONFLICT (user_id, report_date, report_type) +DO UPDATE SET + total_deposits = EXCLUDED.total_deposits, + total_withdrawals = EXCLUDED.total_withdrawals, + total_bet_amount = EXCLUDED.total_bet_amount, + total_win_amount = EXCLUDED.total_win_amount, + rounds_played = EXCLUDED.rounds_played, + updated_at = NOW() +RETURNING id, user_id, report_date, report_type, total_deposits, total_withdrawals, net_contribution, total_bet_amount, total_win_amount, net_result, rounds_played, avg_bet_size, created_at, updated_at +` + +type UpsertPlayerActivityReportParams struct { + UserID int64 `json:"user_id"` + ReportDate pgtype.Date `json:"report_date"` + ReportType string `json:"report_type"` + TotalDeposits pgtype.Numeric `json:"total_deposits"` + TotalWithdrawals pgtype.Numeric `json:"total_withdrawals"` + TotalBetAmount pgtype.Numeric `json:"total_bet_amount"` + TotalWinAmount pgtype.Numeric `json:"total_win_amount"` + RoundsPlayed pgtype.Int8 `json:"rounds_played"` +} + +func (q *Queries) UpsertPlayerActivityReport(ctx context.Context, arg UpsertPlayerActivityReportParams) (VirtualGamePlayerActivityReport, error) { + row := q.db.QueryRow(ctx, UpsertPlayerActivityReport, + arg.UserID, + arg.ReportDate, + arg.ReportType, + arg.TotalDeposits, + arg.TotalWithdrawals, + arg.TotalBetAmount, + arg.TotalWinAmount, + arg.RoundsPlayed, + ) + var i VirtualGamePlayerActivityReport + err := row.Scan( + &i.ID, + &i.UserID, + &i.ReportDate, + &i.ReportType, + &i.TotalDeposits, + &i.TotalWithdrawals, + &i.NetContribution, + &i.TotalBetAmount, + &i.TotalWinAmount, + &i.NetResult, + &i.RoundsPlayed, + &i.AvgBetSize, + &i.CreatedAt, + &i.UpdatedAt, + ) + return i, err +} diff --git a/internal/domain/virtual_report.go b/internal/domain/virtual_report.go new file mode 100644 index 0000000..4b8778a --- /dev/null +++ b/internal/domain/virtual_report.go @@ -0,0 +1,149 @@ +package domain + +import ( + "math/big" + "time" + + dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" +) + +type FinancialReport struct { + ID int64 `json:"id"` + GameID string `json:"gameId"` + ProviderID string `json:"providerId"` + ReportDate string `json:"reportDate"` // YYYY-MM-DD + ReportType string `json:"reportType"` + TotalBets float64 `json:"totalBets"` + TotalWins float64 `json:"totalWins"` + GGR float64 `json:"ggr"` + RTP float64 `json:"rtp"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt *time.Time `json:"updatedAt,omitempty"` +} + +func ConvertDBFinancialReport(dbReport dbgen.VirtualGameFinancialReport) FinancialReport { + return FinancialReport{ + ID: dbReport.ID, + GameID: dbReport.GameID, + ProviderID: dbReport.ProviderID, + ReportDate: dbReport.ReportDate.Time.Format("2006-01-02"), + ReportType: dbReport.ReportType, + TotalBets: float64(dbReport.TotalBets.Exp), + TotalWins: float64(dbReport.TotalWins.Exp), + GGR: float64(dbReport.Ggr.Exp), + RTP: float64(dbReport.Rtp.Exp), + CreatedAt: dbReport.CreatedAt.Time, + UpdatedAt: &dbReport.UpdatedAt.Time, + } +} + +type CompanyReport struct { + ID int64 `json:"id"` + CompanyID int64 `json:"companyId"` + ProviderID string `json:"providerId"` + ReportDate string `json:"reportDate"` // YYYY-MM-DD + ReportType string `json:"reportType"` + TotalBetAmount float64 `json:"totalBetAmount"` + TotalWinAmount float64 `json:"totalWinAmount"` + NetProfit float64 `json:"netProfit"` + ProfitMargin float64 `json:"profitMargin"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt *time.Time `json:"updatedAt,omitempty"` +} + +// ConvertDBCompanyReport converts the SQLC generated CompanyReport struct to domain.CompanyReport +func ConvertDBCompanyReport(dbReport dbgen.VirtualGameCompanyReport) CompanyReport { + var updatedAt *time.Time + if !dbReport.UpdatedAt.Time.IsZero() { + updatedAt = &dbReport.UpdatedAt.Time + } + + // convert big.Int-backed numeric fields to float64 safely + var totalBetAmount float64 + if dbReport.TotalBetAmount.Int != nil { + if f, _ := new(big.Float).SetInt(dbReport.TotalBetAmount.Int).Float64(); true { + totalBetAmount = f + } + } + + var totalWinAmount float64 + if dbReport.TotalWinAmount.Int != nil { + if f, _ := new(big.Float).SetInt(dbReport.TotalWinAmount.Int).Float64(); true { + totalWinAmount = f + } + } + + var netProfit float64 + if dbReport.NetProfit.Int != nil { + if f, _ := new(big.Float).SetInt(dbReport.NetProfit.Int).Float64(); true { + netProfit = f + } + } + + var profitMargin float64 + if dbReport.ProfitMargin.Int != nil { + if f, _ := new(big.Float).SetInt(dbReport.ProfitMargin.Int).Float64(); true { + profitMargin = f + } + } + + return CompanyReport{ + ID: dbReport.ID, + CompanyID: dbReport.CompanyID, + ProviderID: dbReport.ProviderID, + ReportDate: dbReport.ReportDate.Time.Format("2006-01-02"), + ReportType: dbReport.ReportType, + TotalBetAmount: totalBetAmount, + TotalWinAmount: totalWinAmount, + NetProfit: netProfit, + ProfitMargin: profitMargin, + CreatedAt: dbReport.CreatedAt.Time, + UpdatedAt: updatedAt, + } +} + +type CompanyProfitTrend struct { + ReportDate string `json:"reportDate"` + TotalProfit float64 `json:"totalProfit"` +} + +type PlayerActivityReport struct { + ID int64 `json:"id"` + UserID int64 `json:"userId"` + ReportDate string `json:"reportDate"` // YYYY-MM-DD + ReportType string `json:"reportType"` + TotalDeposits float64 `json:"totalDeposits"` + TotalWithdrawals float64 `json:"totalWithdrawals"` + NetContribution float64 `json:"netContribution"` + TotalBetAmount float64 `json:"totalBetAmount"` + TotalWinAmount float64 `json:"totalWinAmount"` + NetResult float64 `json:"netResult"` + RoundsPlayed int64 `json:"roundsPlayed"` + AvgBetSize float64 `json:"avgBetSize"` + CreatedAt time.Time `json:"createdAt"` + UpdatedAt *time.Time `json:"updatedAt,omitempty"` +} + +func ConvertDBPlayerActivityReport(dbReport dbgen.VirtualGamePlayerActivityReport) PlayerActivityReport { + return PlayerActivityReport{ + ID: dbReport.ID, + UserID: dbReport.UserID, + ReportDate: dbReport.ReportDate.Time.Format("2006-01-02"), + ReportType: dbReport.ReportType, + TotalDeposits: float64(dbReport.TotalDeposits.Exp), + TotalWithdrawals: float64(dbReport.TotalWithdrawals.Exp), + NetContribution: float64(dbReport.NetContribution.Exp), + TotalBetAmount: float64(dbReport.TotalBetAmount.Exp), + TotalWinAmount: float64(dbReport.TotalWinAmount.Exp), + NetResult: float64(dbReport.NetResult.Exp), + RoundsPlayed: dbReport.RoundsPlayed.Int64, + AvgBetSize: float64(dbReport.AvgBetSize.Exp), + CreatedAt: dbReport.CreatedAt.Time, + UpdatedAt: &dbReport.UpdatedAt.Time, + } +} + +type TopPlayerNetResult struct { + UserID int64 `json:"userId"` + TotalNet float64 `json:"totalNet"` +} diff --git a/internal/ports/virtual_report.go b/internal/ports/virtual_report.go new file mode 100644 index 0000000..ddc6078 --- /dev/null +++ b/internal/ports/virtual_report.go @@ -0,0 +1,27 @@ +package ports + +import ( + "context" + + "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" +) + +type VirtualGameReportStore interface { + CreateFinancialReport(ctx context.Context, report domain.FinancialReport) (domain.FinancialReport, error) + UpsertFinancialReport(ctx context.Context, report domain.FinancialReport) (domain.FinancialReport, error) + GetFinancialReportByID(ctx context.Context, id int64) (domain.FinancialReport, error) + GetFinancialReportsForGame(ctx context.Context, gameID, providerID string, from, to string) ([]domain.FinancialReport, error) + GetDailyFinancialReports(ctx context.Context, reportDate string) ([]domain.FinancialReport, error) + DeleteFinancialReport(ctx context.Context, id int64) error + CreateCompanyReport(ctx context.Context, report domain.CompanyReport) (domain.CompanyReport, error) + UpsertCompanyReport(ctx context.Context, report domain.CompanyReport) (domain.CompanyReport, error) + GetCompanyReportByID(ctx context.Context, id int64) (domain.CompanyReport, error) + GetCompanyReportsInRange(ctx context.Context, companyID int64, providerID string, startDate, endDate string) ([]domain.CompanyReport, error) + GetCompanyProfitTrend(ctx context.Context, companyID int64, providerID string, startDate, endDate string) ([]domain.CompanyProfitTrend, error) + CreatePlayerActivityReport(ctx context.Context, report domain.PlayerActivityReport) (domain.PlayerActivityReport, error) + GetPlayerActivityByID(ctx context.Context, id int64) (domain.PlayerActivityReport, error) + GetPlayerActivityByDate(ctx context.Context, userID int64, reportDate, reportType string) (domain.PlayerActivityReport, error) + GetPlayerActivityRange(ctx context.Context, userID int64, startDate, endDate string) ([]domain.PlayerActivityReport, error) + GetTopPlayersByNetResult(ctx context.Context, startDate, endDate string, limit int) ([]domain.TopPlayerNetResult, error) + DeletePlayerActivityReport(ctx context.Context, id int64) error +} diff --git a/internal/repository/bet.go b/internal/repository/bet.go index bde09f5..cec0a20 100644 --- a/internal/repository/bet.go +++ b/internal/repository/bet.go @@ -122,6 +122,14 @@ func (s *Store) GetAllBets(ctx context.Context, filter domain.BetFilter) ([]doma CreatedAfter: filter.CreatedAfter.ToPG(), }) + if err != nil { + // domain.MongoDBLogger.Error("failed to get all bets", + // zap.Any("filter", filter), + // zap.Error(err), + // ) + return nil, 0, err + } + var result []domain.GetBet = make([]domain.GetBet, 0, len(bets)) for _, bet := range bets { result = append(result, domain.ConvertDBBetWithOutcomes(bet)) diff --git a/internal/repository/report.go b/internal/repository/report.go deleted file mode 100644 index b3f7f56..0000000 --- a/internal/repository/report.go +++ /dev/null @@ -1,106 +0,0 @@ -package repository - -import ( - "context" - "fmt" - - dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" - "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" - "github.com/SamuelTariku/FortuneBet-Backend/internal/ports" - "github.com/jackc/pgx/v5/pgtype" -) - -// Interface for ReportStore -func NewReportStore(s *Store) ports.ReportStore { return s } - -func (s *Store) CreateReportRequest(ctx context.Context, report domain.CreateReportRequest) (domain.ReportRequest, error) { - reportMetadata, err := report.Metadata.ToPG() - if err != nil { - return domain.ReportRequest{}, err - } - - dbReportRequest, err := s.queries.CreateReportRequest(ctx, dbgen.CreateReportRequestParams{ - CompanyID: report.CompanyID.ToPG(), - RequestedBy: report.RequestedBy.ToPG(), - Type: string(report.Type), - Metadata: reportMetadata, - }) - - if err != nil { - return domain.ReportRequest{}, fmt.Errorf("failed to create report request: %w", err) - } - - return domain.ConvertDBReportRequest(dbReportRequest) -} - -func (s *Store) GetAllReportRequests(ctx context.Context, filter domain.ReportRequestFilter) ([]domain.ReportRequestDetail, int64, error) { - dbReportRequests, err := s.queries.GetAllReportRequests(ctx, dbgen.GetAllReportRequestsParams{ - CompanyID: filter.CompanyID.ToPG(), - Type: filter.Type.ToPG(), - Status: filter.Status.ToPG(), - Limit: filter.Limit.ToPG(), - Offset: pgtype.Int4{ - Int32: int32(filter.Offset.Value * filter.Limit.Value), - Valid: filter.Offset.Valid, - }, - RequestedBy: filter.RequestedBy.ToPG(), - }) - if err != nil { - return nil, 0, err - } - total, err := s.queries.GetTotalReportRequests(ctx, dbgen.GetTotalReportRequestsParams{ - CompanyID: filter.CompanyID.ToPG(), - Type: filter.Type.ToPG(), - Status: filter.Status.ToPG(), - RequestedBy: filter.RequestedBy.ToPG(), - }) - if err != nil { - return nil, 0, err - } - result, err := domain.ConvertDBReportRequestDetailList(dbReportRequests) - if err != nil { - return nil, 0, err - } - return result, total, nil -} -func (s *Store) GetReportRequestByRequestedByID(ctx context.Context, requestedBy int64, filter domain.ReportRequestFilter) ([]domain.ReportRequestDetail, error) { - dbReportRequests, err := s.queries.GetReportRequestByRequestedByID(ctx, dbgen.GetReportRequestByRequestedByIDParams{ - RequestedBy: pgtype.Int8{ - Int64: requestedBy, - Valid: true, - }, - Type: filter.Type.ToPG(), - Status: filter.Status.ToPG(), - Limit: filter.Limit.ToPG(), - Offset: pgtype.Int4{ - Int32: int32(filter.Offset.Value * filter.Limit.Value), - Valid: filter.Offset.Valid, - }, - }) - if err != nil { - return nil, err - } - return domain.ConvertDBReportRequestDetailList(dbReportRequests) -} - -func (s *Store) GetReportRequestByID(ctx context.Context, ID int64) (domain.ReportRequestDetail, error) { - dbReportRequest, err := s.queries.GetReportRequestByID(ctx, ID) - if err != nil { - return domain.ReportRequestDetail{}, err - } - return domain.ConvertDBReportRequestDetail(dbReportRequest) -} - -func (s *Store) UpdateReportRequest(ctx context.Context, report domain.UpdateRequestRequest) error { - err := s.queries.UpdateReportRequest(ctx, dbgen.UpdateReportRequestParams{ - ID: report.ID, - FilePath: report.FilePath.ToPG(), - RejectReason: report.RejectReason.ToPG(), - Status: report.Status.ToPG(), - }) - - if err != nil { - return fmt.Errorf("failed to update report request: %w", err) - } - return nil -} diff --git a/internal/repository/virtual_report.go b/internal/repository/virtual_report.go new file mode 100644 index 0000000..a384220 --- /dev/null +++ b/internal/repository/virtual_report.go @@ -0,0 +1,450 @@ +package repository + +import ( + "context" + "fmt" + "time" + + dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db" + "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" + "github.com/SamuelTariku/FortuneBet-Backend/internal/ports" + "github.com/jackc/pgx/v5/pgtype" +) + +// NewVirtualGameReportStore returns a new VirtualGameReportStore interface +func NewVirtualGameReportStore(s *Store) ports.VirtualGameReportStore { + return s +} + +// ------------------- Financial Reports ------------------- +func (s *Store) CreateFinancialReport(ctx context.Context, report domain.FinancialReport) (domain.FinancialReport, error) { + // pgtype.Numeric no longer exposes a Set method in this pgx version; + // use zero-value pgtype.Numeric here (or replace with a proper conversion helper). + totalBets := pgtype.Numeric{} + totalWins := pgtype.Numeric{} + + // parse report.ReportDate (try RFC3339 then YYYY-MM-DD) + t, err := time.Parse(time.RFC3339, report.ReportDate) + if err != nil { + t, err = time.Parse("2006-01-02", report.ReportDate) + if err != nil { + return domain.FinancialReport{}, fmt.Errorf("invalid report date: %w", err) + } + } + + dbReport, err := s.queries.CreateFinancialReport(ctx, dbgen.CreateFinancialReportParams{ + GameID: report.GameID, + ProviderID: report.ProviderID, + ReportDate: pgtype.Date{Time: t}, + ReportType: report.ReportType, + TotalBets: totalBets, + TotalWins: totalWins, + }) + if err != nil { + return domain.FinancialReport{}, fmt.Errorf("failed to create financial report: %w", err) + } + return domain.ConvertDBFinancialReport(dbReport), nil +} + +func (s *Store) UpsertFinancialReport(ctx context.Context, report domain.FinancialReport) (domain.FinancialReport, error) { + totalBets := pgtype.Numeric{} + totalWins := pgtype.Numeric{} + + // parse report.ReportDate + t, err := time.Parse(time.RFC3339, report.ReportDate) + if err != nil { + t, err = time.Parse("2006-01-02", report.ReportDate) + if err != nil { + return domain.FinancialReport{}, fmt.Errorf("invalid report date: %w", err) + } + } + + dbReport, err := s.queries.UpsertFinancialReport(ctx, dbgen.UpsertFinancialReportParams{ + GameID: report.GameID, + ProviderID: report.ProviderID, + ReportDate: pgtype.Date{Time: t}, + ReportType: report.ReportType, + TotalBets: totalBets, + TotalWins: totalWins, + }) + if err != nil { + return domain.FinancialReport{}, fmt.Errorf("failed to upsert financial report: %w", err) + } + + return domain.ConvertDBFinancialReport(dbReport), nil +} + +// GetFinancialReportByID fetches a single report by its ID +func (s *Store) GetFinancialReportByID(ctx context.Context, id int64) (domain.FinancialReport, error) { + dbReport, err := s.queries.GetFinancialReportByID(ctx, id) + if err != nil { + return domain.FinancialReport{}, fmt.Errorf("failed to get financial report by ID: %w", err) + } + return domain.ConvertDBFinancialReport(dbReport), nil +} + +// GetFinancialReportsForGame fetches all reports for a specific game + provider in a date range +func (s *Store) GetFinancialReportsForGame(ctx context.Context, gameID, providerID string, from, to string) ([]domain.FinancialReport, error) { + fromDate, err := time.Parse("2006-01-02", from) + if err != nil { + return nil, fmt.Errorf("invalid from date: %w", err) + } + toDate, err := time.Parse("2006-01-02", to) + if err != nil { + return nil, fmt.Errorf("invalid to date: %w", err) + } + + dbReports, err := s.queries.GetFinancialReportsForGame(ctx, dbgen.GetFinancialReportsForGameParams{ + GameID: gameID, + ProviderID: providerID, + ReportDate: pgtype.Date{Time: fromDate}, + ReportDate_2: pgtype.Date{Time: toDate}, + }) + if err != nil { + return nil, fmt.Errorf("failed to get financial reports for game: %w", err) + } + + var result []domain.FinancialReport + for _, r := range dbReports { + result = append(result, domain.ConvertDBFinancialReport(r)) + } + + return result, nil +} + +func (s *Store) GetDailyFinancialReports(ctx context.Context, reportDate string) ([]domain.FinancialReport, error) { + t, err := time.Parse("2006-01-02", reportDate) + if err != nil { + return nil, fmt.Errorf("invalid report date: %w", err) + } + + dbReports, err := s.queries.GetDailyFinancialReports(ctx, pgtype.Date{Time: t}) + if err != nil { + return nil, fmt.Errorf("failed to get daily financial reports: %w", err) + } + + var result []domain.FinancialReport + for _, r := range dbReports { + result = append(result, domain.ConvertDBFinancialReport(r)) + } + + return result, nil +} + +// DeleteFinancialReport deletes a financial report by ID +func (s *Store) DeleteFinancialReport(ctx context.Context, id int64) error { + err := s.queries.DeleteFinancialReport(ctx, id) + if err != nil { + return fmt.Errorf("failed to delete financial report: %w", err) + } + return nil +} + +// CreateCompanyReport inserts a new company-level financial report +func (s *Store) CreateCompanyReport(ctx context.Context, report domain.CompanyReport) (domain.CompanyReport, error) { + // parse report date + t, err := time.Parse("2006-01-02", report.ReportDate) + if err != nil { + return domain.CompanyReport{}, fmt.Errorf("invalid report date: %w", err) + } + + dbReport, err := s.queries.CreateCompanyReport(ctx, dbgen.CreateCompanyReportParams{ + CompanyID: report.CompanyID, + ProviderID: report.ProviderID, + ReportDate: pgtype.Date{Time: t}, + ReportType: report.ReportType, + TotalBetAmount: pgtype.Numeric{}, // zero value; set actual value if required + TotalWinAmount: pgtype.Numeric{}, + }) + if err != nil { + return domain.CompanyReport{}, fmt.Errorf("failed to create company report: %w", err) + } + + return domain.ConvertDBCompanyReport(dbReport), nil +} + +func (s *Store) UpsertCompanyReport(ctx context.Context, report domain.CompanyReport) (domain.CompanyReport, error) { + // Convert report date + t, err := time.Parse("2006-01-02", report.ReportDate) + if err != nil { + t, err = time.Parse(time.RFC3339, report.ReportDate) + if err != nil { + return domain.CompanyReport{}, fmt.Errorf("invalid report date: %w", err) + } + } + + dbReport, err := s.queries.UpsertCompanyReport(ctx, dbgen.UpsertCompanyReportParams{ + CompanyID: report.CompanyID, + ProviderID: report.ProviderID, + ReportDate: pgtype.Date{Time: t}, + ReportType: report.ReportType, + TotalBetAmount: func() pgtype.Numeric { + var n pgtype.Numeric + _ = n.Scan(report.TotalBetAmount) + return n + }(), + TotalWinAmount: func() pgtype.Numeric { + var n pgtype.Numeric + _ = n.Scan(report.TotalWinAmount) + return n + }(), + }) + if err != nil { + return domain.CompanyReport{}, fmt.Errorf("failed to upsert company report: %w", err) + } + + return domain.ConvertDBCompanyReport(dbReport), nil +} + +func (s *Store) GetCompanyReportByID(ctx context.Context, id int64) (domain.CompanyReport, error) { + dbReport, err := s.queries.GetCompanyReportByID(ctx, id) + if err != nil { + return domain.CompanyReport{}, fmt.Errorf("failed to get company report by ID: %w", err) + } + + return domain.ConvertDBCompanyReport(dbReport), nil +} + +func (s *Store) GetCompanyReportsInRange(ctx context.Context, companyID int64, providerID string, startDate, endDate string) ([]domain.CompanyReport, error) { + start, err := time.Parse("2006-01-02", startDate) + if err != nil { + start, err = time.Parse(time.RFC3339, startDate) + if err != nil { + return nil, fmt.Errorf("invalid start date: %w", err) + } + } + + end, err := time.Parse("2006-01-02", endDate) + if err != nil { + end, err = time.Parse(time.RFC3339, endDate) + if err != nil { + return nil, fmt.Errorf("invalid end date: %w", err) + } + } + + dbReports, err := s.queries.GetCompanyReportsInRange(ctx, dbgen.GetCompanyReportsInRangeParams{ + CompanyID: companyID, + ProviderID: providerID, + ReportDate: pgtype.Date{Time: start}, + ReportDate_2: pgtype.Date{Time: end}, + }) + if err != nil { + return nil, fmt.Errorf("failed to get company reports in range: %w", err) + } + + reports := make([]domain.CompanyReport, 0, len(dbReports)) + for _, r := range dbReports { + reports = append(reports, domain.ConvertDBCompanyReport(r)) + } + + return reports, nil +} + +func (s *Store) GetCompanyProfitTrend(ctx context.Context, companyID int64, providerID string, startDate, endDate string) ([]domain.CompanyProfitTrend, error) { + start, err := time.Parse("2006-01-02", startDate) + if err != nil { + start, err = time.Parse(time.RFC3339, startDate) + if err != nil { + return nil, fmt.Errorf("invalid start date: %w", err) + } + } + + end, err := time.Parse("2006-01-02", endDate) + if err != nil { + end, err = time.Parse(time.RFC3339, endDate) + if err != nil { + return nil, fmt.Errorf("invalid end date: %w", err) + } + } + + rows, err := s.queries.GetCompanyProfitTrend(ctx, dbgen.GetCompanyProfitTrendParams{ + CompanyID: companyID, + ProviderID: providerID, + ReportDate: pgtype.Date{Time: start}, + ReportDate_2: pgtype.Date{Time: end}, + }) + if err != nil { + return nil, fmt.Errorf("failed to get company profit trend: %w", err) + } + + trends := make([]domain.CompanyProfitTrend, 0, len(rows)) + for _, r := range rows { + trends = append(trends, domain.CompanyProfitTrend{ + ReportDate: r.ReportDate.Time.Format("2006-01-02"), + TotalProfit: float64(r.TotalProfit), + }) + } + return trends, nil +} + +// CreatePlayerActivityReport inserts a new player activity report +func (s *Store) CreatePlayerActivityReport(ctx context.Context, report domain.PlayerActivityReport) (domain.PlayerActivityReport, error) { + t, err := time.Parse("2006-01-02", report.ReportDate) + if err != nil { + t, err = time.Parse(time.RFC3339, report.ReportDate) + if err != nil { + return domain.PlayerActivityReport{}, fmt.Errorf("invalid report date: %w", err) + } + } + + createParams := dbgen.CreatePlayerActivityReportParams{ + UserID: report.UserID, + ReportDate: pgtype.Date{Time: t}, + ReportType: report.ReportType, + TotalDeposits: func() pgtype.Numeric { + var n pgtype.Numeric + _ = n.Scan(report.TotalDeposits) + return n + }(), + TotalWithdrawals: func() pgtype.Numeric { + var n pgtype.Numeric + _ = n.Scan(report.TotalWithdrawals) + return n + }(), + TotalBetAmount: func() pgtype.Numeric { + var n pgtype.Numeric + _ = n.Scan(report.TotalBetAmount) + return n + }(), + TotalWinAmount: func() pgtype.Numeric { + var n pgtype.Numeric + _ = n.Scan(report.TotalWinAmount) + return n + }(), + RoundsPlayed: pgtype.Int8{Int64: int64(report.RoundsPlayed)}, + } + + var dbReport dbgen.VirtualGamePlayerActivityReport + dbReport, err = s.queries.CreatePlayerActivityReport(ctx, createParams) + if err != nil { + // try upsert as a fallback + upsertParams := dbgen.UpsertPlayerActivityReportParams{ + UserID: report.UserID, + ReportDate: pgtype.Date{Time: t}, + ReportType: report.ReportType, + TotalDeposits: pgtype.Numeric{Exp: int32(report.TotalDeposits)}, + TotalWithdrawals: pgtype.Numeric{Exp: int32(report.TotalWithdrawals)}, + TotalBetAmount: pgtype.Numeric{Exp: int32(report.TotalBetAmount)}, + TotalWinAmount: pgtype.Numeric{Exp: int32(report.TotalWinAmount)}, + RoundsPlayed: pgtype.Int8{Int64: int64(report.RoundsPlayed)}, + } + dbReport, err = s.queries.UpsertPlayerActivityReport(ctx, upsertParams) + if err != nil { + return domain.PlayerActivityReport{}, fmt.Errorf("failed to create or upsert player activity report: %w", err) + } + } + + return domain.ConvertDBPlayerActivityReport(dbReport), nil +} + +func (s *Store) GetPlayerActivityByID(ctx context.Context, id int64) (domain.PlayerActivityReport, error) { + dbReport, err := s.queries.GetPlayerActivityByID(ctx, id) + if err != nil { + return domain.PlayerActivityReport{}, err + } + return domain.ConvertDBPlayerActivityReport(dbReport), nil +} + +// GetPlayerActivityByDate fetches a player activity report for a specific user and date +func (s *Store) GetPlayerActivityByDate(ctx context.Context, userID int64, reportDate, reportType string) (domain.PlayerActivityReport, error) { + t, err := time.Parse("2006-01-02", reportDate) + if err != nil { + t, err = time.Parse(time.RFC3339, reportDate) + if err != nil { + return domain.PlayerActivityReport{}, fmt.Errorf("invalid report date: %w", err) + } + } + + dbReport, err := s.queries.GetPlayerActivityByDate(ctx, dbgen.GetPlayerActivityByDateParams{ + UserID: userID, + ReportDate: pgtype.Date{Time: t}, + ReportType: reportType, + }) + if err != nil { + return domain.PlayerActivityReport{}, err + } + + return domain.ConvertDBPlayerActivityReport(dbReport), nil +} + +// GetPlayerActivityRange fetches all activity reports for a user in a date range +func (s *Store) GetPlayerActivityRange(ctx context.Context, userID int64, startDate, endDate string) ([]domain.PlayerActivityReport, error) { + start, err := time.Parse("2006-01-02", startDate) + if err != nil { + start, err = time.Parse(time.RFC3339, startDate) + if err != nil { + return nil, fmt.Errorf("invalid start date: %w", err) + } + } + + end, err := time.Parse("2006-01-02", endDate) + if err != nil { + end, err = time.Parse(time.RFC3339, endDate) + if err != nil { + return nil, fmt.Errorf("invalid end date: %w", err) + } + } + + dbReports, err := s.queries.GetPlayerActivityRange(ctx, dbgen.GetPlayerActivityRangeParams{ + UserID: userID, + ReportDate: pgtype.Date{Time: start}, + ReportDate_2: pgtype.Date{Time: end}, + }) + if err != nil { + return nil, err + } + + activities := make([]domain.PlayerActivityReport, 0, len(dbReports)) + for _, r := range dbReports { + activities = append(activities, domain.ConvertDBPlayerActivityReport(r)) + } + return activities, nil +} + +// GetTopPlayersByNetResult returns the top N players by net result in a date range +func (s *Store) GetTopPlayersByNetResult(ctx context.Context, startDate, endDate string, limit int) ([]domain.TopPlayerNetResult, error) { + start, err := time.Parse("2006-01-02", startDate) + if err != nil { + start, err = time.Parse(time.RFC3339, startDate) + if err != nil { + return nil, fmt.Errorf("invalid start date: %w", err) + } + } + + end, err := time.Parse("2006-01-02", endDate) + if err != nil { + end, err = time.Parse(time.RFC3339, endDate) + if err != nil { + return nil, fmt.Errorf("invalid end date: %w", err) + } + } + + rows, err := s.conn.Query(ctx, `SELECT user_id, SUM(net_result) AS total_net + FROM virtual_game_player_activity_reports + WHERE report_date BETWEEN $1 AND $2 + GROUP BY user_id + ORDER BY total_net DESC + LIMIT $3`, start, end, limit) + if err != nil { + return nil, fmt.Errorf("failed to fetch top players: %w", err) + } + defer rows.Close() + + var topPlayers []domain.TopPlayerNetResult + for rows.Next() { + var tp domain.TopPlayerNetResult + var totalNet pgtype.Numeric + if err := rows.Scan(&tp.UserID, &totalNet); err != nil { + return nil, err + } + tp.TotalNet = float64(totalNet.Exp) + topPlayers = append(topPlayers, tp) + } + return topPlayers, nil +} + +// DeletePlayerActivityReport deletes a player activity report by its ID +func (s *Store) DeletePlayerActivityReport(ctx context.Context, id int64) error { + err := s.queries.DeletePlayerActivityReport(ctx, id) + return err +} diff --git a/internal/web_server/app.go b/internal/web_server/app.go index 6b2f6a5..7994537 100644 --- a/internal/web_server/app.go +++ b/internal/web_server/app.go @@ -23,7 +23,6 @@ import ( "github.com/SamuelTariku/FortuneBet-Backend/internal/services/raffle" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/recommendation" referralservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/referal" - "github.com/SamuelTariku/FortuneBet-Backend/internal/services/report" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/result" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/santimpay" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/settings" @@ -75,22 +74,22 @@ type App struct { userSvc *user.Service betSvc *bet.Service virtualGameSvc virtualgameservice.VirtualGameService - reportSvc report.ReportService - chapaSvc *chapa.Service - walletSvc *wallet.Service - transactionSvc *transaction.Service - ticketSvc *ticket.Service - branchSvc *branch.Service - companySvc *company.Service - validator *customvalidator.CustomValidator - JwtConfig jwtutil.JwtConfig - Logger *slog.Logger - prematchSvc *odds.ServiceImpl - eventSvc *event.Service - leagueSvc *league.Service - resultSvc *result.Service - statSvc *stats.Service - mongoLoggerSvc *zap.Logger + // reportSvc report.ReportService + chapaSvc *chapa.Service + walletSvc *wallet.Service + transactionSvc *transaction.Service + ticketSvc *ticket.Service + branchSvc *branch.Service + companySvc *company.Service + validator *customvalidator.CustomValidator + JwtConfig jwtutil.JwtConfig + Logger *slog.Logger + prematchSvc *odds.ServiceImpl + eventSvc *event.Service + leagueSvc *league.Service + resultSvc *result.Service + statSvc *stats.Service + mongoLoggerSvc *zap.Logger } func NewApp( @@ -113,7 +112,7 @@ func NewApp( userSvc *user.Service, ticketSvc *ticket.Service, betSvc *bet.Service, - reportSvc report.ReportService, + // reportSvc report.ReportService, chapaSvc *chapa.Service, walletSvc *wallet.Service, transactionSvc *transaction.Service, @@ -166,15 +165,15 @@ func NewApp( fiber: app, port: port, - settingSvc: settingSvc, - authSvc: authSvc, - validator: validator, - logger: logger, - JwtConfig: JwtConfig, - userSvc: userSvc, - ticketSvc: ticketSvc, - betSvc: betSvc, - reportSvc: reportSvc, + settingSvc: settingSvc, + authSvc: authSvc, + validator: validator, + logger: logger, + JwtConfig: JwtConfig, + userSvc: userSvc, + ticketSvc: ticketSvc, + betSvc: betSvc, + // reportSvc: reportSvc, chapaSvc: chapaSvc, walletSvc: walletSvc, transactionSvc: transactionSvc, diff --git a/internal/web_server/handlers/handlers.go b/internal/web_server/handlers/handlers.go index ccf51e0..1353ab1 100644 --- a/internal/web_server/handlers/handlers.go +++ b/internal/web_server/handlers/handlers.go @@ -23,7 +23,6 @@ import ( "github.com/SamuelTariku/FortuneBet-Backend/internal/services/raffle" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/recommendation" referralservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/referal" - "github.com/SamuelTariku/FortuneBet-Backend/internal/services/report" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/result" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/santimpay" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/settings" @@ -44,23 +43,23 @@ import ( ) type Handler struct { - directDepositSvc *directdeposit.Service - orchestrationSvc *orchestration.Service - enetPulseSvc *enetpulse.Service - telebirrSvc *telebirr.TelebirrService - arifpaySvc *arifpay.ArifpayService - santimpaySvc *santimpay.SantimPayService - issueReportingSvc *issuereporting.Service - instSvc *institutions.Service - currSvc *currency.Service - logger *slog.Logger - settingSvc *settings.Service - notificationSvc *notificationservice.Service - userSvc *user.Service - referralSvc *referralservice.Service - raffleSvc *raffle.Service - bonusSvc *bonus.Service - reportSvc report.ReportService + directDepositSvc *directdeposit.Service + orchestrationSvc *orchestration.Service + enetPulseSvc *enetpulse.Service + telebirrSvc *telebirr.TelebirrService + arifpaySvc *arifpay.ArifpayService + santimpaySvc *santimpay.SantimPayService + issueReportingSvc *issuereporting.Service + instSvc *institutions.Service + currSvc *currency.Service + logger *slog.Logger + settingSvc *settings.Service + notificationSvc *notificationservice.Service + userSvc *user.Service + referralSvc *referralservice.Service + raffleSvc *raffle.Service + bonusSvc *bonus.Service + // reportSvc report.ReportService chapaSvc *chapa.Service walletSvc *wallet.Service transactionSvc *transaction.Service @@ -99,7 +98,7 @@ func New( settingSvc *settings.Service, notificationSvc *notificationservice.Service, validator *customvalidator.CustomValidator, - reportSvc report.ReportService, + // reportSvc report.ReportService, chapaSvc *chapa.Service, walletSvc *wallet.Service, referralSvc *referralservice.Service, @@ -127,19 +126,19 @@ func New( mongoLoggerSvc *zap.Logger, ) *Handler { return &Handler{ - directDepositSvc: directDepositSvc, - orchestrationSvc: orchestrationSvc, - enetPulseSvc: enetPulseSvc, - telebirrSvc: telebirrSvc, - arifpaySvc: arifpaySvc, - santimpaySvc: santimpaySvc, - issueReportingSvc: issueReportingSvc, - instSvc: instSvc, - currSvc: currSvc, - logger: logger, - settingSvc: settingSvc, - notificationSvc: notificationSvc, - reportSvc: reportSvc, + directDepositSvc: directDepositSvc, + orchestrationSvc: orchestrationSvc, + enetPulseSvc: enetPulseSvc, + telebirrSvc: telebirrSvc, + arifpaySvc: arifpaySvc, + santimpaySvc: santimpaySvc, + issueReportingSvc: issueReportingSvc, + instSvc: instSvc, + currSvc: currSvc, + logger: logger, + settingSvc: settingSvc, + notificationSvc: notificationSvc, + // reportSvc: reportSvc, chapaSvc: chapaSvc, walletSvc: walletSvc, referralSvc: referralSvc, diff --git a/internal/web_server/handlers/report.go b/internal/web_server/handlers/report.go deleted file mode 100644 index 9338197..0000000 --- a/internal/web_server/handlers/report.go +++ /dev/null @@ -1,481 +0,0 @@ -package handlers - -import ( - "context" - "fmt" - "math" - "os" - "sort" - "strconv" - "strings" - "time" - - "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" - "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response" - "github.com/gofiber/fiber/v2" - "go.uber.org/zap" -) - -// GetDashboardReport returns a comprehensive dashboard report -// @Summary Get dashboard report -// @Description Returns a comprehensive dashboard report with key metrics -// @Tags Reports -// @Accept json -// @Produce json -// @Param company_id query int false "Company ID filter" -// @Param branch_id query int false "Branch ID filter" -// @Param user_id query int false "User ID filter" -// @Param start_time query string false "Start time filter (RFC3339 format)" -// @Param end_time query string false "End time filter (RFC3339 format)" -// @Param sport_id query string false "Sport ID filter" -// @Param status query int false "Status filter (0=Pending, 1=Win, 2=Loss, 3=Half, 4=Void, 5=Error)" -// @Security ApiKeyAuth -// @Success 200 {object} domain.DashboardSummary -// @Failure 400 {object} domain.ErrorResponse -// @Failure 401 {object} domain.ErrorResponse -// @Failure 500 {object} domain.ErrorResponse -// @Router /api/v1/reports/dashboard [get] -func (h *Handler) GetDashboardReport(c *fiber.Ctx) error { - role := c.Locals("role").(domain.Role) - - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) - defer cancel() - - // Parse query parameters - filter, err := parseReportFilter(c, role) - if err != nil { - return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ - Message: "Invalid filter parameters", - Error: err.Error(), - }) - } - - // Get report data - summary, err := h.reportSvc.GetDashboardSummary(ctx, filter) - if err != nil { - h.logger.Error("failed to get dashboard report", "error", err) - return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{ - Message: "Failed to generate report", - Error: err.Error(), - }) - } - - res := domain.ConvertDashboardSummaryToRes(summary) - - return c.Status(fiber.StatusOK).JSON(domain.Response{ - Message: "Dashboard reports generated successfully", - Success: true, - StatusCode: 200, - Data: res, - }) - - // return c.Status(fiber.StatusOK).JSON(summary) -} - -// parseReportFilter parses query parameters into ReportFilter -func parseReportFilter(c *fiber.Ctx, role domain.Role) (domain.ReportFilter, error) { - var filter domain.ReportFilter - var err error - - if c.Query("company_id") != "" && role == domain.RoleSuperAdmin { - - companyID, err := strconv.ParseInt(c.Query("company_id"), 10, 64) - if err != nil { - return domain.ReportFilter{}, fmt.Errorf("invalid company_id: %w", err) - } - filter.CompanyID = domain.ValidInt64{Value: companyID, Valid: true} - } else { - filter.CompanyID = c.Locals("company_id").(domain.ValidInt64) - - } - - if c.Query("branch_id") != "" && role == domain.RoleSuperAdmin { - branchID, err := strconv.ParseInt(c.Query("branch_id"), 10, 64) - if err != nil { - return domain.ReportFilter{}, fmt.Errorf("invalid branch_id: %w", err) - } - filter.BranchID = domain.ValidInt64{Value: branchID, Valid: true} - } else { - filter.BranchID = c.Locals("branch_id").(domain.ValidInt64) - } - - if c.Query("user_id") != "" { - userID, err := strconv.ParseInt(c.Query("user_id"), 10, 64) - if err != nil { - return domain.ReportFilter{}, fmt.Errorf("invalid user_id: %w", err) - } - filter.UserID = domain.ValidInt64{Value: userID, Valid: true} - } - - if c.Query("start_time") != "" { - startTime, err := time.Parse(time.RFC3339, c.Query("start_time")) - if err != nil { - return domain.ReportFilter{}, fmt.Errorf("invalid start_time: %w", err) - } - filter.StartTime = domain.ValidTime{Value: startTime, Valid: true} - } - - if c.Query("end_time") != "" { - endTime, err := time.Parse(time.RFC3339, c.Query("end_time")) - if err != nil { - return domain.ReportFilter{}, fmt.Errorf("invalid end_time: %w", err) - } - filter.EndTime = domain.ValidTime{Value: endTime, Valid: true} - } - - if c.Query("sport_id") != "" { - filter.SportID = domain.ValidString{Value: c.Query("sport_id"), Valid: true} - } - - if c.Query("status") != "" { - status, err := strconv.ParseInt(c.Query("status"), 10, 32) - if err != nil { - return domain.ReportFilter{}, fmt.Errorf("invalid status: %w", err) - } - filter.Status = domain.ValidOutcomeStatus{Value: domain.OutcomeStatus(status), Valid: true} - } - - return filter, err -} - -// DownloadReportFile godoc -// @Summary Download a CSV report file -// @Description Downloads a generated report CSV file from the server -// @Tags Reports -// @Param filename path string true "Name of the report file to download (e.g., report_daily_2025-06-21.csv)" -// @Produce text/csv -// @Success 200 {file} file "CSV file will be downloaded" -// @Failure 400 {object} domain.ErrorResponse "Missing or invalid filename" -// @Failure 404 {object} domain.ErrorResponse "Report file not found" -// @Failure 500 {object} domain.ErrorResponse "Internal server error while serving the file" -// @Router /api/v1/report-files/download/{filename} [get] -func (h *Handler) DownloadReportFile(c *fiber.Ctx) error { - filename := c.Params("filename") - if filename == "" || strings.Contains(filename, "..") { - return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ - Message: "Invalid filename parameter", - Error: "filename is required and must not contain '..'", - }) - } - - reportDir := "C:/Users/User/Desktop/reports" - - // Ensure reports directory exists - if _, err := os.Stat(reportDir); os.IsNotExist(err) { - if err := os.MkdirAll(reportDir, os.ModePerm); err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{ - Message: "Failed to create report directory", - Error: err.Error(), - }) - } - } - - filePath := fmt.Sprintf("%s/%s", reportDir, filename) - - // Check if the report file exists - if _, err := os.Stat(filePath); os.IsNotExist(err) { - return c.Status(fiber.StatusNotFound).JSON(domain.ErrorResponse{ - Message: "Report file not found", - Error: "no such file", - }) - } - - // Set download headers - c.Set("Content-Type", "text/csv") - c.Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", filename)) - - // Serve the file - if err := c.SendFile(filePath); err != nil { - return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{ - Message: "Failed to serve file", - Error: err.Error(), - }) - } - - return nil -} - -// ListReportFiles godoc -// @Summary List available report CSV files -// @Description Returns a paginated list of generated report CSV files with search capability -// @Tags Reports -// @Produce json -// @Param search query string false "Search term to filter filenames" -// @Param page query int false "Page number (default: 1)" default(1) -// @Param limit query int false "Items per page (default: 20, max: 100)" default(20) -// @Success 200 {object} domain.PaginatedFileResponse "Paginated list of CSV report filenames" -// @Failure 400 {object} domain.ErrorResponse "Invalid pagination parameters" -// @Failure 500 {object} domain.ErrorResponse "Failed to read report directory" -// @Router /api/v1/report-files/list [get] -func (h *Handler) ListReportFiles(c *fiber.Ctx) error { - reportDir := "C:/Users/User/Desktop/reports" - searchTerm := c.Query("search") - page := c.QueryInt("page", 1) - limit := c.QueryInt("limit", 20) - - // Validate pagination parameters - if page < 1 { - return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ - Message: "Invalid page number", - Error: "Page must be greater than 0", - }) - } - - if limit < 1 || limit > 100 { - return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{ - Message: "Invalid limit value", - Error: "Limit must be between 1 and 100", - }) - } - - // Create the reports directory if it doesn't exist - if _, err := os.Stat(reportDir); os.IsNotExist(err) { - if err := os.MkdirAll(reportDir, os.ModePerm); err != nil { - h.mongoLoggerSvc.Error("failed to create report directory", - zap.Int64("status_code", fiber.StatusInternalServerError), - zap.Error(err), - zap.Time("timestamp", time.Now()), - ) - return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{ - Message: "Failed to create report directory", - Error: err.Error(), - }) - } - } - - files, err := os.ReadDir(reportDir) - if err != nil { - h.mongoLoggerSvc.Error("failed to read report directory", - zap.Int64("status_code", fiber.StatusInternalServerError), - zap.Error(err), - zap.Time("timestamp", time.Now()), - ) - return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{ - Message: "Failed to read report directory", - Error: err.Error(), - }) - } - - var allFiles []string - for _, file := range files { - if !file.IsDir() && strings.HasSuffix(file.Name(), ".csv") { - // Apply search filter if provided - if searchTerm == "" || strings.Contains(strings.ToLower(file.Name()), strings.ToLower(searchTerm)) { - allFiles = append(allFiles, file.Name()) - } - } - } - - // Sort files by name (descending to show newest first) - sort.Slice(allFiles, func(i, j int) bool { - return allFiles[i] > allFiles[j] - }) - - // Calculate pagination values - total := len(allFiles) - startIdx := (page - 1) * limit - endIdx := startIdx + limit - - // Adjust end index if it exceeds the slice length - if endIdx > total { - endIdx = total - } - - // Handle case where start index is beyond available items - if startIdx >= total { - return c.Status(fiber.StatusOK).JSON(domain.PaginatedFileResponse{ - Response: domain.Response{ - StatusCode: fiber.StatusOK, - Message: "No files found for the requested page", - Success: true, - }, - Data: []string{}, - Pagination: domain.Pagination{ - Total: total, - TotalPages: int(math.Ceil(float64(total) / float64(limit))), - CurrentPage: page, - Limit: limit, - }, - }) - } - - paginatedFiles := allFiles[startIdx:endIdx] - - return c.Status(fiber.StatusOK).JSON(domain.PaginatedFileResponse{ - Response: domain.Response{ - StatusCode: fiber.StatusOK, - Message: "Report files retrieved successfully", - Success: true, - }, - Data: paginatedFiles, - Pagination: domain.Pagination{ - Total: total, - TotalPages: int(math.Ceil(float64(total) / float64(limit))), - CurrentPage: page, - Limit: limit, - }, - }) -} - -func (h *Handler) CreateReportRequest(c *fiber.Ctx) error { - userID := c.Locals("user_id").(int64) - companyID := c.Locals("company_id").(domain.ValidInt64) - - var req domain.CreateReportRequestReq - if err := c.BodyParser(&req); err != nil { - h.BadRequestLogger().Error( - "Failed to parse CreateReportRequestReq", - zap.Error(err), - ) - return fiber.NewError(fiber.StatusBadRequest, "Invalid request:", err.Error()) - } - valErrs, ok := h.validator.Validate(c, req) - if !ok { - var errMsg string - for field, msg := range valErrs { - errMsg += fmt.Sprintf("%s: %s; ", field, msg) - } - h.BadRequestLogger().Error( - "Failed to validate CreateReportRequestReq", - zap.String("errMsg", errMsg), - ) - return fiber.NewError(fiber.StatusBadRequest, errMsg) - } - - request, err := h.reportSvc.CreateReportRequest(c.Context(), domain.CreateReportRequest{ - CompanyID: companyID, - RequestedBy: domain.ValidInt64{ - Value: userID, - Valid: true, - }, - Type: domain.ReportRequestType(req.Type), - Metadata: req.Metadata, - }) - - if err != nil { - h.InternalServerErrorLogger().Error("Failed to create report request", zap.Error(err)) - return fiber.NewError(fiber.StatusInternalServerError, err.Error()) - } - - res := domain.ConvertReportRequest(request) - - return response.WriteJSON(c, fiber.StatusOK, "Report Request has been created", res, nil) -} - -func (h *Handler) GetAllReportRequests(c *fiber.Ctx) error { - companyID := c.Locals("company_id").(domain.ValidInt64) - - page := c.QueryInt("page", 1) - pageSize := c.QueryInt("page_size", 10) - limit := domain.ValidInt32{ - Value: int32(pageSize), - Valid: true, - } - offset := domain.ValidInt32{ - Value: int32(page - 1), - Valid: true, - } - - statusQuery := c.Query("status") - var reportStatus domain.ValidReportRequestStatus - if statusQuery != "" { - reportStatusParsed, err := domain.ParseReportRequestStatus(statusQuery) - if err != nil { - h.BadRequestLogger().Error("Failed to parse statusQuery", - zap.String("status", statusQuery), - zap.Error(err), - ) - return fiber.NewError(fiber.StatusBadRequest, "invalid report status") - } - reportStatus = domain.ValidReportRequestStatus{ - Value: reportStatusParsed, - Valid: true, - } - } - - typeQuery := c.Query("type") - var reportType domain.ValidReportRequestType - if typeQuery != "" { - reportTypeParsed, err := domain.ParseReportRequestType(typeQuery) - if err != nil { - h.BadRequestLogger().Error("Failed to parse typeQuery", - zap.String("type", typeQuery), - zap.Error(err), - ) - return fiber.NewError(fiber.StatusBadRequest, "invalid report type") - } - reportType = domain.ValidReportRequestType{ - Value: reportTypeParsed, - Valid: true, - } - } - - requesterQuery := c.Query("requester") - var requestedBy domain.ValidInt64 - if requesterQuery != "" { - parsedRequestedBy, err := strconv.ParseInt(requesterQuery, 10, 64) - if err != nil { - h.BadRequestLogger().Error("Failed to parse requester", - zap.String("requester", requesterQuery), - zap.Error(err), - ) - return fiber.NewError(fiber.StatusBadRequest, "invalid report requester") - } - requestedBy = domain.ValidInt64{ - Value: parsedRequestedBy, - Valid: true, - } - } - requests, total, err := h.reportSvc.GetAllReportRequests(c.Context(), domain.ReportRequestFilter{ - CompanyID: companyID, - Limit: limit, - Offset: offset, - Status: reportStatus, - Type: reportType, - RequestedBy: requestedBy, - }) - if err != nil { - h.InternalServerErrorLogger().Error("Failed to retrieve all report requests", - zap.Error(err), - ) - return fiber.NewError(fiber.StatusInternalServerError, err.Error()) - } - - res := domain.ConvertReportRequestDetailList(requests) - - return response.WritePaginatedJSON(c, fiber.StatusOK, "All Report Requests successfully retrieved", res, nil, page, int(total)) -} - -func (h *Handler) DownloadReportByID(c *fiber.Ctx) error { - requestID := c.Params("id") - id, err := strconv.ParseInt(requestID, 10, 64) - if err != nil { - h.BadRequestLogger().Info("Invalid report request ID", - zap.String("requestID", requestID), - zap.Error(err), - ) - return fiber.NewError(fiber.StatusBadRequest, "Invalid request ID") - } - - file, err := h.reportSvc.CheckAndFetchReportFile(c.Context(), id) - - if err != nil { - h.InternalServerErrorLogger().Error("Failed to check and fetch report file", - zap.Error(err), - zap.String("requestID", requestID), - ) - return fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("Failed to check and fetch report file:%v", err.Error())) - } - - c.Set("Content-Type", "text/csv") - c.Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%s\"", file)) - - if err := c.SendFile(file); err != nil { - h.InternalServerErrorLogger().Error("Unable to download report file", - zap.Error(err), - zap.String("requestID", requestID), - ) - return fiber.NewError(fiber.StatusInternalServerError, fmt.Sprintf("Unable to download report file:%v", err.Error())) - } - return nil -} diff --git a/internal/web_server/routes.go b/internal/web_server/routes.go index 883f723..fca33a4 100644 --- a/internal/web_server/routes.go +++ b/internal/web_server/routes.go @@ -33,7 +33,7 @@ func (a *App) initAppRoutes() { a.settingSvc, a.NotidicationStore, a.validator, - a.reportSvc, + // a.reportSvc, a.chapaSvc, a.walletSvc, a.referralSvc, @@ -408,13 +408,13 @@ func (a *App) initAppRoutes() { groupV1.Get("/currencies/convert", h.ConvertCurrency) //Report Routes - groupV1.Get("/reports/dashboard", a.authMiddleware, a.OnlyAdminAndAbove, h.GetDashboardReport) - groupV1.Get("/report-files/download/:filename", h.DownloadReportFile) - groupV1.Get("/report-files/list", a.authMiddleware, a.OnlyAdminAndAbove, h.ListReportFiles) + // groupV1.Get("/reports/dashboard", a.authMiddleware, a.OnlyAdminAndAbove, h.GetDashboardReport) + // groupV1.Get("/report-files/download/:filename", h.DownloadReportFile) + // groupV1.Get("/report-files/list", a.authMiddleware, a.OnlyAdminAndAbove, h.ListReportFiles) - groupV1.Post("/reports/requests", a.authMiddleware, a.OnlyAdminAndAbove, h.CreateReportRequest) - groupV1.Get("/reports/requests", a.authMiddleware, a.OnlyAdminAndAbove, h.GetAllReportRequests) - groupV1.Get("/reports/download/:id", a.authMiddleware, a.OnlyAdminAndAbove, h.DownloadReportByID) + // groupV1.Post("/reports/requests", a.authMiddleware, a.OnlyAdminAndAbove, h.CreateReportRequest) + // groupV1.Get("/reports/requests", a.authMiddleware, a.OnlyAdminAndAbove, h.GetAllReportRequests) + // groupV1.Get("/reports/download/:id", a.authMiddleware, a.OnlyAdminAndAbove, h.DownloadReportByID) //Alea Play Virtual Game Routes groupV1.Get("/alea-play/launch", a.authMiddleware, h.LaunchAleaGame)