feat: bet and branch filters, admin company, customer wallet

This commit is contained in:
Samuel Tariku 2025-06-25 22:47:06 +03:00
parent 53ef3ee1f0
commit 4d5c90ab05
26 changed files with 615 additions and 117 deletions

View File

@ -286,7 +286,8 @@ CREATE VIEW branch_details AS
SELECT branches.*,
CONCAT(users.first_name, ' ', users.last_name) AS manager_name,
users.phone_number AS manager_phone_number,
wallets.balance
wallets.balance,
wallets.is_active AS wallet_is_active
FROM branches
LEFT JOIN users ON branches.branch_manager_id = users.id
LEFT JOin wallets ON wallets.id = branches.wallet_id;
@ -307,6 +308,25 @@ SELECT tickets.*,
FROM tickets
LEFT JOIN ticket_outcomes ON tickets.id = ticket_outcomes.ticket_id
GROUP BY tickets.id;
CREATE VIEW customer_wallet_details AS
SELECT cw.id,
cw.customer_id,
rw.id AS regular_id,
rw.balance AS regular_balance,
sw.id AS static_id,
sw.balance AS static_balance,
rw.is_active as regular_is_active,
sw.is_active as static_is_active,
rw.updated_at as regular_updated_at,
sw.updated_at as static_updated_at,
cw.created_at,
users.first_name,
users.last_name,
users.phone_number
FROM customer_wallets cw
JOIN wallets rw ON cw.regular_wallet_id = rw.id
JOIN wallets sw ON cw.static_wallet_id = sw.id
JOIN users ON users.id = cw.customer_id;
-- Foreign Keys
ALTER TABLE users
ADD CONSTRAINT unique_email UNIQUE (email),

View File

