fix: fixing issues on transaction

This commit is contained in:
Samuel Tariku 2025-07-04 00:09:03 +03:00
parent 1a5b545f37
commit a06d77da01
20 changed files with 467 additions and 127 deletions

View File

@ -152,7 +152,7 @@ func main() {
cfg.FIXER_API_KEY, cfg.FIXER_API_KEY,
cfg.FIXER_BASE_URL, cfg.FIXER_BASE_URL,
) )
transactionSvc := transaction.NewService(store, *branchSvc, *betSvc, *walletSvc) transactionSvc := transaction.NewService(store, *branchSvc, *betSvc, *walletSvc, *userSvc)
reportSvc := report.NewService( reportSvc := report.NewService(
bet.BetStore(store), bet.BetStore(store),
@ -167,8 +167,6 @@ func main() {
logger, logger,
) )
go httpserver.SetupReportCronJobs(context.Background(), reportSvc) go httpserver.SetupReportCronJobs(context.Background(), reportSvc)
bankRepository := repository.NewBankRepository(store) bankRepository := repository.NewBankRepository(store)

View File

@ -207,7 +207,8 @@ CREATE TABLE IF NOT EXISTS shop_deposits (
id BIGSERIAL PRIMARY KEY, id BIGSERIAL PRIMARY KEY,
shop_transaction_id BIGINT NOT NULL, shop_transaction_id BIGINT NOT NULL,
customer_id BIGINT NOT NULL, customer_id BIGINT NOT NULL,
wallet_transfer_id BIGINT NOT NULL, wallet_transfer_id BIGINT,
branch_wallet_id BIGINT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(shop_transaction_id) UNIQUE(shop_transaction_id)
@ -406,6 +407,7 @@ SELECT sb.*,
st.verified AS transaction_verified, st.verified AS transaction_verified,
bets.status, bets.status,
bets.total_odds, bets.total_odds,
bets.expires,
JSON_AGG(bet_outcomes.*) AS outcomes JSON_AGG(bet_outcomes.*) AS outcomes
FROM shop_bets AS sb FROM shop_bets AS sb
JOIN shop_transactions st ON st.id = sb.shop_transaction_id JOIN shop_transactions st ON st.id = sb.shop_transaction_id
@ -502,6 +504,52 @@ VALUES (
NULL, NULL,
FALSE FALSE
); );
INSERT INTO wallets (
balance,
is_withdraw,
is_bettable,
is_transferable,
user_id,
is_active,
created_at,
updated_at
)
VALUES (
10000,
TRUE,
TRUE,
TRUE,
1,
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
);
INSERT INTO wallets (
balance,
is_withdraw,
is_bettable,
is_transferable,
user_id,
is_active,
created_at,
updated_at
)
VALUES (
10000,
FALSE,
TRUE,
TRUE,
1,
TRUE,
CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP
);
INSERT INTO customer_wallets (
customer_id,
regular_wallet_id,
static_wallet_id
)
VALUES (1, 1, 2);
INSERT INTO users ( INSERT INTO users (
first_name, first_name,
last_name, last_name,
@ -606,7 +654,7 @@ VALUES (
TRUE, TRUE,
TRUE, TRUE,
TRUE, TRUE,
1, 2,
TRUE, TRUE,
CURRENT_TIMESTAMP, CURRENT_TIMESTAMP,
CURRENT_TIMESTAMP CURRENT_TIMESTAMP
@ -619,7 +667,7 @@ INSERT INTO companies (
values ( values (
'Test Company', 'Test Company',
2, 2,
1 3
); );
INSERT INTO wallets ( INSERT INTO wallets (
balance, balance,
@ -654,7 +702,7 @@ INSERT INTO branches (
values ( values (
'Test Branch', 'Test Branch',
'Addis Ababa', 'Addis Ababa',
2, 4,
2, 2,
1, 1,
TRUE, TRUE,

View File

@ -135,7 +135,7 @@ WHERE id = $1;
INSERT INTO shop_deposits ( INSERT INTO shop_deposits (
shop_transaction_id, shop_transaction_id,
customer_id, customer_id,
wallet_transfer_id branch_wallet_id
) )
VALUES ($1, $2, $3) VALUES ($1, $2, $3)
RETURNING *; RETURNING *;
@ -170,4 +170,9 @@ WHERE id = $1;
-- name: GetShopDepositByShopTransactionID :one -- name: GetShopDepositByShopTransactionID :one
SELECT * SELECT *
FROM shop_deposit_detail FROM shop_deposit_detail
WHERE shop_transaction_id = $1; WHERE shop_transaction_id = $1;
-- name: UpdateShopDepositTransferID :exec
UPDATE shop_deposits
SET wallet_transfer_id = $2,
updated_at = CURRENT_TIMESTAMP
WHERE id = $1;

View File

@ -435,7 +435,8 @@ type ShopDeposit struct {
ID int64 `json:"id"` ID int64 `json:"id"`
ShopTransactionID int64 `json:"shop_transaction_id"` ShopTransactionID int64 `json:"shop_transaction_id"`
CustomerID int64 `json:"customer_id"` CustomerID int64 `json:"customer_id"`
WalletTransferID int64 `json:"wallet_transfer_id"` WalletTransferID pgtype.Int8 `json:"wallet_transfer_id"`
BranchWalletID int64 `json:"branch_wallet_id"`
CreatedAt pgtype.Timestamp `json:"created_at"` CreatedAt pgtype.Timestamp `json:"created_at"`
UpdatedAt pgtype.Timestamp `json:"updated_at"` UpdatedAt pgtype.Timestamp `json:"updated_at"`
} }
@ -444,7 +445,8 @@ type ShopDepositDetail struct {
ID int64 `json:"id"` ID int64 `json:"id"`
ShopTransactionID int64 `json:"shop_transaction_id"` ShopTransactionID int64 `json:"shop_transaction_id"`
CustomerID int64 `json:"customer_id"` CustomerID int64 `json:"customer_id"`
WalletTransferID int64 `json:"wallet_transfer_id"` WalletTransferID pgtype.Int8 `json:"wallet_transfer_id"`
BranchWalletID int64 `json:"branch_wallet_id"`
CreatedAt pgtype.Timestamp `json:"created_at"` CreatedAt pgtype.Timestamp `json:"created_at"`
UpdatedAt pgtype.Timestamp `json:"updated_at"` UpdatedAt pgtype.Timestamp `json:"updated_at"`
FullName string `json:"full_name"` FullName string `json:"full_name"`

View File

@ -55,26 +55,27 @@ const CreateShopDeposit = `-- name: CreateShopDeposit :one
INSERT INTO shop_deposits ( INSERT INTO shop_deposits (
shop_transaction_id, shop_transaction_id,
customer_id, customer_id,
wallet_transfer_id branch_wallet_id
) )
VALUES ($1, $2, $3) VALUES ($1, $2, $3)
RETURNING id, shop_transaction_id, customer_id, wallet_transfer_id, created_at, updated_at RETURNING id, shop_transaction_id, customer_id, wallet_transfer_id, branch_wallet_id, created_at, updated_at
` `
type CreateShopDepositParams struct { type CreateShopDepositParams struct {
ShopTransactionID int64 `json:"shop_transaction_id"` ShopTransactionID int64 `json:"shop_transaction_id"`
CustomerID int64 `json:"customer_id"` CustomerID int64 `json:"customer_id"`
WalletTransferID int64 `json:"wallet_transfer_id"` BranchWalletID int64 `json:"branch_wallet_id"`
} }
func (q *Queries) CreateShopDeposit(ctx context.Context, arg CreateShopDepositParams) (ShopDeposit, error) { func (q *Queries) CreateShopDeposit(ctx context.Context, arg CreateShopDepositParams) (ShopDeposit, error) {
row := q.db.QueryRow(ctx, CreateShopDeposit, arg.ShopTransactionID, arg.CustomerID, arg.WalletTransferID) row := q.db.QueryRow(ctx, CreateShopDeposit, arg.ShopTransactionID, arg.CustomerID, arg.BranchWalletID)
var i ShopDeposit var i ShopDeposit
err := row.Scan( err := row.Scan(
&i.ID, &i.ID,
&i.ShopTransactionID, &i.ShopTransactionID,
&i.CustomerID, &i.CustomerID,
&i.WalletTransferID, &i.WalletTransferID,
&i.BranchWalletID,
&i.CreatedAt, &i.CreatedAt,
&i.UpdatedAt, &i.UpdatedAt,
) )
@ -251,7 +252,7 @@ func (q *Queries) GetAllShopBets(ctx context.Context, arg GetAllShopBetsParams)
} }
const GetAllShopDeposit = `-- name: GetAllShopDeposit :many const GetAllShopDeposit = `-- name: GetAllShopDeposit :many
SELECT id, shop_transaction_id, customer_id, wallet_transfer_id, created_at, updated_at, full_name, phone_number, branch_id, company_id, amount, transaction_verified SELECT id, shop_transaction_id, customer_id, wallet_transfer_id, branch_wallet_id, created_at, updated_at, full_name, phone_number, branch_id, company_id, amount, transaction_verified
FROM shop_deposit_detail FROM shop_deposit_detail
WHERE ( WHERE (
full_name ILIKE '%' || $1 || '%' full_name ILIKE '%' || $1 || '%'
@ -304,6 +305,7 @@ func (q *Queries) GetAllShopDeposit(ctx context.Context, arg GetAllShopDepositPa
&i.ShopTransactionID, &i.ShopTransactionID,
&i.CustomerID, &i.CustomerID,
&i.WalletTransferID, &i.WalletTransferID,
&i.BranchWalletID,
&i.CreatedAt, &i.CreatedAt,
&i.UpdatedAt, &i.UpdatedAt,
&i.FullName, &i.FullName,
@ -545,7 +547,7 @@ func (q *Queries) GetShopBetByShopTransactionID(ctx context.Context, shopTransac
} }
const GetShopDepositByID = `-- name: GetShopDepositByID :one const GetShopDepositByID = `-- name: GetShopDepositByID :one
SELECT id, shop_transaction_id, customer_id, wallet_transfer_id, created_at, updated_at, full_name, phone_number, branch_id, company_id, amount, transaction_verified SELECT id, shop_transaction_id, customer_id, wallet_transfer_id, branch_wallet_id, created_at, updated_at, full_name, phone_number, branch_id, company_id, amount, transaction_verified
FROM shop_deposit_detail FROM shop_deposit_detail
WHERE id = $1 WHERE id = $1
` `
@ -558,6 +560,7 @@ func (q *Queries) GetShopDepositByID(ctx context.Context, id int64) (ShopDeposit
&i.ShopTransactionID, &i.ShopTransactionID,
&i.CustomerID, &i.CustomerID,
&i.WalletTransferID, &i.WalletTransferID,
&i.BranchWalletID,
&i.CreatedAt, &i.CreatedAt,
&i.UpdatedAt, &i.UpdatedAt,
&i.FullName, &i.FullName,
@ -571,7 +574,7 @@ func (q *Queries) GetShopDepositByID(ctx context.Context, id int64) (ShopDeposit
} }
const GetShopDepositByShopTransactionID = `-- name: GetShopDepositByShopTransactionID :one const GetShopDepositByShopTransactionID = `-- name: GetShopDepositByShopTransactionID :one
SELECT id, shop_transaction_id, customer_id, wallet_transfer_id, created_at, updated_at, full_name, phone_number, branch_id, company_id, amount, transaction_verified SELECT id, shop_transaction_id, customer_id, wallet_transfer_id, branch_wallet_id, created_at, updated_at, full_name, phone_number, branch_id, company_id, amount, transaction_verified
FROM shop_deposit_detail FROM shop_deposit_detail
WHERE shop_transaction_id = $1 WHERE shop_transaction_id = $1
` `
@ -584,6 +587,7 @@ func (q *Queries) GetShopDepositByShopTransactionID(ctx context.Context, shopTra
&i.ShopTransactionID, &i.ShopTransactionID,
&i.CustomerID, &i.CustomerID,
&i.WalletTransferID, &i.WalletTransferID,
&i.BranchWalletID,
&i.CreatedAt, &i.CreatedAt,
&i.UpdatedAt, &i.UpdatedAt,
&i.FullName, &i.FullName,
@ -723,6 +727,23 @@ func (q *Queries) UpdateShopBetCashoutID(ctx context.Context, arg UpdateShopBetC
return err return err
} }
const UpdateShopDepositTransferID = `-- name: UpdateShopDepositTransferID :exec
UPDATE shop_deposits
SET wallet_transfer_id = $2,
updated_at = CURRENT_TIMESTAMP
WHERE id = $1
`
type UpdateShopDepositTransferIDParams struct {
ID int64 `json:"id"`
WalletTransferID pgtype.Int8 `json:"wallet_transfer_id"`
}
func (q *Queries) UpdateShopDepositTransferID(ctx context.Context, arg UpdateShopDepositTransferIDParams) error {
_, err := q.db.Exec(ctx, UpdateShopDepositTransferID, arg.ID, arg.WalletTransferID)
return err
}
const UpdateShopTransactionVerified = `-- name: UpdateShopTransactionVerified :exec const UpdateShopTransactionVerified = `-- name: UpdateShopTransactionVerified :exec
UPDATE shop_transactions UPDATE shop_transactions
SET verified = $2, SET verified = $2,

View File

@ -116,6 +116,100 @@ type DashboardSummary struct {
ReadNotifications int64 `json:"read_notifications"` ReadNotifications int64 `json:"read_notifications"`
UnreadNotifications int64 `json:"unread_notifications"` UnreadNotifications int64 `json:"unread_notifications"`
} }
type DashboardSummaryRes struct {
TotalStakes float32 `json:"total_stakes"`
TotalBets int64 `json:"total_bets"`
ActiveBets int64 `json:"active_bets"`
WinBalance float32 `json:"win_balance"`
TotalWins int64 `json:"total_wins"`
TotalLosses int64 `json:"total_losses"`
CustomerCount int64 `json:"customer_count"`
Profit float32 `json:"profit"`
WinRate float64 `json:"win_rate"`
AverageStake float32 `json:"average_stake"`
TotalDeposits float32 `json:"total_deposits"`
TotalWithdrawals float32 `json:"total_withdrawals"`
ActiveCustomers int64 `json:"active_customers"`
BranchesCount int64 `json:"branches_count"`
ActiveBranches int64 `json:"active_branches"`
TotalCashiers int64 `json:"total_cashiers"`
ActiveCashiers int64 `json:"active_cashiers"`
InactiveCashiers int64 `json:"inactive_cashiers"`
TotalWallets int64 `json:"total_wallets"`
TotalGames int64 `json:"total_games"`
ActiveGames int64 `json:"active_games"`
InactiveGames int64 `json:"inactive_games"`
TotalManagers int64 `json:"total_managers"`
ActiveManagers int64 `json:"active_managers"`
InactiveManagers int64 `json:"inactive_managers"`
InactiveBranches int64 `json:"inactive_branches"`
TotalAdmins int64 `json:"total_admins"`
ActiveAdmins int64 `json:"active_admins"`
InactiveAdmins int64 `json:"inactive_admins"`
TotalCompanies int64 `json:"total_companies"`
ActiveCompanies int64 `json:"active_companies"`
InactiveCompanies int64 `json:"inactive_companies"`
InactiveCustomers int64 `json:"inactive_customers"`
TotalNotifications int64 `json:"total_notifications"`
ReadNotifications int64 `json:"read_notifications"`
UnreadNotifications int64 `json:"unread_notifications"`
}
func ConvertDashboardSummaryToRes(summary DashboardSummary) DashboardSummaryRes {
return DashboardSummaryRes{
TotalStakes: summary.TotalStakes.Float32(),
TotalBets: summary.TotalBets,
ActiveBets: summary.ActiveBets,
WinBalance: summary.WinBalance.Float32(),
TotalWins: summary.TotalWins,
TotalLosses: summary.TotalLosses,
CustomerCount: summary.CustomerCount,
Profit: summary.Profit.Float32(),
WinRate: summary.WinRate,
AverageStake: summary.AverageStake.Float32(),
TotalDeposits: summary.TotalDeposits.Float32(),
TotalWithdrawals: summary.TotalWithdrawals.Float32(),
ActiveCustomers: summary.ActiveCustomers,
BranchesCount: summary.BranchesCount,
ActiveBranches: summary.ActiveBranches,
TotalCashiers: summary.TotalCashiers,
ActiveCashiers: summary.ActiveCashiers,
InactiveCashiers: summary.InactiveCashiers,
TotalWallets: summary.TotalWallets,
TotalGames: summary.TotalGames,
ActiveGames: summary.ActiveGames,
InactiveGames: summary.InactiveGames,
TotalManagers: summary.TotalManagers,
ActiveManagers: summary.ActiveManagers,
InactiveManagers: summary.InactiveManagers,
InactiveBranches: summary.InactiveBranches,
TotalAdmins: summary.TotalAdmins,
ActiveAdmins: summary.ActiveAdmins,
InactiveAdmins: summary.InactiveAdmins,
TotalCompanies: summary.TotalCompanies,
ActiveCompanies: summary.ActiveCompanies,
InactiveCompanies: summary.InactiveCompanies,
InactiveCustomers: summary.InactiveCustomers,
TotalNotifications: summary.TotalNotifications,
ReadNotifications: summary.ReadNotifications,
UnreadNotifications: summary.UnreadNotifications,
}
}
type CustomerActivity struct { type CustomerActivity struct {
CustomerID int64 `json:"customer_id"` CustomerID int64 `json:"customer_id"`

View File

@ -1,17 +1,20 @@
package domain package domain
import "time" import (
"time"
)
type ShopDeposit struct { type ShopDeposit struct {
ID int64 ID int64
ShopTransactionID int64 ShopTransactionID int64
CustomerID int64 CustomerID int64
WalletTransferID int64 WalletTransferID ValidInt64
BranchWalletID int64
} }
type CreateShopDeposit struct { type CreateShopDeposit struct {
ShopTransactionID int64 ShopTransactionID int64
CustomerID int64 CustomerID int64
WalletTransferID int64 BranchWalletID int64
} }
type ShopDepositFilter struct { type ShopDepositFilter struct {
@ -26,7 +29,8 @@ type ShopDepositDetail struct {
ID int64 ID int64
ShopTransactionID int64 ShopTransactionID int64
CustomerID int64 CustomerID int64
WalletTransferID int64 BranchWalletID int64
WalletTransferID ValidInt64
FullName string FullName string
PhoneNumber string PhoneNumber string
Amount Currency Amount Currency
@ -38,31 +42,37 @@ type ShopDepositDetail struct {
} }
type ShopDepositReq struct { type ShopDepositReq struct {
CustomerID int64 `json:"customer_id" example:"1"` CustomerID int64 `json:"customer_id" example:"1"`
Amount float32 `json:"amount" example:"100.0"` Amount float32 `json:"amount" example:"100.0"`
PaymentOption PaymentOption `json:"payment_option" example:"1"` PaymentOption PaymentOption `json:"payment_option" example:"1"`
FullName string `json:"full_name" example:"John Smith"` // FullName string `json:"full_name" example:"John Smith"`
PhoneNumber string `json:"phone_number" example:"0911111111"` // PhoneNumber string `json:"phone_number" example:"0911111111"`
BankCode string `json:"bank_code"` BankCode string `json:"bank_code"`
BeneficiaryName string `json:"beneficiary_name"` BeneficiaryName string `json:"beneficiary_name"`
AccountName string `json:"account_name"` AccountName string `json:"account_name"`
AccountNumber string `json:"account_number"` AccountNumber string `json:"account_number"`
ReferenceNumber string `json:"reference_number"` ReferenceNumber string `json:"reference_number"`
BranchID *int64 `json:"branch_id,omitempty" example:"1"` BranchID *int64 `json:"branch_id,omitempty" example:"1"`
} }
type ShopDepositRes struct { type ShopDepositRes struct {
ID int64 `json:"id"` ID int64 `json:"id"`
ShopTransactionID int64 `json:"shop_transaction_id"` ShopTransactionID int64 `json:"shop_transaction_id"`
CustomerID int64 `json:"customer_id"` CustomerID int64 `json:"customer_id"`
WalletTransferID int64 `json:"wallet_transfer_id"` WalletTransferID *int64 `json:"wallet_transfer_id,omitempty"`
} }
func ConvertShopDeposit(shopDeposit ShopDeposit) ShopDepositRes { func ConvertShopDeposit(shopDeposit ShopDeposit) ShopDepositRes {
return ShopDepositRes{
res := ShopDepositRes{
ID: shopDeposit.ID, ID: shopDeposit.ID,
ShopTransactionID: shopDeposit.ShopTransactionID, ShopTransactionID: shopDeposit.ShopTransactionID,
CustomerID: shopDeposit.CustomerID, CustomerID: shopDeposit.CustomerID,
WalletTransferID: shopDeposit.WalletTransferID,
} }
if shopDeposit.WalletTransferID.Valid {
res.WalletTransferID = &shopDeposit.WalletTransferID.Value
}
return res
} }

View File

@ -13,16 +13,24 @@ func convertShopDeposit(deposit dbgen.ShopDeposit) domain.ShopDeposit {
ID: deposit.ID, ID: deposit.ID,
ShopTransactionID: deposit.ShopTransactionID, ShopTransactionID: deposit.ShopTransactionID,
CustomerID: deposit.CustomerID, CustomerID: deposit.CustomerID,
WalletTransferID: deposit.WalletTransferID, BranchWalletID: deposit.BranchWalletID,
WalletTransferID: domain.ValidInt64{
Value: deposit.WalletTransferID.Int64,
Valid: deposit.WalletTransferID.Valid,
},
} }
} }
func convertShopDepositDetail(deposit dbgen.ShopDepositDetail) domain.ShopDepositDetail { func convertShopDepositDetail(deposit dbgen.ShopDepositDetail) domain.ShopDepositDetail {
return domain.ShopDepositDetail{ return domain.ShopDepositDetail{
ID: deposit.ID, ID: deposit.ID,
ShopTransactionID: deposit.ShopTransactionID, ShopTransactionID: deposit.ShopTransactionID,
CustomerID: deposit.CustomerID, CustomerID: deposit.CustomerID,
WalletTransferID: deposit.WalletTransferID, BranchWalletID: deposit.BranchWalletID,
WalletTransferID: domain.ValidInt64{
Value: deposit.WalletTransferID.Int64,
Valid: deposit.WalletTransferID.Valid,
},
FullName: deposit.FullName, FullName: deposit.FullName,
PhoneNumber: deposit.PhoneNumber, PhoneNumber: deposit.PhoneNumber,
Amount: domain.Currency(deposit.Amount), Amount: domain.Currency(deposit.Amount),
@ -37,7 +45,7 @@ func convertCreateShopDeposit(deposit domain.CreateShopDeposit) dbgen.CreateShop
return dbgen.CreateShopDepositParams{ return dbgen.CreateShopDepositParams{
ShopTransactionID: deposit.ShopTransactionID, ShopTransactionID: deposit.ShopTransactionID,
CustomerID: deposit.CustomerID, CustomerID: deposit.CustomerID,
WalletTransferID: deposit.WalletTransferID, BranchWalletID: deposit.BranchWalletID,
} }
} }
@ -102,3 +110,13 @@ func (s *Store) GetShopDepositByShopTransactionID(ctx context.Context, shopTrans
return convertShopDepositDetail(deposit), err return convertShopDepositDetail(deposit), err
} }
func (s *Store) UpdateShopDepositTransferID(ctx context.Context, id int64, transferID domain.ValidInt64) error {
return s.queries.UpdateShopDepositTransferID(ctx, dbgen.UpdateShopDepositTransferIDParams{
WalletTransferID: pgtype.Int8{
Int64: transferID.Value,
Valid: transferID.Valid,
},
ID: id,
})
}

View File

@ -196,7 +196,7 @@ func (s *Store) GetShopTransactionByBranch(ctx context.Context, id int64) ([]dom
return result, nil return result, nil
} }
func (s *Store) UpdateShopTransactionVerified(ctx context.Context, id int64, verified bool, approvedBy int64, approverName string) error { func (s *Store) UpdateShopTransactionVerified(ctx context.Context, id int64, verified bool, approvedBy int64) error {
err := s.queries.UpdateShopTransactionVerified(ctx, dbgen.UpdateShopTransactionVerifiedParams{ err := s.queries.UpdateShopTransactionVerified(ctx, dbgen.UpdateShopTransactionVerifiedParams{
ID: id, ID: id,
ApprovedBy: pgtype.Int8{ ApprovedBy: pgtype.Int8{

View File

@ -215,7 +215,7 @@ func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, url, sour
for sportIndex, sportID := range sportIDs { for sportIndex, sportID := range sportIDs {
var totalPages int = 1 var totalPages int = 1
var page int = 0 var page int = 0
var limit int = 200 var limit int = 1
var count int = 0 var count int = 0
for page <= totalPages { for page <= totalPages {
page = page + 1 page = page + 1

View File

@ -11,7 +11,7 @@ type TransactionStore interface {
GetAllShopTransactions(ctx context.Context, filter domain.ShopTransactionFilter) ([]domain.ShopTransactionDetail, error) GetAllShopTransactions(ctx context.Context, filter domain.ShopTransactionFilter) ([]domain.ShopTransactionDetail, error)
GetShopTransactionByID(ctx context.Context, id int64) (domain.ShopTransactionDetail, error) GetShopTransactionByID(ctx context.Context, id int64) (domain.ShopTransactionDetail, error)
GetShopTransactionByBranch(ctx context.Context, id int64) ([]domain.ShopTransactionDetail, error) GetShopTransactionByBranch(ctx context.Context, id int64) ([]domain.ShopTransactionDetail, error)
UpdateShopTransactionVerified(ctx context.Context, id int64, verified bool, approvedBy int64, approverName string) error UpdateShopTransactionVerified(ctx context.Context, id int64, verified bool, approvedBy int64) error
GetTransactionTotals(ctx context.Context, filter domain.ReportFilter) (deposits, withdrawals domain.Currency, err error) GetTransactionTotals(ctx context.Context, filter domain.ReportFilter) (deposits, withdrawals domain.Currency, err error)
GetBranchTransactionTotals(ctx context.Context, filter domain.ReportFilter) (map[int64]domain.BranchTransactions, error) GetBranchTransactionTotals(ctx context.Context, filter domain.ReportFilter) (map[int64]domain.BranchTransactions, error)
@ -28,4 +28,5 @@ type TransactionStore interface {
GetAllShopDeposit(ctx context.Context, filter domain.ShopDepositFilter) ([]domain.ShopDepositDetail, error) GetAllShopDeposit(ctx context.Context, filter domain.ShopDepositFilter) ([]domain.ShopDepositDetail, error)
GetShopDepositByID(ctx context.Context, id int64) (domain.ShopDepositDetail, error) GetShopDepositByID(ctx context.Context, id int64) (domain.ShopDepositDetail, error)
GetShopDepositByShopTransactionID(ctx context.Context, shopTransactionID int64) (domain.ShopDepositDetail, error) GetShopDepositByShopTransactionID(ctx context.Context, shopTransactionID int64) (domain.ShopDepositDetail, error)
UpdateShopDepositTransferID(ctx context.Context, id int64, transferID domain.ValidInt64) error
} }

View File

@ -3,10 +3,13 @@ package transaction
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"time"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/branch" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/branch"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
) )
@ -16,6 +19,8 @@ var (
ErrUnauthorizedCompanyID = errors.New("unauthorized company id") ErrUnauthorizedCompanyID = errors.New("unauthorized company id")
ErrUnauthorizedBranchManager = errors.New("unauthorized branch manager") ErrUnauthorizedBranchManager = errors.New("unauthorized branch manager")
ErrCustomerRoleNotAuthorized = errors.New("customer role not authorized") ErrCustomerRoleNotAuthorized = errors.New("customer role not authorized")
ErrDepositCannotBeUnverified = errors.New("deposit cannot be unverified")
ErrShopBetHasExpired = errors.New("shop bet has already been expired")
) )
type Service struct { type Service struct {
@ -23,14 +28,16 @@ type Service struct {
branchSvc branch.Service branchSvc branch.Service
betSvc bet.Service betSvc bet.Service
walletSvc wallet.Service walletSvc wallet.Service
userSvc user.Service
} }
func NewService(transactionStore TransactionStore, branchSvc branch.Service, betSvc bet.Service, walletSvc wallet.Service) *Service { func NewService(transactionStore TransactionStore, branchSvc branch.Service, betSvc bet.Service, walletSvc wallet.Service, userSvc user.Service) *Service {
return &Service{ return &Service{
transactionStore: transactionStore, transactionStore: transactionStore,
branchSvc: branchSvc, branchSvc: branchSvc,
betSvc: betSvc, betSvc: betSvc,
walletSvc: walletSvc, walletSvc: walletSvc,
userSvc: userSvc,
} }
} }
@ -46,8 +53,88 @@ func (s *Service) GetAllShopTransactions(ctx context.Context, filter domain.Shop
func (s *Service) GetShopTransactionByBranch(ctx context.Context, id int64) ([]domain.ShopTransactionDetail, error) { func (s *Service) GetShopTransactionByBranch(ctx context.Context, id int64) ([]domain.ShopTransactionDetail, error) {
return s.transactionStore.GetShopTransactionByBranch(ctx, id) return s.transactionStore.GetShopTransactionByBranch(ctx, id)
} }
func (s *Service) UpdateShopTransactionVerified(ctx context.Context, id int64, verified bool, approvedBy int64, approverName string) error { func (s *Service) UpdateShopTransactionVerified(ctx context.Context, id int64, verified bool, approvedBy int64, role domain.Role, companyID domain.ValidInt64, branchID domain.ValidInt64) error {
return s.transactionStore.UpdateShopTransactionVerified(ctx, id, verified, approvedBy, approverName) // TODO: Move this into a service role verification service
// Checks to make sure only the same company and branch can modify this
transaction, err := s.GetShopTransactionByID(ctx, id)
if role != domain.RoleSuperAdmin {
if !companyID.Valid || companyID.Value != transaction.CompanyID {
// s.logger.Error("Failed to parse UpdateTransactionVerified request", "error", err)
return fmt.Errorf("user cannot modify another companies data")
}
if role == domain.RoleCashier {
if !branchID.Valid || branchID.Value != transaction.BranchID {
// h.logger.Error("Failed to parse UpdateTransactionVerified request", "error", "Unauthorized")
return fmt.Errorf("user cannot modify another companies data")
}
}
}
if err != nil {
return err
}
switch transaction.Type {
case domain.TRANSACTION_BET:
if verified {
bet, err := s.GetShopBetByShopTransactionID(ctx, transaction.ID)
if err != nil {
return err
}
var firstEvent time.Time = bet.Outcomes[0].Expires
for _, outcome := range bet.Outcomes {
if outcome.Expires.Before(firstEvent) {
firstEvent = outcome.Expires
}
}
fmt.Printf("\n\n Shop bet expire %v - now %v \n\n", firstEvent, time.Now().UTC())
if firstEvent.Before(time.Now()) {
return ErrShopBetHasExpired
}
}
case domain.TRANSACTION_DEPOSIT:
if !verified {
// TODO: Figure out what to do here? Should i return the money or verify the faulty verify
return ErrDepositCannotBeUnverified
}
deposit, err := s.GetShopDepositByShopTransactionID(ctx, transaction.ID)
if err != nil {
return err
}
customerWallet, err := s.walletSvc.GetCustomerWallet(ctx, deposit.CustomerID)
if err != nil {
return ErrUserHasNoCustomerWallet
}
transfer, err := s.walletSvc.TransferToWallet(ctx,
deposit.BranchWalletID, customerWallet.RegularID, transaction.Amount, domain.TRANSFER_DIRECT, domain.ValidInt64{
Value: transaction.UserID,
Valid: true,
},
fmt.Sprintf("Transferred %v to customer wallet due to shop deposit", transaction.Amount),
)
if err != nil {
return err
}
err = s.UpdateShopDepositTransferID(ctx, deposit.ID, domain.ValidInt64{
Value: transfer.ID,
Valid: true,
})
if err != nil {
return err
}
}
return s.transactionStore.UpdateShopTransactionVerified(ctx, id, verified, approvedBy)
} }
func (s *Service) GetBranchByRole(ctx context.Context, branchID *int64, role domain.Role, userID int64, userCompanyID domain.ValidInt64) (*int64, *int64, error) { func (s *Service) GetBranchByRole(ctx context.Context, branchID *int64, role domain.Role, userID int64, userCompanyID domain.ValidInt64) (*int64, *int64, error) {
@ -65,7 +152,7 @@ func (s *Service) GetBranchByRole(ctx context.Context, branchID *int64, role dom
return nil, nil, ErrInvalidBetID return nil, nil, ErrInvalidBetID
} }
// Check if the user has access to the company // Check if the user has access to the company
if role != domain.RoleSuperAdmin { if role != domain.RoleSuperAdmin {
if !userCompanyID.Valid || userCompanyID.Value != branch.CompanyID { if !userCompanyID.Valid || userCompanyID.Value != branch.CompanyID {
return nil, nil, ErrUnauthorizedCompanyID return nil, nil, ErrUnauthorizedCompanyID

View File

@ -44,9 +44,7 @@ func (s *Service) CreateShopBet(ctx context.Context, userID int64, role domain.R
if err != nil { if err != nil {
return domain.ShopBet{}, err return domain.ShopBet{}, err
} }
cashoutID, err := s.GenerateCashoutID() cashoutID, err := s.GenerateCashoutID()
if err != nil { if err != nil {
return domain.ShopBet{}, err return domain.ShopBet{}, err
} }

View File

@ -2,16 +2,21 @@ package transaction
import ( import (
"context" "context"
"fmt" "errors"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
) )
var (
ErrUserHasNoCustomerWallet = errors.New("user has no customer wallet")
)
func (s *Service) CreateShopDeposit(ctx context.Context, userID int64, role domain.Role, req domain.ShopDepositReq) (domain.ShopDeposit, error) { func (s *Service) CreateShopDeposit(ctx context.Context, userID int64, role domain.Role, req domain.ShopDepositReq) (domain.ShopDeposit, error) {
var branchID int64 var branchID int64
var companyID int64 var companyID int64
var senderID int64 var senderID int64
if role == domain.RoleAdmin || role == domain.RoleBranchManager || role == domain.RoleSuperAdmin { switch role {
case domain.RoleAdmin, domain.RoleBranchManager, domain.RoleSuperAdmin:
if req.BranchID == nil { if req.BranchID == nil {
// h.logger.Error("CashoutReq Branch ID is required for this user role") // h.logger.Error("CashoutReq Branch ID is required for this user role")
return domain.ShopDeposit{}, ErrBranchRequiredForRole return domain.ShopDeposit{}, ErrBranchRequiredForRole
@ -25,7 +30,7 @@ func (s *Service) CreateShopDeposit(ctx context.Context, userID int64, role doma
branchID = branch.ID branchID = branch.ID
companyID = branch.CompanyID companyID = branch.CompanyID
senderID = branch.WalletID senderID = branch.WalletID
} else if role == domain.RoleCashier { case domain.RoleCashier:
branch, err := s.branchSvc.GetBranchByCashier(ctx, userID) branch, err := s.branchSvc.GetBranchByCashier(ctx, userID)
if err != nil { if err != nil {
// h.logger.Error("CashoutReq failed, branch id invalid") // h.logger.Error("CashoutReq failed, branch id invalid")
@ -34,21 +39,19 @@ func (s *Service) CreateShopDeposit(ctx context.Context, userID int64, role doma
branchID = branch.ID branchID = branch.ID
companyID = branch.CompanyID companyID = branch.CompanyID
senderID = branch.WalletID senderID = branch.WalletID
} else { default:
return domain.ShopDeposit{}, ErrCustomerRoleNotAuthorized return domain.ShopDeposit{}, ErrCustomerRoleNotAuthorized
} }
customerWallet, err := s.walletSvc.GetCustomerWallet(ctx, req.CustomerID) user, err := s.userSvc.GetUserByID(ctx, req.CustomerID)
if err != nil { if err != nil {
return domain.ShopDeposit{}, err return domain.ShopDeposit{}, err
} }
transfer, err := s.walletSvc.TransferToWallet(ctx, if err != nil {
senderID, customerWallet.RegularID, domain.ToCurrency(req.Amount), domain.TRANSFER_DIRECT, return domain.ShopDeposit{}, err
domain.ValidInt64{Value: userID, Valid: true}, }
fmt.Sprintf("Transferred %v from customer wallet deposit", req.Amount),
)
newTransaction, err := s.CreateShopTransaction(ctx, domain.CreateShopTransaction{ newTransaction, err := s.CreateShopTransaction(ctx, domain.CreateShopTransaction{
Amount: domain.Currency(req.Amount), Amount: domain.Currency(req.Amount),
@ -56,8 +59,8 @@ func (s *Service) CreateShopDeposit(ctx context.Context, userID int64, role doma
CompanyID: companyID, CompanyID: companyID,
UserID: userID, UserID: userID,
Type: domain.TRANSACTION_DEPOSIT, Type: domain.TRANSACTION_DEPOSIT,
FullName: req.FullName, FullName: user.FirstName + " " + user.LastName,
PhoneNumber: req.PhoneNumber, PhoneNumber: user.PhoneNumber,
PaymentOption: req.PaymentOption, PaymentOption: req.PaymentOption,
BankCode: domain.ValidString{ BankCode: domain.ValidString{
Value: req.BankCode, Value: req.BankCode,
@ -93,7 +96,7 @@ func (s *Service) CreateShopDeposit(ctx context.Context, userID int64, role doma
return s.transactionStore.CreateShopDeposit(ctx, domain.CreateShopDeposit{ return s.transactionStore.CreateShopDeposit(ctx, domain.CreateShopDeposit{
ShopTransactionID: newTransaction.ID, ShopTransactionID: newTransaction.ID,
CustomerID: req.CustomerID, CustomerID: req.CustomerID,
WalletTransferID: transfer.ID, BranchWalletID: senderID,
}) })
} }
@ -112,3 +115,7 @@ func (s *Service) GetShopDepositByID(ctx context.Context, id int64) (domain.Shop
func (s *Service) GetShopDepositByShopTransactionID(ctx context.Context, shopTransactionID int64) (domain.ShopDepositDetail, error) { func (s *Service) GetShopDepositByShopTransactionID(ctx context.Context, shopTransactionID int64) (domain.ShopDepositDetail, error) {
return s.transactionStore.GetShopDepositByShopTransactionID(ctx, shopTransactionID) return s.transactionStore.GetShopDepositByShopTransactionID(ctx, shopTransactionID)
} }
func (s *Service) UpdateShopDepositTransferID(ctx context.Context, id int64, transferID domain.ValidInt64) error {
return s.transactionStore.UpdateShopDepositTransferID(ctx, id, transferID)
}

View File

@ -19,9 +19,10 @@ func (s *Service) CreateWallet(ctx context.Context, wallet domain.CreateWallet)
func (s *Service) CreateCustomerWallet(ctx context.Context, customerID int64) (domain.CustomerWallet, error) { func (s *Service) CreateCustomerWallet(ctx context.Context, customerID int64) (domain.CustomerWallet, error) {
regularWallet, err := s.CreateWallet(ctx, domain.CreateWallet{ regularWallet, err := s.CreateWallet(ctx, domain.CreateWallet{
IsWithdraw: true, IsWithdraw: true,
IsBettable: true, IsBettable: true,
UserID: customerID, IsTransferable: true,
UserID: customerID,
}) })
if err != nil { if err != nil {
@ -29,9 +30,10 @@ func (s *Service) CreateCustomerWallet(ctx context.Context, customerID int64) (d
} }
staticWallet, err := s.CreateWallet(ctx, domain.CreateWallet{ staticWallet, err := s.CreateWallet(ctx, domain.CreateWallet{
IsWithdraw: false, IsWithdraw: false,
IsBettable: true, IsBettable: true,
UserID: customerID, IsTransferable: true,
UserID: customerID,
}) })
if err != nil { if err != nil {
@ -139,7 +141,7 @@ func (s *Service) DeductFromWallet(ctx context.Context, id int64, amount domain.
// Log the transfer here for reference // Log the transfer here for reference
newTransfer, err := s.transferStore.CreateTransfer(ctx, domain.CreateTransfer{ newTransfer, err := s.transferStore.CreateTransfer(ctx, domain.CreateTransfer{
Message: message, Message: message,
Amount: amount, Amount: amount,
Verified: true, Verified: true,
SenderWalletID: domain.ValidInt64{ SenderWalletID: domain.ValidInt64{

View File

@ -123,20 +123,20 @@ func (h *Handler) CreateBetWithFastCode(c *fiber.Ctx) error {
return fiber.NewError(fiber.StatusBadRequest, "falied to get user information") return fiber.NewError(fiber.StatusBadRequest, "falied to get user information")
} }
branch, err := h.branchSvc.GetBranchByID(c.Context(), user.CompanyID.Value) // branch, err := h.branchSvc.GetBranchByID(c.Context(), user)
if err != nil { // if err != nil {
h.mongoLoggerSvc.Error("falied to get branch of user", // h.mongoLoggerSvc.Error("falied to get branch of user",
zap.Int("status_code", fiber.StatusInternalServerError), // zap.Int("status_code", fiber.StatusInternalServerError),
zap.Error(err), // zap.Error(err),
zap.Time("timestamp", time.Now()), // zap.Time("timestamp", time.Now()),
) // )
return fiber.NewError(fiber.StatusBadRequest, "falied to get branch of user") // return fiber.NewError(fiber.StatusBadRequest, "falied to get branch of user")
} // }
newReq := domain.CreateBetReq{ newReq := domain.CreateBetReq{
Amount: float32(bet.Amount), Amount: float32(bet.Amount),
Outcomes: bet_outcomes, Outcomes: bet_outcomes,
BranchID: &branch.ID, BranchID: nil,
FullName: user.FirstName, FullName: user.FirstName,
PhoneNumber: user.PhoneNumber, PhoneNumber: user.PhoneNumber,
} }
@ -151,31 +151,12 @@ func (h *Handler) CreateBetWithFastCode(c *fiber.Ctx) error {
return fiber.NewError(fiber.StatusBadRequest, "Failed to create bet") return fiber.NewError(fiber.StatusBadRequest, "Failed to create bet")
} }
wallets, err := h.walletSvc.GetWalletsByUser(c.Context(), bet.UserID.Value) wallet, err := h.walletSvc.GetCustomerWallet(c.Context(), bet.UserID.Value)
var staticWallet domain.Wallet
var staticFound bool
for _, wallet := range wallets {
if !wallet.IsWithdraw {
staticWallet = wallet
staticFound = true
break
}
}
if err != nil || staticFound == false {
fmt.Println("wallet error: ", err)
h.mongoLoggerSvc.Error("Failed to get static wallet of user",
zap.Int("status_code", fiber.StatusOK),
zap.Int64("user_id", user.ID),
zap.Time("timestamp", time.Now()),
)
return fiber.NewError(fiber.StatusBadRequest, "Failed to get wallets of user")
}
// amount added for fast code owner can be fetched from settings in db // amount added for fast code owner can be fetched from settings in db
amount := domain.Currency(100) amount := domain.Currency(100)
_, err = h.walletSvc.AddToWallet(c.Context(), staticWallet.ID, amount, domain.ValidInt64{}, _, err = h.walletSvc.AddToWallet(c.Context(), wallet.StaticID, amount, domain.ValidInt64{},
domain.TRANSFER_DIRECT, domain.PaymentDetails{}, fmt.Sprintf("Added %v to static wallet by referring using fast_code", amount.Float32())) domain.TRANSFER_DIRECT, domain.PaymentDetails{}, fmt.Sprintf("Added %v to static wallet by referring using fast_code", amount.Float32()))
if err != nil { if err != nil {
h.mongoLoggerSvc.Error("Failed to add reward to static bet", h.mongoLoggerSvc.Error("Failed to add reward to static bet",
@ -417,6 +398,9 @@ func (h *Handler) GetAllBet(c *fiber.Ctx) error {
} }
} }
fmt.Printf("Filters - BranchID: %+v, CompanyID: %+v, IsShopBet: %+v, Query: %+v, CreatedBefore: %+v, CreatedAfter: %+v\n",
branchID, companyID, isShopBet, searchString, createdBefore, createdAfter)
bets, err := h.betSvc.GetAllBets(c.Context(), domain.BetFilter{ bets, err := h.betSvc.GetAllBets(c.Context(), domain.BetFilter{
BranchID: branchID, BranchID: branchID,
CompanyID: companyID, CompanyID: companyID,

View File

@ -54,11 +54,13 @@ func (h *Handler) GetDashboardReport(c *fiber.Ctx) error {
}) })
} }
res := domain.ConvertDashboardSummaryToRes(summary)
return c.Status(fiber.StatusOK).JSON(domain.Response{ return c.Status(fiber.StatusOK).JSON(domain.Response{
Message: "Dashboard reports generated successfully", Message: "Dashboard reports generated successfully",
Success: true, Success: true,
StatusCode: 200, StatusCode: 200,
Data: summary, Data: res,
}) })
// return c.Status(fiber.StatusOK).JSON(summary) // return c.Status(fiber.StatusOK).JSON(summary)

View File

@ -1,6 +1,7 @@
package handlers package handlers
import ( import (
"fmt"
"log/slog" "log/slog"
"strconv" "strconv"
"time" "time"
@ -49,6 +50,40 @@ func (h *Handler) CreateShopBet(c *fiber.Ctx) error {
return response.WriteJSON(c, fiber.StatusOK, "Transaction created successfully", res, nil) return response.WriteJSON(c, fiber.StatusOK, "Transaction created successfully", res, nil)
} }
// CashoutBet godoc
// @Summary Cashout bet at branch
// @Description Cashout bet at branch
// @Tags transaction
// @Accept json
// @Produce json
// @Param createBet body domain.CashoutReq true "cashout bet"
// @Success 200 {object} TransactionRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /shop/bet/{id} [get]
func (h *Handler) GetShopBetByBetID(c *fiber.Ctx) error {
betIDstr := c.Params("id")
betID, err := strconv.ParseInt(betIDstr, 10, 64)
if err != nil {
h.logger.Error("CashoutReq failed bet id is invalid", "error", nil)
return response.WriteJSON(c, fiber.StatusBadRequest, "bet ID is invalid", nil, nil)
}
bet, err := h.transactionSvc.GetShopBetByBetID(c.Context(), betID)
if err != nil {
h.logger.Error("CashoutReq failed invalid bet id", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid bet ID", err, nil)
}
res := domain.ConvertShopBetDetail(bet)
return response.WriteJSON(c, fiber.StatusOK, "Shop bet fetched successfully", res, nil)
}
// CashoutBet godoc // CashoutBet godoc
// @Summary Cashout bet at branch // @Summary Cashout bet at branch
// @Description Cashout bet at branch // @Description Cashout bet at branch
@ -196,18 +231,23 @@ func (h *Handler) DepositForCustomer(c *fiber.Ctx) error {
if err := c.BodyParser(&req); err != nil { if err := c.BodyParser(&req); err != nil {
h.logger.Error("CreateTransferReq failed", "error", err) h.logger.Error("CreateTransferReq failed", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) return fiber.NewError(fiber.StatusBadRequest, err.Error())
} }
valErrs, ok := h.validator.Validate(c, req) valErrs, ok := h.validator.Validate(c, req)
if !ok { if !ok {
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) var errMsg string
for field, msg := range valErrs {
errMsg += fmt.Sprintf("%s: %s; ", field, msg)
}
return fiber.NewError(fiber.StatusBadRequest, errMsg)
} }
deposit, err := h.transactionSvc.CreateShopDeposit(c.Context(), userID, role, req) deposit, err := h.transactionSvc.CreateShopDeposit(c.Context(), userID, role, req)
if err != nil { if err != nil {
return response.WriteJSON(c, fiber.StatusBadRequest, "Failed to create shop deposit", err, nil) fmt.Printf("Shop Deposit Error %v \n", err)
return fiber.NewError(fiber.StatusBadRequest, err.Error())
} }
res := domain.ConvertShopDeposit(deposit) res := domain.ConvertShopDeposit(deposit)
@ -319,6 +359,34 @@ func (h *Handler) GetTransactionByID(c *fiber.Ctx) error {
return response.WriteJSON(c, fiber.StatusOK, "Transaction retrieved successfully", res, nil) return response.WriteJSON(c, fiber.StatusOK, "Transaction retrieved successfully", res, nil)
} }
// GetShopBetByTransactionID godoc
// @Summary Gets shop bet by transaction id
// @Description Gets a single shop bet by transaction id
// @Tags transaction
// @Accept json
// @Produce json
// @Param id path int true "Transaction ID"
// @Success 200 {object} TransactionRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /shop/transaction/{id}/bet [get]
func (h *Handler) GetShopBetByTransactionID(c *fiber.Ctx) error {
transactionID := c.Params("id")
id, err := strconv.ParseInt(transactionID, 10, 64)
if err != nil {
h.logger.Error("Invalid transaction ID", "transactionID", transactionID, "error", err)
return fiber.NewError(fiber.StatusBadRequest, "Invalid transaction ID")
}
transaction, err := h.transactionSvc.GetShopBetByShopTransactionID(c.Context(), id)
if err != nil {
h.logger.Error("Failed to get transaction by ID", "transactionID", id, "error", err)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve transaction")
}
res := domain.ConvertShopBetDetail(transaction)
return response.WriteJSON(c, fiber.StatusOK, "Shop bet retrieved successfully", res, nil)
}
type UpdateTransactionVerifiedReq struct { type UpdateTransactionVerifiedReq struct {
Verified bool `json:"verified" example:"true"` Verified bool `json:"verified" example:"true"`
} }
@ -339,6 +407,7 @@ func (h *Handler) UpdateTransactionVerified(c *fiber.Ctx) error {
transactionID := c.Params("id") transactionID := c.Params("id")
userID := c.Locals("user_id").(int64) userID := c.Locals("user_id").(int64)
companyID := c.Locals("company_id").(domain.ValidInt64) companyID := c.Locals("company_id").(domain.ValidInt64)
branchID := c.Locals("branch_id").(domain.ValidInt64)
role := c.Locals("role").(domain.Role) role := c.Locals("role").(domain.Role)
id, err := strconv.ParseInt(transactionID, 10, 64) id, err := strconv.ParseInt(transactionID, 10, 64)
@ -359,20 +428,7 @@ func (h *Handler) UpdateTransactionVerified(c *fiber.Ctx) error {
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
} }
transaction, err := h.transactionSvc.GetShopTransactionByID(c.Context(), id) err = h.transactionSvc.UpdateShopTransactionVerified(c.Context(), id, req.Verified, userID, role, companyID, branchID)
if role != domain.RoleSuperAdmin {
if !companyID.Valid || companyID.Value != transaction.CompanyID {
h.logger.Error("Failed to parse UpdateTransactionVerified request", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
}
}
user, err := h.userSvc.GetUserById(c.Context(), userID)
if err != nil {
h.logger.Error("Invalid user ID", "userID", userID, "error", err)
return fiber.NewError(fiber.StatusBadRequest, "Invalid user ID")
}
err = h.transactionSvc.UpdateShopTransactionVerified(c.Context(), id, req.Verified, userID, user.FirstName+" "+user.LastName)
if err != nil { if err != nil {
h.logger.Error("Failed to update transaction verification", "transactionID", id, "error", err) h.logger.Error("Failed to update transaction verification", "transactionID", id, "error", err)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update transaction verification") return fiber.NewError(fiber.StatusInternalServerError, "Failed to update transaction verification")

View File

@ -552,7 +552,7 @@ func (h *Handler) DeleteUser(c *fiber.Ctx) error {
type UpdateUserSuspendReq struct { type UpdateUserSuspendReq struct {
UserID int64 `json:"user_id" validate:"required" example:"123"` UserID int64 `json:"user_id" validate:"required" example:"123"`
Suspended bool `json:"suspended" validate:"required" example:"true"` Suspended bool `json:"suspended" example:"true"`
} }
type UpdateUserSuspendRes struct { type UpdateUserSuspendRes struct {
UserID int64 `json:"user_id"` UserID int64 `json:"user_id"`
@ -576,9 +576,13 @@ func (h *Handler) UpdateUserSuspend(c *fiber.Ctx) error {
h.logger.Error("Failed to parse UpdateUserSuspend request", "error", err) h.logger.Error("Failed to parse UpdateUserSuspend request", "error", err)
return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") return fiber.NewError(fiber.StatusBadRequest, "Invalid request body")
} }
fmt.Printf("user suspended %v \n", req)
if valErrs, ok := h.validator.Validate(c, req); !ok { if valErrs, ok := h.validator.Validate(c, req); !ok {
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) var errMsg string
for field, msg := range valErrs {
errMsg += fmt.Sprintf("%s: %s; ", field, msg)
}
return fiber.NewError(fiber.StatusBadRequest, errMsg)
} }
err := h.userSvc.UpdateUserSuspend(c.Context(), req.UserID, req.Suspended) err := h.userSvc.UpdateUserSuspend(c.Context(), req.UserID, req.Suspended)

View File

@ -101,7 +101,7 @@ func (a *App) initAppRoutes() {
a.fiber.Get("/user/single/:id", a.authMiddleware, h.GetUserByID) a.fiber.Get("/user/single/:id", a.authMiddleware, h.GetUserByID)
a.fiber.Delete("/user/delete/:id", a.authMiddleware, h.DeleteUser) a.fiber.Delete("/user/delete/:id", a.authMiddleware, h.DeleteUser)
a.fiber.Post("/user/suspend", a.authMiddleware, h.UpdateUserSuspend) a.fiber.Post("/user/suspend", a.authMiddleware, h.UpdateUserSuspend)
a.fiber.Get("/user/bets", a.authMiddleware, h.GetBetByUserID) a.fiber.Get("/user/ress", a.authMiddleware, h.GetBetByUserID)
a.fiber.Get("/user/wallet", a.authMiddleware, h.GetCustomerWallet) a.fiber.Get("/user/wallet", a.authMiddleware, h.GetCustomerWallet)
a.fiber.Post("/user/search", a.authMiddleware, h.SearchUserByNameOrPhone) a.fiber.Post("/user/search", a.authMiddleware, h.SearchUserByNameOrPhone)
@ -279,13 +279,16 @@ func (a *App) initAppRoutes() {
// Transactions /shop/transactions // Transactions /shop/transactions
a.fiber.Post("/shop/bet", a.authMiddleware, a.CompanyOnly, h.CreateShopBet) a.fiber.Post("/shop/bet", a.authMiddleware, a.CompanyOnly, h.CreateShopBet)
a.fiber.Get("/shop/bet/:id", a.authMiddleware, a.CompanyOnly, h.GetShopBetByBetID)
a.fiber.Post("/shop/bet/:id/cashout", a.authMiddleware, a.CompanyOnly, h.CashoutBet) a.fiber.Post("/shop/bet/:id/cashout", a.authMiddleware, a.CompanyOnly, h.CashoutBet)
a.fiber.Post("/shop/bet/:id/generate", a.authMiddleware, a.CompanyOnly, h.CashoutBet)
a.fiber.Get("/shop/cashout/:id", a.authMiddleware, a.CompanyOnly, h.GetShopBetByCashoutID) a.fiber.Get("/shop/cashout/:id", a.authMiddleware, a.CompanyOnly, h.GetShopBetByCashoutID)
a.fiber.Post("/shop/cashout", a.authMiddleware, a.CompanyOnly, h.CashoutByCashoutID) a.fiber.Post("/shop/cashout", a.authMiddleware, a.CompanyOnly, h.CashoutByCashoutID)
a.fiber.Post("/shop/deposit", a.authMiddleware, a.CompanyOnly, h.DepositForCustomer) a.fiber.Post("/shop/deposit", a.authMiddleware, a.CompanyOnly, h.DepositForCustomer)
// a.fiber.Get("/shop/deposit", a.authMiddleware, a.CompanyOnly, h.DepositForCustomer) // a.fiber.Get("/shop/deposit", a.authMiddleware, a.CompanyOnly, h.DepositForCustomer)
a.fiber.Get("/shop/transaction", a.authMiddleware, h.GetAllTransactions) a.fiber.Get("/shop/transaction", a.authMiddleware, h.GetAllTransactions)
a.fiber.Get("/shop/transaction/:id", a.authMiddleware, h.GetTransactionByID) a.fiber.Get("/shop/transaction/:id", a.authMiddleware, h.GetTransactionByID)
a.fiber.Get("/shop/transaction/:id/bet", a.authMiddleware, h.GetShopBetByTransactionID)
a.fiber.Put("/shop/transaction/:id", a.authMiddleware, h.UpdateTransactionVerified) a.fiber.Put("/shop/transaction/:id", a.authMiddleware, h.UpdateTransactionVerified)
// Notification Routes // Notification Routes