From a06d77da01d26d83f628d55572d58731ac1569f6 Mon Sep 17 00:00:00 2001 From: Samuel Tariku Date: Fri, 4 Jul 2025 00:09:03 +0300 Subject: [PATCH] fix: fixing issues on transaction --- cmd/main.go | 4 +- db/migrations/000001_fortune.up.sql | 56 ++++++++++- db/query/shop_transactions.sql | 9 +- gen/db/models.go | 6 +- gen/db/shop_transactions.sql.go | 35 +++++-- internal/domain/report.go | 94 ++++++++++++++++++ internal/domain/shop_deposit.go | 52 ++++++---- internal/repository/shop_deposit.go | 30 ++++-- internal/repository/shop_transaction.go | 2 +- internal/services/event/service.go | 2 +- internal/services/transaction/port.go | 3 +- internal/services/transaction/service.go | 95 ++++++++++++++++++- internal/services/transaction/shop_bet.go | 2 - internal/services/transaction/shop_deposit.go | 33 ++++--- internal/services/wallet/wallet.go | 16 ++-- internal/web_server/handlers/bet_handler.go | 46 +++------ internal/web_server/handlers/report.go | 4 +- internal/web_server/handlers/shop_handler.go | 90 ++++++++++++++---- internal/web_server/handlers/user.go | 10 +- internal/web_server/routes.go | 5 +- 20 files changed, 467 insertions(+), 127 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 495954d..a6fa58d 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -152,7 +152,7 @@ func main() { cfg.FIXER_API_KEY, cfg.FIXER_BASE_URL, ) - transactionSvc := transaction.NewService(store, *branchSvc, *betSvc, *walletSvc) + transactionSvc := transaction.NewService(store, *branchSvc, *betSvc, *walletSvc, *userSvc) reportSvc := report.NewService( bet.BetStore(store), @@ -167,8 +167,6 @@ func main() { logger, ) - - go httpserver.SetupReportCronJobs(context.Background(), reportSvc) bankRepository := repository.NewBankRepository(store) diff --git a/db/migrations/000001_fortune.up.sql b/db/migrations/000001_fortune.up.sql index fca0b48..fbfadab 100644 --- a/db/migrations/000001_fortune.up.sql +++ b/db/migrations/000001_fortune.up.sql @@ -207,7 +207,8 @@ CREATE TABLE IF NOT EXISTS shop_deposits ( id BIGSERIAL PRIMARY KEY, shop_transaction_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, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, UNIQUE(shop_transaction_id) @@ -406,6 +407,7 @@ SELECT sb.*, st.verified AS transaction_verified, bets.status, bets.total_odds, + bets.expires, JSON_AGG(bet_outcomes.*) AS outcomes FROM shop_bets AS sb JOIN shop_transactions st ON st.id = sb.shop_transaction_id @@ -502,6 +504,52 @@ VALUES ( NULL, 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 ( first_name, last_name, @@ -606,7 +654,7 @@ VALUES ( TRUE, TRUE, TRUE, - 1, + 2, TRUE, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP @@ -619,7 +667,7 @@ INSERT INTO companies ( values ( 'Test Company', 2, - 1 + 3 ); INSERT INTO wallets ( balance, @@ -654,7 +702,7 @@ INSERT INTO branches ( values ( 'Test Branch', 'Addis Ababa', - 2, + 4, 2, 1, TRUE, diff --git a/db/query/shop_transactions.sql b/db/query/shop_transactions.sql index 4896008..a9f003b 100644 --- a/db/query/shop_transactions.sql +++ b/db/query/shop_transactions.sql @@ -135,7 +135,7 @@ WHERE id = $1; INSERT INTO shop_deposits ( shop_transaction_id, customer_id, - wallet_transfer_id + branch_wallet_id ) VALUES ($1, $2, $3) RETURNING *; @@ -170,4 +170,9 @@ WHERE id = $1; -- name: GetShopDepositByShopTransactionID :one SELECT * FROM shop_deposit_detail -WHERE shop_transaction_id = $1; \ No newline at end of file +WHERE shop_transaction_id = $1; +-- name: UpdateShopDepositTransferID :exec +UPDATE shop_deposits +SET wallet_transfer_id = $2, + updated_at = CURRENT_TIMESTAMP +WHERE id = $1; \ No newline at end of file diff --git a/gen/db/models.go b/gen/db/models.go index 1edaf34..e378fe5 100644 --- a/gen/db/models.go +++ b/gen/db/models.go @@ -435,7 +435,8 @@ type ShopDeposit struct { ID int64 `json:"id"` ShopTransactionID int64 `json:"shop_transaction_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"` UpdatedAt pgtype.Timestamp `json:"updated_at"` } @@ -444,7 +445,8 @@ type ShopDepositDetail struct { ID int64 `json:"id"` ShopTransactionID int64 `json:"shop_transaction_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"` UpdatedAt pgtype.Timestamp `json:"updated_at"` FullName string `json:"full_name"` diff --git a/gen/db/shop_transactions.sql.go b/gen/db/shop_transactions.sql.go index 6018736..bcd884e 100644 --- a/gen/db/shop_transactions.sql.go +++ b/gen/db/shop_transactions.sql.go @@ -55,26 +55,27 @@ const CreateShopDeposit = `-- name: CreateShopDeposit :one INSERT INTO shop_deposits ( shop_transaction_id, customer_id, - wallet_transfer_id + branch_wallet_id ) 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 { ShopTransactionID int64 `json:"shop_transaction_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) { - 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 err := row.Scan( &i.ID, &i.ShopTransactionID, &i.CustomerID, &i.WalletTransferID, + &i.BranchWalletID, &i.CreatedAt, &i.UpdatedAt, ) @@ -251,7 +252,7 @@ func (q *Queries) GetAllShopBets(ctx context.Context, arg GetAllShopBetsParams) } 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 WHERE ( full_name ILIKE '%' || $1 || '%' @@ -304,6 +305,7 @@ func (q *Queries) GetAllShopDeposit(ctx context.Context, arg GetAllShopDepositPa &i.ShopTransactionID, &i.CustomerID, &i.WalletTransferID, + &i.BranchWalletID, &i.CreatedAt, &i.UpdatedAt, &i.FullName, @@ -545,7 +547,7 @@ func (q *Queries) GetShopBetByShopTransactionID(ctx context.Context, shopTransac } 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 WHERE id = $1 ` @@ -558,6 +560,7 @@ func (q *Queries) GetShopDepositByID(ctx context.Context, id int64) (ShopDeposit &i.ShopTransactionID, &i.CustomerID, &i.WalletTransferID, + &i.BranchWalletID, &i.CreatedAt, &i.UpdatedAt, &i.FullName, @@ -571,7 +574,7 @@ func (q *Queries) GetShopDepositByID(ctx context.Context, id int64) (ShopDeposit } 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 WHERE shop_transaction_id = $1 ` @@ -584,6 +587,7 @@ func (q *Queries) GetShopDepositByShopTransactionID(ctx context.Context, shopTra &i.ShopTransactionID, &i.CustomerID, &i.WalletTransferID, + &i.BranchWalletID, &i.CreatedAt, &i.UpdatedAt, &i.FullName, @@ -723,6 +727,23 @@ func (q *Queries) UpdateShopBetCashoutID(ctx context.Context, arg UpdateShopBetC 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 UPDATE shop_transactions SET verified = $2, diff --git a/internal/domain/report.go b/internal/domain/report.go index 77bf4bf..bdca3d6 100644 --- a/internal/domain/report.go +++ b/internal/domain/report.go @@ -116,6 +116,100 @@ type DashboardSummary struct { ReadNotifications int64 `json:"read_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 { CustomerID int64 `json:"customer_id"` diff --git a/internal/domain/shop_deposit.go b/internal/domain/shop_deposit.go index 6703ba7..9b13438 100644 --- a/internal/domain/shop_deposit.go +++ b/internal/domain/shop_deposit.go @@ -1,17 +1,20 @@ package domain -import "time" +import ( + "time" +) type ShopDeposit struct { ID int64 ShopTransactionID int64 CustomerID int64 - WalletTransferID int64 + WalletTransferID ValidInt64 + BranchWalletID int64 } type CreateShopDeposit struct { ShopTransactionID int64 CustomerID int64 - WalletTransferID int64 + BranchWalletID int64 } type ShopDepositFilter struct { @@ -26,7 +29,8 @@ type ShopDepositDetail struct { ID int64 ShopTransactionID int64 CustomerID int64 - WalletTransferID int64 + BranchWalletID int64 + WalletTransferID ValidInt64 FullName string PhoneNumber string Amount Currency @@ -38,31 +42,37 @@ type ShopDepositDetail struct { } type ShopDepositReq struct { - CustomerID int64 `json:"customer_id" example:"1"` - Amount float32 `json:"amount" example:"100.0"` - PaymentOption PaymentOption `json:"payment_option" example:"1"` - FullName string `json:"full_name" example:"John Smith"` - PhoneNumber string `json:"phone_number" example:"0911111111"` - BankCode string `json:"bank_code"` - BeneficiaryName string `json:"beneficiary_name"` - AccountName string `json:"account_name"` - AccountNumber string `json:"account_number"` - ReferenceNumber string `json:"reference_number"` - BranchID *int64 `json:"branch_id,omitempty" example:"1"` + CustomerID int64 `json:"customer_id" example:"1"` + Amount float32 `json:"amount" example:"100.0"` + PaymentOption PaymentOption `json:"payment_option" example:"1"` + // FullName string `json:"full_name" example:"John Smith"` + // PhoneNumber string `json:"phone_number" example:"0911111111"` + BankCode string `json:"bank_code"` + BeneficiaryName string `json:"beneficiary_name"` + AccountName string `json:"account_name"` + AccountNumber string `json:"account_number"` + ReferenceNumber string `json:"reference_number"` + BranchID *int64 `json:"branch_id,omitempty" example:"1"` } type ShopDepositRes struct { - ID int64 `json:"id"` - ShopTransactionID int64 `json:"shop_transaction_id"` - CustomerID int64 `json:"customer_id"` - WalletTransferID int64 `json:"wallet_transfer_id"` + ID int64 `json:"id"` + ShopTransactionID int64 `json:"shop_transaction_id"` + CustomerID int64 `json:"customer_id"` + WalletTransferID *int64 `json:"wallet_transfer_id,omitempty"` } func ConvertShopDeposit(shopDeposit ShopDeposit) ShopDepositRes { - return ShopDepositRes{ + + res := ShopDepositRes{ ID: shopDeposit.ID, ShopTransactionID: shopDeposit.ShopTransactionID, CustomerID: shopDeposit.CustomerID, - WalletTransferID: shopDeposit.WalletTransferID, } + + if shopDeposit.WalletTransferID.Valid { + res.WalletTransferID = &shopDeposit.WalletTransferID.Value + } + + return res } diff --git a/internal/repository/shop_deposit.go b/internal/repository/shop_deposit.go index abb2079..1f73ea7 100644 --- a/internal/repository/shop_deposit.go +++ b/internal/repository/shop_deposit.go @@ -13,16 +13,24 @@ func convertShopDeposit(deposit dbgen.ShopDeposit) domain.ShopDeposit { ID: deposit.ID, ShopTransactionID: deposit.ShopTransactionID, 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 { return domain.ShopDepositDetail{ - ID: deposit.ID, - ShopTransactionID: deposit.ShopTransactionID, - CustomerID: deposit.CustomerID, - WalletTransferID: deposit.WalletTransferID, + ID: deposit.ID, + ShopTransactionID: deposit.ShopTransactionID, + CustomerID: deposit.CustomerID, + BranchWalletID: deposit.BranchWalletID, + WalletTransferID: domain.ValidInt64{ + Value: deposit.WalletTransferID.Int64, + Valid: deposit.WalletTransferID.Valid, + }, FullName: deposit.FullName, PhoneNumber: deposit.PhoneNumber, Amount: domain.Currency(deposit.Amount), @@ -37,7 +45,7 @@ func convertCreateShopDeposit(deposit domain.CreateShopDeposit) dbgen.CreateShop return dbgen.CreateShopDepositParams{ ShopTransactionID: deposit.ShopTransactionID, 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 } + +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, + }) +} diff --git a/internal/repository/shop_transaction.go b/internal/repository/shop_transaction.go index 038ca16..d3a2b9c 100644 --- a/internal/repository/shop_transaction.go +++ b/internal/repository/shop_transaction.go @@ -196,7 +196,7 @@ func (s *Store) GetShopTransactionByBranch(ctx context.Context, id int64) ([]dom 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{ ID: id, ApprovedBy: pgtype.Int8{ diff --git a/internal/services/event/service.go b/internal/services/event/service.go index 592241c..9161491 100644 --- a/internal/services/event/service.go +++ b/internal/services/event/service.go @@ -215,7 +215,7 @@ func (s *service) fetchUpcomingEventsFromProvider(ctx context.Context, url, sour for sportIndex, sportID := range sportIDs { var totalPages int = 1 var page int = 0 - var limit int = 200 + var limit int = 1 var count int = 0 for page <= totalPages { page = page + 1 diff --git a/internal/services/transaction/port.go b/internal/services/transaction/port.go index ebaa694..20aebcd 100644 --- a/internal/services/transaction/port.go +++ b/internal/services/transaction/port.go @@ -11,7 +11,7 @@ type TransactionStore interface { GetAllShopTransactions(ctx context.Context, filter domain.ShopTransactionFilter) ([]domain.ShopTransactionDetail, error) GetShopTransactionByID(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) 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) GetShopDepositByID(ctx context.Context, id int64) (domain.ShopDepositDetail, error) GetShopDepositByShopTransactionID(ctx context.Context, shopTransactionID int64) (domain.ShopDepositDetail, error) + UpdateShopDepositTransferID(ctx context.Context, id int64, transferID domain.ValidInt64) error } diff --git a/internal/services/transaction/service.go b/internal/services/transaction/service.go index 756fbd6..979553f 100644 --- a/internal/services/transaction/service.go +++ b/internal/services/transaction/service.go @@ -3,10 +3,13 @@ package transaction import ( "context" "errors" + "fmt" + "time" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/bet" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/branch" + "github.com/SamuelTariku/FortuneBet-Backend/internal/services/user" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet" ) @@ -16,6 +19,8 @@ var ( ErrUnauthorizedCompanyID = errors.New("unauthorized company id") ErrUnauthorizedBranchManager = errors.New("unauthorized branch manager") 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 { @@ -23,14 +28,16 @@ type Service struct { branchSvc branch.Service betSvc bet.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{ transactionStore: transactionStore, branchSvc: branchSvc, betSvc: betSvc, 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) { return s.transactionStore.GetShopTransactionByBranch(ctx, id) } -func (s *Service) UpdateShopTransactionVerified(ctx context.Context, id int64, verified bool, approvedBy int64, approverName string) error { - return s.transactionStore.UpdateShopTransactionVerified(ctx, id, verified, approvedBy, approverName) +func (s *Service) UpdateShopTransactionVerified(ctx context.Context, id int64, verified bool, approvedBy int64, role domain.Role, companyID domain.ValidInt64, branchID domain.ValidInt64) error { + // 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) { @@ -65,7 +152,7 @@ func (s *Service) GetBranchByRole(ctx context.Context, branchID *int64, role dom 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 !userCompanyID.Valid || userCompanyID.Value != branch.CompanyID { return nil, nil, ErrUnauthorizedCompanyID diff --git a/internal/services/transaction/shop_bet.go b/internal/services/transaction/shop_bet.go index 0a301f4..d634639 100644 --- a/internal/services/transaction/shop_bet.go +++ b/internal/services/transaction/shop_bet.go @@ -44,9 +44,7 @@ func (s *Service) CreateShopBet(ctx context.Context, userID int64, role domain.R if err != nil { return domain.ShopBet{}, err } - cashoutID, err := s.GenerateCashoutID() - if err != nil { return domain.ShopBet{}, err } diff --git a/internal/services/transaction/shop_deposit.go b/internal/services/transaction/shop_deposit.go index 7ef1016..bc155df 100644 --- a/internal/services/transaction/shop_deposit.go +++ b/internal/services/transaction/shop_deposit.go @@ -2,16 +2,21 @@ package transaction import ( "context" - "fmt" + "errors" "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) { var branchID int64 var companyID 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 { // h.logger.Error("CashoutReq Branch ID is required for this user role") return domain.ShopDeposit{}, ErrBranchRequiredForRole @@ -25,7 +30,7 @@ func (s *Service) CreateShopDeposit(ctx context.Context, userID int64, role doma branchID = branch.ID companyID = branch.CompanyID senderID = branch.WalletID - } else if role == domain.RoleCashier { + case domain.RoleCashier: branch, err := s.branchSvc.GetBranchByCashier(ctx, userID) if err != nil { // 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 companyID = branch.CompanyID senderID = branch.WalletID - } else { + default: return domain.ShopDeposit{}, ErrCustomerRoleNotAuthorized } - customerWallet, err := s.walletSvc.GetCustomerWallet(ctx, req.CustomerID) + user, err := s.userSvc.GetUserByID(ctx, req.CustomerID) if err != nil { return domain.ShopDeposit{}, err } - transfer, err := s.walletSvc.TransferToWallet(ctx, - senderID, customerWallet.RegularID, domain.ToCurrency(req.Amount), domain.TRANSFER_DIRECT, - domain.ValidInt64{Value: userID, Valid: true}, - fmt.Sprintf("Transferred %v from customer wallet deposit", req.Amount), - ) + if err != nil { + return domain.ShopDeposit{}, err + } newTransaction, err := s.CreateShopTransaction(ctx, domain.CreateShopTransaction{ Amount: domain.Currency(req.Amount), @@ -56,8 +59,8 @@ func (s *Service) CreateShopDeposit(ctx context.Context, userID int64, role doma CompanyID: companyID, UserID: userID, Type: domain.TRANSACTION_DEPOSIT, - FullName: req.FullName, - PhoneNumber: req.PhoneNumber, + FullName: user.FirstName + " " + user.LastName, + PhoneNumber: user.PhoneNumber, PaymentOption: req.PaymentOption, BankCode: domain.ValidString{ 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{ ShopTransactionID: newTransaction.ID, 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) { 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) +} diff --git a/internal/services/wallet/wallet.go b/internal/services/wallet/wallet.go index a80b50c..9973a69 100644 --- a/internal/services/wallet/wallet.go +++ b/internal/services/wallet/wallet.go @@ -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) { regularWallet, err := s.CreateWallet(ctx, domain.CreateWallet{ - IsWithdraw: true, - IsBettable: true, - UserID: customerID, + IsWithdraw: true, + IsBettable: true, + IsTransferable: true, + UserID: customerID, }) if err != nil { @@ -29,9 +30,10 @@ func (s *Service) CreateCustomerWallet(ctx context.Context, customerID int64) (d } staticWallet, err := s.CreateWallet(ctx, domain.CreateWallet{ - IsWithdraw: false, - IsBettable: true, - UserID: customerID, + IsWithdraw: false, + IsBettable: true, + IsTransferable: true, + UserID: customerID, }) if err != nil { @@ -139,7 +141,7 @@ func (s *Service) DeductFromWallet(ctx context.Context, id int64, amount domain. // Log the transfer here for reference newTransfer, err := s.transferStore.CreateTransfer(ctx, domain.CreateTransfer{ - Message: message, + Message: message, Amount: amount, Verified: true, SenderWalletID: domain.ValidInt64{ diff --git a/internal/web_server/handlers/bet_handler.go b/internal/web_server/handlers/bet_handler.go index 15f93f6..52a5e6c 100644 --- a/internal/web_server/handlers/bet_handler.go +++ b/internal/web_server/handlers/bet_handler.go @@ -123,20 +123,20 @@ func (h *Handler) CreateBetWithFastCode(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, "falied to get user information") } - branch, err := h.branchSvc.GetBranchByID(c.Context(), user.CompanyID.Value) - if err != nil { - h.mongoLoggerSvc.Error("falied to get branch of user", - zap.Int("status_code", fiber.StatusInternalServerError), - zap.Error(err), - zap.Time("timestamp", time.Now()), - ) - return fiber.NewError(fiber.StatusBadRequest, "falied to get branch of user") - } + // branch, err := h.branchSvc.GetBranchByID(c.Context(), user) + // if err != nil { + // h.mongoLoggerSvc.Error("falied to get branch of user", + // zap.Int("status_code", fiber.StatusInternalServerError), + // zap.Error(err), + // zap.Time("timestamp", time.Now()), + // ) + // return fiber.NewError(fiber.StatusBadRequest, "falied to get branch of user") + // } newReq := domain.CreateBetReq{ Amount: float32(bet.Amount), Outcomes: bet_outcomes, - BranchID: &branch.ID, + BranchID: nil, FullName: user.FirstName, PhoneNumber: user.PhoneNumber, } @@ -151,31 +151,12 @@ func (h *Handler) CreateBetWithFastCode(c *fiber.Ctx) error { return fiber.NewError(fiber.StatusBadRequest, "Failed to create bet") } - wallets, err := h.walletSvc.GetWalletsByUser(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") - } + wallet, err := h.walletSvc.GetCustomerWallet(c.Context(), bet.UserID.Value) // amount added for fast code owner can be fetched from settings in db 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())) if err != nil { 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{ BranchID: branchID, CompanyID: companyID, diff --git a/internal/web_server/handlers/report.go b/internal/web_server/handlers/report.go index c2ed79f..3e68773 100644 --- a/internal/web_server/handlers/report.go +++ b/internal/web_server/handlers/report.go @@ -54,11 +54,13 @@ func (h *Handler) GetDashboardReport(c *fiber.Ctx) error { }) } + res := domain.ConvertDashboardSummaryToRes(summary) + return c.Status(fiber.StatusOK).JSON(domain.Response{ Message: "Dashboard reports generated successfully", Success: true, StatusCode: 200, - Data: summary, + Data: res, }) // return c.Status(fiber.StatusOK).JSON(summary) diff --git a/internal/web_server/handlers/shop_handler.go b/internal/web_server/handlers/shop_handler.go index 5d0d99c..af2b2d5 100644 --- a/internal/web_server/handlers/shop_handler.go +++ b/internal/web_server/handlers/shop_handler.go @@ -1,6 +1,7 @@ package handlers import ( + "fmt" "log/slog" "strconv" "time" @@ -49,6 +50,40 @@ func (h *Handler) CreateShopBet(c *fiber.Ctx) error { 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 // @Summary 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 { 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) 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) 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) @@ -319,6 +359,34 @@ func (h *Handler) GetTransactionByID(c *fiber.Ctx) error { 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 { Verified bool `json:"verified" example:"true"` } @@ -339,6 +407,7 @@ func (h *Handler) UpdateTransactionVerified(c *fiber.Ctx) error { transactionID := c.Params("id") userID := c.Locals("user_id").(int64) companyID := c.Locals("company_id").(domain.ValidInt64) + branchID := c.Locals("branch_id").(domain.ValidInt64) role := c.Locals("role").(domain.Role) 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) } - transaction, err := h.transactionSvc.GetShopTransactionByID(c.Context(), id) - 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) + err = h.transactionSvc.UpdateShopTransactionVerified(c.Context(), id, req.Verified, userID, role, companyID, branchID) if err != nil { h.logger.Error("Failed to update transaction verification", "transactionID", id, "error", err) return fiber.NewError(fiber.StatusInternalServerError, "Failed to update transaction verification") diff --git a/internal/web_server/handlers/user.go b/internal/web_server/handlers/user.go index bc55bec..22ca0b1 100644 --- a/internal/web_server/handlers/user.go +++ b/internal/web_server/handlers/user.go @@ -552,7 +552,7 @@ func (h *Handler) DeleteUser(c *fiber.Ctx) error { type UpdateUserSuspendReq struct { 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 { 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) return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") } - + fmt.Printf("user suspended %v \n", req) 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) diff --git a/internal/web_server/routes.go b/internal/web_server/routes.go index c1b48d6..74ef540 100644 --- a/internal/web_server/routes.go +++ b/internal/web_server/routes.go @@ -101,7 +101,7 @@ func (a *App) initAppRoutes() { a.fiber.Get("/user/single/:id", a.authMiddleware, h.GetUserByID) a.fiber.Delete("/user/delete/:id", a.authMiddleware, h.DeleteUser) 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.Post("/user/search", a.authMiddleware, h.SearchUserByNameOrPhone) @@ -279,13 +279,16 @@ func (a *App) initAppRoutes() { // Transactions /shop/transactions 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/generate", a.authMiddleware, a.CompanyOnly, h.CashoutBet) 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/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/: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) // Notification Routes