Merge branch 'main' into ticket-bet
This commit is contained in:
commit
0b03bfaa42
|
|
@ -153,7 +153,7 @@ func main() {
|
||||||
virtualGameSvc := virtualgameservice.New(vitualGameRepo, *walletSvc, store, cfg, logger)
|
virtualGameSvc := virtualgameservice.New(vitualGameRepo, *walletSvc, store, cfg, logger)
|
||||||
aleaService := alea.NewAleaPlayService(vitualGameRepo, *walletSvc, cfg, logger)
|
aleaService := alea.NewAleaPlayService(vitualGameRepo, *walletSvc, cfg, logger)
|
||||||
veliCLient := veli.NewClient(cfg, walletSvc)
|
veliCLient := veli.NewClient(cfg, walletSvc)
|
||||||
veliVirtualGameService := veli.New(vitualGameRepo, veliCLient, walletSvc, wallet.TransferStore(store), cfg)
|
veliVirtualGameService := veli.New(virtualGameSvc,vitualGameRepo, veliCLient, walletSvc, wallet.TransferStore(store), cfg)
|
||||||
recommendationSvc := recommendation.NewService(recommendationRepo)
|
recommendationSvc := recommendation.NewService(recommendationRepo)
|
||||||
chapaClient := chapa.NewClient(cfg.CHAPA_BASE_URL, cfg.CHAPA_SECRET_KEY)
|
chapaClient := chapa.NewClient(cfg.CHAPA_BASE_URL, cfg.CHAPA_SECRET_KEY)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,28 @@ CREATE TABLE IF NOT EXISTS virtual_game_providers (
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMPTZ
|
updated_at TIMESTAMPTZ
|
||||||
);
|
);
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS virtual_games (
|
||||||
|
id BIGSERIAL PRIMARY KEY,
|
||||||
|
game_id VARCHAR(150) NOT NULL,
|
||||||
|
provider_id VARCHAR(100) NOT NULL REFERENCES virtual_game_providers(provider_id) ON DELETE CASCADE,
|
||||||
|
name VARCHAR(255) NOT NULL,
|
||||||
|
category VARCHAR(100),
|
||||||
|
device_type VARCHAR(100),
|
||||||
|
volatility VARCHAR(50),
|
||||||
|
rtp NUMERIC(5,2),
|
||||||
|
has_demo BOOLEAN DEFAULT FALSE,
|
||||||
|
has_free_bets BOOLEAN DEFAULT FALSE,
|
||||||
|
bets NUMERIC[] DEFAULT '{}',
|
||||||
|
thumbnail TEXT,
|
||||||
|
status INT,
|
||||||
|
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
updated_at TIMESTAMPTZ
|
||||||
|
);
|
||||||
|
|
||||||
|
CREATE UNIQUE INDEX IF NOT EXISTS ux_virtual_games_provider_game
|
||||||
|
ON virtual_games (provider_id, game_id);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS wallets (
|
CREATE TABLE IF NOT EXISTS wallets (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
balance BIGINT NOT NULL DEFAULT 0,
|
balance BIGINT NOT NULL DEFAULT 0,
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,3 @@
|
||||||
CREATE TABLE IF NOT EXISTS virtual_games (
|
|
||||||
id BIGSERIAL PRIMARY KEY,
|
|
||||||
name VARCHAR(255) NOT NULL,
|
|
||||||
provider VARCHAR(255) NOT NULL,
|
|
||||||
category VARCHAR(100),
|
|
||||||
min_bet NUMERIC(10, 2) NOT NULL,
|
|
||||||
max_bet NUMERIC(10, 2) NOT NULL,
|
|
||||||
volatility VARCHAR(50),
|
|
||||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
|
||||||
rtp NUMERIC(5, 2) CHECK (rtp >= 0 AND rtp <= 100),
|
|
||||||
is_featured BOOLEAN NOT NULL DEFAULT FALSE,
|
|
||||||
popularity_score INT DEFAULT 0,
|
|
||||||
thumbnail_url TEXT,
|
|
||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
||||||
updated_at TIMESTAMPTZ
|
|
||||||
);
|
|
||||||
CREATE TABLE virtual_game_sessions (
|
CREATE TABLE virtual_game_sessions (
|
||||||
id BIGSERIAL PRIMARY KEY,
|
id BIGSERIAL PRIMARY KEY,
|
||||||
user_id BIGINT NOT NULL REFERENCES users(id),
|
user_id BIGINT NOT NULL REFERENCES users(id),
|
||||||
|
|
|
||||||
|
|
@ -122,3 +122,67 @@ SELECT game_id
|
||||||
FROM favorite_games
|
FROM favorite_games
|
||||||
WHERE user_id = $1;
|
WHERE user_id = $1;
|
||||||
|
|
||||||
|
-- name: CreateVirtualGame :one
|
||||||
|
INSERT INTO virtual_games (
|
||||||
|
game_id,
|
||||||
|
provider_id,
|
||||||
|
name,
|
||||||
|
category,
|
||||||
|
device_type,
|
||||||
|
volatility,
|
||||||
|
rtp,
|
||||||
|
has_demo,
|
||||||
|
has_free_bets,
|
||||||
|
bets,
|
||||||
|
thumbnail,
|
||||||
|
status
|
||||||
|
) VALUES (
|
||||||
|
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12
|
||||||
|
)
|
||||||
|
RETURNING
|
||||||
|
id,
|
||||||
|
game_id,
|
||||||
|
provider_id,
|
||||||
|
name,
|
||||||
|
category,
|
||||||
|
device_type,
|
||||||
|
volatility,
|
||||||
|
rtp,
|
||||||
|
has_demo,
|
||||||
|
has_free_bets,
|
||||||
|
bets,
|
||||||
|
thumbnail,
|
||||||
|
status,
|
||||||
|
created_at,
|
||||||
|
updated_at;
|
||||||
|
|
||||||
|
-- name: GetAllVirtualGames :many
|
||||||
|
SELECT
|
||||||
|
vg.id,
|
||||||
|
vg.game_id,
|
||||||
|
vg.provider_id,
|
||||||
|
vp.provider_name,
|
||||||
|
vg.name,
|
||||||
|
vg.category,
|
||||||
|
vg.device_type,
|
||||||
|
vg.volatility,
|
||||||
|
vg.rtp,
|
||||||
|
vg.has_demo,
|
||||||
|
vg.has_free_bets,
|
||||||
|
vg.bets,
|
||||||
|
vg.thumbnail,
|
||||||
|
vg.status,
|
||||||
|
vg.created_at,
|
||||||
|
vg.updated_at
|
||||||
|
FROM virtual_games vg
|
||||||
|
JOIN virtual_game_providers vp ON vg.provider_id = vp.provider_id
|
||||||
|
WHERE
|
||||||
|
($1::text IS NULL OR vg.category = $1) -- category filter (optional)
|
||||||
|
AND ($2::text IS NULL OR vg.name ILIKE '%' || $2 || '%') -- search by name (optional)
|
||||||
|
ORDER BY vg.created_at DESC
|
||||||
|
LIMIT $3 OFFSET $4;
|
||||||
|
|
||||||
|
-- name: DeleteAllVirtualGames :exec
|
||||||
|
DELETE FROM virtual_games;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -810,20 +810,21 @@ type UserGameInteraction struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type VirtualGame struct {
|
type VirtualGame struct {
|
||||||
ID int64 `json:"id"`
|
ID int64 `json:"id"`
|
||||||
Name string `json:"name"`
|
GameID string `json:"game_id"`
|
||||||
Provider string `json:"provider"`
|
ProviderID string `json:"provider_id"`
|
||||||
Category pgtype.Text `json:"category"`
|
Name string `json:"name"`
|
||||||
MinBet pgtype.Numeric `json:"min_bet"`
|
Category pgtype.Text `json:"category"`
|
||||||
MaxBet pgtype.Numeric `json:"max_bet"`
|
DeviceType pgtype.Text `json:"device_type"`
|
||||||
Volatility pgtype.Text `json:"volatility"`
|
Volatility pgtype.Text `json:"volatility"`
|
||||||
IsActive bool `json:"is_active"`
|
Rtp pgtype.Numeric `json:"rtp"`
|
||||||
Rtp pgtype.Numeric `json:"rtp"`
|
HasDemo pgtype.Bool `json:"has_demo"`
|
||||||
IsFeatured bool `json:"is_featured"`
|
HasFreeBets pgtype.Bool `json:"has_free_bets"`
|
||||||
PopularityScore pgtype.Int4 `json:"popularity_score"`
|
Bets []pgtype.Numeric `json:"bets"`
|
||||||
ThumbnailUrl pgtype.Text `json:"thumbnail_url"`
|
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||||
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
Status pgtype.Int4 `json:"status"`
|
||||||
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type VirtualGameHistory struct {
|
type VirtualGameHistory struct {
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,92 @@ func (q *Queries) CountVirtualGameProviders(ctx context.Context) (int64, error)
|
||||||
return total, err
|
return total, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CreateVirtualGame = `-- name: CreateVirtualGame :one
|
||||||
|
INSERT INTO virtual_games (
|
||||||
|
game_id,
|
||||||
|
provider_id,
|
||||||
|
name,
|
||||||
|
category,
|
||||||
|
device_type,
|
||||||
|
volatility,
|
||||||
|
rtp,
|
||||||
|
has_demo,
|
||||||
|
has_free_bets,
|
||||||
|
bets,
|
||||||
|
thumbnail,
|
||||||
|
status
|
||||||
|
) VALUES (
|
||||||
|
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12
|
||||||
|
)
|
||||||
|
RETURNING
|
||||||
|
id,
|
||||||
|
game_id,
|
||||||
|
provider_id,
|
||||||
|
name,
|
||||||
|
category,
|
||||||
|
device_type,
|
||||||
|
volatility,
|
||||||
|
rtp,
|
||||||
|
has_demo,
|
||||||
|
has_free_bets,
|
||||||
|
bets,
|
||||||
|
thumbnail,
|
||||||
|
status,
|
||||||
|
created_at,
|
||||||
|
updated_at
|
||||||
|
`
|
||||||
|
|
||||||
|
type CreateVirtualGameParams struct {
|
||||||
|
GameID string `json:"game_id"`
|
||||||
|
ProviderID string `json:"provider_id"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Category pgtype.Text `json:"category"`
|
||||||
|
DeviceType pgtype.Text `json:"device_type"`
|
||||||
|
Volatility pgtype.Text `json:"volatility"`
|
||||||
|
Rtp pgtype.Numeric `json:"rtp"`
|
||||||
|
HasDemo pgtype.Bool `json:"has_demo"`
|
||||||
|
HasFreeBets pgtype.Bool `json:"has_free_bets"`
|
||||||
|
Bets []pgtype.Numeric `json:"bets"`
|
||||||
|
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||||
|
Status pgtype.Int4 `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CreateVirtualGame(ctx context.Context, arg CreateVirtualGameParams) (VirtualGame, error) {
|
||||||
|
row := q.db.QueryRow(ctx, CreateVirtualGame,
|
||||||
|
arg.GameID,
|
||||||
|
arg.ProviderID,
|
||||||
|
arg.Name,
|
||||||
|
arg.Category,
|
||||||
|
arg.DeviceType,
|
||||||
|
arg.Volatility,
|
||||||
|
arg.Rtp,
|
||||||
|
arg.HasDemo,
|
||||||
|
arg.HasFreeBets,
|
||||||
|
arg.Bets,
|
||||||
|
arg.Thumbnail,
|
||||||
|
arg.Status,
|
||||||
|
)
|
||||||
|
var i VirtualGame
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.GameID,
|
||||||
|
&i.ProviderID,
|
||||||
|
&i.Name,
|
||||||
|
&i.Category,
|
||||||
|
&i.DeviceType,
|
||||||
|
&i.Volatility,
|
||||||
|
&i.Rtp,
|
||||||
|
&i.HasDemo,
|
||||||
|
&i.HasFreeBets,
|
||||||
|
&i.Bets,
|
||||||
|
&i.Thumbnail,
|
||||||
|
&i.Status,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
const CreateVirtualGameHistory = `-- name: CreateVirtualGameHistory :one
|
const CreateVirtualGameHistory = `-- name: CreateVirtualGameHistory :one
|
||||||
INSERT INTO virtual_game_histories (
|
INSERT INTO virtual_game_histories (
|
||||||
session_id,
|
session_id,
|
||||||
|
|
@ -284,6 +370,15 @@ func (q *Queries) DeleteAllVirtualGameProviders(ctx context.Context) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DeleteAllVirtualGames = `-- name: DeleteAllVirtualGames :exec
|
||||||
|
DELETE FROM virtual_games
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) DeleteAllVirtualGames(ctx context.Context) error {
|
||||||
|
_, err := q.db.Exec(ctx, DeleteAllVirtualGames)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
const DeleteVirtualGameProvider = `-- name: DeleteVirtualGameProvider :exec
|
const DeleteVirtualGameProvider = `-- name: DeleteVirtualGameProvider :exec
|
||||||
DELETE FROM virtual_game_providers
|
DELETE FROM virtual_game_providers
|
||||||
WHERE provider_id = $1
|
WHERE provider_id = $1
|
||||||
|
|
@ -294,6 +389,101 @@ func (q *Queries) DeleteVirtualGameProvider(ctx context.Context, providerID stri
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const GetAllVirtualGames = `-- name: GetAllVirtualGames :many
|
||||||
|
SELECT
|
||||||
|
vg.id,
|
||||||
|
vg.game_id,
|
||||||
|
vg.provider_id,
|
||||||
|
vp.provider_name,
|
||||||
|
vg.name,
|
||||||
|
vg.category,
|
||||||
|
vg.device_type,
|
||||||
|
vg.volatility,
|
||||||
|
vg.rtp,
|
||||||
|
vg.has_demo,
|
||||||
|
vg.has_free_bets,
|
||||||
|
vg.bets,
|
||||||
|
vg.thumbnail,
|
||||||
|
vg.status,
|
||||||
|
vg.created_at,
|
||||||
|
vg.updated_at
|
||||||
|
FROM virtual_games vg
|
||||||
|
JOIN virtual_game_providers vp ON vg.provider_id = vp.provider_id
|
||||||
|
WHERE
|
||||||
|
($1::text IS NULL OR vg.category = $1) -- category filter (optional)
|
||||||
|
AND ($2::text IS NULL OR vg.name ILIKE '%' || $2 || '%') -- search by name (optional)
|
||||||
|
ORDER BY vg.created_at DESC
|
||||||
|
LIMIT $3 OFFSET $4
|
||||||
|
`
|
||||||
|
|
||||||
|
type GetAllVirtualGamesParams struct {
|
||||||
|
Column1 string `json:"column_1"`
|
||||||
|
Column2 string `json:"column_2"`
|
||||||
|
Limit int32 `json:"limit"`
|
||||||
|
Offset int32 `json:"offset"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetAllVirtualGamesRow struct {
|
||||||
|
ID int64 `json:"id"`
|
||||||
|
GameID string `json:"game_id"`
|
||||||
|
ProviderID string `json:"provider_id"`
|
||||||
|
ProviderName string `json:"provider_name"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Category pgtype.Text `json:"category"`
|
||||||
|
DeviceType pgtype.Text `json:"device_type"`
|
||||||
|
Volatility pgtype.Text `json:"volatility"`
|
||||||
|
Rtp pgtype.Numeric `json:"rtp"`
|
||||||
|
HasDemo pgtype.Bool `json:"has_demo"`
|
||||||
|
HasFreeBets pgtype.Bool `json:"has_free_bets"`
|
||||||
|
Bets []pgtype.Numeric `json:"bets"`
|
||||||
|
Thumbnail pgtype.Text `json:"thumbnail"`
|
||||||
|
Status pgtype.Int4 `json:"status"`
|
||||||
|
CreatedAt pgtype.Timestamptz `json:"created_at"`
|
||||||
|
UpdatedAt pgtype.Timestamptz `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) GetAllVirtualGames(ctx context.Context, arg GetAllVirtualGamesParams) ([]GetAllVirtualGamesRow, error) {
|
||||||
|
rows, err := q.db.Query(ctx, GetAllVirtualGames,
|
||||||
|
arg.Column1,
|
||||||
|
arg.Column2,
|
||||||
|
arg.Limit,
|
||||||
|
arg.Offset,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
var items []GetAllVirtualGamesRow
|
||||||
|
for rows.Next() {
|
||||||
|
var i GetAllVirtualGamesRow
|
||||||
|
if err := rows.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.GameID,
|
||||||
|
&i.ProviderID,
|
||||||
|
&i.ProviderName,
|
||||||
|
&i.Name,
|
||||||
|
&i.Category,
|
||||||
|
&i.DeviceType,
|
||||||
|
&i.Volatility,
|
||||||
|
&i.Rtp,
|
||||||
|
&i.HasDemo,
|
||||||
|
&i.HasFreeBets,
|
||||||
|
&i.Bets,
|
||||||
|
&i.Thumbnail,
|
||||||
|
&i.Status,
|
||||||
|
&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 GetVirtualGameProviderByID = `-- name: GetVirtualGameProviderByID :one
|
const GetVirtualGameProviderByID = `-- name: GetVirtualGameProviderByID :one
|
||||||
SELECT id, provider_id, provider_name, logo_dark, logo_light, enabled, created_at, updated_at
|
SELECT id, provider_id, provider_name, logo_dark, logo_light, enabled, created_at, updated_at
|
||||||
FROM virtual_game_providers
|
FROM virtual_game_providers
|
||||||
|
|
|
||||||
|
|
@ -93,15 +93,7 @@ type GetCompanyRes struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConvertCompany(company Company) CompanyRes {
|
func ConvertCompany(company Company) CompanyRes {
|
||||||
return CompanyRes{
|
return CompanyRes(company)
|
||||||
ID: company.ID,
|
|
||||||
Name: company.Name,
|
|
||||||
Slug: company.Slug,
|
|
||||||
AdminID: company.AdminID,
|
|
||||||
WalletID: company.WalletID,
|
|
||||||
IsActive: company.IsActive,
|
|
||||||
DeductedPercentage: company.DeductedPercentage,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConvertGetCompany(company GetCompany) GetCompanyRes {
|
func ConvertGetCompany(company GetCompany) GetCompanyRes {
|
||||||
|
|
|
||||||
|
|
@ -310,7 +310,7 @@ func validateSettings[T any](
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
return fmt.Errorf(strings.Join(errs, "; "))
|
return errors.New(strings.Join(errs, "; "))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -382,7 +382,7 @@ func (vsl *ValidSettingList) ValidateAllSettings() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(errs) > 0 {
|
if len(errs) > 0 {
|
||||||
return fmt.Errorf(strings.Join(errs, "; "))
|
return errors.New(strings.Join(errs, "; "))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -414,7 +414,7 @@ func ConvertDBGlobalSettingList(settings []dbgen.GlobalSetting) (SettingList, er
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := dbSettingList.ValidateAllSettings(); err != nil {
|
if err := dbSettingList.ValidateAllSettings(); err != nil {
|
||||||
fmt.Printf("setting validation error: %v \n")
|
fmt.Printf("setting validation error: %v \n", err)
|
||||||
MongoDBLogger.Warn("setting validation error", zap.Error(err))
|
MongoDBLogger.Warn("setting validation error", zap.Error(err))
|
||||||
return SettingList{}, err
|
return SettingList{}, err
|
||||||
}
|
}
|
||||||
|
|
@ -436,7 +436,7 @@ func ConvertDBOverrideSettingList(settings []dbgen.GetOverrideSettingsRow) (Sett
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := dbSettingList.ValidateAllSettings(); err != nil {
|
if err := dbSettingList.ValidateAllSettings(); err != nil {
|
||||||
fmt.Printf("setting validation error: %v \n")
|
fmt.Printf("setting validation error: %v \n", err)
|
||||||
MongoDBLogger.Warn("setting validation error", zap.Error(err))
|
MongoDBLogger.Warn("setting validation error", zap.Error(err))
|
||||||
return SettingList{}, err
|
return SettingList{}, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,11 +34,7 @@ type CompanySettingRes struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConvertSetting(setting Setting) SettingRes {
|
func ConvertSetting(setting Setting) SettingRes {
|
||||||
return SettingRes{
|
return SettingRes(setting)
|
||||||
Key: setting.Key,
|
|
||||||
Value: setting.Value,
|
|
||||||
UpdatedAt: setting.UpdatedAt,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConvertCompanySetting(companySetting dbgen.CompanySetting) CompanySetting {
|
func ConvertCompanySetting(companySetting dbgen.CompanySetting) CompanySetting {
|
||||||
|
|
|
||||||
|
|
@ -298,4 +298,20 @@ type VirtualGameProviderPagination struct {
|
||||||
TotalCount int64 `json:"total_count"`
|
TotalCount int64 `json:"total_count"`
|
||||||
Limit int32 `json:"limit"`
|
Limit int32 `json:"limit"`
|
||||||
Offset int32 `json:"offset"`
|
Offset int32 `json:"offset"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UnifiedGame struct {
|
||||||
|
GameID string `json:"gameId"`
|
||||||
|
ProviderID string `json:"providerId"`
|
||||||
|
Provider string `json:"provider"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Category string `json:"category,omitempty"`
|
||||||
|
DeviceType string `json:"deviceType,omitempty"`
|
||||||
|
Volatility string `json:"volatility,omitempty"`
|
||||||
|
RTP *float64 `json:"rtp,omitempty"`
|
||||||
|
HasDemo bool `json:"hasDemo"`
|
||||||
|
HasFreeBets bool `json:"hasFreeBets"`
|
||||||
|
Bets []float64 `json:"bets,omitempty"`
|
||||||
|
Thumbnail string `json:"thumbnail,omitempty"`
|
||||||
|
Status int `json:"status,omitempty"`
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||||
|
|
@ -186,34 +185,3 @@ func (s *Store) GetOddsWithSettingsByEventID(ctx context.Context, upcomingID str
|
||||||
func (s *Store) DeleteOddsForEvent(ctx context.Context, eventID string) error {
|
func (s *Store) DeleteOddsForEvent(ctx context.Context, eventID string) error {
|
||||||
return s.queries.DeleteOddsForEvent(ctx, eventID)
|
return s.queries.DeleteOddsForEvent(ctx, eventID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getString(v interface{}) string {
|
|
||||||
if s, ok := v.(string); ok {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
|
|
||||||
func getConvertedFloat(v interface{}) float64 {
|
|
||||||
if s, ok := v.(string); ok {
|
|
||||||
f, err := strconv.ParseFloat(s, 64)
|
|
||||||
if err == nil {
|
|
||||||
return f
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func getFloat(v interface{}) float64 {
|
|
||||||
if n, ok := v.(float64); ok {
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func getMap(v interface{}) map[string]interface{} {
|
|
||||||
if m, ok := v.(map[string]interface{}); ok {
|
|
||||||
return m
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -150,7 +150,7 @@ func (s *Store) GetAllUsers(ctx context.Context, filter domain.UserFilter) ([]do
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
totalCount, err := s.queries.GetTotalUsers(ctx, dbgen.GetTotalUsersParams{
|
totalCount, _ := s.queries.GetTotalUsers(ctx, dbgen.GetTotalUsersParams{
|
||||||
Role: filter.Role,
|
Role: filter.Role,
|
||||||
CompanyID: pgtype.Int8{
|
CompanyID: pgtype.Int8{
|
||||||
Int64: filter.CompanyID.Value,
|
Int64: filter.CompanyID.Value,
|
||||||
|
|
@ -199,7 +199,7 @@ func (s *Store) GetAllCashiers(ctx context.Context, filter domain.UserFilter) ([
|
||||||
BranchLocation: user.BranchLocation,
|
BranchLocation: user.BranchLocation,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
totalCount, err := s.queries.GetTotalUsers(ctx, dbgen.GetTotalUsersParams{
|
totalCount, _ := s.queries.GetTotalUsers(ctx, dbgen.GetTotalUsersParams{
|
||||||
Role: string(domain.RoleCashier),
|
Role: string(domain.RoleCashier),
|
||||||
})
|
})
|
||||||
return userList, totalCount, nil
|
return userList, totalCount, nil
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,10 @@ type VirtualGameRepository interface {
|
||||||
GetGameCounts(ctx context.Context, filter domain.ReportFilter) (total, active, inactive int64, err error)
|
GetGameCounts(ctx context.Context, filter domain.ReportFilter) (total, active, inactive int64, err error)
|
||||||
GetUserGameHistory(ctx context.Context, userID int64) ([]domain.VirtualGameHistory, error)
|
GetUserGameHistory(ctx context.Context, userID int64) ([]domain.VirtualGameHistory, error)
|
||||||
CreateVirtualGameHistory(ctx context.Context, his *domain.VirtualGameHistory) error
|
CreateVirtualGameHistory(ctx context.Context, his *domain.VirtualGameHistory) error
|
||||||
|
|
||||||
|
CreateVirtualGame(ctx context.Context, arg dbgen.CreateVirtualGameParams) (dbgen.VirtualGame, error)
|
||||||
|
ListAllVirtualGames(ctx context.Context, arg dbgen.GetAllVirtualGamesParams) ([]dbgen.GetAllVirtualGamesRow, error)
|
||||||
|
RemoveAllVirtualGames(ctx context.Context) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type VirtualGameRepo struct {
|
type VirtualGameRepo struct {
|
||||||
|
|
@ -94,8 +98,8 @@ func (r *VirtualGameRepo) CreateVirtualGameProvider(ctx context.Context, arg dbg
|
||||||
return r.store.queries.CreateVirtualGameProvider(ctx, arg)
|
return r.store.queries.CreateVirtualGameProvider(ctx, arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *VirtualGameRepo) RemoveVirtualGameProvider(ctx context.Context, arg dbgen.CreateVirtualGameProviderParams) (dbgen.VirtualGameProvider, error) {
|
func (r *VirtualGameRepo) RemoveVirtualGameProvider(ctx context.Context, providerID string) error {
|
||||||
return r.store.queries.CreateVirtualGameProvider(ctx, arg)
|
return r.store.queries.DeleteVirtualGameProvider(ctx, providerID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *VirtualGameRepo) DeleteAllVirtualGameProviders(ctx context.Context) error {
|
func (r *VirtualGameRepo) DeleteAllVirtualGameProviders(ctx context.Context) error {
|
||||||
|
|
@ -300,26 +304,15 @@ func (r *VirtualGameRepo) GetUserGameHistory(ctx context.Context, userID int64)
|
||||||
return history, nil
|
return history, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// func (r *VirtualGameRepo) WithTransaction(ctx context.Context, fn func(ctx context.Context) error) error {
|
func (r *VirtualGameRepo) CreateVirtualGame(ctx context.Context, arg dbgen.CreateVirtualGameParams) (dbgen.VirtualGame, error) {
|
||||||
// _, tx, err := r.store.BeginTx(ctx)
|
return r.store.queries.CreateVirtualGame(ctx, arg)
|
||||||
// if err != nil {
|
}
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// txCtx := context.WithValue(ctx, contextTxKey, tx)
|
func (r *VirtualGameRepo) ListAllVirtualGames(ctx context.Context, arg dbgen.GetAllVirtualGamesParams) ([]dbgen.GetAllVirtualGamesRow, error) {
|
||||||
|
return r.store.queries.GetAllVirtualGames(ctx, arg)
|
||||||
|
}
|
||||||
|
|
||||||
// defer func() {
|
func (r *VirtualGameRepo) RemoveAllVirtualGames(ctx context.Context) error {
|
||||||
// if p := recover(); p != nil {
|
return r.store.queries.DeleteAllVirtualGames(ctx)
|
||||||
// tx.Rollback(ctx)
|
}
|
||||||
// panic(p)
|
|
||||||
// }
|
|
||||||
// }()
|
|
||||||
|
|
||||||
// err = fn(txCtx)
|
|
||||||
// if err != nil {
|
|
||||||
// tx.Rollback(ctx)
|
|
||||||
// return err
|
|
||||||
// }
|
|
||||||
|
|
||||||
// return tx.Commit(ctx)
|
|
||||||
// }
|
|
||||||
|
|
|
||||||
|
|
@ -734,12 +734,12 @@ func (s *ServiceImpl) DeleteOddsForEvent(ctx context.Context, eventID string) er
|
||||||
return s.store.DeleteOddsForEvent(ctx, eventID)
|
return s.store.DeleteOddsForEvent(ctx, eventID)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getString(v interface{}) string {
|
// func getString(v interface{}) string {
|
||||||
if str, ok := v.(string); ok {
|
// if str, ok := v.(string); ok {
|
||||||
return str
|
// return str
|
||||||
}
|
// }
|
||||||
return ""
|
// return ""
|
||||||
}
|
// }
|
||||||
|
|
||||||
func getInt(v interface{}) int {
|
func getInt(v interface{}) int {
|
||||||
if n, ok := v.(float64); ok {
|
if n, ok := v.(float64); ok {
|
||||||
|
|
@ -761,17 +761,17 @@ func getMap(v interface{}) map[string]interface{} {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMapArray(v interface{}) []map[string]interface{} {
|
// func getMapArray(v interface{}) []map[string]interface{} {
|
||||||
result := []map[string]interface{}{}
|
// result := []map[string]interface{}{}
|
||||||
if arr, ok := v.([]interface{}); ok {
|
// if arr, ok := v.([]interface{}); ok {
|
||||||
for _, item := range arr {
|
// for _, item := range arr {
|
||||||
if m, ok := item.(map[string]interface{}); ok {
|
// if m, ok := item.(map[string]interface{}); ok {
|
||||||
result = append(result, m)
|
// result = append(result, m)
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return result
|
// return result
|
||||||
}
|
// }
|
||||||
|
|
||||||
func convertRawMessage(rawMessages []json.RawMessage) ([]map[string]interface{}, error) {
|
func convertRawMessage(rawMessages []json.RawMessage) ([]map[string]interface{}, error) {
|
||||||
var result []map[string]interface{}
|
var result []map[string]interface{}
|
||||||
|
|
|
||||||
|
|
@ -44,16 +44,198 @@ func (s *Service) AddProviders(ctx context.Context, req domain.ProviderRequest)
|
||||||
createParams := dbgen.CreateVirtualGameProviderParams{
|
createParams := dbgen.CreateVirtualGameProviderParams{
|
||||||
ProviderID: p.ProviderID,
|
ProviderID: p.ProviderID,
|
||||||
ProviderName: p.ProviderName,
|
ProviderName: p.ProviderName,
|
||||||
LogoDark: pgtype.Text{String: p.LogoForDark, Valid: true},
|
LogoDark: pgtype.Text{String: p.LogoForDark, Valid: p.LogoForDark != ""},
|
||||||
LogoLight: pgtype.Text{String: p.LogoForLight, Valid: true},
|
LogoLight: pgtype.Text{String: p.LogoForLight, Valid: p.LogoForLight != ""},
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
if _, err := s.repo.CreateVirtualGameProvider(ctx, createParams); err != nil {
|
if _, err := s.repo.CreateVirtualGameProvider(ctx, createParams); err != nil {
|
||||||
// Log error but continue with other providers
|
|
||||||
return nil, fmt.Errorf("failed to add provider %s: %w", p.ProviderID, err)
|
return nil, fmt.Errorf("failed to add provider %s: %w", p.ProviderID, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 4. Always add "popok" provider manually
|
||||||
|
popokParams := dbgen.CreateVirtualGameProviderParams{
|
||||||
|
ProviderID: "popok",
|
||||||
|
ProviderName: "Popok Gaming",
|
||||||
|
LogoDark: pgtype.Text{String: "/static/logos/popok-dark.png", Valid: true}, // adjust as needed
|
||||||
|
LogoLight: pgtype.Text{String: "/static/logos/popok-light.png", Valid: true}, // adjust as needed
|
||||||
|
Enabled: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := s.repo.CreateVirtualGameProvider(ctx, popokParams); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to add popok provider: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optionally also append it to the response for consistency
|
||||||
|
// res.Items = append(res.Items, domain.VirtualGameProvider{
|
||||||
|
// ProviderID: uuid.New().String(),
|
||||||
|
// ProviderName: "Popok Gaming",
|
||||||
|
// LogoForDark: "/static/logos/popok-dark.png",
|
||||||
|
// LogoForLight: "/static/logos/popok-light.png",
|
||||||
|
// })
|
||||||
|
|
||||||
return &res, nil
|
return &res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetAllVirtualGames(ctx context.Context, params dbgen.GetAllVirtualGamesParams) ([]domain.UnifiedGame, error) {
|
||||||
|
// Build params for repo call
|
||||||
|
|
||||||
|
rows, err := s.repo.ListAllVirtualGames(ctx, params)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch virtual games: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var allGames []domain.UnifiedGame
|
||||||
|
for _, r := range rows {
|
||||||
|
// --- Convert nullable Rtp to *float64 ---
|
||||||
|
var rtpPtr *float64
|
||||||
|
if r.Rtp.Valid {
|
||||||
|
rtpFloat, err := r.Rtp.Float64Value()
|
||||||
|
if err == nil {
|
||||||
|
rtpPtr = new(float64)
|
||||||
|
*rtpPtr = rtpFloat.Float64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var betsFloat64 []float64
|
||||||
|
for _, bet := range r.Bets {
|
||||||
|
if bet.Valid {
|
||||||
|
betFloat, err := bet.Float64Value()
|
||||||
|
if err == nil {
|
||||||
|
betsFloat64 = append(betsFloat64, betFloat.Float64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
allGames = append(allGames, domain.UnifiedGame{
|
||||||
|
GameID: r.GameID,
|
||||||
|
ProviderID: r.ProviderID,
|
||||||
|
Provider: r.ProviderName,
|
||||||
|
Name: r.Name,
|
||||||
|
Category: r.Category.String,
|
||||||
|
DeviceType: r.DeviceType.String,
|
||||||
|
Volatility: r.Volatility.String,
|
||||||
|
RTP: rtpPtr,
|
||||||
|
HasDemo: r.HasDemo.Bool,
|
||||||
|
HasFreeBets: r.HasFreeBets.Bool,
|
||||||
|
Bets: betsFloat64,
|
||||||
|
Thumbnail: r.Thumbnail.String,
|
||||||
|
Status: int(r.Status.Int32), // nullable status
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return allGames, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) FetchAndStoreAllVirtualGames(ctx context.Context, req domain.ProviderRequest, currency string) ([]domain.UnifiedGame, error) {
|
||||||
|
var allGames []domain.UnifiedGame
|
||||||
|
|
||||||
|
// --- 1. Get providers from external API ---
|
||||||
|
providersRes, err := s.GetProviders(ctx, req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch providers: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 2. Fetch games for each provider ---
|
||||||
|
for _, p := range providersRes.Items {
|
||||||
|
games, err := s.GetGames(ctx, domain.GameListRequest{
|
||||||
|
BrandID: s.cfg.VeliGames.BrandID,
|
||||||
|
ProviderID: p.ProviderID,
|
||||||
|
Page: req.Page,
|
||||||
|
Size: req.Size,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
continue // skip failing provider but continue others
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, g := range games {
|
||||||
|
unified := domain.UnifiedGame{
|
||||||
|
GameID: g.GameID,
|
||||||
|
ProviderID: g.ProviderID,
|
||||||
|
Provider: p.ProviderName,
|
||||||
|
Name: g.Name,
|
||||||
|
Category: g.Category,
|
||||||
|
DeviceType: g.DeviceType,
|
||||||
|
// Volatility: g.Volatility,
|
||||||
|
// RTP: g.RTP,
|
||||||
|
HasDemo: g.HasDemoMode,
|
||||||
|
HasFreeBets: g.HasFreeBets,
|
||||||
|
}
|
||||||
|
allGames = append(allGames, unified)
|
||||||
|
|
||||||
|
// --- Save to DB ---
|
||||||
|
_, _ = s.repo.CreateVirtualGame(ctx, dbgen.CreateVirtualGameParams{
|
||||||
|
GameID: g.GameID,
|
||||||
|
ProviderID: g.ProviderID,
|
||||||
|
Name: g.Name,
|
||||||
|
Category: pgtype.Text{
|
||||||
|
String: g.Category,
|
||||||
|
Valid: g.Category != "",
|
||||||
|
},
|
||||||
|
DeviceType: pgtype.Text{
|
||||||
|
String: g.DeviceType,
|
||||||
|
Valid: g.DeviceType != "",
|
||||||
|
},
|
||||||
|
// Volatility: g.Volatility,
|
||||||
|
// RTP: g.RTP,
|
||||||
|
HasDemo: pgtype.Bool{
|
||||||
|
Bool: g.HasDemoMode,
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
HasFreeBets: pgtype.Bool{
|
||||||
|
Bool: g.HasFreeBets,
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
// Bets: g.Bets,
|
||||||
|
// Thumbnail: g.Thumbnail,
|
||||||
|
// Status: g.Status,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- 3. Handle PopOK separately ---
|
||||||
|
popokGames, err := s.virtualGameSvc.ListGames(ctx, currency)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to fetch PopOK games: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, g := range popokGames {
|
||||||
|
unified := domain.UnifiedGame{
|
||||||
|
GameID: fmt.Sprintf("popok-%d", g.ID),
|
||||||
|
ProviderID: "popok",
|
||||||
|
Provider: "PopOK",
|
||||||
|
Name: g.GameName,
|
||||||
|
Category: "Crash",
|
||||||
|
Bets: g.Bets,
|
||||||
|
Thumbnail: g.Thumbnail,
|
||||||
|
Status: g.Status,
|
||||||
|
}
|
||||||
|
allGames = append(allGames, unified)
|
||||||
|
|
||||||
|
// --- Convert []float64 to []pgtype.Numeric ---
|
||||||
|
var betsNumeric []pgtype.Numeric
|
||||||
|
for _, bet := range g.Bets {
|
||||||
|
var num pgtype.Numeric
|
||||||
|
_ = num.Scan(bet)
|
||||||
|
betsNumeric = append(betsNumeric, num)
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Save to DB ---
|
||||||
|
_, _ = s.repo.CreateVirtualGame(ctx, dbgen.CreateVirtualGameParams{
|
||||||
|
GameID: fmt.Sprintf("popok-%d", g.ID),
|
||||||
|
ProviderID: "popok",
|
||||||
|
Name: g.GameName,
|
||||||
|
Bets: betsNumeric,
|
||||||
|
Thumbnail: pgtype.Text{
|
||||||
|
String: g.Thumbnail,
|
||||||
|
Valid: g.Thumbnail != "",
|
||||||
|
},
|
||||||
|
Status: pgtype.Int4{
|
||||||
|
Int32: int32(g.Status),
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return allGames, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,13 @@ package veli
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
)
|
)
|
||||||
|
|
||||||
type VeliVirtualGameService interface {
|
type VeliVirtualGameService interface {
|
||||||
|
FetchAndStoreAllVirtualGames(ctx context.Context, req domain.ProviderRequest, currency string) ([]domain.UnifiedGame, error)
|
||||||
|
GetAllVirtualGames(ctx context.Context, params dbgen.GetAllVirtualGamesParams) ([]domain.UnifiedGame, error)
|
||||||
AddProviders(ctx context.Context, req domain.ProviderRequest) (*domain.ProviderResponse, error)
|
AddProviders(ctx context.Context, req domain.ProviderRequest) (*domain.ProviderResponse, error)
|
||||||
GetProviders(ctx context.Context, req domain.ProviderRequest) (*domain.ProviderResponse, error)
|
GetProviders(ctx context.Context, req domain.ProviderRequest) (*domain.ProviderResponse, error)
|
||||||
GetGames(ctx context.Context, req domain.GameListRequest) ([]domain.GameEntity, error)
|
GetGames(ctx context.Context, req domain.GameListRequest) ([]domain.GameEntity, error)
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/config"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/config"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/repository"
|
||||||
|
virtualgameservice "github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -20,6 +21,7 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
|
virtualGameSvc virtualgameservice.VirtualGameService
|
||||||
repo repository.VirtualGameRepository
|
repo repository.VirtualGameRepository
|
||||||
client *Client
|
client *Client
|
||||||
walletSvc *wallet.Service
|
walletSvc *wallet.Service
|
||||||
|
|
@ -27,8 +29,9 @@ type Service struct {
|
||||||
cfg *config.Config
|
cfg *config.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(repo repository.VirtualGameRepository,client *Client, walletSvc *wallet.Service, transferStore wallet.TransferStore, cfg *config.Config) *Service {
|
func New(virtualGameSvc virtualgameservice.VirtualGameService,repo repository.VirtualGameRepository,client *Client, walletSvc *wallet.Service, transferStore wallet.TransferStore, cfg *config.Config) *Service {
|
||||||
return &Service{
|
return &Service{
|
||||||
|
virtualGameSvc: virtualGameSvc,
|
||||||
repo: repo,
|
repo: repo,
|
||||||
client: client,
|
client: client,
|
||||||
walletSvc: walletSvc,
|
walletSvc: walletSvc,
|
||||||
|
|
@ -62,39 +65,102 @@ func (s *Service) GetProviders(ctx context.Context, req domain.ProviderRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) GetGames(ctx context.Context, req domain.GameListRequest) ([]domain.GameEntity, error) {
|
func (s *Service) GetGames(ctx context.Context, req domain.GameListRequest) ([]domain.GameEntity, error) {
|
||||||
sigParams := map[string]any{
|
// 1. Check if provider is enabled in DB
|
||||||
"brandId": req.BrandID, "providerId": req.ProviderID,
|
provider, err := s.repo.GetVirtualGameProviderByID(ctx, req.ProviderID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to check provider %s: %w", req.ProviderID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !provider.Enabled {
|
||||||
|
// Provider exists but is disabled → return empty list (or error if you prefer)
|
||||||
|
return nil, fmt.Errorf("provider %s is disabled", req.ProviderID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Prepare signature params
|
||||||
|
sigParams := map[string]any{
|
||||||
|
"brandId": req.BrandID,
|
||||||
|
"providerId": req.ProviderID,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Call external API
|
||||||
var res struct {
|
var res struct {
|
||||||
Items []domain.GameEntity `json:"items"`
|
Items []domain.GameEntity `json:"items"`
|
||||||
}
|
}
|
||||||
err := s.client.post(ctx, "/game-lists/public/games", req, sigParams, &res)
|
if err := s.client.post(ctx, "/game-lists/public/games", req, sigParams, &res); err != nil {
|
||||||
return res.Items, err
|
return nil, fmt.Errorf("failed to fetch games for provider %s: %w", req.ProviderID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.Items, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) StartGame(ctx context.Context, req domain.GameStartRequest) (*domain.GameStartResponse, error) {
|
func (s *Service) StartGame(ctx context.Context, req domain.GameStartRequest) (*domain.GameStartResponse, error) {
|
||||||
sigParams := map[string]any{
|
// 1. Check if provider is enabled in DB
|
||||||
"sessionId": req.SessionID, "providerId": req.ProviderID,
|
provider, err := s.repo.GetVirtualGameProviderByID(ctx, req.ProviderID)
|
||||||
"gameId": req.GameID, "language": req.Language, "playerId": req.PlayerID,
|
if err != nil {
|
||||||
"currency": req.Currency, "deviceType": req.DeviceType, "country": "US",
|
return nil, fmt.Errorf("failed to check provider %s: %w", req.ProviderID, err)
|
||||||
"ip": req.IP, "brandId": req.BrandID,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !provider.Enabled {
|
||||||
|
// Provider exists but is disabled → return error
|
||||||
|
return nil, fmt.Errorf("provider %s is disabled", req.ProviderID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Prepare signature params
|
||||||
|
sigParams := map[string]any{
|
||||||
|
"sessionId": req.SessionID,
|
||||||
|
"providerId": req.ProviderID,
|
||||||
|
"gameId": req.GameID,
|
||||||
|
"language": req.Language,
|
||||||
|
"playerId": req.PlayerID,
|
||||||
|
"currency": req.Currency,
|
||||||
|
"deviceType": req.DeviceType,
|
||||||
|
"country": "US",
|
||||||
|
"ip": req.IP,
|
||||||
|
"brandId": req.BrandID,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Call external API
|
||||||
var res domain.GameStartResponse
|
var res domain.GameStartResponse
|
||||||
err := s.client.post(ctx, "/unified-api/public/start-game", req, sigParams, &res)
|
if err := s.client.post(ctx, "/unified-api/public/start-game", req, sigParams, &res); err != nil {
|
||||||
return &res, err
|
return nil, fmt.Errorf("failed to start game with provider %s: %w", req.ProviderID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (s *Service) StartDemoGame(ctx context.Context, req domain.DemoGameRequest) (*domain.GameStartResponse, error) {
|
func (s *Service) StartDemoGame(ctx context.Context, req domain.DemoGameRequest) (*domain.GameStartResponse, error) {
|
||||||
sigParams := map[string]any{
|
// 1. Check if provider is enabled in DB
|
||||||
"providerId": req.ProviderID, "gameId": req.GameID,
|
provider, err := s.repo.GetVirtualGameProviderByID(ctx, req.ProviderID)
|
||||||
"language": req.Language, "deviceType": req.DeviceType,
|
if err != nil {
|
||||||
"ip": req.IP, "brandId": req.BrandID,
|
return nil, fmt.Errorf("failed to check provider %s: %w", req.ProviderID, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !provider.Enabled {
|
||||||
|
// Provider exists but is disabled → return error
|
||||||
|
return nil, fmt.Errorf("provider %s is disabled", req.ProviderID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Prepare signature params
|
||||||
|
sigParams := map[string]any{
|
||||||
|
"providerId": req.ProviderID,
|
||||||
|
"gameId": req.GameID,
|
||||||
|
"language": req.Language,
|
||||||
|
"deviceType": req.DeviceType,
|
||||||
|
"ip": req.IP,
|
||||||
|
"brandId": req.BrandID,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Call external API
|
||||||
var res domain.GameStartResponse
|
var res domain.GameStartResponse
|
||||||
err := s.client.post(ctx, "/unified-api/public/start-demo-game", req, sigParams, &res)
|
if err := s.client.post(ctx, "/unified-api/public/start-demo-game", req, sigParams, &res); err != nil {
|
||||||
return &res, err
|
return nil, fmt.Errorf("failed to start demo game with provider %s: %w", req.ProviderID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (s *Service) GetBalance(ctx context.Context, req domain.BalanceRequest) (*domain.BalanceResponse, error) {
|
func (s *Service) GetBalance(ctx context.Context, req domain.BalanceRequest) (*domain.BalanceResponse, error) {
|
||||||
// Retrieve player's real balance from wallet Service
|
// Retrieve player's real balance from wallet Service
|
||||||
playerIDInt64, err := strconv.ParseInt(req.PlayerID, 10, 64)
|
playerIDInt64, err := strconv.ParseInt(req.PlayerID, 10, 64)
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,6 @@ import (
|
||||||
|
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
// "time"
|
|
||||||
|
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
betSvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet"
|
betSvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet"
|
||||||
eventsvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
eventsvc "github.com/SamuelTariku/FortuneBet-Backend/internal/services/event"
|
||||||
|
|
@ -164,87 +162,48 @@ func SetupReportandVirtualGameCronJobs(
|
||||||
spec: "0 0 0 * * *", // Daily at midnight
|
spec: "0 0 0 * * *", // Daily at midnight
|
||||||
period: "daily",
|
period: "daily",
|
||||||
},
|
},
|
||||||
{
|
|
||||||
spec: "0 0 1 * * 0", // Weekly: Sunday at 1 AM
|
|
||||||
period: "weekly",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
spec: "0 0 2 1 * *", // Monthly: 1st day of month at 2 AM
|
|
||||||
period: "monthly",
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, job := range schedule {
|
for _, job := range schedule {
|
||||||
period := job.period
|
period := job.period
|
||||||
|
|
||||||
if _, err := c.AddFunc(job.spec, func() {
|
if _, err := c.AddFunc(job.spec, func() {
|
||||||
now := time.Now()
|
log.Printf("[%s] Running virtual game fetch & store job...", period)
|
||||||
var from, to time.Time
|
|
||||||
|
|
||||||
switch period {
|
brandID := os.Getenv("VELI_BRAND_ID")
|
||||||
case "daily":
|
if brandID == "" {
|
||||||
from = time.Date(now.Year(), now.Month(), now.Day()-1, 0, 0, 0, 0, now.Location())
|
log.Println("VELI_BRAND_ID not set, skipping virtual game sync")
|
||||||
to = time.Date(now.Year(), now.Month(), now.Day()-1, 23, 59, 59, 0, now.Location())
|
return
|
||||||
case "weekly":
|
|
||||||
weekday := int(now.Weekday())
|
|
||||||
daysSinceSunday := (weekday + 7) % 7
|
|
||||||
from = time.Date(now.Year(), now.Month(), now.Day()-daysSinceSunday-7, 0, 0, 0, 0, now.Location())
|
|
||||||
to = from.AddDate(0, 0, 6).Add(time.Hour*23 + time.Minute*59 + time.Second*59)
|
|
||||||
case "monthly":
|
|
||||||
firstOfMonth := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, now.Location())
|
|
||||||
from = firstOfMonth.AddDate(0, -1, 0)
|
|
||||||
to = firstOfMonth.Add(-time.Second)
|
|
||||||
default:
|
|
||||||
log.Printf("Unknown period: %s", period)
|
|
||||||
// return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Generate Reports (skip for test) ---
|
req := domain.ProviderRequest{
|
||||||
if period != "test" {
|
BrandID: brandID,
|
||||||
log.Printf("Running %s report for period %s -> %s", period, from.Format(time.RFC3339), to.Format(time.RFC3339))
|
ExtraData: true,
|
||||||
|
Size: 1000,
|
||||||
|
Page: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
allGames, err := virtualGameService.FetchAndStoreAllVirtualGames(ctx, req, "ETB")
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("[%s] Error fetching/storing virtual games: %v", period, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("[%s] Successfully fetched & stored %d virtual games", period, len(allGames))
|
||||||
|
|
||||||
|
// --- Generate reports only for daily runs ---
|
||||||
|
if period == "daily" {
|
||||||
|
now := time.Now()
|
||||||
|
from := time.Date(now.Year(), now.Month(), now.Day()-1, 0, 0, 0, 0, now.Location())
|
||||||
|
to := time.Date(now.Year(), now.Month(), now.Day()-1, 23, 59, 59, 0, now.Location())
|
||||||
|
|
||||||
|
log.Printf("Running daily report for period %s -> %s", from.Format(time.RFC3339), to.Format(time.RFC3339))
|
||||||
if err := reportService.GenerateReport(ctx, from, to); err != nil {
|
if err := reportService.GenerateReport(ctx, from, to); err != nil {
|
||||||
log.Printf("Error generating %s report: %v", period, err)
|
log.Printf("Error generating daily report: %v", err)
|
||||||
} else {
|
} else {
|
||||||
log.Printf("Successfully generated %s report", period)
|
log.Printf("Successfully generated daily report")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Fetch and Add Virtual Game Providers (daily + test) ---
|
|
||||||
if period == "daily" || period == "test" {
|
|
||||||
log.Printf("Fetching and adding virtual game providers (%s)...", period)
|
|
||||||
|
|
||||||
brandID := os.Getenv("VELI_BRAND_ID")
|
|
||||||
if brandID == "" {
|
|
||||||
log.Println("VELI_BRAND_ID not set, skipping provider sync")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
page := 1
|
|
||||||
size := 1000
|
|
||||||
for {
|
|
||||||
req := domain.ProviderRequest{
|
|
||||||
BrandID: brandID,
|
|
||||||
ExtraData: true,
|
|
||||||
Size: int(size),
|
|
||||||
Page: int(page),
|
|
||||||
}
|
|
||||||
|
|
||||||
res, err := virtualGameService.AddProviders(ctx, req)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Error adding virtual game providers on page %d: %v", page, err)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("[%s] Successfully processed page %d: %d providers", period, page, len(res.Items))
|
|
||||||
|
|
||||||
if len(res.Items) < size {
|
|
||||||
// Last page reached
|
|
||||||
break
|
|
||||||
}
|
|
||||||
page++
|
|
||||||
}
|
|
||||||
log.Printf("[%s] Finished fetching and adding virtual game providers", period)
|
|
||||||
}
|
|
||||||
}); err != nil {
|
}); err != nil {
|
||||||
log.Fatalf("Failed to schedule %s cron job: %v", period, err)
|
log.Fatalf("Failed to schedule %s cron job: %v", period, err)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -158,10 +158,10 @@ func (h *Handler) CreateBetWithFastCode(c *fiber.Ctx) error {
|
||||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create bet:"+err.Error())
|
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create bet:"+err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
wallet, err := h.walletSvc.GetCustomerWallet(c.Context(), bet.UserID)
|
wallet, _ := h.walletSvc.GetCustomerWallet(c.Context(), bet.UserID)
|
||||||
|
|
||||||
// amount added for fast code owner can be fetched from settings in db
|
// amount added for fast code owner can be fetched from settings in db
|
||||||
settingList, err := h.settingSvc.GetOverrideSettingsList(c.Context(), companyID.Value)
|
settingList, _ := h.settingSvc.GetOverrideSettingsList(c.Context(), companyID.Value)
|
||||||
amount := settingList.AmountForBetReferral
|
amount := settingList.AmountForBetReferral
|
||||||
|
|
||||||
_, err = h.walletSvc.AddToWallet(c.Context(), wallet.StaticID, amount, domain.ValidInt64{},
|
_, err = h.walletSvc.AddToWallet(c.Context(), wallet.StaticID, amount, domain.ValidInt64{},
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import (
|
||||||
// @Param cc query string false "Country Code Filter"
|
// @Param cc query string false "Country Code Filter"
|
||||||
// @Param first_start_time query string false "Start Time"
|
// @Param first_start_time query string false "Start Time"
|
||||||
// @Param last_start_time query string false "End Time"
|
// @Param last_start_time query string false "End Time"
|
||||||
// @Success 200 {array} domain.UpcomingEvent
|
// @Success 200 {array} domain.BaseEvent
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/events [get]
|
// @Router /api/v1/events [get]
|
||||||
func (h *Handler) GetAllUpcomingEvents(c *fiber.Ctx) error {
|
func (h *Handler) GetAllUpcomingEvents(c *fiber.Ctx) error {
|
||||||
|
|
@ -174,7 +174,7 @@ func (h *Handler) GetAllUpcomingEvents(c *fiber.Ctx) error {
|
||||||
// @Param cc query string false "Country Code Filter"
|
// @Param cc query string false "Country Code Filter"
|
||||||
// @Param first_start_time query string false "Start Time"
|
// @Param first_start_time query string false "Start Time"
|
||||||
// @Param last_start_time query string false "End Time"
|
// @Param last_start_time query string false "End Time"
|
||||||
// @Success 200 {array} domain.UpcomingEvent
|
// @Success 200 {array} domain.BaseEvent
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/{tenant_slug}/events [get]
|
// @Router /api/v1/{tenant_slug}/events [get]
|
||||||
func (h *Handler) GetTenantUpcomingEvents(c *fiber.Ctx) error {
|
func (h *Handler) GetTenantUpcomingEvents(c *fiber.Ctx) error {
|
||||||
|
|
@ -400,7 +400,7 @@ func (h *Handler) GetTopLeagues(c *fiber.Ctx) error {
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path string true "ID"
|
// @Param id path string true "ID"
|
||||||
// @Success 200 {object} domain.UpcomingEvent
|
// @Success 200 {object} domain.BaseEvent
|
||||||
// @Failure 400 {object} response.APIResponse
|
// @Failure 400 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/events/{id} [get]
|
// @Router /api/v1/events/{id} [get]
|
||||||
|
|
@ -433,7 +433,7 @@ func (h *Handler) GetUpcomingEventByID(c *fiber.Ctx) error {
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Param id path string true "ID"
|
// @Param id path string true "ID"
|
||||||
// @Success 200 {object} domain.UpcomingEvent
|
// @Success 200 {object} domain.BaseEvent
|
||||||
// @Failure 400 {object} response.APIResponse
|
// @Failure 400 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/{tenant_slug}events/{id} [get]
|
// @Router /api/v1/{tenant_slug}events/{id} [get]
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import (
|
||||||
// @Tags leagues
|
// @Tags leagues
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {array} domain.League
|
// @Success 200 {array} domain.BaseLeague
|
||||||
// @Failure 400 {object} response.APIResponse
|
// @Failure 400 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/leagues [get]
|
// @Router /api/v1/leagues [get]
|
||||||
|
|
@ -102,7 +102,7 @@ func (h *Handler) GetAllLeagues(c *fiber.Ctx) error {
|
||||||
// @Tags leagues
|
// @Tags leagues
|
||||||
// @Accept json
|
// @Accept json
|
||||||
// @Produce json
|
// @Produce json
|
||||||
// @Success 200 {array} domain.League
|
// @Success 200 {array} domain.BaseLeague
|
||||||
// @Failure 400 {object} response.APIResponse
|
// @Failure 400 {object} response.APIResponse
|
||||||
// @Failure 500 {object} response.APIResponse
|
// @Failure 500 {object} response.APIResponse
|
||||||
// @Router /api/v1/{tenant_slug}/leagues [get]
|
// @Router /api/v1/{tenant_slug}/leagues [get]
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/veli"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/veli"
|
||||||
|
|
@ -70,6 +71,7 @@ func (h *Handler) GetGamesByProvider(c *fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Default brand if not provided
|
||||||
if req.BrandID == "" {
|
if req.BrandID == "" {
|
||||||
req.BrandID = h.Cfg.VeliGames.BrandID
|
req.BrandID = h.Cfg.VeliGames.BrandID
|
||||||
}
|
}
|
||||||
|
|
@ -77,6 +79,16 @@ func (h *Handler) GetGamesByProvider(c *fiber.Ctx) error {
|
||||||
res, err := h.veliVirtualGameSvc.GetGames(context.Background(), req)
|
res, err := h.veliVirtualGameSvc.GetGames(context.Background(), req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("GetGames error:", err)
|
log.Println("GetGames error:", err)
|
||||||
|
|
||||||
|
// Handle provider disabled case specifically
|
||||||
|
if strings.Contains(err.Error(), "is disabled") {
|
||||||
|
return c.Status(fiber.StatusForbidden).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Provider is disabled",
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback for other errors
|
||||||
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
||||||
Message: "Failed to retrieve games",
|
Message: "Failed to retrieve games",
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
|
|
@ -91,6 +103,7 @@ func (h *Handler) GetGamesByProvider(c *fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// StartGame godoc
|
// StartGame godoc
|
||||||
// @Summary Start a real game session
|
// @Summary Start a real game session
|
||||||
// @Description Starts a real VeliGames session with the given player and game info
|
// @Description Starts a real VeliGames session with the given player and game info
|
||||||
|
|
@ -119,7 +132,10 @@ func (h *Handler) StartGame(c *fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Attach user ID to request
|
||||||
req.PlayerID = fmt.Sprintf("%d", userId)
|
req.PlayerID = fmt.Sprintf("%d", userId)
|
||||||
|
|
||||||
|
// Default brand if not provided
|
||||||
if req.BrandID == "" {
|
if req.BrandID == "" {
|
||||||
req.BrandID = h.Cfg.VeliGames.BrandID
|
req.BrandID = h.Cfg.VeliGames.BrandID
|
||||||
}
|
}
|
||||||
|
|
@ -127,6 +143,16 @@ func (h *Handler) StartGame(c *fiber.Ctx) error {
|
||||||
res, err := h.veliVirtualGameSvc.StartGame(context.Background(), req)
|
res, err := h.veliVirtualGameSvc.StartGame(context.Background(), req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("StartGame error:", err)
|
log.Println("StartGame error:", err)
|
||||||
|
|
||||||
|
// Handle provider disabled case specifically
|
||||||
|
if strings.Contains(err.Error(), "is disabled") {
|
||||||
|
return c.Status(fiber.StatusForbidden).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Provider is disabled",
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback for other errors
|
||||||
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
||||||
Message: "Failed to start game",
|
Message: "Failed to start game",
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
|
|
@ -141,6 +167,7 @@ func (h *Handler) StartGame(c *fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// StartDemoGame godoc
|
// StartDemoGame godoc
|
||||||
// @Summary Start a demo game session
|
// @Summary Start a demo game session
|
||||||
// @Description Starts a demo session of the specified game (must support demo mode)
|
// @Description Starts a demo session of the specified game (must support demo mode)
|
||||||
|
|
@ -161,6 +188,7 @@ func (h *Handler) StartDemoGame(c *fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Default brand if not provided
|
||||||
if req.BrandID == "" {
|
if req.BrandID == "" {
|
||||||
req.BrandID = h.Cfg.VeliGames.BrandID
|
req.BrandID = h.Cfg.VeliGames.BrandID
|
||||||
}
|
}
|
||||||
|
|
@ -168,6 +196,16 @@ func (h *Handler) StartDemoGame(c *fiber.Ctx) error {
|
||||||
res, err := h.veliVirtualGameSvc.StartDemoGame(context.Background(), req)
|
res, err := h.veliVirtualGameSvc.StartDemoGame(context.Background(), req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Println("StartDemoGame error:", err)
|
log.Println("StartDemoGame error:", err)
|
||||||
|
|
||||||
|
// Handle provider disabled case specifically
|
||||||
|
if strings.Contains(err.Error(), "is disabled") {
|
||||||
|
return c.Status(fiber.StatusForbidden).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Provider is disabled",
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback for other errors
|
||||||
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
||||||
Message: "Failed to start demo game",
|
Message: "Failed to start demo game",
|
||||||
Error: err.Error(),
|
Error: err.Error(),
|
||||||
|
|
@ -182,6 +220,7 @@ func (h *Handler) StartDemoGame(c *fiber.Ctx) error {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func (h *Handler) GetBalance(c *fiber.Ctx) error {
|
func (h *Handler) GetBalance(c *fiber.Ctx) error {
|
||||||
var req domain.BalanceRequest
|
var req domain.BalanceRequest
|
||||||
if err := c.BodyParser(&req); err != nil {
|
if err := c.BodyParser(&req); err != nil {
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,10 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
|
||||||
|
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/veli"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/virtualGame/veli"
|
||||||
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
||||||
|
|
@ -22,6 +24,59 @@ type launchVirtualGameRes struct {
|
||||||
LaunchURL string `json:"launch_url"`
|
LaunchURL string `json:"launch_url"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ListVirtualGames godoc
|
||||||
|
// @Summary List all virtual games
|
||||||
|
// @Description Returns all virtual games with optional filters (category, search, pagination)
|
||||||
|
// @Tags VirtualGames - Orchestration
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param category query string false "Filter by category"
|
||||||
|
// @Param search query string false "Search by game name"
|
||||||
|
// @Param limit query int false "Pagination limit"
|
||||||
|
// @Param offset query int false "Pagination offset"
|
||||||
|
// @Success 200 {object} domain.Response{data=[]domain.UnifiedGame}
|
||||||
|
// @Failure 400 {object} domain.ErrorResponse
|
||||||
|
// @Failure 502 {object} domain.ErrorResponse
|
||||||
|
// @Router /api/v1/orchestrator/virtual-games [get]
|
||||||
|
func (h *Handler) ListVirtualGames(c *fiber.Ctx) error {
|
||||||
|
// --- Parse query parameters ---
|
||||||
|
limit := c.QueryInt("limit", 100)
|
||||||
|
if limit <= 0 {
|
||||||
|
limit = 100
|
||||||
|
}
|
||||||
|
offset := c.QueryInt("offset", 0)
|
||||||
|
if offset < 0 {
|
||||||
|
offset = 0
|
||||||
|
}
|
||||||
|
category := c.Query("category", "")
|
||||||
|
search := c.Query("search", "")
|
||||||
|
|
||||||
|
params := dbgen.GetAllVirtualGamesParams{
|
||||||
|
Column1: category,
|
||||||
|
Column2: search,
|
||||||
|
Limit: int32(limit),
|
||||||
|
Offset: int32(offset),
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Call service method ---
|
||||||
|
games, err := h.veliVirtualGameSvc.GetAllVirtualGames(c.Context(), params)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("ListVirtualGames error:", err)
|
||||||
|
return c.Status(fiber.StatusBadGateway).JSON(domain.ErrorResponse{
|
||||||
|
Message: "Failed to fetch virtual games",
|
||||||
|
Error: err.Error(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Return response ---
|
||||||
|
return c.Status(fiber.StatusOK).JSON(domain.Response{
|
||||||
|
Message: "Virtual games fetched successfully",
|
||||||
|
Data: games,
|
||||||
|
StatusCode: fiber.StatusOK,
|
||||||
|
Success: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// RemoveProviderHandler
|
// RemoveProviderHandler
|
||||||
// @Summary Remove a virtual game provider
|
// @Summary Remove a virtual game provider
|
||||||
// @Description Deletes a provider by provider_id
|
// @Description Deletes a provider by provider_id
|
||||||
|
|
|
||||||
|
|
@ -400,7 +400,8 @@ func (a *App) initAppRoutes() {
|
||||||
|
|
||||||
groupV1.Delete("/virtual-game/orchestrator/providers/:provideID", a.authMiddleware, h.RemoveProvider)
|
groupV1.Delete("/virtual-game/orchestrator/providers/:provideID", a.authMiddleware, h.RemoveProvider)
|
||||||
groupV1.Get("/virtual-game/orchestrator/providers/:provideID", a.authMiddleware, h.GetProviderByID)
|
groupV1.Get("/virtual-game/orchestrator/providers/:provideID", a.authMiddleware, h.GetProviderByID)
|
||||||
groupV1.Get("/virtual-game/orchestrator/providers", a.authMiddleware, h.ListProviders)
|
groupV1.Get("/virtual-game/orchestrator/games", h.ListVirtualGames)
|
||||||
|
groupV1.Get("/virtual-game/orchestrator/providers", h.ListProviders)
|
||||||
groupV1.Patch("/virtual-game/orchestrator/providers/:provideID/status", a.authMiddleware, h.SetProviderEnabled)
|
groupV1.Patch("/virtual-game/orchestrator/providers/:provideID/status", a.authMiddleware, h.SetProviderEnabled)
|
||||||
|
|
||||||
//Issue Reporting Routes
|
//Issue Reporting Routes
|
||||||
|
|
|
||||||
BIN
static/logos/popok-dark.png
Normal file
BIN
static/logos/popok-dark.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.4 KiB |
BIN
static/logos/popok-light.png
Normal file
BIN
static/logos/popok-light.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 8.0 KiB |
Loading…
Reference in New Issue
Block a user