@ -63,6 +63,19 @@ wHERE (
AND (
is_shop_bet = sqlc.narg('is_shop_bet')
OR sqlc.narg('is_shop_bet') IS NULL
)
AND (
full_name ILIKE '%' || sqlc.narg('query') || '%'
OR phone_number ILIKE '%' || sqlc.narg('query') || '%'
OR sqlc.narg('query') IS NULL
)
AND (
created_at > sqlc.narg('created_before')
OR sqlc.narg('created_before') IS NULL
)
AND (
created_at < sqlc.narg('created_after')
OR sqlc.narg('created_after') IS NULL
);
-- name: GetBetByID :one
SELECT *
@ -83,7 +96,13 @@ WHERE user_id = $1;
-- name: GetBetOutcomeByEventID :many
SELECT *
FROM bet_outcomes
WHERE event_id = $1;
WHERE (event_id = $1)
AND (
status = sqlc.narg('filter_status')
OR sqlc.narg('filter_status') IS NULL
OR status = sqlc.narg('filter_status_2')
OR sqlc.narg('filter_status_2') IS NULL
);
-- name: GetBetOutcomeByBetID :many
SELECT *
FROM bet_outcomes
@ -103,6 +122,11 @@ UPDATE bet_outcomes
SET status = $1
WHERE id = $2
RETURNING *;
-- name: UpdateBetOutcomeStatusByBetID :one
UPDATE bet_outcomes
SET status = $1
WHERE bet_id = $2
RETURNING *;
-- name: UpdateBetOutcomeStatusForEvent :many
UPDATE bet_outcomes
SEt status = $1
@ -118,6 +142,4 @@ DELETE FROM bets
WHERE id = $1;
-- name: DeleteBetOutcome :exec
DELETE FROM bet_outcomes
WHERE bet_id = $1;
WHERE bet_id = $1;

View File

@ -31,6 +31,23 @@ WHERE (
AND (
is_active = sqlc.narg('is_active')
OR sqlc.narg('is_active') IS NULL
)
AND (
branch_manager_id = sqlc.narg('branch_manager_id')
OR sqlc.narg('branch_manager_id') IS NULL
)
AND (
name ILIKE '%' || sqlc.narg('query') || '%'
OR location ILIKE '%' || sqlc.narg('query') || '%'
OR sqlc.narg('query') IS NULL
)
AND (
created_at > sqlc.narg('created_before')
OR sqlc.narg('created_before') IS NULL
)
AND (
created_at < sqlc.narg('created_after')
OR sqlc.narg('created_after') IS NULL
);
-- name: GetBranchByID :one
SELECT *

View File

@ -26,20 +26,13 @@ WHERE id = $1;
SELECT *
FROM wallets
WHERE user_id = $1;
-- name: GetAllCustomerWallet :many
SELECT *
FROM customer_wallet_details;
-- name: GetCustomerWallet :one
SELECT cw.id,
cw.customer_id,
rw.id AS regular_id,
rw.balance AS regular_balance,
sw.id AS static_id,
sw.balance AS static_balance,
rw.updated_at as regular_updated_at,
sw.updated_at as static_updated_at,
cw.created_at
FROM customer_wallets cw
JOIN wallets rw ON cw.regular_wallet_id = rw.id
JOIN wallets sw ON cw.static_wallet_id = sw.id
WHERE cw.customer_id = $1;
SELECT *
FROM customer_wallet_details
WHERE customer_id = $1;
-- name: GetAllBranchWallets :many
SELECT wallets.id,
wallets.balance,

View File

@ -133,13 +133,29 @@ wHERE (
is_shop_bet = $4
OR $4 IS NULL
)
AND (
full_name ILIKE '%' || $5 || '%'
OR phone_number ILIKE '%' || $5 || '%'
OR $5 IS NULL
)
AND (
created_at > $6
OR $6 IS NULL
)
AND (
created_at < $7
OR $7 IS NULL
)
`
type GetAllBetsParams struct {
BranchID pgtype.Int8 `json:"branch_id"`
CompanyID pgtype.Int8 `json:"company_id"`
UserID pgtype.Int8 `json:"user_id"`
IsShopBet pgtype.Bool `json:"is_shop_bet"`
BranchID pgtype.Int8 `json:"branch_id"`
CompanyID pgtype.Int8 `json:"company_id"`
UserID pgtype.Int8 `json:"user_id"`
IsShopBet pgtype.Bool `json:"is_shop_bet"`
Query pgtype.Text `json:"query"`
CreatedBefore pgtype.Timestamp `json:"created_before"`
CreatedAfter pgtype.Timestamp `json:"created_after"`
}
func (q *Queries) GetAllBets(ctx context.Context, arg GetAllBetsParams) ([]BetWithOutcome, error) {
@ -148,6 +164,9 @@ func (q *Queries) GetAllBets(ctx context.Context, arg GetAllBetsParams) ([]BetWi
arg.CompanyID,
arg.UserID,
arg.IsShopBet,
arg.Query,
arg.CreatedBefore,
arg.CreatedAfter,
)
if err != nil {
return nil, err
@ -394,11 +413,23 @@ func (q *Queries) GetBetOutcomeByBetID(ctx context.Context, betID int64) ([]BetO
const GetBetOutcomeByEventID = `-- name: GetBetOutcomeByEventID :many
SELECT id, bet_id, sport_id, event_id, odd_id, home_team_name, away_team_name, market_id, market_name, odd, odd_name, odd_header, odd_handicap, status, expires
FROM bet_outcomes
WHERE event_id = $1
WHERE (event_id = $1)
AND (
status = $2
OR $2 IS NULL
OR status = $3
OR $3 IS NULL
)
`
func (q *Queries) GetBetOutcomeByEventID(ctx context.Context, eventID int64) ([]BetOutcome, error) {
rows, err := q.db.Query(ctx, GetBetOutcomeByEventID, eventID)
type GetBetOutcomeByEventIDParams struct {
EventID int64 `json:"event_id"`
FilterStatus pgtype.Int4 `json:"filter_status"`
FilterStatus2 pgtype.Int4 `json:"filter_status_2"`
}
func (q *Queries) GetBetOutcomeByEventID(ctx context.Context, arg GetBetOutcomeByEventIDParams) ([]BetOutcome, error) {
rows, err := q.db.Query(ctx, GetBetOutcomeByEventID, arg.EventID, arg.FilterStatus, arg.FilterStatus2)
if err != nil {
return nil, err
}
@ -468,6 +499,41 @@ func (q *Queries) UpdateBetOutcomeStatus(ctx context.Context, arg UpdateBetOutco
return i, err
}
const UpdateBetOutcomeStatusByBetID = `-- name: UpdateBetOutcomeStatusByBetID :one
UPDATE bet_outcomes
SET status = $1
WHERE bet_id = $2
RETURNING id, bet_id, sport_id, event_id, odd_id, home_team_name, away_team_name, market_id, market_name, odd, odd_name, odd_header, odd_handicap, status, expires
`
type UpdateBetOutcomeStatusByBetIDParams struct {
Status int32 `json:"status"`
BetID int64 `json:"bet_id"`
}
func (q *Queries) UpdateBetOutcomeStatusByBetID(ctx context.Context, arg UpdateBetOutcomeStatusByBetIDParams) (BetOutcome, error) {
row := q.db.QueryRow(ctx, UpdateBetOutcomeStatusByBetID, arg.Status, arg.BetID)
var i BetOutcome
err := row.Scan(
&i.ID,
&i.BetID,
&i.SportID,
&i.EventID,
&i.OddID,
&i.HomeTeamName,
&i.AwayTeamName,
&i.MarketID,
&i.MarketName,
&i.Odd,
&i.OddName,
&i.OddHeader,
&i.OddHandicap,
&i.Status,
&i.Expires,
)
return i, err
}
const UpdateBetOutcomeStatusForEvent = `-- name: UpdateBetOutcomeStatusForEvent :many
UPDATE bet_outcomes
SEt status = $1

View File

@ -155,7 +155,7 @@ func (q *Queries) DeleteBranchOperation(ctx context.Context, arg DeleteBranchOpe
}
const GetAllBranches = `-- name: GetAllBranches :many
SELECT id, name, location, is_active, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number, balance
SELECT id, name, location, is_active, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number, balance, wallet_is_active
FROM branch_details
WHERE (
company_id = $1
@ -165,15 +165,43 @@ WHERE (
is_active = $2
OR $2 IS NULL
)
AND (
branch_manager_id = $3
OR $3 IS NULL
)
AND (
name ILIKE '%' || $4 || '%'
OR location ILIKE '%' || $4 || '%'
OR $4 IS NULL
)
AND (
created_at > $5
OR $5 IS NULL
)
AND (
created_at < $6
OR $6 IS NULL
)
`
type GetAllBranchesParams struct {
CompanyID pgtype.Int8 `json:"company_id"`
IsActive pgtype.Bool `json:"is_active"`
CompanyID pgtype.Int8 `json:"company_id"`
IsActive pgtype.Bool `json:"is_active"`
BranchManagerID pgtype.Int8 `json:"branch_manager_id"`
Query pgtype.Text `json:"query"`
CreatedBefore pgtype.Timestamp `json:"created_before"`
CreatedAfter pgtype.Timestamp `json:"created_after"`
}
func (q *Queries) GetAllBranches(ctx context.Context, arg GetAllBranchesParams) ([]BranchDetail, error) {
rows, err := q.db.Query(ctx, GetAllBranches, arg.CompanyID, arg.IsActive)
rows, err := q.db.Query(ctx, GetAllBranches,
arg.CompanyID,
arg.IsActive,
arg.BranchManagerID,
arg.Query,
arg.CreatedBefore,
arg.CreatedAfter,
)
if err != nil {
return nil, err
}
@ -195,6 +223,7 @@ func (q *Queries) GetAllBranches(ctx context.Context, arg GetAllBranchesParams)
&i.ManagerName,
&i.ManagerPhoneNumber,
&i.Balance,
&i.WalletIsActive,
); err != nil {
return nil, err
}
@ -257,7 +286,7 @@ func (q *Queries) GetBranchByCashier(ctx context.Context, userID int64) (Branch,
}
const GetBranchByCompanyID = `-- name: GetBranchByCompanyID :many
SELECT id, name, location, is_active, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number, balance
SELECT id, name, location, is_active, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number, balance, wallet_is_active
FROM branch_details
WHERE company_id = $1
`
@ -285,6 +314,7 @@ func (q *Queries) GetBranchByCompanyID(ctx context.Context, companyID int64) ([]
&i.ManagerName,
&i.ManagerPhoneNumber,
&i.Balance,
&i.WalletIsActive,
); err != nil {
return nil, err
}
@ -297,7 +327,7 @@ func (q *Queries) GetBranchByCompanyID(ctx context.Context, companyID int64) ([]
}
const GetBranchByID = `-- name: GetBranchByID :one
SELECT id, name, location, is_active, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number, balance
SELECT id, name, location, is_active, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number, balance, wallet_is_active
FROM branch_details
WHERE id = $1
`
@ -319,12 +349,13 @@ func (q *Queries) GetBranchByID(ctx context.Context, id int64) (BranchDetail, er
&i.ManagerName,
&i.ManagerPhoneNumber,
&i.Balance,
&i.WalletIsActive,
)
return i, err
}
const GetBranchByManagerID = `-- name: GetBranchByManagerID :many
SELECT id, name, location, is_active, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number, balance
SELECT id, name, location, is_active, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number, balance, wallet_is_active
FROM branch_details
WHERE branch_manager_id = $1
`
@ -352,6 +383,7 @@ func (q *Queries) GetBranchByManagerID(ctx context.Context, branchManagerID int6
&i.ManagerName,
&i.ManagerPhoneNumber,
&i.Balance,
&i.WalletIsActive,
); err != nil {
return nil, err
}
@ -411,7 +443,7 @@ func (q *Queries) GetBranchOperations(ctx context.Context, branchID int64) ([]Ge
}
const SearchBranchByName = `-- name: SearchBranchByName :many
SELECT id, name, location, is_active, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number, balance
SELECT id, name, location, is_active, wallet_id, branch_manager_id, company_id, is_self_owned, created_at, updated_at, manager_name, manager_phone_number, balance, wallet_is_active
FROM branch_details
WHERE name ILIKE '%' || $1 || '%'
`
@ -439,6 +471,7 @@ func (q *Queries) SearchBranchByName(ctx context.Context, dollar_1 pgtype.Text)
&i.ManagerName,
&i.ManagerPhoneNumber,
&i.Balance,
&i.WalletIsActive,
); err != nil {
return nil, err
}

