fix: integration fixes

This commit is contained in:
Samuel Tariku 2025-10-07 13:39:36 +03:00
parent c00110a503
commit d997cde387
34 changed files with 4654 additions and 826 deletions

View File

@ -73,7 +73,8 @@ CREATE TABLE IF NOT EXISTS wallets (
is_active BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(user_id, type)
UNIQUE(user_id, type),
CONSTRAINT balance_positve CHECK (balance >= 0)
);
CREATE TABLE refresh_tokens (
id BIGSERIAL PRIMARY KEY,
@ -184,19 +185,19 @@ CREATE TABLE IF NOT EXISTS banks (
currency VARCHAR(10) NOT NULL,
bank_logo TEXT -- URL or base64 string
);
CREATE TABLE IF NOT EXISTS wallets (
id BIGSERIAL PRIMARY KEY,
balance BIGINT NOT NULL DEFAULT 0,
is_withdraw BOOLEAN NOT NULL,
is_bettable BOOLEAN NOT NULL,
is_transferable BOOLEAN NOT NULL,
user_id BIGINT NOT NULL,
type VARCHAR(255) NOT NULL,
is_active BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT balance_positve CHECK (balance >= 0)
);
-- CREATE TABLE IF NOT EXISTS wallets (
-- id BIGSERIAL PRIMARY KEY,
-- balance BIGINT NOT NULL DEFAULT 0,
-- is_withdraw BOOLEAN NOT NULL,
-- is_bettable BOOLEAN NOT NULL,
-- is_transferable BOOLEAN NOT NULL,
-- user_id BIGINT NOT NULL,
-- type VARCHAR(255) NOT NULL,
-- is_active BOOLEAN NOT NULL DEFAULT true,
-- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-- updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
-- CONSTRAINT balance_positve CHECK (balance >= 0)
-- );
CREATE TABLE IF NOT EXISTS customer_wallets (
id BIGSERIAL PRIMARY KEY,
customer_id BIGINT NOT NULL,
@ -270,7 +271,7 @@ CREATE TABLE IF NOT EXISTS branches (
name VARCHAR(255) NOT NULL,
location TEXT NOT NULL,
profit_percent REAL NOT NULL,
is_active BOOLEAN NOT NULL DEFAULT false,
is_active BOOLEAN NOT NULL DEFAULT true,
wallet_id BIGINT NOT NULL,
branch_manager_id BIGINT NOT NULL,
company_id BIGINT NOT NULL,
@ -406,7 +407,7 @@ CREATE TABLE companies (
admin_id BIGINT NOT NULL,
wallet_id BIGINT NOT NULL,
deducted_percentage REAL NOT NULL,
is_active BOOLEAN NOT NULL DEFAULT false,
is_active BOOLEAN NOT NULL DEFAULT true,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT deducted_percentage_check CHECK (
@ -642,6 +643,7 @@ SELECT sb.*,
st.verified AS transaction_verified,
bets.status,
bets.total_odds,
bets.fast_code,
JSON_AGG (bet_outcomes.*) AS outcomes
FROM shop_bets AS sb
JOIN shop_transactions st ON st.id = sb.shop_transaction_id
@ -655,7 +657,8 @@ GROUP BY sb.id,
st.amount,
st.verified,
bets.status,
bets.total_odds;
bets.total_odds,
bets.fast_code;
CREATE VIEW shop_deposit_detail AS
SELECT sd.*,
st.full_name,

View File

@ -4,9 +4,10 @@ INSERT INTO companies (
slug,
admin_id,
wallet_id,
deducted_percentage
deducted_percentage,
is_active
)
VALUES ($1, $2, $3, $4, $5)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING *;
-- name: GetAllCompanies :many
SELECT *
@ -38,7 +39,7 @@ WHERE slug = $1;
SELECT *
FROM companies_details
WHERE name ILIKE '%' || $1 || '%';
-- name: UpdateCompany :one
-- name: UpdateCompany :exec
UPDATE companies
SET name = COALESCE(sqlc.narg(name), name),
admin_id = COALESCE(sqlc.narg(admin_id), admin_id),
@ -47,9 +48,9 @@ SET name = COALESCE(sqlc.narg(name), name),
sqlc.narg(deducted_percentage),
deducted_percentage
),
slug = COALESCE(sqlc.narg(slug), slug),
updated_at = CURRENT_TIMESTAMP
WHERE id = $1
RETURNING *;
WHERE id = $1;
-- name: DeleteCompany :exec
DELETE FROM companies
WHERE id = $1;

View File

@ -40,8 +40,31 @@ WHERE (
name ILIKE '%' || sqlc.narg('query') || '%'
OR sqlc.narg('query') IS NULL
)
AND (
default_is_active = sqlc.narg('is_active')
OR sqlc.narg('is_active') IS NULL
)
ORDER BY name ASC
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
-- name: GetTotalLeagues :one
SELECT COUNT(*)
FROM leagues
WHERE (
country_code = sqlc.narg('country_code')
OR sqlc.narg('country_code') IS NULL
)
AND (
sport_id = sqlc.narg('sport_id')
OR sqlc.narg('sport_id') IS NULL
)
AND (
name ILIKE '%' || sqlc.narg('query') || '%'
OR sqlc.narg('query') IS NULL
)
AND (
default_is_active = sqlc.narg('is_active')
OR sqlc.narg('is_active') IS NULL
);
-- name: GetTotalLeaguesWithSettings :one
SELECT COUNT(*)
FROM leagues l

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -17,9 +17,10 @@ INSERT INTO companies (
slug,
admin_id,
wallet_id,
deducted_percentage
deducted_percentage,
is_active
)
VALUES ($1, $2, $3, $4, $5)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING id, name, slug, admin_id, wallet_id, deducted_percentage, is_active, created_at, updated_at
`
@ -29,6 +30,7 @@ type CreateCompanyParams struct {
AdminID int64 `json:"admin_id"`
WalletID int64 `json:"wallet_id"`
DeductedPercentage float32 `json:"deducted_percentage"`
IsActive bool `json:"is_active"`
}
func (q *Queries) CreateCompany(ctx context.Context, arg CreateCompanyParams) (Company, error) {
@ -38,6 +40,7 @@ func (q *Queries) CreateCompany(ctx context.Context, arg CreateCompanyParams) (C
arg.AdminID,
arg.WalletID,
arg.DeductedPercentage,
arg.IsActive,
)
var i Company
err := row.Scan(
@ -217,7 +220,7 @@ func (q *Queries) SearchCompanyByName(ctx context.Context, dollar_1 pgtype.Text)
return items, nil
}
const UpdateCompany = `-- name: UpdateCompany :one
const UpdateCompany = `-- name: UpdateCompany :exec
UPDATE companies
SET name = COALESCE($2, name),
admin_id = COALESCE($3, admin_id),
@ -226,9 +229,9 @@ SET name = COALESCE($2, name),
$5,
deducted_percentage
),
slug = COALESCE($6, slug),
updated_at = CURRENT_TIMESTAMP
WHERE id = $1
RETURNING id, name, slug, admin_id, wallet_id, deducted_percentage, is_active, created_at, updated_at
`
type UpdateCompanyParams struct {
@ -237,27 +240,17 @@ type UpdateCompanyParams struct {
AdminID pgtype.Int8 `json:"admin_id"`
IsActive pgtype.Bool `json:"is_active"`
DeductedPercentage pgtype.Float4 `json:"deducted_percentage"`
Slug pgtype.Text `json:"slug"`
}
func (q *Queries) UpdateCompany(ctx context.Context, arg UpdateCompanyParams) (Company, error) {
row := q.db.QueryRow(ctx, UpdateCompany,
func (q *Queries) UpdateCompany(ctx context.Context, arg UpdateCompanyParams) error {
_, err := q.db.Exec(ctx, UpdateCompany,
arg.ID,
arg.Name,
arg.AdminID,
arg.IsActive,
arg.DeductedPercentage,
arg.Slug,
)
var i Company
err := row.Scan(
&i.ID,
&i.Name,
&i.Slug,
&i.AdminID,
&i.WalletID,
&i.DeductedPercentage,
&i.IsActive,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
return err
}

View File

@ -48,14 +48,19 @@ WHERE (
name ILIKE '%' || $3 || '%'
OR $3 IS NULL
)
AND (
default_is_active = $4
OR $4 IS NULL
)
ORDER BY name ASC
LIMIT $5 OFFSET $4
LIMIT $6 OFFSET $5
`
type GetAllLeaguesParams struct {
CountryCode pgtype.Text `json:"country_code"`
SportID pgtype.Int4 `json:"sport_id"`
Query pgtype.Text `json:"query"`
IsActive pgtype.Bool `json:"is_active"`
Offset pgtype.Int4 `json:"offset"`
Limit pgtype.Int4 `json:"limit"`
}
@ -65,6 +70,7 @@ func (q *Queries) GetAllLeagues(ctx context.Context, arg GetAllLeaguesParams) ([
arg.CountryCode,
arg.SportID,
arg.Query,
arg.IsActive,
arg.Offset,
arg.Limit,
)
@ -199,6 +205,46 @@ func (q *Queries) GetAllLeaguesWithSettings(ctx context.Context, arg GetAllLeagu
return items, nil
}
const GetTotalLeagues = `-- name: GetTotalLeagues :one
SELECT COUNT(*)
FROM leagues
WHERE (
country_code = $1
OR $1 IS NULL
)
AND (
sport_id = $2
OR $2 IS NULL
)
AND (
name ILIKE '%' || $3 || '%'
OR $3 IS NULL
)
AND (
default_is_active = $4
OR $4 IS NULL
)
`
type GetTotalLeaguesParams struct {
CountryCode pgtype.Text `json:"country_code"`
SportID pgtype.Int4 `json:"sport_id"`
Query pgtype.Text `json:"query"`
IsActive pgtype.Bool `json:"is_active"`
}
func (q *Queries) GetTotalLeagues(ctx context.Context, arg GetTotalLeaguesParams) (int64, error) {
row := q.db.QueryRow(ctx, GetTotalLeagues,
arg.CountryCode,
arg.SportID,
arg.Query,
arg.IsActive,
)
var count int64
err := row.Scan(&count)
return count, err
}
const GetTotalLeaguesWithSettings = `-- name: GetTotalLeaguesWithSettings :one
SELECT COUNT(*)
FROM leagues l

View File

@ -687,6 +687,7 @@ type ShopBetDetail struct {
TransactionVerified bool `json:"transaction_verified"`
Status int32 `json:"status"`
TotalOdds float32 `json:"total_odds"`
FastCode string `json:"fast_code"`
Outcomes []BetOutcome `json:"outcomes"`
}

View File

@ -173,7 +173,7 @@ func (q *Queries) CreateShopTransaction(ctx context.Context, arg CreateShopTrans
}
const GetAllShopBets = `-- name: GetAllShopBets :many
SELECT id, shop_transaction_id, cashout_id, cashed_out_by, bet_id, number_of_outcomes, cashed_out, created_at, updated_at, customer_full_name, customer_phone_number, branch_id, company_id, amount, transaction_verified, status, total_odds, outcomes
SELECT id, shop_transaction_id, cashout_id, cashed_out_by, bet_id, number_of_outcomes, cashed_out, created_at, updated_at, customer_full_name, customer_phone_number, branch_id, company_id, amount, transaction_verified, status, total_odds, fast_code, outcomes
FROM shop_bet_detail
WHERE (
full_name ILIKE '%' || $1 || '%'
@ -239,6 +239,7 @@ func (q *Queries) GetAllShopBets(ctx context.Context, arg GetAllShopBetsParams)
&i.TransactionVerified,
&i.Status,
&i.TotalOdds,
&i.FastCode,
&i.Outcomes,
); err != nil {
return nil, err
@ -419,7 +420,7 @@ func (q *Queries) GetAllShopTransactions(ctx context.Context, arg GetAllShopTran
}
const GetShopBetByBetID = `-- name: GetShopBetByBetID :one
SELECT id, shop_transaction_id, cashout_id, cashed_out_by, bet_id, number_of_outcomes, cashed_out, created_at, updated_at, customer_full_name, customer_phone_number, branch_id, company_id, amount, transaction_verified, status, total_odds, outcomes
SELECT id, shop_transaction_id, cashout_id, cashed_out_by, bet_id, number_of_outcomes, cashed_out, created_at, updated_at, customer_full_name, customer_phone_number, branch_id, company_id, amount, transaction_verified, status, total_odds, fast_code, outcomes
FROM shop_bet_detail
WHERE bet_id = $1
`
@ -445,13 +446,14 @@ func (q *Queries) GetShopBetByBetID(ctx context.Context, betID int64) (ShopBetDe
&i.TransactionVerified,
&i.Status,
&i.TotalOdds,
&i.FastCode,
&i.Outcomes,
)
return i, err
}
const GetShopBetByCashoutID = `-- name: GetShopBetByCashoutID :one
SELECT id, shop_transaction_id, cashout_id, cashed_out_by, bet_id, number_of_outcomes, cashed_out, created_at, updated_at, customer_full_name, customer_phone_number, branch_id, company_id, amount, transaction_verified, status, total_odds, outcomes
SELECT id, shop_transaction_id, cashout_id, cashed_out_by, bet_id, number_of_outcomes, cashed_out, created_at, updated_at, customer_full_name, customer_phone_number, branch_id, company_id, amount, transaction_verified, status, total_odds, fast_code, outcomes
FROM shop_bet_detail
WHERE cashout_id = $1
`
@ -477,13 +479,14 @@ func (q *Queries) GetShopBetByCashoutID(ctx context.Context, cashoutID string) (
&i.TransactionVerified,
&i.Status,
&i.TotalOdds,
&i.FastCode,
&i.Outcomes,
)
return i, err
}
const GetShopBetByID = `-- name: GetShopBetByID :one
SELECT id, shop_transaction_id, cashout_id, cashed_out_by, bet_id, number_of_outcomes, cashed_out, created_at, updated_at, customer_full_name, customer_phone_number, branch_id, company_id, amount, transaction_verified, status, total_odds, outcomes
SELECT id, shop_transaction_id, cashout_id, cashed_out_by, bet_id, number_of_outcomes, cashed_out, created_at, updated_at, customer_full_name, customer_phone_number, branch_id, company_id, amount, transaction_verified, status, total_odds, fast_code, outcomes
FROM shop_bet_detail
WHERE id = $1
`
@ -509,13 +512,14 @@ func (q *Queries) GetShopBetByID(ctx context.Context, id int64) (ShopBetDetail,
&i.TransactionVerified,
&i.Status,
&i.TotalOdds,
&i.FastCode,
&i.Outcomes,
)
return i, err
}
const GetShopBetByShopTransactionID = `-- name: GetShopBetByShopTransactionID :one
SELECT id, shop_transaction_id, cashout_id, cashed_out_by, bet_id, number_of_outcomes, cashed_out, created_at, updated_at, customer_full_name, customer_phone_number, branch_id, company_id, amount, transaction_verified, status, total_odds, outcomes
SELECT id, shop_transaction_id, cashout_id, cashed_out_by, bet_id, number_of_outcomes, cashed_out, created_at, updated_at, customer_full_name, customer_phone_number, branch_id, company_id, amount, transaction_verified, status, total_odds, fast_code, outcomes
FROM shop_bet_detail
WHERE shop_transaction_id = $1
`
@ -541,6 +545,7 @@ func (q *Queries) GetShopBetByShopTransactionID(ctx context.Context, shopTransac
&i.TransactionVerified,
&i.Status,
&i.TotalOdds,
&i.FastCode,
&i.Outcomes,
)
return i, err

View File

@ -45,6 +45,8 @@ type CreateCompany struct {
AdminID int64
WalletID int64
DeductedPercentage float32
Slug string
IsActive bool
}
type UpdateCompany struct {
@ -53,18 +55,22 @@ type UpdateCompany struct {
AdminID ValidInt64
IsActive ValidBool
DeductedPercentage ValidFloat32
Slug ValidString
}
type CreateCompanyReq struct {
Name string `json:"name" example:"CompanyName"`
AdminID int64 `json:"admin_id" example:"1"`
DeductedPercentage float32 `json:"deducted_percentage" example:"0.1" validate:"lt=1"`
Slug string `json:"slug"`
IsActive bool `json:"is_active"`
}
type UpdateCompanyReq struct {
Name *string `json:"name,omitempty" example:"CompanyName"`
AdminID *int64 `json:"admin_id,omitempty" example:"1"`
IsActive *bool `json:"is_active,omitempty" example:"true"`
DeductedPercentage *float32 `json:"deducted_percentage,omitempty" example:"0.1" validate:"lt=1"`
Slug *string `json:"slug"`
}
type CompanyRes struct {
@ -113,13 +119,14 @@ func ConvertGetCompany(company GetCompany) GetCompanyRes {
}
}
func ConvertCreateCompany(company CreateCompany, uniqueSlug string) dbgen.CreateCompanyParams {
func ConvertCreateCompany(company CreateCompany) dbgen.CreateCompanyParams {
return dbgen.CreateCompanyParams{
Name: company.Name,
Slug: uniqueSlug,
Slug: company.Slug,
AdminID: company.AdminID,
WalletID: company.WalletID,
DeductedPercentage: company.DeductedPercentage,
IsActive: company.IsActive,
}
}
@ -154,31 +161,22 @@ func ConvertDBCompanyDetails(dbCompany dbgen.CompaniesDetail) GetCompany {
func ConvertUpdateCompany(updateCompany UpdateCompany) dbgen.UpdateCompanyParams {
newUpdateCompany := dbgen.UpdateCompanyParams{
ID: updateCompany.ID,
Name: pgtype.Text{
String: updateCompany.Name.Value,
Valid: updateCompany.Name.Valid,
},
AdminID: pgtype.Int8{
Int64: updateCompany.AdminID.Value,
Valid: updateCompany.AdminID.Valid,
},
IsActive: pgtype.Bool{
Bool: updateCompany.IsActive.Value,
Valid: updateCompany.IsActive.Valid,
},
DeductedPercentage: pgtype.Float4{
Float32: updateCompany.DeductedPercentage.Value,
Valid: updateCompany.DeductedPercentage.Valid,
},
ID: updateCompany.ID,
Name: updateCompany.Name.ToPG(),
AdminID: updateCompany.AdminID.ToPG(),
IsActive: updateCompany.IsActive.ToPG(),
DeductedPercentage: updateCompany.DeductedPercentage.ToPG(),
Slug: updateCompany.Slug.ToPG(),
}
return newUpdateCompany
}
func ConvertUpdateCompanyReq(req UpdateCompanyReq) UpdateCompany {
func ConvertUpdateCompanyReq(req UpdateCompanyReq, companyID int64) UpdateCompany {
var updateCompany UpdateCompany
updateCompany.ID = companyID
if req.Name != nil {
updateCompany.Name = ValidString{
Value: *req.Name,
@ -206,6 +204,12 @@ func ConvertUpdateCompanyReq(req UpdateCompanyReq) UpdateCompany {
Valid: true,
}
}
if req.Slug != nil {
updateCompany.Slug = ValidString{
Value: *req.Slug,
Valid: true,
}
}
return updateCompany
}

View File

@ -34,6 +34,7 @@ type ShopBetDetail struct {
CompanyID int64
FullName string
PhoneNumber string
FastCode string
CashoutID string
CashedOut bool
BetID int64
@ -80,6 +81,7 @@ type ShopBetRes struct {
CompanyID int64 `json:"company_id" example:"2"`
FullName string `json:"full_name" example:"John"`
PhoneNumber string `json:"phone_number" example:"1234567890"`
FastCode string `json:"fast_code" example:"12SD1"`
CashoutID string `json:"cashout_id" example:"21234"`
CashedOut bool `json:"cashed_out" example:"false"`
BetID int64 `json:"bet_id" example:"1"`
@ -111,6 +113,7 @@ func ConvertShopBetDetail(shopBet ShopBetDetail) ShopBetRes {
CompanyID: shopBet.CompanyID,
FullName: shopBet.FullName,
PhoneNumber: shopBet.PhoneNumber,
FastCode: shopBet.FastCode,
CashoutID: shopBet.CashoutID,
CashedOut: shopBet.CashedOut,
BetID: shopBet.BetID,

View File

@ -1,6 +1,13 @@
package domain
import "time"
import (
"errors"
"time"
)
var (
ErrWalletIDDuplicate = errors.New("there already exists user id with wallet_type")
)
type Wallet struct {
ID int64

View File

@ -103,8 +103,11 @@ func (s *Store) GetAllBets(ctx context.Context, filter domain.BetFilter) ([]doma
Query: filter.Query.ToPG(),
CreatedBefore: filter.CreatedBefore.ToPG(),
CreatedAfter: filter.CreatedAfter.ToPG(),
Offset: filter.Offset.ToPG(),
Limit: filter.Limit.ToPG(),
Offset: pgtype.Int4{
Int32: int32(filter.Offset.Value * filter.Limit.Value),
Valid: filter.Offset.Valid,
},
Limit: filter.Limit.ToPG(),
})
if err != nil {
domain.MongoDBLogger.Error("failed to get all bets",

View File

@ -0,0 +1,12 @@
package repository
import (
"errors"
"github.com/jackc/pgx/v5/pgconn"
)
func IsUniqueViolation(err error) bool {
var pgErr *pgconn.PgError
return errors.As(err, &pgErr) && pgErr.Code == "23505"
}

View File

@ -2,36 +2,34 @@ package repository
import (
"context"
"errors"
"fmt"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/SamuelTariku/FortuneBet-Backend/internal/pkgs/helpers"
"github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgtype"
)
func (s *Store) CreateCompany(ctx context.Context, company domain.CreateCompany) (domain.Company, error) {
baseSlug := helpers.GenerateSlug(company.Name)
uniqueSlug := baseSlug
i := 1
// baseSlug := helpers.GenerateSlug(company.Name)
// uniqueSlug := baseSlug
// i := 1
for {
_, err := s.queries.GetCompanyUsingSlug(ctx, uniqueSlug)
if err != nil {
if errors.Is(err, pgx.ErrNoRows) {
// slug is unique
break
} else {
// real DB error
return domain.Company{}, err
}
}
uniqueSlug = fmt.Sprintf("%s-%d", baseSlug, i)
i++
}
// for {
// _, err := s.queries.GetCompanyUsingSlug(ctx, uniqueSlug)
// if err != nil {
// if errors.Is(err, pgx.ErrNoRows) {
// // slug is unique
// break
// } else {
// // real DB error
// return domain.Company{}, err
// }
// }
// uniqueSlug = fmt.Sprintf("%s-%d", baseSlug, i)
// i++
// }
fmt.Printf("\ncompany %v\n\n", company)
dbCompany, err := s.queries.CreateCompany(ctx, domain.ConvertCreateCompany(company))
dbCompany, err := s.queries.CreateCompany(ctx, domain.ConvertCreateCompany(company, uniqueSlug))
if err != nil {
return domain.Company{}, err
}
@ -87,14 +85,15 @@ func (s *Store) GetCompanyBySlug(ctx context.Context, slug string) (domain.Compa
return domain.ConvertDBCompany(dbCompany), nil
}
func (s *Store) UpdateCompany(ctx context.Context, company domain.UpdateCompany) (domain.Company, error) {
dbCompany, err := s.queries.UpdateCompany(ctx, domain.ConvertUpdateCompany(company))
func (s *Store) UpdateCompany(ctx context.Context, company domain.UpdateCompany) error {
fmt.Printf("company %v\n", company)
err := s.queries.UpdateCompany(ctx, domain.ConvertUpdateCompany(company))
if err != nil {
return domain.Company{}, err
return err
}
return domain.ConvertDBCompany(dbCompany), nil
return nil
}
func (s *Store) DeleteCompany(ctx context.Context, id int64) error {

View File

@ -22,11 +22,15 @@ func (s *Store) GetLiveEventIDs(ctx context.Context) ([]int64, error) {
func (s *Store) GetAllEvents(ctx context.Context, filter domain.EventFilter) ([]domain.BaseEvent, int64, error) {
events, err := s.queries.GetAllEvents(ctx, dbgen.GetAllEventsParams{
LeagueID: filter.LeagueID.ToPG(),
SportID: filter.SportID.ToPG(),
Query: filter.Query.ToPG(),
Limit: filter.Limit.ToPG(),
Offset: filter.Offset.ToPG(),
LeagueID: filter.LeagueID.ToPG(),
SportID: filter.SportID.ToPG(),
Query: filter.Query.ToPG(),
Limit: filter.Limit.ToPG(),
Offset: pgtype.Int4{
Int32: int32(filter.Offset.Value * filter.Limit.Value),
Valid: filter.Offset.Valid,
},
FirstStartTime: filter.FirstStartTime.ToPG(),
LastStartTime: filter.LastStartTime.ToPG(),
CountryCode: filter.CountryCode.ToPG(),

View File

@ -16,7 +16,7 @@ func (s *Store) SaveLeagueSettings(ctx context.Context, leagueSettings domain.Cr
return s.queries.SaveLeagueSettings(ctx, domain.ConvertCreateLeagueSettings(leagueSettings))
}
func (s *Store) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.BaseLeague, error) {
func (s *Store) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.BaseLeague,int64, error) {
l, err := s.queries.GetAllLeagues(ctx, dbgen.GetAllLeaguesParams{
Query: filter.Query.ToPG(),
CountryCode: filter.CountryCode.ToPG(),
@ -31,10 +31,17 @@ func (s *Store) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) (
},
})
if err != nil {
return nil, err
return nil, 0, err
}
return domain.ConvertDBBaseLeagues(l), nil
total, err := s.queries.GetTotalLeagues(ctx, dbgen.GetTotalLeaguesParams{
Query: filter.Query.ToPG(),
CountryCode: filter.CountryCode.ToPG(),
SportID: filter.SportID.ToPG(),
IsActive: filter.IsActive.ToPG(),
})
return domain.ConvertDBBaseLeagues(l), total, nil
}
func (s *Store) GetAllLeaguesByCompany(ctx context.Context, companyID int64, filter domain.LeagueFilter) ([]domain.LeagueWithSettings, int64, error) {

View File

@ -35,6 +35,7 @@ func convertDBShopBetDetail(bet dbgen.ShopBetDetail) domain.ShopBetDetail {
CompanyID: bet.CompanyID,
FullName: bet.CustomerFullName,
PhoneNumber: bet.CustomerPhoneNumber,
FastCode: bet.FastCode,
CashoutID: bet.CashoutID,
CashedOut: bet.CashedOut,
BetID: bet.BetID,
@ -63,7 +64,7 @@ func (s *Store) CreateShopBet(ctx context.Context, bet domain.CreateShopBet) (do
if err != nil {
return domain.ShopBet{}, err
}
return convertDBShopBet(newShopBet), err
}
@ -108,7 +109,7 @@ func (s *Store) GetShopBetByID(ctx context.Context, id int64) (domain.ShopBetDet
fmt.Printf("GetShopBetByID Repo BetID %d err %v \n", id, err.Error())
return domain.ShopBetDetail{}, err
}
return convertDBShopBetDetail(bet), nil
}

View File

@ -111,7 +111,7 @@ func (s *Store) GetAllUsers(ctx context.Context, filter domain.UserFilter) ([]do
Valid: filter.PageSize.Valid,
},
Offset: pgtype.Int4{
Int32: int32(filter.Page.Value),
Int32: int32(filter.Page.Value * filter.PageSize.Value),
Valid: filter.Page.Valid,
},
Query: pgtype.Text{

View File

@ -4,7 +4,6 @@ import (
"context"
"database/sql"
"errors"
"fmt"
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
@ -30,7 +29,7 @@ type VirtualGameRepository interface {
RemoveFavoriteGame(ctx context.Context, userID, gameID int64) error
ListFavoriteGames(ctx context.Context, userID int64) ([]int64, error)
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)
CreateVirtualGameHistory(ctx context.Context, his *domain.VirtualGameHistory) error
@ -255,36 +254,36 @@ func (r *VirtualGameRepo) UpdateVirtualGameTransactionStatus(ctx context.Context
})
}
func (r *VirtualGameRepo) GetGameCounts(ctx context.Context, filter domain.ReportFilter) (total, active, inactive int64, err error) {
query := `SELECT
COUNT(*) as total,
COUNT(CASE WHEN is_active = true THEN 1 END) as active,
COUNT(CASE WHEN is_active = false THEN 1 END) as inactive
FROM virtual_games`
// func (r *VirtualGameRepo) GetGameCounts(ctx context.Context, filter domain.ReportFilter) (total, active, inactive int64, err error) {
// query := `SELECT
// COUNT(*) as total,
// COUNT(CASE WHEN is_active = true THEN 1 END) as active,
// COUNT(CASE WHEN is_active = false THEN 1 END) as inactive
// FROM virtual_games`
args := []interface{}{}
argPos := 1
// args := []interface{}{}
// argPos := 1
// Add filters if provided
if filter.StartTime.Valid {
query += fmt.Sprintf(" WHERE created_at >= $%d", argPos)
args = append(args, filter.StartTime.Value)
argPos++
}
if filter.EndTime.Valid {
query += fmt.Sprintf(" AND created_at <= $%d", argPos)
args = append(args, filter.EndTime.Value)
argPos++
}
// // Add filters if provided
// if filter.StartTime.Valid {
// query += fmt.Sprintf(" WHERE created_at >= $%d", argPos)
// args = append(args, filter.StartTime.Value)
// argPos++
// }
// if filter.EndTime.Valid {
// query += fmt.Sprintf(" AND created_at <= $%d", argPos)
// args = append(args, filter.EndTime.Value)
// argPos++
// }
row := r.store.conn.QueryRow(ctx, query, args...)
err = row.Scan(&total, &active, &inactive)
if err != nil {
return 0, 0, 0, fmt.Errorf("failed to get game counts: %w", err)
}
// row := r.store.conn.QueryRow(ctx, query, args...)
// err = row.Scan(&total, &active, &inactive)
// if err != nil {
// return 0, 0, 0, fmt.Errorf("failed to get game counts: %w", err)
// }
return total, active, inactive, nil
}
// return total, active, inactive, nil
// }
func (r *VirtualGameRepo) GetUserGameHistory(ctx context.Context, userID int64) ([]domain.VirtualGameHistory, error) {
query := `SELECT game_id FROM virtual_game_histories WHERE user_id = $1 AND transaction_type = 'BET' ORDER BY created_at DESC LIMIT 100`
@ -315,4 +314,3 @@ func (r *VirtualGameRepo) ListAllVirtualGames(ctx context.Context, arg dbgen.Get
func (r *VirtualGameRepo) RemoveAllVirtualGames(ctx context.Context) error {
return r.store.queries.DeleteAllVirtualGames(ctx)
}

View File

@ -71,6 +71,9 @@ func convertDBGetCustomerWallet(customerWallet dbgen.CustomerWalletDetail) domai
func (s *Store) CreateWallet(ctx context.Context, wallet domain.CreateWallet) (domain.Wallet, error) {
newWallet, err := s.queries.CreateWallet(ctx, convertCreateWallet(wallet))
if err != nil {
if IsUniqueViolation(err) {
return domain.Wallet{}, domain.ErrWalletIDDuplicate
}
return domain.Wallet{}, err
}
return convertDBWallet(newWallet), nil

View File

@ -12,7 +12,7 @@ type CompanyStore interface {
SearchCompanyByName(ctx context.Context, name string) ([]domain.GetCompany, error)
GetCompanyByID(ctx context.Context, id int64) (domain.GetCompany, error)
GetCompanyBySlug(ctx context.Context, slug string) (domain.Company, error)
UpdateCompany(ctx context.Context, company domain.UpdateCompany) (domain.Company, error)
UpdateCompany(ctx context.Context, company domain.UpdateCompany) (error)
DeleteCompany(ctx context.Context, id int64) error
GetCompanyCounts(ctx context.Context, filter domain.ReportFilter) (total, active, inactive int64, err error)

View File

@ -34,7 +34,7 @@ func (s *Service) SearchCompanyByName(ctx context.Context, name string) ([]domai
return s.companyStore.SearchCompanyByName(ctx, name)
}
func (s *Service) UpdateCompany(ctx context.Context, company domain.UpdateCompany) (domain.Company, error) {
func (s *Service) UpdateCompany(ctx context.Context, company domain.UpdateCompany) (error) {
return s.companyStore.UpdateCompany(ctx, company)
}
func (s *Service) DeleteCompany(ctx context.Context, id int64) error {

View File

@ -9,7 +9,7 @@ import (
type Service interface {
SaveLeague(ctx context.Context, league domain.CreateLeague) error
SaveLeagueSettings(ctx context.Context, leagueSettings domain.CreateLeagueSettings) error
GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.BaseLeague, error)
GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.BaseLeague, int64, error)
GetAllLeaguesByCompany(ctx context.Context, companyID int64, filter domain.LeagueFilter) ([]domain.LeagueWithSettings, int64, error)
CheckLeagueSupport(ctx context.Context, leagueID int64, companyID int64) (bool, error)
UpdateLeague(ctx context.Context, league domain.UpdateLeague) error

View File

@ -25,7 +25,7 @@ func (s *service) SaveLeagueSettings(ctx context.Context, leagueSettings domain.
return s.store.SaveLeagueSettings(ctx, leagueSettings)
}
func (s *service) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.BaseLeague, error) {
func (s *service) GetAllLeagues(ctx context.Context, filter domain.LeagueFilter) ([]domain.BaseLeague, int64, error) {
return s.store.GetAllLeagues(ctx, filter)
}
@ -43,4 +43,4 @@ func (s *service) UpdateLeague(ctx context.Context, league domain.UpdateLeague)
func (s *service) UpdateGlobalLeagueSettings(ctx context.Context, league domain.UpdateGlobalLeagueSettings) error {
return s.store.UpdateGlobalLeagueSettings(ctx, league)
}
}

View File

@ -135,11 +135,11 @@ func (s *Service) GetDashboardSummary(ctx context.Context, filter domain.ReportF
}
// Get sport/game metrics
summary.TotalGames, summary.ActiveGames, summary.InactiveGames, err = s.virtulaGamesStore.GetGameCounts(ctx, filter)
if err != nil {
s.logger.Error("failed to get game counts", "error", err)
return domain.DashboardSummary{}, err
}
// summary.TotalGames, summary.ActiveGames, summary.InactiveGames, err = s.virtulaGamesStore.GetGameCounts(ctx, filter)
// if err != nil {
// s.logger.Error("failed to get game counts", "error", err)
// return domain.DashboardSummary{}, err
// }
// Get company metrics
summary.TotalCompanies, summary.ActiveCompanies, summary.InactiveCompanies, err = s.companyStore.GetCompanyCounts(ctx, filter)

View File

@ -23,7 +23,7 @@ type VirtualGameService interface {
ProcessTournamentWin(ctx context.Context, req *domain.PopOKWinRequest) (*domain.PopOKWinResponse, error)
ProcessPromoWin(ctx context.Context, req *domain.PopOKWinRequest) (*domain.PopOKWinResponse, error)
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)
ListGames(ctx context.Context, currency string) ([]domain.PopOKGame, error)
RecommendGames(ctx context.Context, userID int64) ([]domain.GameRecommendation, error)
AddFavoriteGame(ctx context.Context, userID, gameID int64) error

View File

@ -657,9 +657,9 @@ func (s *service) verifySignature(callback *domain.PopOKCallback) bool {
return expected == callback.Signature
}
func (s *service) GetGameCounts(ctx context.Context, filter domain.ReportFilter) (total, active, inactive int64, err error) {
return s.repo.GetGameCounts(ctx, filter)
}
// func (s *service) GetGameCounts(ctx context.Context, filter domain.ReportFilter) (total, active, inactive int64, err error) {
// return s.repo.GetGameCounts(ctx, filter)
// }
func (s *service) ListGames(ctx context.Context, currency string) ([]domain.PopOKGame, error) {
now := time.Now().Format("02-01-2006 15:04:05") // dd-mm-yyyy hh:mm:ss

View File

@ -95,7 +95,7 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S
}
for _, job := range schedule {
// job.task()
job.task()
if _, err := c.AddFunc(job.spec, job.task); err != nil {
mongoLogger.Error("Failed to schedule data fetching cron job",
zap.Error(err),

View File

@ -103,25 +103,25 @@ func (h *Handler) CreateAdmin(c *fiber.Ctx) error {
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create admin:"+err.Error())
}
if req.CompanyID != nil {
_, err := h.companySvc.UpdateCompany(c.Context(), domain.UpdateCompany{
ID: *req.CompanyID,
AdminID: domain.ValidInt64{
Value: newUser.ID,
Valid: true,
},
})
if err != nil {
h.mongoLoggerSvc.Error("failed to update company with new admin",
zap.Int64("status_code", fiber.StatusInternalServerError),
zap.Int64("company_id", *req.CompanyID),
zap.Int64("admin_id", newUser.ID),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update company"+err.Error())
}
}
// if req.CompanyID != nil {
// _, err := h.companySvc.UpdateCompany(c.Context(), domain.UpdateCompany{
// ID: *req.CompanyID,
// AdminID: domain.ValidInt64{
// Value: newUser.ID,
// Valid: true,
// },
// })
// if err != nil {
// h.mongoLoggerSvc.Error("failed to update company with new admin",
// zap.Int64("status_code", fiber.StatusInternalServerError),
// zap.Int64("company_id", *req.CompanyID),
// zap.Int64("admin_id", newUser.ID),
// zap.Error(err),
// zap.Time("timestamp", time.Now()),
// )
// return fiber.NewError(fiber.StatusInternalServerError, "Failed to update company"+err.Error())
// }
// }
h.mongoLoggerSvc.Info("admin created successfully",
zap.Int64("admin_id", newUser.ID),
@ -196,7 +196,7 @@ func (h *Handler) GetAllAdmins(c *fiber.Ctx) error {
Valid: true,
}
}
companyFilter := int64(c.QueryInt("company_id"))
filter := domain.UserFilter{
Role: string(domain.RoleAdmin),
@ -283,7 +283,7 @@ func (h *Handler) GetAllAdmins(c *fiber.Ctx) error {
zap.Time("timestamp", time.Now()),
)
return response.WritePaginatedJSON(c, fiber.StatusOK, "Admins retrieved successfully", result, nil, filter.Page.Value, int(total))
return response.WritePaginatedJSON(c, fiber.StatusOK, "Admins retrieved successfully", result, nil, filter.Page.Value+1, int(total))
}
// GetAdminByID godoc

View File

@ -1,6 +1,7 @@
package handlers
import (
"errors"
"fmt"
"strconv"
"time"
@ -82,17 +83,31 @@ func (h *Handler) CreateCompany(c *fiber.Ctx) error {
AdminID: user.ID,
WalletID: newWallet.ID,
DeductedPercentage: req.DeductedPercentage,
Slug: req.Slug,
IsActive: req.IsActive,
})
if err != nil {
if errors.Is(err, domain.ErrWalletIDDuplicate) {
h.mongoLoggerSvc.Error("CreateCompanyReq failed to create company",
zap.Int64("userID", user.ID),
zap.String("name", req.Name),
zap.Int("status_code", fiber.StatusBadRequest),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusBadRequest, "this admin already has a company assigned to him")
}
h.mongoLoggerSvc.Error("CreateCompanyReq failed to create company",
zap.Int64("userID", user.ID),
zap.String("name", req.Name),
zap.String("Name", req.Name),
zap.Int("status_code", fiber.StatusInternalServerError),
zap.Error(err),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
@ -361,11 +376,12 @@ func (h *Handler) UpdateCompany(c *fiber.Ctx) error {
return fiber.NewError(fiber.StatusBadRequest, errMsg)
}
company, err := h.companySvc.UpdateCompany(c.Context(), domain.ConvertUpdateCompanyReq(req))
err = h.companySvc.UpdateCompany(c.Context(), domain.ConvertUpdateCompanyReq(req, id))
if err != nil {
h.mongoLoggerSvc.Error("Failed to update company",
zap.Int64("companyID", id),
zap.Any("req", req),
zap.Int("status_code", fiber.StatusInternalServerError),
zap.Error(err),
zap.Time("timestamp", time.Now()),
@ -373,9 +389,7 @@ func (h *Handler) UpdateCompany(c *fiber.Ctx) error {
return fiber.NewError(fiber.StatusInternalServerError, err.Error())
}
res := domain.ConvertCompany(company)
return response.WriteJSON(c, fiber.StatusOK, "Company Updated", res, nil)
return response.WriteJSON(c, fiber.StatusOK, "Company Updated", nil, nil)
}

View File

@ -86,7 +86,7 @@ func (h *Handler) GetAllLeagues(c *fiber.Ctx) error {
zap.Bool("sport_id_valid", sportID.Valid),
}
leagues, err := h.leagueSvc.GetAllLeagues(c.Context(), domain.LeagueFilter{
leagues, total, err := h.leagueSvc.GetAllLeagues(c.Context(), domain.LeagueFilter{
CountryCode: countryCode,
IsActive: isActive,
SportID: sportID,
@ -104,7 +104,7 @@ func (h *Handler) GetAllLeagues(c *fiber.Ctx) error {
res := domain.ConvertBaseLeagueResList(leagues)
return response.WriteJSON(c, fiber.StatusOK, "All leagues retrieved", res, nil)
return response.WritePaginatedJSON(c, fiber.StatusOK, "All leagues retrieved successfully", res, nil, page, int(total))
}
// GetAllLeaguesForTenant godoc

View File

@ -328,9 +328,9 @@ func (h *Handler) RegisterUser(c *fiber.Ctx) error {
}
// TODO: Remove later
_, err = h.walletSvc.AddToWallet(
c.Context(), newWallet.RegularID, domain.ToCurrency(10000.0), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{},
"Added 10000.0 to wallet only as test for deployment")
// _, err = h.walletSvc.AddToWallet(
// c.Context(), newWallet.RegularID, domain.ToCurrency(10000.0), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{},
// "Added 10000.0 to wallet only as test for deployment")
if err != nil {
h.mongoLoggerSvc.Error("Failed to update wallet for user",