diff --git a/db/migrations/000001_fortune.up.sql b/db/migrations/000001_fortune.up.sql index 56f3d51..1db8ddb 100644 --- a/db/migrations/000001_fortune.up.sql +++ b/db/migrations/000001_fortune.up.sql @@ -47,6 +47,7 @@ CREATE TABLE IF NOT EXISTS bets ( status INT NOT NULL, full_name VARCHAR(255) NOT NULL, phone_number VARCHAR(255) NOT NULL, + company_id BIGINT, branch_id BIGINT, user_id BIGINT, cashed_out BOOLEAN DEFAULT FALSE NOT NULL, @@ -342,7 +343,8 @@ INSERT INTO users ( created_at, updated_at, suspended_at, - suspended + suspended, + company_id ) VALUES ( 'Test', @@ -356,7 +358,8 @@ VALUES ( CURRENT_TIMESTAMP, CURRENT_TIMESTAMP, NULL, - FALSE + FALSE, + 1 ); INSERT INTO users ( first_name, diff --git a/db/query/bet.sql b/db/query/bet.sql index 7d3eab5..335cf56 100644 --- a/db/query/bet.sql +++ b/db/query/bet.sql @@ -8,9 +8,10 @@ INSERT INTO bets ( branch_id, user_id, is_shop_bet, - cashout_id + cashout_id, + company_id ) -VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) +VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) RETURNING *; -- name: CreateBetOutcome :copyfrom INSERT INTO bet_outcomes ( @@ -45,7 +46,19 @@ VALUES ( ); -- name: GetAllBets :many SELECT * -FROM bet_with_outcomes; +FROM bet_with_outcomes +wHERE ( + branch_id = $1 + OR $1 IS NULL + ) + AND ( + company_id = $2 + OR $2 IS NULL + ) + AND ( + user_id = $3 + OR $3 IS NULL + ); -- name: GetBetByID :one SELECT * FROM bet_with_outcomes diff --git a/db/query/transactions.sql b/db/query/transactions.sql index 83e8787..e63d5a9 100644 --- a/db/query/transactions.sql +++ b/db/query/transactions.sql @@ -42,7 +42,19 @@ VALUES ( RETURNING *; -- name: GetAllTransactions :many SELECT * -FROM transactions; +FROM transactions +wHERE ( + branch_id = sqlc.narg('branch_id') + OR sqlc.narg('branch_id') IS NULL + ) + AND ( + company_id = sqlc.narg('company_id') + OR sqlc.narg('company_id') IS NULL + ) + AND ( + cashier_id = sqlc.narg('cashier_id') + OR sqlc.narg('cashier_id') IS NULL + ); -- name: GetTransactionByID :one SELECT * FROM transactions diff --git a/gen/db/bet.sql.go b/gen/db/bet.sql.go index 40cd43b..e4cde1d 100644 --- a/gen/db/bet.sql.go +++ b/gen/db/bet.sql.go @@ -21,10 +21,11 @@ INSERT INTO bets ( branch_id, user_id, is_shop_bet, - cashout_id + cashout_id, + company_id ) -VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) -RETURNING id, amount, total_odds, status, full_name, phone_number, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet +VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) +RETURNING id, amount, total_odds, status, full_name, phone_number, company_id, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet ` type CreateBetParams struct { @@ -37,6 +38,7 @@ type CreateBetParams struct { UserID pgtype.Int8 `json:"user_id"` IsShopBet bool `json:"is_shop_bet"` CashoutID string `json:"cashout_id"` + CompanyID pgtype.Int8 `json:"company_id"` } func (q *Queries) CreateBet(ctx context.Context, arg CreateBetParams) (Bet, error) { @@ -50,6 +52,7 @@ func (q *Queries) CreateBet(ctx context.Context, arg CreateBetParams) (Bet, erro arg.UserID, arg.IsShopBet, arg.CashoutID, + arg.CompanyID, ) var i Bet err := row.Scan( @@ -59,6 +62,7 @@ func (q *Queries) CreateBet(ctx context.Context, arg CreateBetParams) (Bet, erro &i.Status, &i.FullName, &i.PhoneNumber, + &i.CompanyID, &i.BranchID, &i.UserID, &i.CashedOut, @@ -107,12 +111,30 @@ func (q *Queries) DeleteBetOutcome(ctx context.Context, betID int64) error { } const GetAllBets = `-- name: GetAllBets :many -SELECT id, amount, total_odds, status, full_name, phone_number, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet, outcomes +SELECT id, amount, total_odds, status, full_name, phone_number, company_id, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet, outcomes FROM bet_with_outcomes +wHERE ( + branch_id = $1 + OR $1 IS NULL + ) + AND ( + company_id = $2 + OR $2 IS NULL + ) + AND ( + user_id = $3 + OR $3 IS NULL + ) ` -func (q *Queries) GetAllBets(ctx context.Context) ([]BetWithOutcome, error) { - rows, err := q.db.Query(ctx, GetAllBets) +type GetAllBetsParams struct { + BranchID pgtype.Int8 `json:"branch_id"` + CompanyID pgtype.Int8 `json:"company_id"` + UserID pgtype.Int8 `json:"user_id"` +} + +func (q *Queries) GetAllBets(ctx context.Context, arg GetAllBetsParams) ([]BetWithOutcome, error) { + rows, err := q.db.Query(ctx, GetAllBets, arg.BranchID, arg.CompanyID, arg.UserID) if err != nil { return nil, err } @@ -127,6 +149,7 @@ func (q *Queries) GetAllBets(ctx context.Context) ([]BetWithOutcome, error) { &i.Status, &i.FullName, &i.PhoneNumber, + &i.CompanyID, &i.BranchID, &i.UserID, &i.CashedOut, @@ -147,7 +170,7 @@ func (q *Queries) GetAllBets(ctx context.Context) ([]BetWithOutcome, error) { } const GetBetByBranchID = `-- name: GetBetByBranchID :many -SELECT id, amount, total_odds, status, full_name, phone_number, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet, outcomes +SELECT id, amount, total_odds, status, full_name, phone_number, company_id, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet, outcomes FROM bet_with_outcomes WHERE branch_id = $1 ` @@ -168,6 +191,7 @@ func (q *Queries) GetBetByBranchID(ctx context.Context, branchID pgtype.Int8) ([ &i.Status, &i.FullName, &i.PhoneNumber, + &i.CompanyID, &i.BranchID, &i.UserID, &i.CashedOut, @@ -188,7 +212,7 @@ func (q *Queries) GetBetByBranchID(ctx context.Context, branchID pgtype.Int8) ([ } const GetBetByCashoutID = `-- name: GetBetByCashoutID :one -SELECT id, amount, total_odds, status, full_name, phone_number, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet, outcomes +SELECT id, amount, total_odds, status, full_name, phone_number, company_id, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet, outcomes FROM bet_with_outcomes WHERE cashout_id = $1 ` @@ -203,6 +227,7 @@ func (q *Queries) GetBetByCashoutID(ctx context.Context, cashoutID string) (BetW &i.Status, &i.FullName, &i.PhoneNumber, + &i.CompanyID, &i.BranchID, &i.UserID, &i.CashedOut, @@ -216,7 +241,7 @@ func (q *Queries) GetBetByCashoutID(ctx context.Context, cashoutID string) (BetW } const GetBetByID = `-- name: GetBetByID :one -SELECT id, amount, total_odds, status, full_name, phone_number, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet, outcomes +SELECT id, amount, total_odds, status, full_name, phone_number, company_id, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet, outcomes FROM bet_with_outcomes WHERE id = $1 ` @@ -231,6 +256,7 @@ func (q *Queries) GetBetByID(ctx context.Context, id int64) (BetWithOutcome, err &i.Status, &i.FullName, &i.PhoneNumber, + &i.CompanyID, &i.BranchID, &i.UserID, &i.CashedOut, @@ -244,7 +270,7 @@ func (q *Queries) GetBetByID(ctx context.Context, id int64) (BetWithOutcome, err } const GetBetByUserID = `-- name: GetBetByUserID :many -SELECT id, amount, total_odds, status, full_name, phone_number, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet, outcomes +SELECT id, amount, total_odds, status, full_name, phone_number, company_id, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet, outcomes FROM bet_with_outcomes WHERE user_id = $1 ` @@ -265,6 +291,7 @@ func (q *Queries) GetBetByUserID(ctx context.Context, userID pgtype.Int8) ([]Bet &i.Status, &i.FullName, &i.PhoneNumber, + &i.CompanyID, &i.BranchID, &i.UserID, &i.CashedOut, diff --git a/gen/db/models.go b/gen/db/models.go index 7c65cfc..d4b2712 100644 --- a/gen/db/models.go +++ b/gen/db/models.go @@ -62,6 +62,7 @@ type Bet struct { Status int32 `json:"status"` FullName string `json:"full_name"` PhoneNumber string `json:"phone_number"` + CompanyID pgtype.Int8 `json:"company_id"` BranchID pgtype.Int8 `json:"branch_id"` UserID pgtype.Int8 `json:"user_id"` CashedOut bool `json:"cashed_out"` @@ -96,6 +97,7 @@ type BetWithOutcome struct { Status int32 `json:"status"` FullName string `json:"full_name"` PhoneNumber string `json:"phone_number"` + CompanyID pgtype.Int8 `json:"company_id"` BranchID pgtype.Int8 `json:"branch_id"` UserID pgtype.Int8 `json:"user_id"` CashedOut bool `json:"cashed_out"` @@ -383,6 +385,32 @@ type User struct { ReferredBy pgtype.Text `json:"referred_by"` } +type UserGameInteraction struct { + ID int64 `json:"id"` + UserID int64 `json:"user_id"` + GameID int64 `json:"game_id"` + InteractionType string `json:"interaction_type"` + Amount pgtype.Numeric `json:"amount"` + DurationSeconds pgtype.Int4 `json:"duration_seconds"` + CreatedAt pgtype.Timestamptz `json:"created_at"` +} + +type VirtualGame struct { + ID int64 `json:"id"` + Name string `json:"name"` + Provider string `json:"provider"` + Category string `json:"category"` + MinBet pgtype.Numeric `json:"min_bet"` + MaxBet pgtype.Numeric `json:"max_bet"` + Volatility string `json:"volatility"` + Rtp pgtype.Numeric `json:"rtp"` + IsFeatured pgtype.Bool `json:"is_featured"` + PopularityScore pgtype.Int4 `json:"popularity_score"` + ThumbnailUrl pgtype.Text `json:"thumbnail_url"` + CreatedAt pgtype.Timestamptz `json:"created_at"` + UpdatedAt pgtype.Timestamptz `json:"updated_at"` +} + type VirtualGameSession struct { ID int64 `json:"id"` UserID int64 `json:"user_id"` diff --git a/gen/db/transactions.sql.go b/gen/db/transactions.sql.go index 7d33130..5bce39f 100644 --- a/gen/db/transactions.sql.go +++ b/gen/db/transactions.sql.go @@ -130,10 +130,28 @@ func (q *Queries) CreateTransaction(ctx context.Context, arg CreateTransactionPa const GetAllTransactions = `-- name: GetAllTransactions :many SELECT id, amount, branch_id, company_id, cashier_id, cashier_name, bet_id, number_of_outcomes, type, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, approved_by, approver_name, branch_location, branch_name, created_at, updated_at FROM transactions +wHERE ( + branch_id = $1 + OR $1 IS NULL + ) + AND ( + company_id = $2 + OR $2 IS NULL + ) + AND ( + cashier_id = $3 + OR $3 IS NULL + ) ` -func (q *Queries) GetAllTransactions(ctx context.Context) ([]Transaction, error) { - rows, err := q.db.Query(ctx, GetAllTransactions) +type GetAllTransactionsParams struct { + BranchID pgtype.Int8 `json:"branch_id"` + CompanyID pgtype.Int8 `json:"company_id"` + CashierID pgtype.Int8 `json:"cashier_id"` +} + +func (q *Queries) GetAllTransactions(ctx context.Context, arg GetAllTransactionsParams) ([]Transaction, error) { + rows, err := q.db.Query(ctx, GetAllTransactions, arg.BranchID, arg.CompanyID, arg.CashierID) if err != nil { return nil, err } diff --git a/internal/domain/bet.go b/internal/domain/bet.go index 9c5b53b..cbd904e 100644 --- a/internal/domain/bet.go +++ b/internal/domain/bet.go @@ -48,6 +48,7 @@ type Bet struct { FullName string PhoneNumber string BranchID ValidInt64 // Can Be Nullable + CompanyID ValidInt64 // Can Be Nullable UserID ValidInt64 // Can Be Nullable IsShopBet bool CashedOut bool @@ -55,6 +56,12 @@ type Bet struct { CreatedAt time.Time } +type BetFilter struct { + BranchID ValidInt64 // Can Be Nullable + CompanyID ValidInt64 // Can Be Nullable + UserID ValidInt64 // Can Be Nullable +} + type GetBet struct { ID int64 Amount Currency @@ -63,6 +70,7 @@ type GetBet struct { FullName string PhoneNumber string BranchID ValidInt64 // Can Be Nullable + CompanyID ValidInt64 // Can Be Nullable UserID ValidInt64 // Can Be Nullable IsShopBet bool CashedOut bool @@ -77,6 +85,7 @@ type CreateBet struct { Status OutcomeStatus FullName string PhoneNumber string + CompanyID ValidInt64 // Can Be Nullable BranchID ValidInt64 // Can Be Nullable UserID ValidInt64 // Can Be Nullable IsShopBet bool @@ -164,3 +173,4 @@ func ConvertBet(bet GetBet) BetRes { CreatedAt: bet.CreatedAt, } } + diff --git a/internal/domain/common.go b/internal/domain/common.go index fcccacb..5393aac 100644 --- a/internal/domain/common.go +++ b/internal/domain/common.go @@ -59,3 +59,14 @@ type Response struct { Success bool `json:"success"` StatusCode int `json:"status_code"` } + +func CalculateWinnings(amount Currency, totalOdds float32) Currency { + + vat := amount.Float32() * 0.15 + stakeAfterVat := amount.Float32() - vat + possibleWin := stakeAfterVat * totalOdds + incomeTax := possibleWin * 0.15 + + return ToCurrency(possibleWin - incomeTax) + +} diff --git a/internal/domain/league.go b/internal/domain/league.go index a4a9cc2..fbe4bd0 100644 --- a/internal/domain/league.go +++ b/internal/domain/league.go @@ -14,6 +14,13 @@ var SupportedLeagues = []int64{ 10047168, // US MLS 10044469, // Ethiopian Premier League 10050282, //UEFA Nations League + 10044685, //FIFA Club World Cup + 10082328, //Kings League World Cup + 10081269, //CONCACAF Champions Cup + 10040162, //Asia - World Cup Qualifying + 10067624, //South America - World Cup Qualifying + 10067913, // Europe - World Cup Qualifying + 10067624, // South America - World Cup Qualifying 10043156, //England FA Cup 10042103, //France Cup @@ -22,18 +29,38 @@ var SupportedLeagues = []int64{ 10041187, //Kenya Super League 10041315, //Italian Serie A 10041391, //Netherlands Eredivisie + 10036538, //Spain Segunda + 10041058, //Denmark Superligaen + 10077480, //Women’s International + 10046936, // USA NPSL + 10085159, //Baller League UK + 10040601, //Argentina Cup + 10037440, //Brazil Serie A + 10043205, //Copa Sudamericana + + 10037327, //Austria Landesliga + 10082020, //USA USL League One Cup + 10037075, //International Match + 10046648, //Kenya Cup + 10040485, //Kenya Super League + 10041369, //Norway Eliteserien // Basketball 173998768, //NBA 10041830, //NBA 10049984, //WNBA 10037165, //German Bundesliga - 10036608, //Italian Lega 1 - 10040795, //EuroLeague + 10036608, //Italian Lega 1 + 10040795, //EuroLeague + 10084178, //Kenya Premier League + 10043548, //International Women // Ice Hockey 10037477, //NHL 10037447, //AHL + 10074238, // AIHL 10069385, //IIHF World Championship + // Cricket + } diff --git a/internal/domain/oddres.go b/internal/domain/oddres.go index 48540f0..5b4a39f 100644 --- a/internal/domain/oddres.go +++ b/internal/domain/oddres.go @@ -49,3 +49,76 @@ type IceHockeyOddsResponse struct { FirstPeriod OddsSection `json:"1st_period"` Others []OddsSection `json:"others"` } +type CricketOddsResponse struct { + EventID string `json:"event_id"` + FI string `json:"FI"` + First_Over OddsSection `json:"1st_over"` + First_Innings OddsSection `json:"innings_1"` + Main OddsSection `json:"main"` + Match OddsSection `json:"match"` + Others []OddsSection `json:"others"` + Player OddsSection `json:"player"` + Team OddsSection `json:"team"` +} +type VolleyballOddsResponse struct { + EventID string `json:"event_id"` + FI string `json:"FI"` + Main OddsSection `json:"main"` + Others []OddsSection `json:"others"` +} +type DartsOddsResponse struct { + EventID string `json:"event_id"` + FI string `json:"FI"` + OneEightys OddsSection `json:"180s"` + Extra OddsSection `json:"extra"` + Leg OddsSection `json:"leg"` + Main OddsSection `json:"main"` + Others []OddsSection `json:"others"` +} + +type FutsalOddsResponse struct { + EventID string `json:"event_id"` + FI string `json:"FI"` + Main OddsSection `json:"main"` + Score OddsSection `json:"score"` + Others []OddsSection `json:"others"` +} + +type AmericanFootballOddsResponse struct { + EventID string `json:"event_id"` + FI string `json:"FI"` + HalfProps OddsSection `json:"half_props"` + Main OddsSection `json:"main"` + QuarterProps OddsSection `json:"quarter_props"` + Others []OddsSection `json:"others"` +} + +type RugbyLeagueOddsResponse struct { + EventID string `json:"event_id"` + FI string `json:"FI"` + TenMinute OddsSection `json:"10minute"` + Half OddsSection `json:"half"` + Main OddsSection `json:"main"` + Main2 OddsSection `json:"main_2"` + Others []OddsSection `json:"others"` + Player OddsSection `json:"player"` + Score OddsSection `json:"score"` + Team OddsSection `json:"team"` +} +type RugbyUnionOddsResponse struct { + EventID string `json:"event_id"` + FI string `json:"FI"` + Half OddsSection `json:"half"` + Main OddsSection `json:"main"` + Main2 OddsSection `json:"main_2"` + Others []OddsSection `json:"others"` + Player OddsSection `json:"player"` + Score OddsSection `json:"score"` + Team OddsSection `json:"team"` +} +type BaseballOddsResponse struct { + EventID string `json:"event_id"` + FI string `json:"FI"` + Main OddsSection `json:"main"` + MainProps OddsSection `json:"main_props"` +} diff --git a/internal/domain/resultres.go b/internal/domain/resultres.go index 493c0c9..7c92367 100644 --- a/internal/domain/resultres.go +++ b/internal/domain/resultres.go @@ -290,3 +290,168 @@ type FutsalResultResponse struct { ConfirmedAt string `json:"confirmed_at"` Bet365ID string `json:"bet365_id"` } + +// NFLResultResponse represents the structure for NFL game results +type NFLResultResponse struct { + ID string `json:"id"` + SportID string `json:"sport_id"` + Time string `json:"time"` + TimeStatus string `json:"time_status"` + League struct { + ID string `json:"id"` + Name string `json:"name"` + CC string `json:"cc"` + } `json:"league"` + Home struct { + ID string `json:"id"` + Name string `json:"name"` + ImageID string `json:"image_id"` + CC string `json:"cc"` + } `json:"home"` + Away struct { + ID string `json:"id"` + Name string `json:"name"` + ImageID string `json:"image_id"` + CC string `json:"cc"` + } `json:"away"` + SS string `json:"ss"` + Scores struct { + FirstQuarter Score `json:"1"` + SecondQuarter Score `json:"2"` + ThirdQuarter Score `json:"3"` + FourthQuarter Score `json:"4"` + Overtime Score `json:"5"` + TotalScore Score `json:"7"` + } `json:"scores"` + Stats struct { + FirstDowns []string `json:"first_downs"` + TotalYards []string `json:"total_yards"` + PassingYards []string `json:"passing_yards"` + RushingYards []string `json:"rushing_yards"` + Turnovers []string `json:"turnovers"` + TimeOfPossession []string `json:"time_of_possession"` + ThirdDownEfficiency []string `json:"third_down_efficiency"` + FourthDownEfficiency []string `json:"fourth_down_efficiency"` + } `json:"stats"` + Extra struct { + HomePos string `json:"home_pos"` + AwayPos string `json:"away_pos"` + StadiumData map[string]string `json:"stadium_data"` + Round string `json:"round"` + } `json:"extra"` + Events []map[string]string `json:"events"` + HasLineup int `json:"has_lineup"` + ConfirmedAt string `json:"confirmed_at"` + Bet365ID string `json:"bet365_id"` +} + +// RugbyResultResponse represents the structure for Rugby game results +type RugbyResultResponse struct { + ID string `json:"id"` + SportID string `json:"sport_id"` + Time string `json:"time"` + TimeStatus string `json:"time_status"` + League struct { + ID string `json:"id"` + Name string `json:"name"` + CC string `json:"cc"` + } `json:"league"` + Home struct { + ID string `json:"id"` + Name string `json:"name"` + ImageID string `json:"image_id"` + CC string `json:"cc"` + } `json:"home"` + Away struct { + ID string `json:"id"` + Name string `json:"name"` + ImageID string `json:"image_id"` + CC string `json:"cc"` + } `json:"away"` + SS string `json:"ss"` + Scores struct { + FirstHalf Score `json:"1"` + SecondHalf Score `json:"2"` + TotalScore Score `json:"7"` + } `json:"scores"` + Stats struct { + Tries []string `json:"tries"` + Conversions []string `json:"conversions"` + Penalties []string `json:"penalties"` + DropGoals []string `json:"drop_goals"` + Possession []string `json:"possession"` + Territory []string `json:"territory"` + Lineouts []string `json:"lineouts"` + Scrums []string `json:"scrums"` + PenaltiesConceded []string `json:"penalties_conceded"` + } `json:"stats"` + Extra struct { + HomePos string `json:"home_pos"` + AwayPos string `json:"away_pos"` + StadiumData map[string]string `json:"stadium_data"` + Round string `json:"round"` + } `json:"extra"` + Events []map[string]string `json:"events"` + HasLineup int `json:"has_lineup"` + ConfirmedAt string `json:"confirmed_at"` + Bet365ID string `json:"bet365_id"` +} + +// BaseballResultResponse represents the structure for Baseball game results +type BaseballResultResponse struct { + ID string `json:"id"` + SportID string `json:"sport_id"` + Time string `json:"time"` + TimeStatus string `json:"time_status"` + League struct { + ID string `json:"id"` + Name string `json:"name"` + CC string `json:"cc"` + } `json:"league"` + Home struct { + ID string `json:"id"` + Name string `json:"name"` + ImageID string `json:"image_id"` + CC string `json:"cc"` + } `json:"home"` + Away struct { + ID string `json:"id"` + Name string `json:"name"` + ImageID string `json:"image_id"` + CC string `json:"cc"` + } `json:"away"` + SS string `json:"ss"` + Scores struct { + FirstInning Score `json:"1"` + SecondInning Score `json:"2"` + ThirdInning Score `json:"3"` + FourthInning Score `json:"4"` + FifthInning Score `json:"5"` + SixthInning Score `json:"6"` + SeventhInning Score `json:"7"` + EighthInning Score `json:"8"` + NinthInning Score `json:"9"` + ExtraInnings Score `json:"10"` + TotalScore Score `json:"11"` + } `json:"scores"` + Stats struct { + Hits []string `json:"hits"` + Errors []string `json:"errors"` + LeftOnBase []string `json:"left_on_base"` + Strikeouts []string `json:"strikeouts"` + Walks []string `json:"walks"` + HomeRuns []string `json:"home_runs"` + TotalBases []string `json:"total_bases"` + BattingAverage []string `json:"batting_average"` + } `json:"stats"` + Extra struct { + HomePos string `json:"home_pos"` + AwayPos string `json:"away_pos"` + StadiumData map[string]string `json:"stadium_data"` + Round string `json:"round"` + } `json:"extra"` + Events []map[string]string `json:"events"` + HasLineup int `json:"has_lineup"` + ConfirmedAt string `json:"confirmed_at"` + Bet365ID string `json:"bet365_id"` +} diff --git a/internal/domain/sportmarket.go b/internal/domain/sportmarket.go index b5b7845..11756f0 100644 --- a/internal/domain/sportmarket.go +++ b/internal/domain/sportmarket.go @@ -171,32 +171,28 @@ type AmericanFootballMarket int64 const ( // Main - AMERICAN_FOOTBALL_MONEY_LINE AmericanFootballMarket = 170001 - AMERICAN_FOOTBALL_SPREAD AmericanFootballMarket = 170002 - AMERICAN_FOOTBALL_TOTAL_POINTS AmericanFootballMarket = 170003 + AMERICAN_FOOTBALL_GAME_LINES AmericanFootballMarket = 1441 ) -type RugbyMarket int64 +type RugbyLeagueMarket int64 const ( // Main - RUGBY_MONEY_LINE RugbyMarket = 180001 - RUGBY_SPREAD RugbyMarket = 180002 - RUGBY_TOTAL_POINTS RugbyMarket = 180003 - RUGBY_HANDICAP RugbyMarket = 180004 - RUGBY_FIRST_HALF RugbyMarket = 180005 - RUGBY_SECOND_HALF RugbyMarket = 180006 + RUGBY_L_GAME_BETTING_2_WAY RugbyLeagueMarket = 190006 +) + +type RugbyUnionMarket int64 + +const ( + // Main + RUGBY_U_GAME_BETTING_2_WAY RugbyLeagueMarket = 80007 ) type BaseballMarket int64 const ( // Main - BASEBALL_MONEY_LINE BaseballMarket = 190001 - BASEBALL_SPREAD BaseballMarket = 190002 - BASEBALL_TOTAL_RUNS BaseballMarket = 190003 - BASEBALL_FIRST_INNING BaseballMarket = 190004 - BASEBALL_FIRST_5_INNINGS BaseballMarket = 190005 + BASEBALL_GAME_LINES BaseballMarket = 1096 ) // TODO: Move this into the database so that it can be modified dynamically @@ -229,7 +225,7 @@ var SupportedMarkets = map[int64]bool{ int64(BASKETBALL_RESULT_AND_BOTH_TEAMS_TO_SCORE_X_POINTS): true, int64(BASKETBALL_DOUBLE_RESULT): true, int64(BASKETBALL_MATCH_RESULT_AND_TOTAL): true, - int64(BASKETBALL_MATCH_HANDICAP_AND_TOTAL): false, + int64(BASKETBALL_MATCH_HANDICAP_AND_TOTAL): true, int64(BASKETBALL_GAME_TOTAL_ODD_EVEN): true, int64(BASKETBALL_TEAM_TOTALS): true, int64(BASKETBALL_TEAM_TOTAL_ODD_EVEN): true, @@ -250,7 +246,7 @@ var SupportedMarkets = map[int64]bool{ int64(BASKETBALL_FIRST_HALF_TEAM_TO_SCORE_X_POINTS): false, int64(BASKETBALL_FIRST_QUARTER): true, - int64(BASKETBALL_FIRST_QUARTER_HANDICAP_AND_TOTAL): false, + int64(BASKETBALL_FIRST_QUARTER_HANDICAP_AND_TOTAL): true, int64(BASKETBALL_FIRST_QUARTER_DOUBLE_CHANCE): true, int64(BASKETBALL_FIRST_QUARTER_TEAM_TOTALS): true, int64(BASKETBALL_FIRST_QUARTER_WINNING_MARGIN): false, @@ -259,7 +255,7 @@ var SupportedMarkets = map[int64]bool{ int64(BASKETBALL_TEAM_WITH_HIGHEST_SCORING_QUARTER): true, int64(BASKETBALL_QUARTER_CORRECT_SCORE): false, int64(BASKETBALL_FIRST_QUARTER_3_WAY_LINES): false, - int64(BASKETBALL_FIRST_QUARTER_RESULT_AND_TOTAL): false, + int64(BASKETBALL_FIRST_QUARTER_RESULT_AND_TOTAL): true, int64(BASKETBALL_FIRST_QUARTER_RACE_TO_POINTS): false, int64(BASKETBALL_FIRST_QUARTER_BOTH_TEAMS_TO_SCORE_X_POINTS): false, int64(BASKETBALL_FIRST_QUARTER_TEAM_TO_SCORE_X_POINTS): false, @@ -325,22 +321,14 @@ var SupportedMarkets = map[int64]bool{ int64(FUTSAL_RACE_TO_GOALS): false, // American Football Markets - int64(AMERICAN_FOOTBALL_MONEY_LINE): true, - int64(AMERICAN_FOOTBALL_SPREAD): true, - int64(AMERICAN_FOOTBALL_TOTAL_POINTS): true, + int64(AMERICAN_FOOTBALL_GAME_LINES): true, - // Rugby Markets - int64(RUGBY_MONEY_LINE): true, - int64(RUGBY_SPREAD): true, - int64(RUGBY_TOTAL_POINTS): true, - int64(RUGBY_HANDICAP): true, - int64(RUGBY_FIRST_HALF): true, - int64(RUGBY_SECOND_HALF): true, + // Rugby League Markets + int64(RUGBY_L_GAME_BETTING_2_WAY): true, + + // Ruby Union Markets + int64(RUGBY_U_GAME_BETTING_2_WAY): true, // Baseball Markets - int64(BASEBALL_MONEY_LINE): true, - int64(BASEBALL_SPREAD): true, - int64(BASEBALL_TOTAL_RUNS): true, - int64(BASEBALL_FIRST_INNING): true, - int64(BASEBALL_FIRST_5_INNINGS): true, + int64(BASEBALL_GAME_LINES): true, } diff --git a/internal/domain/sports_result.go b/internal/domain/sports_result.go index 16bceb1..c29a402 100644 --- a/internal/domain/sports_result.go +++ b/internal/domain/sports_result.go @@ -1,290 +1,125 @@ package domain -import ( - "encoding/json" - "strconv" - "strings" -) +// import ( +// "encoding/json" +// "strconv" +// "strings" +// ) -// NFLResultResponse represents the structure for NFL game results -type NFLResultResponse struct { - ID string `json:"id"` - SportID string `json:"sport_id"` - Time string `json:"time"` - TimeStatus string `json:"time_status"` - League struct { - ID string `json:"id"` - Name string `json:"name"` - CC string `json:"cc"` - } `json:"league"` - Home struct { - ID string `json:"id"` - Name string `json:"name"` - ImageID string `json:"image_id"` - CC string `json:"cc"` - } `json:"home"` - Away struct { - ID string `json:"id"` - Name string `json:"name"` - ImageID string `json:"image_id"` - CC string `json:"cc"` - } `json:"away"` - SS string `json:"ss"` - Scores struct { - FirstQuarter Score `json:"1"` - SecondQuarter Score `json:"2"` - ThirdQuarter Score `json:"3"` - FourthQuarter Score `json:"4"` - Overtime Score `json:"5"` - TotalScore Score `json:"7"` - } `json:"scores"` - Stats struct { - FirstDowns []string `json:"first_downs"` - TotalYards []string `json:"total_yards"` - PassingYards []string `json:"passing_yards"` - RushingYards []string `json:"rushing_yards"` - Turnovers []string `json:"turnovers"` - TimeOfPossession []string `json:"time_of_possession"` - ThirdDownEfficiency []string `json:"third_down_efficiency"` - FourthDownEfficiency []string `json:"fourth_down_efficiency"` - } `json:"stats"` - Extra struct { - HomePos string `json:"home_pos"` - AwayPos string `json:"away_pos"` - StadiumData map[string]string `json:"stadium_data"` - Round string `json:"round"` - } `json:"extra"` - Events []map[string]string `json:"events"` - HasLineup int `json:"has_lineup"` - ConfirmedAt string `json:"confirmed_at"` - Bet365ID string `json:"bet365_id"` -} +// // ParseNFLResult parses NFL result from raw JSON data +// func ParseNFLResult(data json.RawMessage) (*NFLResultResponse, error) { +// var result NFLResultResponse +// if err := json.Unmarshal(data, &result); err != nil { +// return nil, err +// } +// return &result, nil +// } -// RugbyResultResponse represents the structure for Rugby game results -type RugbyResultResponse struct { - ID string `json:"id"` - SportID string `json:"sport_id"` - Time string `json:"time"` - TimeStatus string `json:"time_status"` - League struct { - ID string `json:"id"` - Name string `json:"name"` - CC string `json:"cc"` - } `json:"league"` - Home struct { - ID string `json:"id"` - Name string `json:"name"` - ImageID string `json:"image_id"` - CC string `json:"cc"` - } `json:"home"` - Away struct { - ID string `json:"id"` - Name string `json:"name"` - ImageID string `json:"image_id"` - CC string `json:"cc"` - } `json:"away"` - SS string `json:"ss"` - Scores struct { - FirstHalf Score `json:"1"` - SecondHalf Score `json:"2"` - TotalScore Score `json:"7"` - } `json:"scores"` - Stats struct { - Tries []string `json:"tries"` - Conversions []string `json:"conversions"` - Penalties []string `json:"penalties"` - DropGoals []string `json:"drop_goals"` - Possession []string `json:"possession"` - Territory []string `json:"territory"` - Lineouts []string `json:"lineouts"` - Scrums []string `json:"scrums"` - PenaltiesConceded []string `json:"penalties_conceded"` - } `json:"stats"` - Extra struct { - HomePos string `json:"home_pos"` - AwayPos string `json:"away_pos"` - StadiumData map[string]string `json:"stadium_data"` - Round string `json:"round"` - } `json:"extra"` - Events []map[string]string `json:"events"` - HasLineup int `json:"has_lineup"` - ConfirmedAt string `json:"confirmed_at"` - Bet365ID string `json:"bet365_id"` -} +// // ParseRugbyResult parses Rugby result from raw JSON data +// func ParseRugbyResult(data json.RawMessage) (*RugbyResultResponse, error) { +// var result RugbyResultResponse +// if err := json.Unmarshal(data, &result); err != nil { +// return nil, err +// } +// return &result, nil +// } -// BaseballResultResponse represents the structure for Baseball game results -type BaseballResultResponse struct { - ID string `json:"id"` - SportID string `json:"sport_id"` - Time string `json:"time"` - TimeStatus string `json:"time_status"` - League struct { - ID string `json:"id"` - Name string `json:"name"` - CC string `json:"cc"` - } `json:"league"` - Home struct { - ID string `json:"id"` - Name string `json:"name"` - ImageID string `json:"image_id"` - CC string `json:"cc"` - } `json:"home"` - Away struct { - ID string `json:"id"` - Name string `json:"name"` - ImageID string `json:"image_id"` - CC string `json:"cc"` - } `json:"away"` - SS string `json:"ss"` - Scores struct { - FirstInning Score `json:"1"` - SecondInning Score `json:"2"` - ThirdInning Score `json:"3"` - FourthInning Score `json:"4"` - FifthInning Score `json:"5"` - SixthInning Score `json:"6"` - SeventhInning Score `json:"7"` - EighthInning Score `json:"8"` - NinthInning Score `json:"9"` - ExtraInnings Score `json:"10"` - TotalScore Score `json:"11"` - } `json:"scores"` - Stats struct { - Hits []string `json:"hits"` - Errors []string `json:"errors"` - LeftOnBase []string `json:"left_on_base"` - Strikeouts []string `json:"strikeouts"` - Walks []string `json:"walks"` - HomeRuns []string `json:"home_runs"` - TotalBases []string `json:"total_bases"` - BattingAverage []string `json:"batting_average"` - } `json:"stats"` - Extra struct { - HomePos string `json:"home_pos"` - AwayPos string `json:"away_pos"` - StadiumData map[string]string `json:"stadium_data"` - Round string `json:"round"` - } `json:"extra"` - Events []map[string]string `json:"events"` - HasLineup int `json:"has_lineup"` - ConfirmedAt string `json:"confirmed_at"` - Bet365ID string `json:"bet365_id"` -} +// // ParseRugbyUnionResult parses Rugby Union result from raw JSON data +// func ParseRugbyUnionResult(data json.RawMessage) (*RugbyResultResponse, error) { +// return ParseRugbyResult(data) +// } -// ParseNFLResult parses NFL result from raw JSON data -func ParseNFLResult(data json.RawMessage) (*NFLResultResponse, error) { - var result NFLResultResponse - if err := json.Unmarshal(data, &result); err != nil { - return nil, err - } - return &result, nil -} +// // ParseRugbyLeagueResult parses Rugby League result from raw JSON data +// func ParseRugbyLeagueResult(data json.RawMessage) (*RugbyResultResponse, error) { +// return ParseRugbyResult(data) +// } -// ParseRugbyResult parses Rugby result from raw JSON data -func ParseRugbyResult(data json.RawMessage) (*RugbyResultResponse, error) { - var result RugbyResultResponse - if err := json.Unmarshal(data, &result); err != nil { - return nil, err - } - return &result, nil -} +// // ParseBaseballResult parses Baseball result from raw JSON data +// func ParseBaseballResult(data json.RawMessage) (*BaseballResultResponse, error) { +// var result BaseballResultResponse +// if err := json.Unmarshal(data, &result); err != nil { +// return nil, err +// } +// return &result, nil +// } -// ParseRugbyUnionResult parses Rugby Union result from raw JSON data -func ParseRugbyUnionResult(data json.RawMessage) (*RugbyResultResponse, error) { - return ParseRugbyResult(data) -} +// // GetNFLWinner determines the winner of an NFL game +// func GetNFLWinner(result *NFLResultResponse) (string, error) { +// homeScore, err := strconv.Atoi(result.Scores.TotalScore.Home) +// if err != nil { +// return "", err +// } +// awayScore, err := strconv.Atoi(result.Scores.TotalScore.Away) +// if err != nil { +// return "", err +// } -// ParseRugbyLeagueResult parses Rugby League result from raw JSON data -func ParseRugbyLeagueResult(data json.RawMessage) (*RugbyResultResponse, error) { - return ParseRugbyResult(data) -} +// if homeScore > awayScore { +// return result.Home.Name, nil +// } else if awayScore > homeScore { +// return result.Away.Name, nil +// } +// return "Draw", nil +// } -// ParseBaseballResult parses Baseball result from raw JSON data -func ParseBaseballResult(data json.RawMessage) (*BaseballResultResponse, error) { - var result BaseballResultResponse - if err := json.Unmarshal(data, &result); err != nil { - return nil, err - } - return &result, nil -} +// // GetRugbyWinner determines the winner of a Rugby game +// func GetRugbyWinner(result *RugbyResultResponse) (string, error) { +// homeScore, err := strconv.Atoi(result.Scores.TotalScore.Home) +// if err != nil { +// return "", err +// } +// awayScore, err := strconv.Atoi(result.Scores.TotalScore.Away) +// if err != nil { +// return "", err +// } -// GetNFLWinner determines the winner of an NFL game -func GetNFLWinner(result *NFLResultResponse) (string, error) { - homeScore, err := strconv.Atoi(result.Scores.TotalScore.Home) - if err != nil { - return "", err - } - awayScore, err := strconv.Atoi(result.Scores.TotalScore.Away) - if err != nil { - return "", err - } +// if homeScore > awayScore { +// return result.Home.Name, nil +// } else if awayScore > homeScore { +// return result.Away.Name, nil +// } +// return "Draw", nil +// } - if homeScore > awayScore { - return result.Home.Name, nil - } else if awayScore > homeScore { - return result.Away.Name, nil - } - return "Draw", nil -} +// // GetBaseballWinner determines the winner of a Baseball game +// func GetBaseballWinner(result *BaseballResultResponse) (string, error) { +// homeScore, err := strconv.Atoi(result.Scores.TotalScore.Home) +// if err != nil { +// return "", err +// } +// awayScore, err := strconv.Atoi(result.Scores.TotalScore.Away) +// if err != nil { +// return "", err +// } -// GetRugbyWinner determines the winner of a Rugby game -func GetRugbyWinner(result *RugbyResultResponse) (string, error) { - homeScore, err := strconv.Atoi(result.Scores.TotalScore.Home) - if err != nil { - return "", err - } - awayScore, err := strconv.Atoi(result.Scores.TotalScore.Away) - if err != nil { - return "", err - } +// if homeScore > awayScore { +// return result.Home.Name, nil +// } else if awayScore > homeScore { +// return result.Away.Name, nil +// } +// return "Draw", nil +// } - if homeScore > awayScore { - return result.Home.Name, nil - } else if awayScore > homeScore { - return result.Away.Name, nil - } - return "Draw", nil -} +// // FormatNFLScore formats the NFL score in a readable format +// func FormatNFLScore(result *NFLResultResponse) string { +// return strings.Join([]string{ +// result.Home.Name + " " + result.Scores.TotalScore.Home, +// result.Away.Name + " " + result.Scores.TotalScore.Away, +// }, " - ") +// } -// GetBaseballWinner determines the winner of a Baseball game -func GetBaseballWinner(result *BaseballResultResponse) (string, error) { - homeScore, err := strconv.Atoi(result.Scores.TotalScore.Home) - if err != nil { - return "", err - } - awayScore, err := strconv.Atoi(result.Scores.TotalScore.Away) - if err != nil { - return "", err - } +// // FormatRugbyScore formats the Rugby score in a readable format +// func FormatRugbyScore(result *RugbyResultResponse) string { +// return strings.Join([]string{ +// result.Home.Name + " " + result.Scores.TotalScore.Home, +// result.Away.Name + " " + result.Scores.TotalScore.Away, +// }, " - ") +// } - if homeScore > awayScore { - return result.Home.Name, nil - } else if awayScore > homeScore { - return result.Away.Name, nil - } - return "Draw", nil -} - -// FormatNFLScore formats the NFL score in a readable format -func FormatNFLScore(result *NFLResultResponse) string { - return strings.Join([]string{ - result.Home.Name + " " + result.Scores.TotalScore.Home, - result.Away.Name + " " + result.Scores.TotalScore.Away, - }, " - ") -} - -// FormatRugbyScore formats the Rugby score in a readable format -func FormatRugbyScore(result *RugbyResultResponse) string { - return strings.Join([]string{ - result.Home.Name + " " + result.Scores.TotalScore.Home, - result.Away.Name + " " + result.Scores.TotalScore.Away, - }, " - ") -} - -// FormatBaseballScore formats the Baseball score in a readable format -func FormatBaseballScore(result *BaseballResultResponse) string { - return strings.Join([]string{ - result.Home.Name + " " + result.Scores.TotalScore.Home, - result.Away.Name + " " + result.Scores.TotalScore.Away, - }, " - ") -} +// // FormatBaseballScore formats the Baseball score in a readable format +// func FormatBaseballScore(result *BaseballResultResponse) string { +// return strings.Join([]string{ +// result.Home.Name + " " + result.Scores.TotalScore.Home, +// result.Away.Name + " " + result.Scores.TotalScore.Away, +// }, " - ") +// } diff --git a/internal/domain/transaction.go b/internal/domain/transaction.go index 6e4668e..427ec81 100644 --- a/internal/domain/transaction.go +++ b/internal/domain/transaction.go @@ -47,6 +47,12 @@ type Transaction struct { UpdatedAt time.Time CreatedAt time.Time } + +type TransactionFilter struct { + CompanyID ValidInt64 + BranchID ValidInt64 + CashierID ValidInt64 +} type CreateTransaction struct { Amount Currency BranchID int64 diff --git a/internal/repository/bet.go b/internal/repository/bet.go index 24fe5b8..28ea2ff 100644 --- a/internal/repository/bet.go +++ b/internal/repository/bet.go @@ -22,6 +22,10 @@ func convertDBBet(bet dbgen.Bet) domain.Bet { Value: bet.BranchID.Int64, Valid: bet.BranchID.Valid, }, + CompanyID: domain.ValidInt64{ + Value: bet.CompanyID.Int64, + Valid: bet.CompanyID.Valid, + }, UserID: domain.ValidInt64{ Value: bet.UserID.Int64, Valid: bet.UserID.Valid, @@ -111,6 +115,7 @@ func convertCreateBet(bet domain.CreateBet) dbgen.CreateBetParams { Status: int32(bet.Status), FullName: bet.FullName, PhoneNumber: bet.PhoneNumber, + BranchID: pgtype.Int8{ Int64: bet.BranchID.Value, Valid: bet.BranchID.Valid, @@ -168,8 +173,21 @@ func (s *Store) GetBetByCashoutID(ctx context.Context, id string) (domain.GetBet return convertDBBetWithOutcomes(bet), nil } -func (s *Store) GetAllBets(ctx context.Context) ([]domain.GetBet, error) { - bets, err := s.queries.GetAllBets(ctx) +func (s *Store) GetAllBets(ctx context.Context, filter domain.BetFilter) ([]domain.GetBet, error) { + bets, err := s.queries.GetAllBets(ctx, dbgen.GetAllBetsParams{ + BranchID: pgtype.Int8{ + Int64: filter.BranchID.Value, + Valid: filter.BranchID.Valid, + }, + CompanyID: pgtype.Int8{ + Int64: filter.CompanyID.Value, + Valid: filter.CompanyID.Valid, + }, + UserID: pgtype.Int8{ + Int64: filter.UserID.Value, + Valid: filter.UserID.Valid, + }, + }) if err != nil { return nil, err } diff --git a/internal/repository/transaction.go b/internal/repository/transaction.go index da53fc3..dd38797 100644 --- a/internal/repository/transaction.go +++ b/internal/repository/transaction.go @@ -84,8 +84,21 @@ func (s *Store) GetTransactionByID(ctx context.Context, id int64) (domain.Transa return convertDBTransaction(transaction), nil } -func (s *Store) GetAllTransactions(ctx context.Context) ([]domain.Transaction, error) { - transaction, err := s.queries.GetAllTransactions(ctx) +func (s *Store) GetAllTransactions(ctx context.Context, filter domain.TransactionFilter) ([]domain.Transaction, error) { + transaction, err := s.queries.GetAllTransactions(ctx, dbgen.GetAllTransactionsParams{ + BranchID: pgtype.Int8{ + Int64: filter.BranchID.Value, + Valid: filter.BranchID.Valid, + }, + CompanyID: pgtype.Int8{ + Int64: filter.CompanyID.Value, + Valid: filter.CompanyID.Valid, + }, + CashierID: pgtype.Int8{ + Int64: filter.CashierID.Value, + Valid: filter.CashierID.Valid, + }, + }) if err != nil { return nil, err diff --git a/internal/services/bet/port.go b/internal/services/bet/port.go index 452083a..358bdee 100644 --- a/internal/services/bet/port.go +++ b/internal/services/bet/port.go @@ -11,7 +11,7 @@ type BetStore interface { CreateBetOutcome(ctx context.Context, outcomes []domain.CreateBetOutcome) (int64, error) GetBetByCashoutID(ctx context.Context, id string) (domain.GetBet, error) GetBetByID(ctx context.Context, id int64) (domain.GetBet, error) - GetAllBets(ctx context.Context) ([]domain.GetBet, error) + GetAllBets(ctx context.Context, filter domain.BetFilter) ([]domain.GetBet, error) GetBetByBranchID(ctx context.Context, BranchID int64) ([]domain.GetBet, error) GetBetByUserID(ctx context.Context, UserID int64) ([]domain.GetBet, error) GetBetOutcomeByEventID(ctx context.Context, eventID int64) ([]domain.BetOutcome, error) diff --git a/internal/services/bet/service.go b/internal/services/bet/service.go index 65af3d7..470b9de 100644 --- a/internal/services/bet/service.go +++ b/internal/services/bet/service.go @@ -197,6 +197,11 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID Value: branch.ID, Valid: true, } + + newBet.CompanyID = domain.ValidInt64{ + Value: branch.CompanyID, + Valid: true, + } newBet.UserID = domain.ValidInt64{ Value: userID, Valid: true, @@ -227,6 +232,10 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID Value: branch.ID, Valid: true, } + newBet.CompanyID = domain.ValidInt64{ + Value: branch.CompanyID, + Valid: true, + } newBet.UserID = domain.ValidInt64{ Value: userID, Valid: true, @@ -483,8 +492,8 @@ func (s *Service) GetBetByID(ctx context.Context, id int64) (domain.GetBet, erro func (s *Service) GetBetByCashoutID(ctx context.Context, id string) (domain.GetBet, error) { return s.betStore.GetBetByCashoutID(ctx, id) } -func (s *Service) GetAllBets(ctx context.Context) ([]domain.GetBet, error) { - return s.betStore.GetAllBets(ctx) +func (s *Service) GetAllBets(ctx context.Context, filter domain.BetFilter) ([]domain.GetBet, error) { + return s.betStore.GetAllBets(ctx, filter) } func (s *Service) GetBetByBranchID(ctx context.Context, branchID int64) ([]domain.GetBet, error) { @@ -500,6 +509,41 @@ func (s *Service) UpdateCashOut(ctx context.Context, id int64, cashedOut bool) e } func (s *Service) UpdateStatus(ctx context.Context, id int64, status domain.OutcomeStatus) error { + + bet, err := s.GetBetByID(ctx, id) + if err != nil { + s.logger.Error("Failed to update bet status. Invalid bet id") + return err + } + + if bet.IsShopBet || + status == domain.OUTCOME_STATUS_ERROR || + status == domain.OUTCOME_STATUS_PENDING || + status == domain.OUTCOME_STATUS_LOSS { + return s.betStore.UpdateStatus(ctx, id, status) + } + + customerWallet, err := s.walletSvc.GetCustomerWallet(ctx, id) + if err != nil { + s.logger.Error("Failed to update bet status. Invalid customer wallet id") + return err + } + + var amount domain.Currency + if status == domain.OUTCOME_STATUS_WIN { + amount = domain.CalculateWinnings(bet.Amount, bet.TotalOdds) + } else if status == domain.OUTCOME_STATUS_HALF { + amount = (domain.CalculateWinnings(bet.Amount, bet.TotalOdds)) / 2 + } else { + amount = bet.Amount + } + err = s.walletSvc.AddToWallet(ctx, customerWallet.RegularID, amount) + + if err != nil { + s.logger.Error("Failed to update bet status. Failed to update user wallet") + return err + } + return s.betStore.UpdateStatus(ctx, id, status) } diff --git a/internal/services/event/service.go b/internal/services/event/service.go index b24a8ec..4959b15 100644 --- a/internal/services/event/service.go +++ b/internal/services/event/service.go @@ -7,7 +7,6 @@ import ( "io" "log" "net/http" - "slices" "strconv" "sync" "time" @@ -189,8 +188,8 @@ func (s *service) FetchUpcomingEvents(ctx context.Context) error { source string }{ {"https://api.b365api.com/v1/bet365/upcoming?sport_id=%d&token=%s&page=%d", "bet365"}, - {"https://api.b365api.com/v1/betfair/sb/upcoming?sport_id=%d&token=%s&page=%d", "betfair"}, - {"https://api.b365api.com/v1/1xbet/upcoming?sport_id=%d&token=%s&page=%d", "1xbet"}, + // {"https://api.b365api.com/v1/betfair/sb/upcoming?sport_id=%d&token=%s&page=%d", "betfair"}, + // {"https://api.b365api.com/v1/1xbet/upcoming?sport_id=%d&token=%s&page=%d", "1xbet"}, } for _, url := range urls { @@ -207,16 +206,23 @@ func (s *service) FetchUpcomingEvents(ctx context.Context) error { } func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, url, source string) { - sportIDs := []int{1, 18, 17} - var totalPages int = 1 - var page int = 0 - var limit int = 100 - var count int = 0 + sportIDs := []int{1, 18, 17, 3, 83, 15, 12, 19, 8, 16, 91} + // TODO: Add the league skipping again when we have dynamic leagues + // b, err := os.OpenFile("logs/skipped_leagues.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + // if err != nil { + // log.Printf("❌ Failed to open leagues file %v", err) + // return + // } for _, sportID := range sportIDs { + var totalPages int = 1 + var page int = 0 + var limit int = 100 + var count int = 0 + log.Printf("Sport ID %d", sportID) for page <= totalPages { page = page + 1 url := fmt.Sprintf("https://api.b365api.com/v1/bet365/upcoming?sport_id=%d&token=%s&page=%d", sportID, s.token, page) - log.Printf("📡 Fetching data for event data page %d", page) + log.Printf("📡 Fetching data for sport %d at page %d", sportID, page) resp, err := http.Get(url) if err != nil { log.Printf("❌ Failed to fetch event data for page %d: %v", page, err) @@ -240,17 +246,21 @@ func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, url, sour // continue // } - leagueID, err := strconv.ParseInt(ev.League.ID, 10, 64) - if err != nil { - log.Printf("❌ Invalid league id, leagueID %v", ev.League.ID) - continue - } + // leagueID, err := strconv.ParseInt(ev.League.ID, 10, 64) + // if err != nil { + // log.Printf("❌ Invalid league id, leagueID %v", ev.League.ID) + // continue + // } - if !slices.Contains(domain.SupportedLeagues, leagueID) { - // fmt.Printf("⚠️ Skipping league %s (%d) as it is not supported\n", ev.League.Name, leagueID) - skippedLeague = append(skippedLeague, ev.League.Name) - continue - } + // if !slices.Contains(domain.SupportedLeagues, leagueID) { + // // fmt.Printf("⚠️ Skipping league %s (%d) as it is not supported\n", ev.League.Name, leagueID) + // _, err = fmt.Fprintf(b, "Skipped league %s (%d) in sport %d\n", ev.League.Name, leagueID, sportID) + // if err != nil { + // fmt.Printf(" Error while logging skipped league") + // } + // skippedLeague = append(skippedLeague, ev.League.Name) + // continue + // } event := domain.UpcomingEvent{ ID: ev.ID, @@ -282,7 +292,7 @@ func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, url, sour } log.Printf("⚠️ Skipped leagues %v", len(skippedLeague)) - // log.Printf("⚠️ Total pages %v", data.Pager.Total) + log.Printf("⚠️ Total pages %v", data.Pager.Total/data.Pager.PerPage) totalPages = data.Pager.Total / data.Pager.PerPage if count >= limit { diff --git a/internal/services/odds/service.go b/internal/services/odds/service.go index 36f3a8a..335c2d0 100644 --- a/internal/services/odds/service.go +++ b/internal/services/odds/service.go @@ -98,6 +98,46 @@ func (s *ServiceImpl) FetchNonLiveOdds(ctx context.Context) error { s.logger.Error("Error while inserting ice hockey odd") errs = append(errs, err) } + case domain.CRICKET: + if err := s.parseCricket(ctx, oddsData.Results[0]); err != nil { + s.logger.Error("Error while inserting cricket odd") + errs = append(errs, err) + } + case domain.VOLLEYBALL: + if err := s.parseVolleyball(ctx, oddsData.Results[0]); err != nil { + s.logger.Error("Error while inserting volleyball odd") + errs = append(errs, err) + } + case domain.DARTS: + if err := s.parseDarts(ctx, oddsData.Results[0]); err != nil { + s.logger.Error("Error while inserting darts odd") + errs = append(errs, err) + } + case domain.FUTSAL: + if err := s.parseFutsal(ctx, oddsData.Results[0]); err != nil { + s.logger.Error("Error while inserting futsal odd") + errs = append(errs, err) + } + case domain.AMERICAN_FOOTBALL: + if err := s.parseAmericanFootball(ctx, oddsData.Results[0]); err != nil { + s.logger.Error("Error while inserting american football odd") + errs = append(errs, err) + } + case domain.RUGBY_LEAGUE: + if err := s.parseRugbyLeague(ctx, oddsData.Results[0]); err != nil { + s.logger.Error("Error while inserting rugby league odd") + errs = append(errs, err) + } + case domain.RUGBY_UNION: + if err := s.parseRugbyUnion(ctx, oddsData.Results[0]); err != nil { + s.logger.Error("Error while inserting rugby union odd") + errs = append(errs, err) + } + case domain.BASEBALL: + if err := s.parseBaseball(ctx, oddsData.Results[0]); err != nil { + s.logger.Error("Error while inserting baseball odd") + errs = append(errs, err) + } } // result := oddsData.Results[0] @@ -223,6 +263,332 @@ func (s *ServiceImpl) parseIceHockey(ctx context.Context, res json.RawMessage) e return nil } +func (s *ServiceImpl) parseCricket(ctx context.Context, res json.RawMessage) error { + var cricketRes domain.CricketOddsResponse + if err := json.Unmarshal(res, &cricketRes); err != nil { + s.logger.Error("Failed to unmarshal ice hockey result", "error", err) + return err + } + if cricketRes.EventID == "" && cricketRes.FI == "" { + s.logger.Error("Skipping result with no valid Event ID") + return fmt.Errorf("Skipping result with no valid Event ID") + } + + sections := map[string]domain.OddsSection{ + "1st_over": cricketRes.Main, + "innings_1": cricketRes.First_Innings, + "main": cricketRes.Main, + "match": cricketRes.Match, + "player": cricketRes.Player, + "team": cricketRes.Team, + } + + var errs []error + + for oddCategory, section := range sections { + if err := s.storeSection(ctx, cricketRes.EventID, cricketRes.FI, oddCategory, section); err != nil { + s.logger.Error("Skipping result with no valid Event ID") + errs = append(errs, err) + continue + } + } + + for _, section := range cricketRes.Others { + if err := s.storeSection(ctx, cricketRes.EventID, cricketRes.FI, "others", section); err != nil { + s.logger.Error("Skipping result with no valid Event ID") + errs = append(errs, err) + continue + } + } + + if len(errs) > 0 { + return errors.Join(errs...) + } + + return nil +} + +func (s *ServiceImpl) parseVolleyball(ctx context.Context, res json.RawMessage) error { + var volleyballRes domain.VolleyballOddsResponse + if err := json.Unmarshal(res, &volleyballRes); err != nil { + s.logger.Error("Failed to unmarshal ice hockey result", "error", err) + return err + } + if volleyballRes.EventID == "" && volleyballRes.FI == "" { + s.logger.Error("Skipping result with no valid Event ID") + return fmt.Errorf("Skipping result with no valid Event ID") + } + sections := map[string]domain.OddsSection{ + "main": volleyballRes.Main, + } + + var errs []error + + for oddCategory, section := range sections { + if err := s.storeSection(ctx, volleyballRes.EventID, volleyballRes.FI, oddCategory, section); err != nil { + s.logger.Error("Skipping result with no valid Event ID") + errs = append(errs, err) + continue + } + } + + for _, section := range volleyballRes.Others { + if err := s.storeSection(ctx, volleyballRes.EventID, volleyballRes.FI, "others", section); err != nil { + s.logger.Error("Skipping result with no valid Event ID") + errs = append(errs, err) + continue + } + } + + if len(errs) > 0 { + return errors.Join(errs...) + } + + return nil +} + +func (s *ServiceImpl) parseDarts(ctx context.Context, res json.RawMessage) error { + var dartsRes domain.DartsOddsResponse + if err := json.Unmarshal(res, &dartsRes); err != nil { + s.logger.Error("Failed to unmarshal ice hockey result", "error", err) + return err + } + if dartsRes.EventID == "" && dartsRes.FI == "" { + s.logger.Error("Skipping result with no valid Event ID") + return fmt.Errorf("Skipping result with no valid Event ID") + } + sections := map[string]domain.OddsSection{ + "180s": dartsRes.OneEightys, + "extra": dartsRes.Extra, + "leg": dartsRes.Leg, + "main": dartsRes.Main, + } + + var errs []error + + for oddCategory, section := range sections { + if err := s.storeSection(ctx, dartsRes.EventID, dartsRes.FI, oddCategory, section); err != nil { + s.logger.Error("Skipping result with no valid Event ID") + errs = append(errs, err) + continue + } + } + + for _, section := range dartsRes.Others { + if err := s.storeSection(ctx, dartsRes.EventID, dartsRes.FI, "others", section); err != nil { + s.logger.Error("Skipping result with no valid Event ID") + errs = append(errs, err) + continue + } + } + + if len(errs) > 0 { + return errors.Join(errs...) + } + + return nil +} + +func (s *ServiceImpl) parseFutsal(ctx context.Context, res json.RawMessage) error { + var futsalRes domain.FutsalOddsResponse + if err := json.Unmarshal(res, &futsalRes); err != nil { + s.logger.Error("Failed to unmarshal ice hockey result", "error", err) + return err + } + if futsalRes.EventID == "" && futsalRes.FI == "" { + s.logger.Error("Skipping result with no valid Event ID") + return fmt.Errorf("Skipping result with no valid Event ID") + } + sections := map[string]domain.OddsSection{ + "main": futsalRes.Main, + "score": futsalRes.Score, + } + + var errs []error + + for oddCategory, section := range sections { + if err := s.storeSection(ctx, futsalRes.EventID, futsalRes.FI, oddCategory, section); err != nil { + s.logger.Error("Skipping result with no valid Event ID") + errs = append(errs, err) + continue + } + } + + for _, section := range futsalRes.Others { + if err := s.storeSection(ctx, futsalRes.EventID, futsalRes.FI, "others", section); err != nil { + s.logger.Error("Skipping result with no valid Event ID") + errs = append(errs, err) + continue + } + } + + if len(errs) > 0 { + return errors.Join(errs...) + } + + return nil +} + +func (s *ServiceImpl) parseAmericanFootball(ctx context.Context, res json.RawMessage) error { + var americanFootballRes domain.AmericanFootballOddsResponse + if err := json.Unmarshal(res, &americanFootballRes); err != nil { + s.logger.Error("Failed to unmarshal ice hockey result", "error", err) + return err + } + if americanFootballRes.EventID == "" && americanFootballRes.FI == "" { + s.logger.Error("Skipping result with no valid Event ID") + return fmt.Errorf("Skipping result with no valid Event ID") + } + sections := map[string]domain.OddsSection{ + "half_props": americanFootballRes.HalfProps, + "main": americanFootballRes.Main, + "quarter_props": americanFootballRes.QuarterProps, + } + + var errs []error + + for oddCategory, section := range sections { + if err := s.storeSection(ctx, americanFootballRes.EventID, americanFootballRes.FI, oddCategory, section); err != nil { + s.logger.Error("Skipping result with no valid Event ID") + errs = append(errs, err) + continue + } + } + + for _, section := range americanFootballRes.Others { + if err := s.storeSection(ctx, americanFootballRes.EventID, americanFootballRes.FI, "others", section); err != nil { + s.logger.Error("Skipping result with no valid Event ID") + errs = append(errs, err) + continue + } + } + + if len(errs) > 0 { + return errors.Join(errs...) + } + + return nil +} + +func (s *ServiceImpl) parseRugbyLeague(ctx context.Context, res json.RawMessage) error { + var rugbyLeagueRes domain.RugbyLeagueOddsResponse + if err := json.Unmarshal(res, &rugbyLeagueRes); err != nil { + s.logger.Error("Failed to unmarshal ice hockey result", "error", err) + return err + } + if rugbyLeagueRes.EventID == "" && rugbyLeagueRes.FI == "" { + s.logger.Error("Skipping result with no valid Event ID") + return fmt.Errorf("Skipping result with no valid Event ID") + } + sections := map[string]domain.OddsSection{ + "10minute": rugbyLeagueRes.TenMinute, + "main": rugbyLeagueRes.Main, + "main_2": rugbyLeagueRes.Main2, + "player": rugbyLeagueRes.Player, + "Score": rugbyLeagueRes.Score, + "Team": rugbyLeagueRes.Team, + } + + var errs []error + + for oddCategory, section := range sections { + if err := s.storeSection(ctx, rugbyLeagueRes.EventID, rugbyLeagueRes.FI, oddCategory, section); err != nil { + s.logger.Error("Skipping result with no valid Event ID") + errs = append(errs, err) + continue + } + } + + for _, section := range rugbyLeagueRes.Others { + if err := s.storeSection(ctx, rugbyLeagueRes.EventID, rugbyLeagueRes.FI, "others", section); err != nil { + s.logger.Error("Skipping result with no valid Event ID") + errs = append(errs, err) + continue + } + } + + if len(errs) > 0 { + return errors.Join(errs...) + } + + return nil +} + +func (s *ServiceImpl) parseRugbyUnion(ctx context.Context, res json.RawMessage) error { + var rugbyUnionRes domain.RugbyUnionOddsResponse + if err := json.Unmarshal(res, &rugbyUnionRes); err != nil { + s.logger.Error("Failed to unmarshal ice hockey result", "error", err) + return err + } + if rugbyUnionRes.EventID == "" && rugbyUnionRes.FI == "" { + s.logger.Error("Skipping result with no valid Event ID") + return fmt.Errorf("Skipping result with no valid Event ID") + } + sections := map[string]domain.OddsSection{ + "main": rugbyUnionRes.Main, + "main_2": rugbyUnionRes.Main2, + "player": rugbyUnionRes.Player, + "Score": rugbyUnionRes.Score, + "Team": rugbyUnionRes.Team, + } + + var errs []error + + for oddCategory, section := range sections { + if err := s.storeSection(ctx, rugbyUnionRes.EventID, rugbyUnionRes.FI, oddCategory, section); err != nil { + s.logger.Error("Skipping result with no valid Event ID") + errs = append(errs, err) + continue + } + } + + for _, section := range rugbyUnionRes.Others { + if err := s.storeSection(ctx, rugbyUnionRes.EventID, rugbyUnionRes.FI, "others", section); err != nil { + s.logger.Error("Skipping result with no valid Event ID") + errs = append(errs, err) + continue + } + } + + if len(errs) > 0 { + return errors.Join(errs...) + } + + return nil +} + +func (s *ServiceImpl) parseBaseball(ctx context.Context, res json.RawMessage) error { + var baseballRes domain.BaseballOddsResponse + if err := json.Unmarshal(res, &baseballRes); err != nil { + s.logger.Error("Failed to unmarshal ice hockey result", "error", err) + return err + } + if baseballRes.EventID == "" && baseballRes.FI == "" { + s.logger.Error("Skipping result with no valid Event ID") + return fmt.Errorf("Skipping result with no valid Event ID") + } + sections := map[string]domain.OddsSection{ + "main": baseballRes.Main, + "mani_props": baseballRes.MainProps, + } + + var errs []error + + for oddCategory, section := range sections { + if err := s.storeSection(ctx, baseballRes.EventID, baseballRes.FI, oddCategory, section); err != nil { + s.logger.Error("Skipping result with no valid Event ID") + errs = append(errs, err) + continue + } + } + + if len(errs) > 0 { + return errors.Join(errs...) + } + + return nil +} + func (s *ServiceImpl) storeSection(ctx context.Context, eventID, fi, sectionName string, section domain.OddsSection) error { if len(section.Sp) == 0 { return nil diff --git a/internal/services/result/eval.go b/internal/services/result/eval.go index 218659c..7352812 100644 --- a/internal/services/result/eval.go +++ b/internal/services/result/eval.go @@ -429,7 +429,7 @@ func evaluateGameLines(outcome domain.BetOutcome, score struct{ Home, Away int } case "Money Line": return evaluateMoneyLine(outcome, score) - case "Spread", "Line": + case "Spread", "Line", "Run Line": // Since Spread betting is essentially the same thing return evaluateAsianHandicap(outcome, score) case "Total": @@ -985,36 +985,6 @@ func evaluateTiedAfterRegulation(outcome domain.BetOutcome, scores []struct{ Hom return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid oddname: %s", outcome.OddName) } -func evaluateRugbyOutcome(outcome domain.BetOutcome, result *domain.RugbyResultResponse) (domain.OutcomeStatus, error) { - finalScore := parseSS(result.SS) - - switch outcome.MarketName { - case "Money Line": - return evaluateRugbyMoneyLine(outcome, finalScore) - case "Spread": - return evaluateRugbySpread(outcome, finalScore) - case "Total Points": - return evaluateRugbyTotalPoints(outcome, finalScore) - default: - return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("unsupported rugby market: %s", outcome.MarketName) - } -} - -func evaluateBaseballOutcome(outcome domain.BetOutcome, result *domain.BaseballResultResponse) (domain.OutcomeStatus, error) { - finalScore := parseSS(result.SS) - - switch outcome.MarketName { - case "Money Line": - return evaluateBaseballMoneyLine(outcome, finalScore) - case "Spread": - return evaluateBaseballSpread(outcome, finalScore) - case "Total Runs": - return evaluateBaseballTotalRuns(outcome, finalScore) - default: - return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("unsupported baseball market: %s", outcome.MarketName) - } -} - func evaluateVolleyballGamelines(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) { switch outcome.OddName { case "Total": @@ -1023,3 +993,16 @@ func evaluateVolleyballGamelines(outcome domain.BetOutcome, score struct{ Home, return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("invalid odd name: %s", outcome.OddName) } } + +func evaluateGameBettingTwoWay(outcome domain.BetOutcome, score struct{ Home, Away int }) (domain.OutcomeStatus, error) { + switch outcome.OddName { + case "Handicap": + return evaluateAsianHandicap(outcome, score) + case "Total": + return evaluateTotalOverUnder(outcome, score) + case "To Win": + return evaluateFullTimeResult(outcome, score) + default: + return domain.OUTCOME_STATUS_ERROR, fmt.Errorf("invalid odd name: %s", outcome.OddName) + } +} diff --git a/internal/services/result/service.go b/internal/services/result/service.go index 02fabaa..acc996e 100644 --- a/internal/services/result/service.go +++ b/internal/services/result/service.go @@ -161,71 +161,6 @@ func (s *Service) FetchAndProcessResults(ctx context.Context) error { return nil } -// func (s *Service) FetchAndStoreResult(ctx context.Context, eventID string) error { -// url := fmt.Sprintf("https://api.b365api.com/v1/bet365/result?token=%s&event_id=%s", s.config.Bet365Token, eventID) - -// res, err := s.client.Get(url) -// if err != nil { -// s.logger.Error("Failed to fetch result", "event_id", eventID, "error", err) -// return fmt.Errorf("failed to fetch result: %w", err) -// } -// defer res.Body.Close() - -// if res.StatusCode != http.StatusOK { -// s.logger.Error("Unexpected status code", "event_id", eventID, "status_code", res.StatusCode) -// return fmt.Errorf("unexpected status code: %d", res.StatusCode) -// } - -// var apiResp domain.BaseResultResponse -// if err := json.NewDecoder(res.Body).Decode(&apiResp); err != nil { -// s.logger.Error("Failed to decode result", "event_id", eventID, "error", err) -// return fmt.Errorf("failed to decode result: %w", err) -// } - -// if apiResp.Success != 1 || len(apiResp.Results) == 0 { -// s.logger.Error("Invalid API response", "event_id", eventID) -// return fmt.Errorf("no result returned from API") -// } - -// r := apiResp.Results[0] -// if r.TimeStatus != "3" { -// s.logger.Warn("Match not yet completed", "event_id", eventID) -// return fmt.Errorf("match not yet completed") -// } - -// eventIDInt, err := strconv.ParseInt(eventID, 10, 64) -// if err != nil { -// s.logger.Error("Failed to parse event_id", "event_id", eventID, "error", err) -// return fmt.Errorf("failed to parse event_id: %w", err) -// } - -// halfScore := "" -// if r.Scores.FirstHalf.Home != "" { -// halfScore = fmt.Sprintf("%s-%s", r.Scores.FirstHalf.Home, r.Scores.FirstHalf.Away) -// } - -// result := domain.Result{ -// EventID: eventIDInt, -// Status: domain.OUTCOME_STATUS_PENDING, -// Score: r.SS, -// FullTimeScore: r.SS, -// HalfTimeScore: halfScore, -// SS: r.SS, -// Scores: make(map[string]domain.Score), -// } -// for k, v := range map[string]domain.Score{ -// "1": r.Scores.FirstHalf, -// "2": r.Scores.SecondHalf, -// } { -// result.Scores[k] = domain.Score{ -// Home: v.Home, -// Away: v.Away, -// } -// } - -// return s.repo.InsertResult(ctx, result) -// } - func (s *Service) fetchResult(ctx context.Context, eventID, oddID, marketID, sportID int64, outcome domain.BetOutcome) (domain.CreateResult, error) { // url := fmt.Sprintf("https://api.b365api.com/v1/bet365/result?token=%s&event_id=%d", s.config.Bet365Token, eventID) url := fmt.Sprintf("https://api.b365api.com/v1/event/view?token=%s&event_id=%d", s.config.Bet365Token, eventID) @@ -598,21 +533,7 @@ func (s *Service) parseNFL(resultRes json.RawMessage, eventID, oddID, marketID i return domain.CreateResult{}, fmt.Errorf("match not yet completed") } - finalScore := parseSS(nflResp.SS) - - var status domain.OutcomeStatus - var err error - - switch outcome.MarketName { - case "Money Line": - status, err = evaluateNFLMoneyLine(outcome, finalScore) - case "Spread": - status, err = evaluateNFLSpread(outcome, finalScore) - case "Total Points": - status, err = evaluateNFLTotalPoints(outcome, finalScore) - default: - return domain.CreateResult{}, fmt.Errorf("unsupported market: %s", outcome.MarketName) - } + status, err := s.evaluateNFLOutcome(outcome, nflResp) if err != nil { s.logger.Error("Failed to evaluate outcome", "event_id", eventID, "market_id", marketID, "error", err) @@ -639,7 +560,7 @@ func (s *Service) parseRugbyUnion(resultRes json.RawMessage, eventID, oddID, mar s.logger.Warn("Match not yet completed", "event_id", eventID) return domain.CreateResult{}, fmt.Errorf("match not yet completed") } - status, err := evaluateRugbyOutcome(outcome, &rugbyResp) + status, err := s.evaluateRugbyOutcome(outcome, rugbyResp) if err != nil { s.logger.Error("Failed to evaluate outcome", "event_id", eventID, "market_id", marketID, "error", err) return domain.CreateResult{}, err @@ -664,7 +585,7 @@ func (s *Service) parseRugbyLeague(resultRes json.RawMessage, eventID, oddID, ma s.logger.Warn("Match not yet completed", "event_id", eventID) return domain.CreateResult{}, fmt.Errorf("match not yet completed") } - status, err := evaluateRugbyOutcome(outcome, &rugbyResp) + status, err := s.evaluateRugbyOutcome(outcome, rugbyResp) if err != nil { s.logger.Error("Failed to evaluate outcome", "event_id", eventID, "market_id", marketID, "error", err) return domain.CreateResult{}, err @@ -689,7 +610,7 @@ func (s *Service) parseBaseball(resultRes json.RawMessage, eventID, oddID, marke s.logger.Warn("Match not yet completed", "event_id", eventID) return domain.CreateResult{}, fmt.Errorf("match not yet completed") } - status, err := evaluateBaseballOutcome(outcome, &baseballResp) + status, err := s.evaluateBaseballOutcome(outcome, baseballResp) if err != nil { s.logger.Error("Failed to evaluate outcome", "event_id", eventID, "market_id", marketID, "error", err) return domain.CreateResult{}, err @@ -986,21 +907,51 @@ func (s *Service) evaluateFutsalOutcome(outcome domain.BetOutcome, res domain.Fu return domain.OUTCOME_STATUS_PENDING, nil } -func (s *Service) EvaluateNFLOutcome(outcome domain.BetOutcome, finalScore struct{ Home, Away int }) (domain.OutcomeStatus, error) { +func (s *Service) evaluateNFLOutcome(outcome domain.BetOutcome, res domain.NFLResultResponse) (domain.OutcomeStatus, error) { if !domain.SupportedMarkets[outcome.MarketID] { s.logger.Warn("Unsupported market type", "market_name", outcome.MarketName) return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("unsupported market type: %s", outcome.MarketName) } + finalScore := parseSS(res.SS) + switch outcome.MarketID { - case int64(domain.AMERICAN_FOOTBALL_MONEY_LINE): - return evaluateNFLMoneyLine(outcome, finalScore) - case int64(domain.AMERICAN_FOOTBALL_SPREAD): - return evaluateNFLSpread(outcome, finalScore) - case int64(domain.AMERICAN_FOOTBALL_TOTAL_POINTS): - return evaluateNFLTotalPoints(outcome, finalScore) + case int64(domain.AMERICAN_FOOTBALL_GAME_LINES): + return evaluateGameLines(outcome, finalScore) default: s.logger.Warn("Market type not implemented", "market_name", outcome.MarketName) return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("market type not implemented: %s", outcome.MarketName) } } + +func (s *Service) evaluateRugbyOutcome(outcome domain.BetOutcome, result domain.RugbyResultResponse) (domain.OutcomeStatus, error) { + if !domain.SupportedMarkets[outcome.MarketID] { + s.logger.Warn("Unsupported market type", "market_name", outcome.MarketName) + return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("unsupported market type: %s", outcome.MarketName) + } + + finalScore := parseSS(result.SS) + + switch outcome.MarketID { + case int64(domain.RUGBY_L_GAME_BETTING_2_WAY): + return evaluateGameBettingTwoWay(outcome, finalScore) + default: + return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("unsupported rugby market: %s", outcome.MarketName) + } +} + +func (s *Service) evaluateBaseballOutcome(outcome domain.BetOutcome, res domain.BaseballResultResponse) (domain.OutcomeStatus, error) { + if !domain.SupportedMarkets[outcome.MarketID] { + s.logger.Warn("Unsupported market type", "market_name", outcome.MarketName) + return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("unsupported market type: %s", outcome.MarketName) + } + + finalScore := parseSS(res.SS) + + switch outcome.MarketID { + case int64(domain.BASEBALL_GAME_LINES): + return evaluateGameLines(outcome, finalScore) + default: + return domain.OUTCOME_STATUS_PENDING, fmt.Errorf("unsupported baseball market: %s", outcome.MarketName) + } +} diff --git a/internal/services/result_checker.go b/internal/services/result_checker.go index 59d4b1c..b16ffe1 100644 --- a/internal/services/result_checker.go +++ b/internal/services/result_checker.go @@ -1,189 +1,189 @@ package services -import ( - "encoding/json" - "fmt" - "time" +// import ( +// "encoding/json" +// "fmt" +// "time" - "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" -) +// "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" +// ) -// ResultCheckerService handles the checking of game results -type ResultCheckerService struct { - // Add any dependencies here (e.g., repositories, external APIs) -} +// // ResultCheckerService handles the checking of game results +// type ResultCheckerService struct { +// // Add any dependencies here (e.g., repositories, external APIs) +// } -// NewResultCheckerService creates a new instance of ResultCheckerService -func NewResultCheckerService() *ResultCheckerService { - return &ResultCheckerService{} -} +// // NewResultCheckerService creates a new instance of ResultCheckerService +// func NewResultCheckerService() *ResultCheckerService { +// return &ResultCheckerService{} +// } -// CheckNFLResult checks the result of an NFL game -func (s *ResultCheckerService) CheckNFLResult(data json.RawMessage) (*domain.Result, error) { - nflResult, err := domain.ParseNFLResult(data) - if err != nil { - return nil, fmt.Errorf("failed to parse NFL result: %w", err) - } +// // CheckNFLResult checks the result of an NFL game +// func (s *ResultCheckerService) CheckNFLResult(data json.RawMessage) (*domain.Result, error) { +// nflResult, err := domain.ParseNFLResult(data) +// if err != nil { +// return nil, fmt.Errorf("failed to parse NFL result: %w", err) +// } - winner, err := domain.GetNFLWinner(nflResult) - if err != nil { - return nil, fmt.Errorf("failed to determine NFL winner: %w", err) - } +// winner, err := domain.GetNFLWinner(nflResult) +// if err != nil { +// return nil, fmt.Errorf("failed to determine NFL winner: %w", err) +// } - score := domain.FormatNFLScore(nflResult) +// score := domain.FormatNFLScore(nflResult) - return &domain.Result{ - Status: determineOutcomeStatus(winner, nflResult.Home.Name, nflResult.Away.Name), - Score: score, - FullTimeScore: score, - SS: nflResult.SS, - Scores: map[string]domain.Score{ - "1": nflResult.Scores.FirstQuarter, - "2": nflResult.Scores.SecondQuarter, - "3": nflResult.Scores.ThirdQuarter, - "4": nflResult.Scores.FourthQuarter, - "5": nflResult.Scores.Overtime, - "7": nflResult.Scores.TotalScore, - }, - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - }, nil -} +// return &domain.Result{ +// Status: determineOutcomeStatus(winner, nflResult.Home.Name, nflResult.Away.Name), +// Score: score, +// FullTimeScore: score, +// SS: nflResult.SS, +// Scores: map[string]domain.Score{ +// "1": nflResult.Scores.FirstQuarter, +// "2": nflResult.Scores.SecondQuarter, +// "3": nflResult.Scores.ThirdQuarter, +// "4": nflResult.Scores.FourthQuarter, +// "5": nflResult.Scores.Overtime, +// "7": nflResult.Scores.TotalScore, +// }, +// CreatedAt: time.Now(), +// UpdatedAt: time.Now(), +// }, nil +// } -// determineOutcomeStatus determines the outcome status based on the winner and teams -func determineOutcomeStatus(winner, homeTeam, awayTeam string) domain.OutcomeStatus { - if winner == "Draw" { - return domain.OUTCOME_STATUS_VOID - } - if winner == homeTeam { - return domain.OUTCOME_STATUS_WIN - } - if winner == awayTeam { - return domain.OUTCOME_STATUS_LOSS - } - return domain.OUTCOME_STATUS_PENDING -} +// // determineOutcomeStatus determines the outcome status based on the winner and teams +// func determineOutcomeStatus(winner, homeTeam, awayTeam string) domain.OutcomeStatus { +// if winner == "Draw" { +// return domain.OUTCOME_STATUS_VOID +// } +// if winner == homeTeam { +// return domain.OUTCOME_STATUS_WIN +// } +// if winner == awayTeam { +// return domain.OUTCOME_STATUS_LOSS +// } +// return domain.OUTCOME_STATUS_PENDING +// } -// CheckRugbyResult checks the result of a Rugby game -func (s *ResultCheckerService) CheckRugbyResult(data json.RawMessage) (*domain.Result, error) { - rugbyResult, err := domain.ParseRugbyResult(data) - if err != nil { - return nil, fmt.Errorf("failed to parse Rugby result: %w", err) - } +// // CheckRugbyResult checks the result of a Rugby game +// func (s *ResultCheckerService) CheckRugbyResult(data json.RawMessage) (*domain.Result, error) { +// rugbyResult, err := domain.ParseRugbyResult(data) +// if err != nil { +// return nil, fmt.Errorf("failed to parse Rugby result: %w", err) +// } - winner, err := domain.GetRugbyWinner(rugbyResult) - if err != nil { - return nil, fmt.Errorf("failed to determine Rugby winner: %w", err) - } +// winner, err := domain.GetRugbyWinner(rugbyResult) +// if err != nil { +// return nil, fmt.Errorf("failed to determine Rugby winner: %w", err) +// } - score := domain.FormatRugbyScore(rugbyResult) +// score := domain.FormatRugbyScore(rugbyResult) - return &domain.Result{ - Status: determineOutcomeStatus(winner, rugbyResult.Home.Name, rugbyResult.Away.Name), - Score: score, - FullTimeScore: score, - SS: rugbyResult.SS, - Scores: map[string]domain.Score{ - "1": rugbyResult.Scores.FirstHalf, - "2": rugbyResult.Scores.SecondHalf, - "7": rugbyResult.Scores.TotalScore, - }, - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - }, nil -} +// return &domain.Result{ +// Status: determineOutcomeStatus(winner, rugbyResult.Home.Name, rugbyResult.Away.Name), +// Score: score, +// FullTimeScore: score, +// SS: rugbyResult.SS, +// Scores: map[string]domain.Score{ +// "1": rugbyResult.Scores.FirstHalf, +// "2": rugbyResult.Scores.SecondHalf, +// "7": rugbyResult.Scores.TotalScore, +// }, +// CreatedAt: time.Now(), +// UpdatedAt: time.Now(), +// }, nil +// } -// CheckBaseballResult checks the result of a Baseball game -func (s *ResultCheckerService) CheckBaseballResult(data json.RawMessage) (*domain.Result, error) { - baseballResult, err := domain.ParseBaseballResult(data) - if err != nil { - return nil, fmt.Errorf("failed to parse Baseball result: %w", err) - } +// // CheckBaseballResult checks the result of a Baseball game +// func (s *ResultCheckerService) CheckBaseballResult(data json.RawMessage) (*domain.Result, error) { +// baseballResult, err := domain.ParseBaseballResult(data) +// if err != nil { +// return nil, fmt.Errorf("failed to parse Baseball result: %w", err) +// } - winner, err := domain.GetBaseballWinner(baseballResult) - if err != nil { - return nil, fmt.Errorf("failed to determine Baseball winner: %w", err) - } +// winner, err := domain.GetBaseballWinner(baseballResult) +// if err != nil { +// return nil, fmt.Errorf("failed to determine Baseball winner: %w", err) +// } - score := domain.FormatBaseballScore(baseballResult) +// score := domain.FormatBaseballScore(baseballResult) - return &domain.Result{ - Status: determineOutcomeStatus(winner, baseballResult.Home.Name, baseballResult.Away.Name), - Score: score, - FullTimeScore: score, - SS: baseballResult.SS, - Scores: map[string]domain.Score{ - "1": baseballResult.Scores.FirstInning, - "2": baseballResult.Scores.SecondInning, - "3": baseballResult.Scores.ThirdInning, - "4": baseballResult.Scores.FourthInning, - "5": baseballResult.Scores.FifthInning, - "6": baseballResult.Scores.SixthInning, - "7": baseballResult.Scores.SeventhInning, - "8": baseballResult.Scores.EighthInning, - "9": baseballResult.Scores.NinthInning, - "10": baseballResult.Scores.ExtraInnings, - "T": baseballResult.Scores.TotalScore, - }, - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - }, nil -} +// return &domain.Result{ +// Status: determineOutcomeStatus(winner, baseballResult.Home.Name, baseballResult.Away.Name), +// Score: score, +// FullTimeScore: score, +// SS: baseballResult.SS, +// Scores: map[string]domain.Score{ +// "1": baseballResult.Scores.FirstInning, +// "2": baseballResult.Scores.SecondInning, +// "3": baseballResult.Scores.ThirdInning, +// "4": baseballResult.Scores.FourthInning, +// "5": baseballResult.Scores.FifthInning, +// "6": baseballResult.Scores.SixthInning, +// "7": baseballResult.Scores.SeventhInning, +// "8": baseballResult.Scores.EighthInning, +// "9": baseballResult.Scores.NinthInning, +// "10": baseballResult.Scores.ExtraInnings, +// "T": baseballResult.Scores.TotalScore, +// }, +// CreatedAt: time.Now(), +// UpdatedAt: time.Now(), +// }, nil +// } -// CheckRugbyUnionResult checks the result of a Rugby Union game -func (s *ResultCheckerService) CheckRugbyUnionResult(data json.RawMessage) (*domain.Result, error) { - rugbyResult, err := domain.ParseRugbyUnionResult(data) - if err != nil { - return nil, fmt.Errorf("failed to parse Rugby Union result: %w", err) - } +// // CheckRugbyUnionResult checks the result of a Rugby Union game +// func (s *ResultCheckerService) CheckRugbyUnionResult(data json.RawMessage) (*domain.Result, error) { +// rugbyResult, err := domain.ParseRugbyUnionResult(data) +// if err != nil { +// return nil, fmt.Errorf("failed to parse Rugby Union result: %w", err) +// } - winner, err := domain.GetRugbyWinner(rugbyResult) - if err != nil { - return nil, fmt.Errorf("failed to determine Rugby Union winner: %w", err) - } +// winner, err := domain.GetRugbyWinner(rugbyResult) +// if err != nil { +// return nil, fmt.Errorf("failed to determine Rugby Union winner: %w", err) +// } - score := domain.FormatRugbyScore(rugbyResult) +// score := domain.FormatRugbyScore(rugbyResult) - return &domain.Result{ - Status: determineOutcomeStatus(winner, rugbyResult.Home.Name, rugbyResult.Away.Name), - Score: score, - FullTimeScore: score, - SS: rugbyResult.SS, - Scores: map[string]domain.Score{ - "1": rugbyResult.Scores.FirstHalf, - "2": rugbyResult.Scores.SecondHalf, - "7": rugbyResult.Scores.TotalScore, - }, - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - }, nil -} +// return &domain.Result{ +// Status: determineOutcomeStatus(winner, rugbyResult.Home.Name, rugbyResult.Away.Name), +// Score: score, +// FullTimeScore: score, +// SS: rugbyResult.SS, +// Scores: map[string]domain.Score{ +// "1": rugbyResult.Scores.FirstHalf, +// "2": rugbyResult.Scores.SecondHalf, +// "7": rugbyResult.Scores.TotalScore, +// }, +// CreatedAt: time.Now(), +// UpdatedAt: time.Now(), +// }, nil +// } -// CheckRugbyLeagueResult checks the result of a Rugby League game -func (s *ResultCheckerService) CheckRugbyLeagueResult(data json.RawMessage) (*domain.Result, error) { - rugbyResult, err := domain.ParseRugbyLeagueResult(data) - if err != nil { - return nil, fmt.Errorf("failed to parse Rugby League result: %w", err) - } +// // CheckRugbyLeagueResult checks the result of a Rugby League game +// func (s *ResultCheckerService) CheckRugbyLeagueResult(data json.RawMessage) (*domain.Result, error) { +// rugbyResult, err := domain.ParseRugbyLeagueResult(data) +// if err != nil { +// return nil, fmt.Errorf("failed to parse Rugby League result: %w", err) +// } - winner, err := domain.GetRugbyWinner(rugbyResult) - if err != nil { - return nil, fmt.Errorf("failed to determine Rugby League winner: %w", err) - } +// winner, err := domain.GetRugbyWinner(rugbyResult) +// if err != nil { +// return nil, fmt.Errorf("failed to determine Rugby League winner: %w", err) +// } - score := domain.FormatRugbyScore(rugbyResult) +// score := domain.FormatRugbyScore(rugbyResult) - return &domain.Result{ - Status: determineOutcomeStatus(winner, rugbyResult.Home.Name, rugbyResult.Away.Name), - Score: score, - FullTimeScore: score, - SS: rugbyResult.SS, - Scores: map[string]domain.Score{ - "1": rugbyResult.Scores.FirstHalf, - "2": rugbyResult.Scores.SecondHalf, - "7": rugbyResult.Scores.TotalScore, - }, - CreatedAt: time.Now(), - UpdatedAt: time.Now(), - }, nil -} +// return &domain.Result{ +// Status: determineOutcomeStatus(winner, rugbyResult.Home.Name, rugbyResult.Away.Name), +// Score: score, +// FullTimeScore: score, +// SS: rugbyResult.SS, +// Scores: map[string]domain.Score{ +// "1": rugbyResult.Scores.FirstHalf, +// "2": rugbyResult.Scores.SecondHalf, +// "7": rugbyResult.Scores.TotalScore, +// }, +// CreatedAt: time.Now(), +// UpdatedAt: time.Now(), +// }, nil +// } diff --git a/internal/services/transaction/port.go b/internal/services/transaction/port.go index d0c500b..2bc6f6b 100644 --- a/internal/services/transaction/port.go +++ b/internal/services/transaction/port.go @@ -9,7 +9,7 @@ import ( type TransactionStore interface { CreateTransaction(ctx context.Context, transaction domain.CreateTransaction) (domain.Transaction, error) GetTransactionByID(ctx context.Context, id int64) (domain.Transaction, error) - GetAllTransactions(ctx context.Context) ([]domain.Transaction, error) + GetAllTransactions(ctx context.Context, filter domain.TransactionFilter) ([]domain.Transaction, error) GetTransactionByBranch(ctx context.Context, id int64) ([]domain.Transaction, error) UpdateTransactionVerified(ctx context.Context, id int64, verified bool, approvedBy int64, approverName string) error } diff --git a/internal/services/transaction/service.go b/internal/services/transaction/service.go index c7504b4..658b938 100644 --- a/internal/services/transaction/service.go +++ b/internal/services/transaction/service.go @@ -22,8 +22,8 @@ func (s *Service) CreateTransaction(ctx context.Context, transaction domain.Crea func (s *Service) GetTransactionByID(ctx context.Context, id int64) (domain.Transaction, error) { return s.transactionStore.GetTransactionByID(ctx, id) } -func (s *Service) GetAllTransactions(ctx context.Context) ([]domain.Transaction, error) { - return s.transactionStore.GetAllTransactions(ctx) +func (s *Service) GetAllTransactions(ctx context.Context, filter domain.TransactionFilter) ([]domain.Transaction, error) { + return s.transactionStore.GetAllTransactions(ctx, filter) } func (s *Service) GetTransactionByBranch(ctx context.Context, id int64) ([]domain.Transaction, error) { return s.transactionStore.GetTransactionByBranch(ctx, id) diff --git a/internal/web_server/handlers/bet_handler.go b/internal/web_server/handlers/bet_handler.go index b5f87ec..0a5d285 100644 --- a/internal/web_server/handlers/bet_handler.go +++ b/internal/web_server/handlers/bet_handler.go @@ -150,7 +150,13 @@ func (h *Handler) RandomBet(c *fiber.Ctx) error { // @Failure 500 {object} response.APIResponse // @Router /bet [get] func (h *Handler) GetAllBet(c *fiber.Ctx) error { - bets, err := h.betSvc.GetAllBets(c.Context()) + companyID := c.Locals("company_id").(domain.ValidInt64) + branchID := c.Locals("branch_id").(domain.ValidInt64) + + bets, err := h.betSvc.GetAllBets(c.Context(), domain.BetFilter{ + BranchID: branchID, + CompanyID: companyID, + }) if err != nil { h.logger.Error("Failed to get bets", "error", err) return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve bets") diff --git a/internal/web_server/handlers/cashier.go b/internal/web_server/handlers/cashier.go index 4fdebfc..18efb18 100644 --- a/internal/web_server/handlers/cashier.go +++ b/internal/web_server/handlers/cashier.go @@ -37,7 +37,7 @@ type CreateCashierReq struct { func (h *Handler) CreateCashier(c *fiber.Ctx) error { // Get user_id from middleware - companyID := c.Locals("company_id").(domain.ValidInt64) + // companyID := c.Locals("company_id").(domain.ValidInt64) var req CreateCashierReq if err := c.BodyParser(&req); err != nil { @@ -48,6 +48,13 @@ func (h *Handler) CreateCashier(c *fiber.Ctx) error { if !ok { return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) } + + // Cashiers inherit the company id from the branch id + branch, err := h.branchSvc.GetBranchByID(c.Context(), req.BranchID) + + if err != nil { + return response.WriteJSON(c, fiber.StatusBadRequest, "Branch ID is invalid", nil, nil) + } userRequest := domain.CreateUserReq{ FirstName: req.FirstName, LastName: req.LastName, @@ -56,7 +63,10 @@ func (h *Handler) CreateCashier(c *fiber.Ctx) error { Password: req.Password, Role: string(domain.RoleCashier), Suspended: req.Suspended, - CompanyID: companyID, + CompanyID: domain.ValidInt64{ + Value: branch.CompanyID, + Valid: true, + }, } fmt.Print(req.Suspended) newUser, err := h.userSvc.CreateUser(c.Context(), userRequest, true) diff --git a/internal/web_server/handlers/prematch.go b/internal/web_server/handlers/prematch.go index b8d3778..9457e1c 100644 --- a/internal/web_server/handlers/prematch.go +++ b/internal/web_server/handlers/prematch.go @@ -82,7 +82,7 @@ func (h *Handler) GetRawOddsByMarketID(c *fiber.Ctx) error { rawOdds, err := h.prematchSvc.GetRawOddsByMarketID(c.Context(), marketID, upcomingID) if err != nil { - h.logger.Error("failed to fetch raw odds", "error", err) + // h.logger.Error("failed to fetch raw odds", "error", err) return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve raw odds", err, nil) } diff --git a/internal/web_server/handlers/transaction_handler.go b/internal/web_server/handlers/transaction_handler.go index 8918023..77189dd 100644 --- a/internal/web_server/handlers/transaction_handler.go +++ b/internal/web_server/handlers/transaction_handler.go @@ -225,35 +225,18 @@ func (h *Handler) CreateTransaction(c *fiber.Ctx) error { // @Router /transaction [get] func (h *Handler) GetAllTransactions(c *fiber.Ctx) error { // Get user_id from middleware - userID := c.Locals("user_id").(int64) - - // Fetch user details - user, err := h.userSvc.GetUserByID(c.Context(), userID) - if err != nil { - h.logger.Error("Failed to fetch user details", "user_id", userID, "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve user details", err, nil) - } + // userID := c.Locals("user_id").(int64) + // role := c.Locals("role").(domain.Role) + companyID := c.Locals("company_id").(domain.ValidInt64) + branchID := c.Locals("branch_id").(domain.ValidInt64) var transactions []domain.Transaction // Check user role and fetch transactions accordingly - // TODO: filtering by the user role - switch user.Role { - case domain.RoleSuperAdmin: - // Admin can fetch all transactions - transactions, err = h.transactionSvc.GetAllTransactions(c.Context()) - case domain.RoleAdmin: - // Admins can fetch transaction for company branches - - transactions, err = h.transactionSvc.GetAllTransactions(c.Context()) - case domain.RoleBranchManager, domain.RoleCashier: - // Branch Manager or Cashier can fetch transactions for their branches - // transactions, err = transactionSvc.GetTransactionByBranch(c.Context(), user.BranchID) - transactions, err = h.transactionSvc.GetAllTransactions(c.Context()) - default: - // Unauthorized role - return response.WriteJSON(c, fiber.StatusForbidden, "Unauthorized", nil, nil) - } + transactions, err := h.transactionSvc.GetAllTransactions(c.Context(), domain.TransactionFilter{ + CompanyID: companyID, + BranchID: branchID, + }) if err != nil { h.logger.Error("Failed to get transactions", "error", err) diff --git a/internal/web_server/middleware.go b/internal/web_server/middleware.go index 8e550cb..33c8829 100644 --- a/internal/web_server/middleware.go +++ b/internal/web_server/middleware.go @@ -53,6 +53,22 @@ func (a *App) authMiddleware(c *fiber.Ctx) error { c.Locals("company_id", claim.CompanyID) c.Locals("refresh_token", refreshToken) + var branchID domain.ValidInt64 + + if claim.Role == domain.RoleCashier { + branch, err := a.branchSvc.GetBranchByCashier(c.Context(), claim.UserId) + if err != nil { + a.logger.Error("Failed to get branch id for bet", "error", err) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to branch id for bet") + } + branchID = domain.ValidInt64{ + Value: branch.ID, + Valid: true, + } + + } + + c.Locals("branch_id", branchID) return c.Next() } diff --git a/makefile b/makefile index 5e85c50..a842d04 100644 --- a/makefile +++ b/makefile @@ -55,9 +55,9 @@ db-up: .PHONY: db-down db-down: @docker compose down + @docker volume rm fortunebet-backend_postgres_data postgres: @docker exec -it fortunebet-backend-postgres-1 psql -U root -d gh - .PHONY: sqlc-gen sqlc-gen: @sqlc generate \ No newline at end of file