View File

@ -143,6 +143,7 @@ type BranchDetail struct {
ManagerName interface{} `json:"manager_name"`
ManagerPhoneNumber pgtype.Text `json:"manager_phone_number"`
Balance pgtype.Int8 `json:"balance"`
WalletIsActive pgtype.Bool `json:"wallet_is_active"`
}
type BranchOperation struct {
@ -181,6 +182,23 @@ type CustomerWallet struct {
UpdatedAt pgtype.Timestamp `json:"updated_at"`
}
type CustomerWalletDetail struct {
ID int64 `json:"id"`
CustomerID int64 `json:"customer_id"`
RegularID int64 `json:"regular_id"`
RegularBalance int64 `json:"regular_balance"`
StaticID int64 `json:"static_id"`
StaticBalance int64 `json:"static_balance"`
RegularIsActive bool `json:"regular_is_active"`
StaticIsActive bool `json:"static_is_active"`
RegularUpdatedAt pgtype.Timestamp `json:"regular_updated_at"`
StaticUpdatedAt pgtype.Timestamp `json:"static_updated_at"`
CreatedAt pgtype.Timestamp `json:"created_at"`
FirstName string `json:"first_name"`
LastName string `json:"last_name"`
PhoneNumber pgtype.Text `json:"phone_number"`
}
type Event struct {
ID string `json:"id"`
SportID pgtype.Int4 `json:"sport_id"`

View File

@ -143,6 +143,46 @@ func (q *Queries) GetAllBranchWallets(ctx context.Context) ([]GetAllBranchWallet
return items, nil
}
const GetAllCustomerWallet = `-- name: GetAllCustomerWallet :many
SELECT id, customer_id, regular_id, regular_balance, static_id, static_balance, regular_is_active, static_is_active, regular_updated_at, static_updated_at, created_at, first_name, last_name, phone_number
FROM customer_wallet_details
`
func (q *Queries) GetAllCustomerWallet(ctx context.Context) ([]CustomerWalletDetail, error) {
rows, err := q.db.Query(ctx, GetAllCustomerWallet)
if err != nil {
return nil, err
}
defer rows.Close()
var items []CustomerWalletDetail
for rows.Next() {
var i CustomerWalletDetail
if err := rows.Scan(
&i.ID,
&i.CustomerID,
&i.RegularID,
&i.RegularBalance,
&i.StaticID,
&i.StaticBalance,
&i.RegularIsActive,
&i.StaticIsActive,
&i.RegularUpdatedAt,
&i.StaticUpdatedAt,
&i.CreatedAt,
&i.FirstName,
&i.LastName,
&i.PhoneNumber,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetAllWallets = `-- name: GetAllWallets :many
SELECT id, balance, is_withdraw, is_bettable, is_transferable, user_id, is_active, created_at, updated_at, currency, bonus_balance, cash_balance
FROM wallets
@ -182,36 +222,14 @@ func (q *Queries) GetAllWallets(ctx context.Context) ([]Wallet, error) {
}
const GetCustomerWallet = `-- name: GetCustomerWallet :one
SELECT cw.id,
cw.customer_id,
rw.id AS regular_id,
rw.balance AS regular_balance,
sw.id AS static_id,
sw.balance AS static_balance,
rw.updated_at as regular_updated_at,
sw.updated_at as static_updated_at,
cw.created_at
FROM customer_wallets cw
JOIN wallets rw ON cw.regular_wallet_id = rw.id
JOIN wallets sw ON cw.static_wallet_id = sw.id
WHERE cw.customer_id = $1
SELECT id, customer_id, regular_id, regular_balance, static_id, static_balance, regular_is_active, static_is_active, regular_updated_at, static_updated_at, created_at, first_name, last_name, phone_number
FROM customer_wallet_details
WHERE customer_id = $1
`
type GetCustomerWalletRow struct {
ID int64 `json:"id"`
CustomerID int64 `json:"customer_id"`
RegularID int64 `json:"regular_id"`
RegularBalance int64 `json:"regular_balance"`
StaticID int64 `json:"static_id"`
StaticBalance int64 `json:"static_balance"`
RegularUpdatedAt pgtype.Timestamp `json:"regular_updated_at"`
StaticUpdatedAt pgtype.Timestamp `json:"static_updated_at"`
CreatedAt pgtype.Timestamp `json:"created_at"`
}
func (q *Queries) GetCustomerWallet(ctx context.Context, customerID int64) (GetCustomerWalletRow, error) {
func (q *Queries) GetCustomerWallet(ctx context.Context, customerID int64) (CustomerWalletDetail, error) {
row := q.db.QueryRow(ctx, GetCustomerWallet, customerID)
var i GetCustomerWalletRow
var i CustomerWalletDetail
err := row.Scan(
&i.ID,
&i.CustomerID,
@ -219,9 +237,14 @@ func (q *Queries) GetCustomerWallet(ctx context.Context, customerID int64) (GetC
&i.RegularBalance,
&i.StaticID,
&i.StaticBalance,
&i.RegularIsActive,
&i.StaticIsActive,
&i.RegularUpdatedAt,
&i.StaticUpdatedAt,
&i.CreatedAt,
&i.FirstName,
&i.LastName,
&i.PhoneNumber,
)
return i, err
}

View File

@ -57,10 +57,13 @@ type Bet struct {
}
type BetFilter struct {
BranchID ValidInt64 // Can Be Nullable
CompanyID ValidInt64 // Can Be Nullable
UserID ValidInt64 // Can Be Nullable
IsShopBet ValidBool
BranchID ValidInt64 // Can Be Nullable
CompanyID ValidInt64 // Can Be Nullable
UserID ValidInt64 // Can Be Nullable
IsShopBet ValidBool
Query ValidString
CreatedBefore ValidTime
CreatedAfter ValidTime
}
type GetBet struct {

View File

@ -7,13 +7,17 @@ type Branch struct {
WalletID int64
BranchManagerID int64
CompanyID int64
IsSuspended bool
IsActive bool
IsSelfOwned bool
}
type BranchFilter struct {
CompanyID ValidInt64
IsSuspended ValidBool
CompanyID ValidInt64
IsActive ValidBool
BranchManagerID ValidInt64
Query ValidString
CreatedBefore ValidTime
CreatedAfter ValidTime
}
type BranchDetail struct {
@ -24,10 +28,11 @@ type BranchDetail struct {
Balance Currency
BranchManagerID int64
CompanyID int64
IsSuspended bool
IsActive bool
IsSelfOwned bool
ManagerName string
ManagerPhoneNumber string
WalletIsActive bool
}
type SupportedOperation struct {
@ -58,7 +63,7 @@ type UpdateBranch struct {
BranchManagerID *int64
CompanyID *int64
IsSelfOwned *bool
IsActive *bool
IsActive *bool
}
type CreateSupportedOperation struct {

View File

@ -15,6 +15,13 @@ type Wallet struct {
CreatedAt time.Time
}
type WalletFilter struct {
IsActive ValidBool
Query ValidString
CreatedBefore ValidTime
CreatedAfter ValidTime
}
type CustomerWallet struct {
ID int64
RegularID int64
@ -28,9 +35,14 @@ type GetCustomerWallet struct {
StaticID int64
StaticBalance Currency
CustomerID int64
RegularIsActive bool
StaticIsActive bool
RegularUpdatedAt time.Time
StaticUpdatedAt time.Time
CreatedAt time.Time
FirstName string
LastName string
PhoneNumber string
}
type BranchWallet struct {

View File

@ -213,6 +213,18 @@ func (s *Store) GetAllBets(ctx context.Context, filter domain.BetFilter) ([]doma
Bool: filter.IsShopBet.Value,
Valid: filter.IsShopBet.Valid,
},
Query: pgtype.Text{
String: filter.Query.Value,
Valid: filter.Query.Valid,
},
CreatedBefore: pgtype.Timestamp{
Time: filter.CreatedBefore.Value,
Valid: filter.CreatedBefore.Valid,
},
CreatedAfter: pgtype.Timestamp{
Time: filter.CreatedAfter.Value,
Valid: filter.CreatedAfter.Valid,
},
})
if err != nil {
domain.MongoDBLogger.Error("failed to get all bets",
@ -312,8 +324,19 @@ func (s *Store) UpdateStatus(ctx context.Context, id int64, status domain.Outcom
return err
}
func (s *Store) GetBetOutcomeByEventID(ctx context.Context, eventID int64) ([]domain.BetOutcome, error) {
outcomes, err := s.queries.GetBetOutcomeByEventID(ctx, eventID)
func (s *Store) GetBetOutcomeByEventID(ctx context.Context, eventID int64, is_filtered bool) ([]domain.BetOutcome, error) {
outcomes, err := s.queries.GetBetOutcomeByEventID(ctx, dbgen.GetBetOutcomeByEventIDParams{
EventID: eventID,
FilterStatus: pgtype.Int4{
Int32: int32(domain.OUTCOME_STATUS_PENDING),
Valid: is_filtered,
},
FilterStatus2: pgtype.Int4{
Int32: int32(domain.OUTCOME_STATUS_ERROR),
Valid: is_filtered,
},
})
if err != nil {
domain.MongoDBLogger.Error("failed to get bet outcomes by event ID",
zap.Int64("event_id", eventID),
@ -364,6 +387,24 @@ func (s *Store) UpdateBetOutcomeStatus(ctx context.Context, id int64, status dom
return res, nil
}
func (s *Store) UpdateBetOutcomeStatusByBetID(ctx context.Context, id int64, status domain.OutcomeStatus) (domain.BetOutcome, error) {
update, err := s.queries.UpdateBetOutcomeStatusByBetID(ctx, dbgen.UpdateBetOutcomeStatusByBetIDParams{
Status: int32(status),
BetID: id,
})
if err != nil {
domain.MongoDBLogger.Error("failed to update bet outcome status",
zap.Int64("id", id),
zap.Int32("status", int32(status)),
zap.Error(err),
)
return domain.BetOutcome{}, err
}
res := convertDBBetOutcomes(update)
return res, nil
}
func (s *Store) UpdateBetOutcomeStatusForEvent(ctx context.Context, eventID int64, status domain.OutcomeStatus) ([]domain.BetOutcome, error) {
outcomes, err := s.queries.UpdateBetOutcomeStatusForEvent(ctx, dbgen.UpdateBetOutcomeStatusForEventParams{
EventID: eventID,
@ -386,10 +427,6 @@ func (s *Store) UpdateBetOutcomeStatusForEvent(ctx context.Context, eventID int6
return result, nil
}
func (s *Store) DeleteBet(ctx context.Context, id int64) error {
return s.queries.DeleteBet(ctx, id)
}
// GetBetSummary returns aggregated bet statistics
func (s *Store) GetBetSummary(ctx context.Context, filter domain.ReportFilter) (
totalStakes domain.Currency,

View File

@ -32,6 +32,8 @@ func convertDBBranchDetail(dbBranch dbgen.BranchDetail) domain.BranchDetail {
ManagerName: dbBranch.ManagerName.(string),
ManagerPhoneNumber: dbBranch.ManagerPhoneNumber.String,
Balance: domain.Currency(dbBranch.Balance.Int64),
IsActive: dbBranch.IsActive,
WalletIsActive: dbBranch.WalletIsActive.Bool,
}
}
@ -140,6 +142,22 @@ func (s *Store) GetAllBranches(ctx context.Context, filter domain.BranchFilter)
Int64: filter.CompanyID.Value,
Valid: filter.CompanyID.Valid,
},
BranchManagerID: pgtype.Int8{
Int64: filter.BranchManagerID.Value,
Valid: filter.BranchManagerID.Valid,
},
Query: pgtype.Text{
String: filter.Query.Value,
Valid: filter.Query.Valid,
},
CreatedBefore: pgtype.Timestamp{
Time: filter.CreatedBefore.Value,
Valid: filter.CreatedBefore.Valid,
},
CreatedAfter: pgtype.Timestamp{
Time: filter.CreatedAfter.Value,
Valid: filter.CreatedAfter.Valid,
},
})
if err != nil {
return nil, err

View File

@ -47,7 +47,7 @@ func convertCreateCustomerWallet(customerWallet domain.CreateCustomerWallet) dbg
}
}
func convertDBGetCustomerWallet(customerWallet dbgen.GetCustomerWalletRow) domain.GetCustomerWallet {
func convertDBGetCustomerWallet(customerWallet dbgen.CustomerWalletDetail) domain.GetCustomerWallet {
return domain.GetCustomerWallet{
ID: customerWallet.ID,
RegularID: customerWallet.RegularID,
@ -55,9 +55,14 @@ func convertDBGetCustomerWallet(customerWallet dbgen.GetCustomerWalletRow) domai
StaticID: customerWallet.StaticID,
StaticBalance: domain.Currency(customerWallet.StaticBalance),
CustomerID: customerWallet.CustomerID,
RegularIsActive: customerWallet.RegularIsActive,
StaticIsActive: customerWallet.StaticIsActive,
RegularUpdatedAt: customerWallet.RegularUpdatedAt.Time,
StaticUpdatedAt: customerWallet.StaticUpdatedAt.Time,
CreatedAt: customerWallet.CreatedAt.Time,
FirstName: customerWallet.FirstName,
LastName: customerWallet.LastName,
PhoneNumber: customerWallet.PhoneNumber.String,
}
}
@ -115,6 +120,19 @@ func (s *Store) GetWalletsByUser(ctx context.Context, userID int64) ([]domain.Wa
return result, nil
}
func (s *Store) GetAllCustomerWallets(ctx context.Context) ([]domain.GetCustomerWallet, error) {
customerWallets, err := s.queries.GetAllCustomerWallet(ctx)
if err != nil {
return nil, err
}
var result []domain.GetCustomerWallet = make([]domain.GetCustomerWallet, 0, len(customerWallets))
for _, wallet := range customerWallets {
result = append(result, convertDBGetCustomerWallet(wallet))
}
return result, nil
}
func (s *Store) GetCustomerWallet(ctx context.Context, customerID int64) (domain.GetCustomerWallet, error) {
customerWallet, err := s.queries.GetCustomerWallet(ctx, customerID)

View File

@ -15,14 +15,14 @@ type BetStore interface {
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)
GetBetOutcomeByEventID(ctx context.Context, eventID int64, is_filtered bool) ([]domain.BetOutcome, error)
GetBetOutcomeByBetID(ctx context.Context, betID int64) ([]domain.BetOutcome, error)
GetBetCount(ctx context.Context, userID int64, outcomesHash string) (int64, error)
UpdateCashOut(ctx context.Context, id int64, cashedOut bool) error
UpdateStatus(ctx context.Context, id int64, status domain.OutcomeStatus) error
UpdateBetOutcomeStatus(ctx context.Context, id int64, status domain.OutcomeStatus) (domain.BetOutcome, error)
UpdateBetOutcomeStatusByBetID(ctx context.Context, id int64, status domain.OutcomeStatus) (domain.BetOutcome, error)
UpdateBetOutcomeStatusForEvent(ctx context.Context, eventID int64, status domain.OutcomeStatus) ([]domain.BetOutcome, error)
DeleteBet(ctx context.Context, id int64) error
GetBetSummary(ctx context.Context, filter domain.ReportFilter) (
totalStakes domain.Currency,

View File

@ -30,10 +30,11 @@ var (
ErrOutcomesNotCompleted = errors.New("Some bet outcomes are still pending")
ErrEventHasBeenRemoved = errors.New("Event has been removed")
ErrEventHasNotEnded = errors.New("Event has not ended yet")
ErrRawOddInvalid = errors.New("Prematch Raw Odd is Invalid")
ErrBranchIDRequired = errors.New("Branch ID required for this role")
ErrOutcomeLimit = errors.New("Too many outcomes on a single bet")
ErrEventHasNotEnded = errors.New("Event has not ended yet")
ErrRawOddInvalid = errors.New("Prematch Raw Odd is Invalid")
ErrBranchIDRequired = errors.New("Branch ID required for this role")
ErrOutcomeLimit = errors.New("Too many outcomes on a single bet")
ErrTotalBalanceNotEnough = errors.New("Total Wallet balance is insufficient to create bet")
)
type Service struct {
@ -326,7 +327,7 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID
newBet.IsShopBet = true
case domain.RoleCustomer:
wallets, err := s.walletSvc.GetWalletsByUser(ctx, userID)
wallets, err := s.walletSvc.GetCustomerWallet(ctx, userID)
if err != nil {
s.mongoLogger.Error("failed to get customer wallets",
zap.Int64("user_id", userID),
@ -334,17 +335,52 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID
)
return domain.CreateBetRes{}, err
}
if req.Amount < wallets.RegularBalance.Float32() {
_, err = s.walletSvc.DeductFromWallet(ctx, wallets.RegularID,
domain.ToCurrency(req.Amount), domain.CustomerWalletType, domain.ValidInt64{}, domain.TRANSFER_DIRECT)
if err != nil {
s.mongoLogger.Error("wallet deduction failed for customer regular wallet",
zap.Int64("customer_id", wallets.CustomerID),
zap.Int64("customer_wallet_id", wallets.ID),
zap.Int64("regular wallet_id", wallets.RegularID),
zap.Float32("amount", req.Amount),
zap.Error(err),
)
return domain.CreateBetRes{}, err
}
} else {
combinedBalance := wallets.RegularBalance + wallets.StaticBalance
if req.Amount > combinedBalance.Float32() {
return domain.CreateBetRes{}, ErrTotalBalanceNotEnough
}
// Empty the regular balance
_, err = s.walletSvc.DeductFromWallet(ctx, wallets.RegularID,
wallets.RegularBalance, domain.CustomerWalletType, domain.ValidInt64{}, domain.TRANSFER_DIRECT)
if err != nil {
s.mongoLogger.Error("wallet deduction failed for customer regular wallet",
zap.Int64("customer_id", wallets.CustomerID),
zap.Int64("customer_wallet_id", wallets.ID),
zap.Int64("regular wallet_id", wallets.RegularID),
zap.Float32("amount", req.Amount),
zap.Error(err),
)
return domain.CreateBetRes{}, err
}
// Empty remaining from static balance
remainingAmount := wallets.RegularBalance - domain.Currency(req.Amount)
_, err = s.walletSvc.DeductFromWallet(ctx, wallets.StaticID,
remainingAmount, domain.CustomerWalletType, domain.ValidInt64{}, domain.TRANSFER_DIRECT)
if err != nil {
s.mongoLogger.Error("wallet deduction failed for customer static wallet",
zap.Int64("customer_id", wallets.CustomerID),
zap.Int64("customer_wallet_id", wallets.ID),
zap.Int64("static wallet_id", wallets.StaticID),
zap.Float32("amount", req.Amount),
zap.Error(err),
)
return domain.CreateBetRes{}, err
}
userWallet := wallets[0]
_, err = s.walletSvc.DeductFromWallet(ctx, userWallet.ID,
domain.ToCurrency(req.Amount), domain.CustomerWalletType, domain.ValidInt64{}, domain.TRANSFER_DIRECT)
if err != nil {
s.mongoLogger.Error("wallet deduction failed for customer",
zap.Int64("wallet_id", userWallet.ID),
zap.Float32("amount", req.Amount),
zap.Error(err),
)
return domain.CreateBetRes{}, err
}
newBet.UserID = domain.ValidInt64{Value: userID, Valid: true}
@ -838,8 +874,23 @@ func (s *Service) UpdateBetOutcomeStatusForEvent(ctx context.Context, eventID in
return outcomes, nil
}
func (s *Service) DeleteBet(ctx context.Context, id int64) error {
return s.betStore.DeleteBet(ctx, id)
func (s *Service) SetBetToRemoved(ctx context.Context, id int64) error {
_, err := s.betStore.UpdateBetOutcomeStatusByBetID(ctx, id, domain.OUTCOME_STATUS_VOID)
if err != nil {
s.mongoLogger.Error("failed to update bet outcome to void", zap.Int64("id", id),
zap.Error(err),
)
return err
}
err = s.betStore.UpdateStatus(ctx, id, domain.OUTCOME_STATUS_VOID)
if err != nil {
s.mongoLogger.Error("failed to update bet to void", zap.Int64("id", id),
zap.Error(err),
)
return err
}
return nil
}
func generateOutcomeHash(outcomes []domain.CreateBetOutcome) (string, error) {

View File

@ -52,7 +52,7 @@ var (
func (s *Service) UpdateResultForOutcomes(ctx context.Context, eventID int64, resultRes json.RawMessage, sportID int64) error {
// TODO: Optimize this since there could be many outcomes with the same event_id and market_id that could be updated the same time
outcomes, err := s.repo.GetBetOutcomeByEventID(ctx, eventID)
outcomes, err := s.repo.GetBetOutcomeByEventID(ctx, eventID, true)
if err != nil {
s.logger.Error("Failed to get pending bet outcomes", "error", err)
return fmt.Errorf("failed to get pending bet outcomes for event %d: %w", eventID, err)
@ -108,7 +108,7 @@ func (s *Service) UpdateResultForOutcomes(ctx context.Context, eventID int64, re
}
func (s *Service) RefundAllOutcomes(ctx context.Context, eventID int64) error {
outcomes, err := s.repo.GetBetOutcomeByEventID(ctx, eventID)
outcomes, err := s.repo.GetBetOutcomeByEventID(ctx, eventID, false)
if err != nil {
s.logger.Error("Failed to get pending bet outcomes", "error", err)

View File

@ -12,6 +12,7 @@ type WalletStore interface {
GetWalletByID(ctx context.Context, id int64) (domain.Wallet, error)
GetAllWallets(ctx context.Context) ([]domain.Wallet, error)
GetWalletsByUser(ctx context.Context, id int64) ([]domain.Wallet, error)
GetAllCustomerWallets(ctx context.Context) ([]domain.GetCustomerWallet, error)
GetCustomerWallet(ctx context.Context, customerID int64) (domain.GetCustomerWallet, error)
GetAllBranchWallets(ctx context.Context) ([]domain.BranchWallet, error)
UpdateBalance(ctx context.Context, id int64, balance domain.Currency) error

View File

@ -57,6 +57,9 @@ func (s *Service) GetWalletsByUser(ctx context.Context, id int64) ([]domain.Wall
return s.walletStore.GetWalletsByUser(ctx, id)
}
func (s *Service) GetAllCustomerWallet(ctx context.Context) ([]domain.GetCustomerWallet, error) {
return s.walletStore.GetAllCustomerWallets(ctx)
}
func (s *Service) GetCustomerWallet(ctx context.Context, customerID int64) (domain.GetCustomerWallet, error) {
return s.walletStore.GetCustomerWallet(ctx, customerID)
}
@ -70,7 +73,7 @@ func (s *Service) UpdateBalance(ctx context.Context, id int64, balance domain.Cu
}
func (s *Service) AddToWallet(
ctx context.Context, id int64, amount domain.Currency, cashierID domain.ValidInt64, paymentMethod domain.PaymentMethod, paymentDetails domain. PaymentDetails) (domain.Transfer, error) {
ctx context.Context, id int64, amount domain.Currency, cashierID domain.ValidInt64, paymentMethod domain.PaymentMethod, paymentDetails domain.PaymentDetails) (domain.Transfer, error) {
wallet, err := s.GetWalletByID(ctx, id)
if err != nil {
return domain.Transfer{}, err

View File

@ -209,13 +209,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 {
role := c.Locals("role").(domain.Role)
companyID := c.Locals("company_id").(domain.ValidInt64)
branchID := c.Locals("branch_id").(domain.ValidInt64)
var isShopBet domain.ValidBool
isShopBetQuery := c.Query("is_shop")
if isShopBetQuery != "" {
if isShopBetQuery != "" && role == domain.RoleSuperAdmin {
isShopBetParse, err := strconv.ParseBool(isShopBetQuery)
if err != nil {
h.mongoLoggerSvc.Error("Failed to parse is_shop_bet",
@ -231,10 +231,47 @@ func (h *Handler) GetAllBet(c *fiber.Ctx) error {
}
}
searchQuery := c.Query("query")
searchString := domain.ValidString{
Value: searchQuery,
Valid: searchQuery != "",
}
createdBeforeQuery := c.Query("created_before")
var createdBefore domain.ValidTime
if createdBeforeQuery != "" {
createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery)
if err != nil {
h.logger.Error("invalid start_time format", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil)
}
createdBefore = domain.ValidTime{
Value: createdBeforeParsed,
Valid: true,
}
}
createdAfterQuery := c.Query("created_after")
var createdAfter domain.ValidTime
if createdAfterQuery != "" {
createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery)
if err != nil {
h.logger.Error("invalid start_time format", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil)
}
createdAfter = domain.ValidTime{
Value: createdAfterParsed,
Valid: true,
}
}
bets, err := h.betSvc.GetAllBets(c.Context(), domain.BetFilter{
BranchID: branchID,
CompanyID: companyID,
IsShopBet: isShopBet,
BranchID: branchID,
CompanyID: companyID,
IsShopBet: isShopBet,
Query: searchString,
CreatedBefore: createdBefore,
CreatedAfter: createdAfter,
})
if err != nil {
h.mongoLoggerSvc.Error("Failed to get bets",
@ -432,7 +469,7 @@ func (h *Handler) DeleteBet(c *fiber.Ctx) error {
return fiber.NewError(fiber.StatusBadRequest, "Invalid bet ID")
}
err = h.betSvc.DeleteBet(c.Context(), id)
err = h.betSvc.SetBetToRemoved(c.Context(), id)
if err != nil {
h.mongoLoggerSvc.Error("Failed to delete bet by ID",
zap.Int64("betID", id),

View File

@ -3,6 +3,7 @@ package handlers
import (
"strconv"
"strings"
"time"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication"
@ -56,6 +57,7 @@ type BranchRes struct {
BranchManagerID int64 `json:"branch_manager_id" example:"1"`
CompanyID int64 `json:"company_id" example:"1"`
IsSelfOwned bool `json:"is_self_owned" example:"false"`
IsActive bool `json:"is_active" example:"false"`
}
type BranchDetailRes struct {
@ -69,6 +71,8 @@ type BranchDetailRes struct {
ManagerName string `json:"manager_name" example:"John Smith"`
ManagerPhoneNumber string `json:"manager_phone_number" example:"0911111111"`
Balance float32 `json:"balance" example:"100.5"`
IsActive bool `json:"is_active" example:"false"`
WalletIsActive bool `json:"is_wallet_active" example:"false"`
}
func convertBranch(branch domain.Branch) BranchRes {
@ -80,6 +84,7 @@ func convertBranch(branch domain.Branch) BranchRes {
BranchManagerID: branch.BranchManagerID,
CompanyID: branch.CompanyID,
IsSelfOwned: branch.IsSelfOwned,
IsActive: branch.IsActive,
}
}
@ -95,6 +100,8 @@ func convertBranchDetail(branch domain.BranchDetail) BranchDetailRes {
ManagerName: branch.ManagerName,
ManagerPhoneNumber: branch.ManagerPhoneNumber,
Balance: branch.Balance.Float32(),
IsActive: branch.IsActive,
WalletIsActive: branch.WalletIsActive,
}
}
@ -391,13 +398,63 @@ func (h *Handler) GetAllBranches(c *fiber.Ctx) error {
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid is_active param", err, nil)
}
branchManagerQuery := c.Query("branch_manager_id")
var branchManagerID domain.ValidInt64
if branchManagerQuery != "" {
parseManagerID, err := strconv.ParseInt(branchManagerQuery, 10, 64)
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, "Failed to parse branch_manager_id")
}
branchManagerID = domain.ValidInt64{
Value: parseManagerID,
Valid: true,
}
}
searchQuery := c.Query("query")
searchString := domain.ValidString{
Value: searchQuery,
Valid: searchQuery != "",
}
createdBeforeQuery := c.Query("created_before")
var createdBefore domain.ValidTime
if createdBeforeQuery != "" {
createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery)
if err != nil {
h.logger.Error("invalid start_time format", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil)
}
createdBefore = domain.ValidTime{
Value: createdBeforeParsed,
Valid: true,
}
}
createdAfterQuery := c.Query("created_after")
var createdAfter domain.ValidTime
if createdAfterQuery != "" {
createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery)
if err != nil {
h.logger.Error("invalid start_time format", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil)
}
createdAfter = domain.ValidTime{
Value: createdAfterParsed,
Valid: true,
}
}
branches, err := h.branchSvc.GetAllBranches(c.Context(),
domain.BranchFilter{
CompanyID: companyID,
IsSuspended: domain.ValidBool{
IsActive: domain.ValidBool{
Value: isActive,
Valid: isActiveValid,
},
BranchManagerID: branchManagerID,
Query: searchString,
CreatedBefore: createdBefore,
CreatedAfter: createdAfter,
})
if err != nil {
h.logger.Error("Failed to get branches", "error", err)

View File

@ -184,7 +184,34 @@ func (h *Handler) GetCompanyByID(c *fiber.Ctx) error {
res := convertGetCompany(company)
return response.WriteJSON(c, fiber.StatusOK, "Company retrieved successfully", res, nil)
}
// GetCompanyForAdmin godoc
// @Summary Gets company by id
// @Description Gets a single company by id
// @Tags company
// @Accept json
// @Produce json
// @Success 200 {object} CompanyRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /admin-company [get]
func (h *Handler) GetCompanyForAdmin(c *fiber.Ctx) error {
companyID := c.Locals("company_id").(domain.ValidInt64)
if !companyID.Valid {
return response.WriteJSON(c, fiber.StatusInternalServerError, "Invalid company ID", nil, nil)
}
company, err := h.companySvc.GetCompanyByID(c.Context(), companyID.Value)
if err != nil {
h.logger.Error("Failed to get company by ID", "companyID", companyID.Value, "error", err)
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to company branch", err, nil)
}
res := convertGetCompany(company)
return response.WriteJSON(c, fiber.StatusOK, "Company retrieved successfully", res, nil)
}
// GetAllCompanies godoc

View File

@ -2,6 +2,7 @@ package handlers
import (
"context"
"os"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/gofiber/fiber/v2"
@ -20,7 +21,7 @@ import (
// @Router /api/v1/logs [get]
func GetLogsHandler(appCtx context.Context) fiber.Handler {
return func(c *fiber.Ctx) error {
client, err := mongo.Connect(appCtx, options.Client().ApplyURI("mongodb://root:secret@mongo:27017/?authSource=admin"))
client, err := mongo.Connect(appCtx, options.Client().ApplyURI(os.Getenv("MONGODB_URL")))
if err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "MongoDB connection failed: "+err.Error())
}

View File

@ -174,11 +174,7 @@ func (h *Handler) RegisterUser(c *fiber.Ctx) error {
return fiber.NewError(fiber.StatusInternalServerError, "Unknown Error")
}
newWallet, err := h.walletSvc.CreateWallet(c.Context(), domain.CreateWallet{
UserID: newUser.ID,
IsWithdraw: true,
IsBettable: true,
})
newWallet, err := h.walletSvc.CreateCustomerWallet(c.Context(), newUser.ID)
if err != nil {
h.logger.Error("Failed to create wallet for user", "userID", newUser.ID, "error", err)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to create user wallet")
@ -193,7 +189,7 @@ func (h *Handler) RegisterUser(c *fiber.Ctx) error {
// TODO: Remove later
_, err = h.walletSvc.AddToWallet(
c.Context(), newWallet.ID, domain.ToCurrency(100.0), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{})
c.Context(), newWallet.RegularID, domain.ToCurrency(100.0), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{})
if err != nil {
h.logger.Error("Failed to update wallet for user", "userID", newUser.ID, "error", err)

View File

@ -9,9 +9,6 @@ import (
"github.com/gofiber/fiber/v2"
)
type UpdateWalletActiveReq struct {
IsActive bool `json:"is_active" validate:"required" example:"true"`
}
type WalletRes struct {
ID int64 `json:"id" example:"1"`
Balance float32 `json:"amount" example:"100.0"`
@ -45,9 +42,14 @@ type CustomerWalletRes struct {
StaticID int64 `json:"static_id" example:"1"`
StaticBalance float32 `json:"static_balance" example:"100.0"`
CustomerID int64 `json:"customer_id" example:"1"`
RegularIsActive bool `json:"regular_is_active" example:"true"`
StaticIsActive bool `json:"static_is_active" example:"true"`
RegularUpdatedAt time.Time `json:"regular_updated_at"`
StaticUpdatedAt time.Time `json:"static_updated_at"`
CreatedAt time.Time `json:"created_at"`
FirstName string `json:"first_name" example:"John"`
LastName string `json:"last_name" example:"Smith"`
PhoneNumber string `json:"phone_number" example:"0911111111"`
}
func ConvertCustomerWallet(wallet domain.GetCustomerWallet) CustomerWalletRes {
@ -58,9 +60,14 @@ func ConvertCustomerWallet(wallet domain.GetCustomerWallet) CustomerWalletRes {
StaticID: wallet.StaticID,
StaticBalance: wallet.StaticBalance.Float32(),
CustomerID: wallet.CustomerID,
RegularIsActive: wallet.RegularIsActive,
StaticIsActive: wallet.StaticIsActive,
RegularUpdatedAt: wallet.RegularUpdatedAt,
StaticUpdatedAt: wallet.StaticUpdatedAt,
CreatedAt: wallet.CreatedAt,
FirstName: wallet.FirstName,
LastName: wallet.LastName,
PhoneNumber: wallet.PhoneNumber,
}
}
@ -173,7 +180,38 @@ func (h *Handler) GetAllBranchWallets(c *fiber.Ctx) error {
}
return response.WriteJSON(c, fiber.StatusOK, "All Wallets retrieved", res, nil)
}
// GetAllCustomerWallets godoc
// @Summary Get all customer wallets
// @Description Retrieve all customer wallets
// @Tags wallet
// @Accept json
// @Produce json
// @Success 200 {array} CustomerWalletRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /customerWallet [get]
func (h *Handler) GetAllCustomerWallets(c *fiber.Ctx) error {
wallets, err := h.walletSvc.GetAllCustomerWallet(c.Context())
if err != nil {
h.logger.Error("Failed to get wallets", "error", err)
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve wallets", err, nil)
}
var res []CustomerWalletRes = make([]CustomerWalletRes, 0, len(wallets))
for _, wallet := range wallets {
res = append(res, ConvertCustomerWallet(wallet))
}
return response.WriteJSON(c, fiber.StatusOK, "All Wallets retrieved", res, nil)
}
type UpdateWalletActiveReq struct {
IsActive bool `json:"is_active" validate:"required" example:"true"`
}
// UpdateWalletActive godoc
@ -255,13 +293,13 @@ func (h *Handler) GetCustomerWallet(c *fiber.Ctx) error {
// h.logger.Info("Fetching customer wallet", "userID", userID)
wallet, err := h.walletSvc.GetWalletsByUser(c.Context(), userID)
wallet, err := h.walletSvc.GetCustomerWallet(c.Context(), userID)
if err != nil {
h.logger.Error("Failed to get customer wallet", "userID", userID, "error", err)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve wallet")
}
res := convertWallet(wallet[0])
res := ConvertCustomerWallet(wallet)
return response.WriteJSON(c, fiber.StatusOK, "Wallet retrieved successfully", res, nil)
}

View File

@ -174,6 +174,7 @@ func (a *App) initAppRoutes() {
a.fiber.Delete("/company/:id", a.authMiddleware, a.SuperAdminOnly, h.DeleteCompany)
a.fiber.Get("/company/:id/branch", a.authMiddleware, h.GetBranchByCompanyID)
a.fiber.Get("/search/company", a.authMiddleware, h.SearchCompany)
a.fiber.Get("/admin-company", a.authMiddleware, h.GetCompanyForAdmin)
// Ticket Routes
a.fiber.Post("/ticket", h.CreateTicket)
@ -195,6 +196,7 @@ func (a *App) initAppRoutes() {
a.fiber.Get("/wallet/:id", h.GetWalletByID)
a.fiber.Put("/wallet/:id", h.UpdateWalletActive)
a.fiber.Get("/branchWallet", a.authMiddleware, h.GetAllBranchWallets)
a.fiber.Get("/customerWallet", a.authMiddleware, h.GetAllCustomerWallets)
a.fiber.Get("/cashierWallet", a.authMiddleware, h.GetWalletForCashier)
// Transfer