From 3e4e9eead7c2bdcee4aa6060739248ce176903c8 Mon Sep 17 00:00:00 2001 From: Samuel Tariku Date: Sun, 29 Jun 2025 21:51:23 +0300 Subject: [PATCH] fix: added message to wallet_transfers and gave it a detailed view --- db/migrations/000001_fortune.up.sql | 7 ++ db/query/cashier.sql | 3 +- db/query/transfer.sql | 8 +- db/query/user.sql | 3 +- gen/db/cashier.sql.go | 3 +- gen/db/models.go | 19 ++++ gen/db/transfer.sql.go | 48 +++++---- gen/db/user.sql.go | 3 +- internal/domain/transaction.go | 3 +- internal/domain/transfer.go | 20 +++- internal/repository/transfer.go | 64 +++++++++--- internal/repository/user.go | 17 +++- internal/services/bet/service.go | 12 +-- internal/services/chapa/service.go | 8 +- internal/services/referal/service.go | 13 ++- internal/services/user/direct.go | 4 +- internal/services/user/port.go | 4 +- internal/services/virtualGame/Alea/service.go | 5 +- internal/services/virtualGame/service.go | 28 ++++-- internal/services/wallet/port.go | 14 +-- internal/services/wallet/transfer.go | 28 +++--- internal/web_server/cron.go | 34 +++---- internal/web_server/handlers/cashier.go | 7 +- internal/web_server/handlers/chapa.go | 4 +- internal/web_server/handlers/manager.go | 3 +- .../handlers/notification_handler.go | 3 +- .../web_server/handlers/transfer_handler.go | 99 ++++++++++++++----- makefile | 2 +- 28 files changed, 324 insertions(+), 142 deletions(-) diff --git a/db/migrations/000001_fortune.up.sql b/db/migrations/000001_fortune.up.sql index 08f2196..0c9a717 100644 --- a/db/migrations/000001_fortune.up.sql +++ b/db/migrations/000001_fortune.up.sql @@ -354,6 +354,13 @@ FROM customer_wallets cw JOIN wallets rw ON cw.regular_wallet_id = rw.id JOIN wallets sw ON cw.static_wallet_id = sw.id JOIN users ON users.id = cw.customer_id; +CREATE VIEW wallet_transfer_details AS +SELECT wt.*, + users.first_name, + users.last_name, + users.phone_number +FROM wallet_transfer wt + LEFT JOIN users ON users.id = wt.cashier_id; -- Foreign Keys ALTER TABLE users ADD CONSTRAINT unique_email UNIQUE (email), diff --git a/db/query/cashier.sql b/db/query/cashier.sql index 974222e..0b0c294 100644 --- a/db/query/cashier.sql +++ b/db/query/cashier.sql @@ -14,7 +14,8 @@ FROM branch_cashiers JOIN users ON branch_cashiers.user_id = users.id JOIN branches ON branches.id = branch_id WHERE ( - full_name ILIKE '%' || sqlc.narg('query') || '%' + first_name ILIKE '%' || sqlc.narg('query') || '%' + OR last_name ILIKE '%' || sqlc.narg('query') || '%' OR phone_number ILIKE '%' || sqlc.narg('query') || '%' OR sqlc.narg('query') IS NULL ) diff --git a/db/query/transfer.sql b/db/query/transfer.sql index 13f7658..9219943 100644 --- a/db/query/transfer.sql +++ b/db/query/transfer.sql @@ -15,19 +15,19 @@ VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) RETURNING *; -- name: GetAllTransfers :many SELECT * -FROM wallet_transfer; +FROM wallet_transfer_details; -- name: GetTransfersByWallet :many SELECT * -FROM wallet_transfer +FROM wallet_transfer_details WHERE receiver_wallet_id = $1 OR sender_wallet_id = $1; -- name: GetTransferByID :one SELECT * -FROM wallet_transfer +FROM wallet_transfer_details WHERE id = $1; -- name: GetTransferByReference :one SELECT * -FROM wallet_transfer +FROM wallet_transfer_details WHERE reference_number = $1; -- name: UpdateTransferVerification :exec UPDATE wallet_transfer diff --git a/db/query/user.sql b/db/query/user.sql index 235d88d..71d935c 100644 --- a/db/query/user.sql +++ b/db/query/user.sql @@ -67,7 +67,8 @@ wHERE ( OR $2 IS NULL ) AND ( - full_name ILIKE '%' || sqlc.narg('query') || '%' + first_name ILIKE '%' || sqlc.narg('query') || '%' + OR last_name ILIKE '%' || sqlc.narg('query') || '%' OR phone_number ILIKE '%' || sqlc.narg('query') || '%' OR sqlc.narg('query') IS NULL ) diff --git a/gen/db/cashier.sql.go b/gen/db/cashier.sql.go index e055e5e..c15f497 100644 --- a/gen/db/cashier.sql.go +++ b/gen/db/cashier.sql.go @@ -21,7 +21,8 @@ FROM branch_cashiers JOIN users ON branch_cashiers.user_id = users.id JOIN branches ON branches.id = branch_id WHERE ( - full_name ILIKE '%' || $1 || '%' + first_name ILIKE '%' || $1 || '%' + OR last_name ILIKE '%' || $1 || '%' OR phone_number ILIKE '%' || $1 || '%' OR $1 IS NULL ) diff --git a/gen/db/models.go b/gen/db/models.go index 173c901..c890cb9 100644 --- a/gen/db/models.go +++ b/gen/db/models.go @@ -597,3 +597,22 @@ type WalletTransfer struct { CreatedAt pgtype.Timestamp `json:"created_at"` UpdatedAt pgtype.Timestamp `json:"updated_at"` } + +type WalletTransferDetail struct { + ID int64 `json:"id"` + Amount pgtype.Int8 `json:"amount"` + Message string `json:"message"` + Type pgtype.Text `json:"type"` + ReceiverWalletID pgtype.Int8 `json:"receiver_wallet_id"` + SenderWalletID pgtype.Int8 `json:"sender_wallet_id"` + CashierID pgtype.Int8 `json:"cashier_id"` + Verified pgtype.Bool `json:"verified"` + ReferenceNumber string `json:"reference_number"` + Status pgtype.Text `json:"status"` + PaymentMethod pgtype.Text `json:"payment_method"` + CreatedAt pgtype.Timestamp `json:"created_at"` + UpdatedAt pgtype.Timestamp `json:"updated_at"` + FirstName pgtype.Text `json:"first_name"` + LastName pgtype.Text `json:"last_name"` + PhoneNumber pgtype.Text `json:"phone_number"` +} diff --git a/gen/db/transfer.sql.go b/gen/db/transfer.sql.go index 236ea5a..b564b72 100644 --- a/gen/db/transfer.sql.go +++ b/gen/db/transfer.sql.go @@ -74,19 +74,19 @@ func (q *Queries) CreateTransfer(ctx context.Context, arg CreateTransferParams) } const GetAllTransfers = `-- name: GetAllTransfers :many -SELECT id, amount, message, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, reference_number, status, payment_method, created_at, updated_at -FROM wallet_transfer +SELECT id, amount, message, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, reference_number, status, payment_method, created_at, updated_at, first_name, last_name, phone_number +FROM wallet_transfer_details ` -func (q *Queries) GetAllTransfers(ctx context.Context) ([]WalletTransfer, error) { +func (q *Queries) GetAllTransfers(ctx context.Context) ([]WalletTransferDetail, error) { rows, err := q.db.Query(ctx, GetAllTransfers) if err != nil { return nil, err } defer rows.Close() - var items []WalletTransfer + var items []WalletTransferDetail for rows.Next() { - var i WalletTransfer + var i WalletTransferDetail if err := rows.Scan( &i.ID, &i.Amount, @@ -101,6 +101,9 @@ func (q *Queries) GetAllTransfers(ctx context.Context) ([]WalletTransfer, error) &i.PaymentMethod, &i.CreatedAt, &i.UpdatedAt, + &i.FirstName, + &i.LastName, + &i.PhoneNumber, ); err != nil { return nil, err } @@ -113,14 +116,14 @@ func (q *Queries) GetAllTransfers(ctx context.Context) ([]WalletTransfer, error) } const GetTransferByID = `-- name: GetTransferByID :one -SELECT id, amount, message, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, reference_number, status, payment_method, created_at, updated_at -FROM wallet_transfer +SELECT id, amount, message, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, reference_number, status, payment_method, created_at, updated_at, first_name, last_name, phone_number +FROM wallet_transfer_details WHERE id = $1 ` -func (q *Queries) GetTransferByID(ctx context.Context, id int64) (WalletTransfer, error) { +func (q *Queries) GetTransferByID(ctx context.Context, id int64) (WalletTransferDetail, error) { row := q.db.QueryRow(ctx, GetTransferByID, id) - var i WalletTransfer + var i WalletTransferDetail err := row.Scan( &i.ID, &i.Amount, @@ -135,19 +138,22 @@ func (q *Queries) GetTransferByID(ctx context.Context, id int64) (WalletTransfer &i.PaymentMethod, &i.CreatedAt, &i.UpdatedAt, + &i.FirstName, + &i.LastName, + &i.PhoneNumber, ) return i, err } const GetTransferByReference = `-- name: GetTransferByReference :one -SELECT id, amount, message, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, reference_number, status, payment_method, created_at, updated_at -FROM wallet_transfer +SELECT id, amount, message, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, reference_number, status, payment_method, created_at, updated_at, first_name, last_name, phone_number +FROM wallet_transfer_details WHERE reference_number = $1 ` -func (q *Queries) GetTransferByReference(ctx context.Context, referenceNumber string) (WalletTransfer, error) { +func (q *Queries) GetTransferByReference(ctx context.Context, referenceNumber string) (WalletTransferDetail, error) { row := q.db.QueryRow(ctx, GetTransferByReference, referenceNumber) - var i WalletTransfer + var i WalletTransferDetail err := row.Scan( &i.ID, &i.Amount, @@ -162,26 +168,29 @@ func (q *Queries) GetTransferByReference(ctx context.Context, referenceNumber st &i.PaymentMethod, &i.CreatedAt, &i.UpdatedAt, + &i.FirstName, + &i.LastName, + &i.PhoneNumber, ) return i, err } const GetTransfersByWallet = `-- name: GetTransfersByWallet :many -SELECT id, amount, message, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, reference_number, status, payment_method, created_at, updated_at -FROM wallet_transfer +SELECT id, amount, message, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, reference_number, status, payment_method, created_at, updated_at, first_name, last_name, phone_number +FROM wallet_transfer_details WHERE receiver_wallet_id = $1 OR sender_wallet_id = $1 ` -func (q *Queries) GetTransfersByWallet(ctx context.Context, receiverWalletID pgtype.Int8) ([]WalletTransfer, error) { +func (q *Queries) GetTransfersByWallet(ctx context.Context, receiverWalletID pgtype.Int8) ([]WalletTransferDetail, error) { rows, err := q.db.Query(ctx, GetTransfersByWallet, receiverWalletID) if err != nil { return nil, err } defer rows.Close() - var items []WalletTransfer + var items []WalletTransferDetail for rows.Next() { - var i WalletTransfer + var i WalletTransferDetail if err := rows.Scan( &i.ID, &i.Amount, @@ -196,6 +205,9 @@ func (q *Queries) GetTransfersByWallet(ctx context.Context, receiverWalletID pgt &i.PaymentMethod, &i.CreatedAt, &i.UpdatedAt, + &i.FirstName, + &i.LastName, + &i.PhoneNumber, ); err != nil { return nil, err } diff --git a/gen/db/user.sql.go b/gen/db/user.sql.go index b838343..1daaec0 100644 --- a/gen/db/user.sql.go +++ b/gen/db/user.sql.go @@ -183,7 +183,8 @@ wHERE ( OR $2 IS NULL ) AND ( - full_name ILIKE '%' || $3 || '%' + first_name ILIKE '%' || $3 || '%' + OR last_name ILIKE '%' || $3 || '%' OR phone_number ILIKE '%' || $3 || '%' OR $3 IS NULL ) diff --git a/internal/domain/transaction.go b/internal/domain/transaction.go index 195369e..d489e2a 100644 --- a/internal/domain/transaction.go +++ b/internal/domain/transaction.go @@ -18,8 +18,7 @@ const ( BANK ) -// Transaction only represents when the user cashes out a bet in the shop -// It probably would be better to call it a CashOut or ShopWithdrawal +// Transaction only represents branch transactions type Transaction struct { ID int64 Amount Currency diff --git a/internal/domain/transfer.go b/internal/domain/transfer.go index 8524cd4..4425ac4 100644 --- a/internal/domain/transfer.go +++ b/internal/domain/transfer.go @@ -43,10 +43,28 @@ type Transfer struct { SenderWalletID ValidInt64 `json:"sender_wallet_id"` ReferenceNumber string `json:"reference_number"` // <-- needed Status string `json:"status"` - CashierID ValidInt64 `json:"cashier_id"` + DepositorID ValidInt64 `json:"depositor_id"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } +type TransferDetail struct { + ID int64 `json:"id"` + Amount Currency `json:"amount"` + Verified bool `json:"verified"` + Message string `json:"message"` + Type TransferType `json:"type"` + PaymentMethod PaymentMethod `json:"payment_method"` + ReceiverWalletID ValidInt64 `json:"receiver_wallet_id"` + SenderWalletID ValidInt64 `json:"sender_wallet_id"` + ReferenceNumber string `json:"reference_number"` // <-- needed + Status string `json:"status"` + DepositorID ValidInt64 `json:"depositor_id"` + DepositorFirstName string `json:"depositor_first_name"` + DepositorLastName string `json:"depositor_last_name"` + DepositorPhoneNumber string `json:"depositor_phone_number"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` +} type CreateTransfer struct { Amount Currency `json:"amount"` diff --git a/internal/repository/transfer.go b/internal/repository/transfer.go index 5b8821a..5816ce7 100644 --- a/internal/repository/transfer.go +++ b/internal/repository/transfer.go @@ -8,12 +8,13 @@ import ( "github.com/jackc/pgx/v5/pgtype" ) -func convertDBTransfer(transfer dbgen.WalletTransfer) domain.Transfer { - return domain.Transfer{ +func convertDBTransferDetail(transfer dbgen.WalletTransferDetail) domain.TransferDetail { + return domain.TransferDetail{ ID: transfer.ID, Amount: domain.Currency(transfer.Amount.Int64), Type: domain.TransferType(transfer.Type.String), Verified: transfer.Verified.Bool, + Message: transfer.Message, ReceiverWalletID: domain.ValidInt64{ Value: transfer.ReceiverWalletID.Int64, Valid: transfer.ReceiverWalletID.Valid, @@ -22,7 +23,36 @@ func convertDBTransfer(transfer dbgen.WalletTransfer) domain.Transfer { Value: transfer.SenderWalletID.Int64, Valid: transfer.SenderWalletID.Valid, }, - CashierID: domain.ValidInt64{ + DepositorID: domain.ValidInt64{ + Value: transfer.CashierID.Int64, + Valid: transfer.CashierID.Valid, + }, + DepositorFirstName: transfer.FirstName.String, + DepositorLastName: transfer.LastName.String, + DepositorPhoneNumber: transfer.PhoneNumber.String, + PaymentMethod: domain.PaymentMethod(transfer.PaymentMethod.String), + ReferenceNumber: transfer.ReferenceNumber, + Status: transfer.Status.String, + CreatedAt: transfer.CreatedAt.Time, + UpdatedAt: transfer.UpdatedAt.Time, + } +} +func convertDBTransfer(transfer dbgen.WalletTransfer) domain.Transfer { + return domain.Transfer{ + ID: transfer.ID, + Amount: domain.Currency(transfer.Amount.Int64), + Type: domain.TransferType(transfer.Type.String), + Verified: transfer.Verified.Bool, + Message: transfer.Message, + ReceiverWalletID: domain.ValidInt64{ + Value: transfer.ReceiverWalletID.Int64, + Valid: transfer.ReceiverWalletID.Valid, + }, + SenderWalletID: domain.ValidInt64{ + Value: transfer.SenderWalletID.Int64, + Valid: transfer.SenderWalletID.Valid, + }, + DepositorID: domain.ValidInt64{ Value: transfer.CashierID.Int64, Valid: transfer.CashierID.Valid, }, @@ -54,6 +84,10 @@ func convertCreateTransfer(transfer domain.CreateTransfer) dbgen.CreateTransferP ReferenceNumber: string(transfer.ReferenceNumber), PaymentMethod: pgtype.Text{String: string(transfer.PaymentMethod), Valid: true}, + Verified: pgtype.Bool{ + Bool: transfer.Verified, + Valid: true, + }, } } @@ -65,47 +99,47 @@ func (s *Store) CreateTransfer(ctx context.Context, transfer domain.CreateTransf return convertDBTransfer(newTransfer), nil } -func (s *Store) GetAllTransfers(ctx context.Context) ([]domain.Transfer, error) { +func (s *Store) GetAllTransfers(ctx context.Context) ([]domain.TransferDetail, error) { transfers, err := s.queries.GetAllTransfers(ctx) if err != nil { return nil, err } - var result []domain.Transfer = make([]domain.Transfer, 0, len(transfers)) + var result []domain.TransferDetail = make([]domain.TransferDetail, 0, len(transfers)) for _, transfer := range transfers { - result = append(result, convertDBTransfer(transfer)) + result = append(result, convertDBTransferDetail(transfer)) } return result, nil } -func (s *Store) GetTransfersByWallet(ctx context.Context, walletID int64) ([]domain.Transfer, error) { +func (s *Store) GetTransfersByWallet(ctx context.Context, walletID int64) ([]domain.TransferDetail, error) { transfers, err := s.queries.GetTransfersByWallet(ctx, pgtype.Int8{Int64: walletID, Valid: true}) if err != nil { return nil, err } - var result []domain.Transfer = make([]domain.Transfer, 0, len(transfers)) + var result []domain.TransferDetail = make([]domain.TransferDetail, 0, len(transfers)) for _, transfer := range transfers { - result = append(result, convertDBTransfer(transfer)) + result = append(result, convertDBTransferDetail(transfer)) } return result, nil } -func (s *Store) GetTransferByReference(ctx context.Context, reference string) (domain.Transfer, error) { +func (s *Store) GetTransferByReference(ctx context.Context, reference string) (domain.TransferDetail, error) { transfer, err := s.queries.GetTransferByReference(ctx, reference) if err != nil { - return domain.Transfer{}, nil + return domain.TransferDetail{}, nil } - return convertDBTransfer(transfer), nil + return convertDBTransferDetail(transfer), nil } -func (s *Store) GetTransferByID(ctx context.Context, id int64) (domain.Transfer, error) { +func (s *Store) GetTransferByID(ctx context.Context, id int64) (domain.TransferDetail, error) { transfer, err := s.queries.GetTransferByID(ctx, id) if err != nil { - return domain.Transfer{}, nil + return domain.TransferDetail{}, nil } - return convertDBTransfer(transfer), nil + return convertDBTransferDetail(transfer), nil } func (s *Store) UpdateTransferVerification(ctx context.Context, id int64, verified bool) error { diff --git a/internal/repository/user.go b/internal/repository/user.go index 0f31933..079ef52 100644 --- a/internal/repository/user.go +++ b/internal/repository/user.go @@ -149,8 +149,21 @@ func (s *Store) GetAllUsers(ctx context.Context, filter domain.UserFilter) ([]do return userList, totalCount, nil } -func (s *Store) GetAllCashiers(ctx context.Context) ([]domain.GetCashier, int64, error) { - users, err := s.queries.GetAllCashiers(ctx) +func (s *Store) GetAllCashiers(ctx context.Context, filter domain.UserFilter) ([]domain.GetCashier, int64, error) { + users, err := s.queries.GetAllCashiers(ctx, dbgen.GetAllCashiersParams{ + Query: pgtype.Text{ + String: filter.Query.Value, + Valid: filter.Query.Valid, + }, + CreatedBefore: pgtype.Timestamptz{ + Time: filter.CreatedBefore.Value, + Valid: filter.CreatedBefore.Valid, + }, + CreatedAfter: pgtype.Timestamptz{ + Time: filter.CreatedAfter.Value, + Valid: filter.CreatedAfter.Valid, + }, + }) if err != nil { return nil, 0, err } diff --git a/internal/services/bet/service.go b/internal/services/bet/service.go index 8f7d23d..06554d5 100644 --- a/internal/services/bet/service.go +++ b/internal/services/bet/service.go @@ -276,7 +276,7 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID Value: userID, Valid: true, }, domain.TRANSFER_DIRECT, - fmt.Sprintf("Deducted %d amount from wallet by system while placing bet", deductedAmount)) + fmt.Sprintf("Deducted %v amount from wallet by system while placing bet", deductedAmount)) if err != nil { s.mongoLogger.Error("failed to deduct from wallet", zap.Int64("wallet_id", branch.WalletID), @@ -312,7 +312,7 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID _, err = s.walletSvc.DeductFromWallet(ctx, branch.WalletID, domain.ToCurrency(deductedAmount), domain.BranchWalletType, domain.ValidInt64{ Value: userID, Valid: true, - }, domain.TRANSFER_DIRECT, fmt.Sprintf("Deducted %d amount from wallet by system while placing bet", deductedAmount)) + }, domain.TRANSFER_DIRECT, fmt.Sprintf("Deducted %v amount from wallet by system while placing bet", deductedAmount)) if err != nil { s.mongoLogger.Error("wallet deduction failed", zap.Int64("wallet_id", branch.WalletID), @@ -339,7 +339,7 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID if req.Amount < wallets.RegularBalance.Float32() { _, err = s.walletSvc.DeductFromWallet(ctx, wallets.RegularID, domain.ToCurrency(req.Amount), domain.CustomerWalletType, domain.ValidInt64{}, - domain.TRANSFER_DIRECT, fmt.Sprintf("Deducted %d amount from wallet by system while placing bet", req.Amount)) + domain.TRANSFER_DIRECT, fmt.Sprintf("Deducted %v amount from wallet by system while placing bet", req.Amount)) if err != nil { s.mongoLogger.Error("wallet deduction failed for customer regular wallet", zap.Int64("customer_id", wallets.CustomerID), @@ -358,7 +358,7 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID // Empty the regular balance _, err = s.walletSvc.DeductFromWallet(ctx, wallets.RegularID, wallets.RegularBalance, domain.CustomerWalletType, domain.ValidInt64{}, domain.TRANSFER_DIRECT, - fmt.Sprintf("Deducted %d amount from wallet by system while placing bet", wallets.RegularBalance.Float32())) + fmt.Sprintf("Deducted %v amount from wallet by system while placing bet", wallets.RegularBalance.Float32())) if err != nil { s.mongoLogger.Error("wallet deduction failed for customer regular wallet", zap.Int64("customer_id", wallets.CustomerID), @@ -373,7 +373,7 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID remainingAmount := wallets.RegularBalance - domain.Currency(req.Amount) _, err = s.walletSvc.DeductFromWallet(ctx, wallets.StaticID, remainingAmount, domain.CustomerWalletType, domain.ValidInt64{}, domain.TRANSFER_DIRECT, - fmt.Sprintf("Deducted %d amount from wallet by system while placing bet", remainingAmount.Float32())) + fmt.Sprintf("Deducted %v amount from wallet by system while placing bet", remainingAmount.Float32())) if err != nil { s.mongoLogger.Error("wallet deduction failed for customer static wallet", zap.Int64("customer_id", wallets.CustomerID), @@ -759,7 +759,7 @@ func (s *Service) UpdateStatus(ctx context.Context, id int64, status domain.Outc } _, err = s.walletSvc.AddToWallet(ctx, customerWallet.RegularID, amount, domain.ValidInt64{}, - domain.TRANSFER_DIRECT, domain.PaymentDetails{}, fmt.Sprintf("Added %d to wallet by system for winning a bet", amount.Float32())) + domain.TRANSFER_DIRECT, domain.PaymentDetails{}, fmt.Sprintf("Added %v to wallet by system for winning a bet", amount.Float32())) if err != nil { s.mongoLogger.Error("failed to add winnings to wallet", diff --git a/internal/services/chapa/service.go b/internal/services/chapa/service.go index e718f45..2f44258 100644 --- a/internal/services/chapa/service.go +++ b/internal/services/chapa/service.go @@ -83,7 +83,7 @@ func (s *Service) InitiateDeposit(ctx context.Context, userID int64, amount doma // Create payment record transfer := domain.CreateTransfer{ - Message: fmt.Sprintf("Depositing %d into wallet using chapa. Reference Number %s", amount, reference), + Message: fmt.Sprintf("Depositing %v into wallet using chapa. Reference Number %v", amount.Float32(), reference), Amount: amount, Type: domain.DEPOSIT, PaymentMethod: domain.TRANSFER_CHAPA, @@ -269,7 +269,7 @@ func (s *Service) ManuallyVerify(ctx context.Context, txRef string) (*domain.Cha // Credit wallet _, err := s.walletStore.AddToWallet(ctx, transfer.SenderWalletID.Value, transfer.Amount, domain.ValidInt64{}, domain.TRANSFER_CHAPA, domain.PaymentDetails{}, - fmt.Sprintf("Added %d to wallet using Chapa", transfer.Amount.Float32())) + fmt.Sprintf("Added %v to wallet using Chapa", transfer.Amount.Float32())) if err != nil { return nil, fmt.Errorf("failed to credit wallet: %w", err) } @@ -330,7 +330,7 @@ func (s *Service) HandleVerifyDepositWebhook(ctx context.Context, transfer domai ReferenceNumber: domain.ValidString{ Value: transfer.Reference, }, - }, fmt.Sprintf("Added %d to wallet using Chapa")); err != nil { + }, fmt.Sprintf("Added %v to wallet using Chapa")); err != nil { return fmt.Errorf("failed to credit user wallet: %w", err) } } @@ -368,7 +368,7 @@ func (s *Service) HandleVerifyWithdrawWebhook(ctx context.Context, payment domai } else { _, err := s.walletStore.AddToWallet(ctx, transfer.SenderWalletID.Value, transfer.Amount, domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{}, - fmt.Sprintf("Added %d to wallet by system because chapa withdraw is unsuccessful")) + fmt.Sprintf("Added %v to wallet by system because chapa withdraw is unsuccessful")) if err != nil { return fmt.Errorf("failed to credit user wallet: %w", err) } diff --git a/internal/services/referal/service.go b/internal/services/referal/service.go index 5585d74..970a239 100644 --- a/internal/services/referal/service.go +++ b/internal/services/referal/service.go @@ -127,7 +127,10 @@ func (s *Service) ProcessReferral(ctx context.Context, referredPhone, referralCo return err } - _, err = s.walletSvc.AddToWallet(ctx, wallets.StaticID, domain.ToCurrency(float32(referral.RewardAmount)), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{}) + _, err = s.walletSvc.AddToWallet(ctx, wallets.StaticID, + domain.ToCurrency(float32(referral.RewardAmount)), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{}, + fmt.Sprintf("Added %v to static wallet because of referral ID %v", referral.RewardAmount, referrerId), + ) if err != nil { s.logger.Error("Failed to add referral reward to static wallet", "walletID", wallets.StaticID, "referrer phone number", referredPhone, "error", err) return err @@ -165,7 +168,9 @@ func (s *Service) ProcessDepositBonus(ctx context.Context, userPhone string, amo walletID := wallets[0].ID bonus := amount * (settings.CashbackPercentage / 100) currentBonus := float64(wallets[0].Balance) - _, err = s.walletSvc.AddToWallet(ctx, walletID, domain.ToCurrency(float32(currentBonus+bonus)), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{}) + _, err = s.walletSvc.AddToWallet(ctx, walletID, domain.ToCurrency(float32(currentBonus+bonus)), domain.ValidInt64{}, + domain.TRANSFER_DIRECT, domain.PaymentDetails{}, + fmt.Sprintf("Added %v to static wallet because of Deposit Cashback Bonus %d", currentBonus+bonus, bonus)) if err != nil { s.logger.Error("Failed to add deposit bonus to wallet", "walletID", walletID, "userID", userID, "bonus", bonus, "error", err) return err @@ -219,7 +224,9 @@ func (s *Service) ProcessBetReferral(ctx context.Context, userPhone string, betA walletID := wallets[0].ID currentBalance := float64(wallets[0].Balance) - _, err = s.walletSvc.AddToWallet(ctx, walletID, domain.ToCurrency(float32(currentBalance+bonus)), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{}) + _, err = s.walletSvc.AddToWallet(ctx, walletID, domain.ToCurrency(float32(currentBalance+bonus)), domain.ValidInt64{}, + domain.TRANSFER_DIRECT, domain.PaymentDetails{}, + fmt.Sprintf("Added %v to static wallet because of bet referral", referral.RewardAmount)) if err != nil { s.logger.Error("Failed to add bet referral bonus to wallet", "walletID", walletID, "referrerID", referrerID, "bonus", bonus, "error", err) return err diff --git a/internal/services/user/direct.go b/internal/services/user/direct.go index b8217b9..9ad4bf4 100644 --- a/internal/services/user/direct.go +++ b/internal/services/user/direct.go @@ -58,8 +58,8 @@ func (s *Service) GetCashiersByBranch(ctx context.Context, branchID int64) ([]do return s.userStore.GetCashiersByBranch(ctx, branchID) } -func (s *Service) GetAllCashiers(ctx context.Context) ([]domain.GetCashier, int64, error){ - return s.userStore.GetAllCashiers(ctx) +func (s *Service) GetAllCashiers(ctx context.Context, filter domain.UserFilter) ([]domain.GetCashier, int64, error){ + return s.userStore.GetAllCashiers(ctx, filter) } func (s *Service) GetCashierByID(ctx context.Context, cashierID int64) (domain.GetCashier, error) { diff --git a/internal/services/user/port.go b/internal/services/user/port.go index 2a9f9f8..992a381 100644 --- a/internal/services/user/port.go +++ b/internal/services/user/port.go @@ -10,8 +10,8 @@ type UserStore interface { CreateUser(ctx context.Context, user domain.User, usedOtpId int64, is_company bool) (domain.User, error) CreateUserWithoutOtp(ctx context.Context, user domain.User, is_company bool) (domain.User, error) GetUserByID(ctx context.Context, id int64) (domain.User, error) - GetAllUsers(ctx context.Context, filter Filter) ([]domain.User, int64, error) - GetAllCashiers(ctx context.Context) ([]domain.GetCashier, int64, error) + GetAllUsers(ctx context.Context, filter domain.UserFilter) ([]domain.User, int64, error) + GetAllCashiers(ctx context.Context, filter domain.UserFilter) ([]domain.GetCashier, int64, error) GetCashierByID(ctx context.Context, cashierID int64) (domain.GetCashier, error) GetCashiersByBranch(ctx context.Context, branchID int64) ([]domain.User, error) UpdateUser(ctx context.Context, user domain.UpdateUserReq) error diff --git a/internal/services/virtualGame/Alea/service.go b/internal/services/virtualGame/Alea/service.go index f3f9a9f..e30a61e 100644 --- a/internal/services/virtualGame/Alea/service.go +++ b/internal/services/virtualGame/Alea/service.go @@ -127,8 +127,9 @@ func (s *AleaPlayService) processTransaction(ctx context.Context, tx *domain.Vir return errors.New("no wallet available for user") } tx.WalletID = wallets[0].ID - - if _, err := s.walletSvc.AddToWallet(ctx, tx.WalletID, domain.Currency(tx.Amount), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{}); err != nil { + _, err = s.walletSvc.AddToWallet(ctx, tx.WalletID, domain.Currency(tx.Amount), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{}, + fmt.Sprintf("Added %v to wallet for winning AleaPlay Virtual Bet", tx.Amount)) + if err != nil { return fmt.Errorf("wallet update failed: %w", err) } diff --git a/internal/services/virtualGame/service.go b/internal/services/virtualGame/service.go index 44ea049..6a412dc 100644 --- a/internal/services/virtualGame/service.go +++ b/internal/services/virtualGame/service.go @@ -138,7 +138,9 @@ func (s *service) HandleCallback(ctx context.Context, callback *domain.PopOKCall return errors.New("unknown transaction type") } - _, err = s.walletSvc.AddToWallet(ctx, walletID, domain.Currency(amount), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{}) + _, err = s.walletSvc.AddToWallet(ctx, walletID, domain.Currency(amount), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{}, + fmt.Sprintf("Added %v to wallet for winning PopOkBet", amount), + ) if err != nil { s.logger.Error("Failed to update wallet", "walletID", walletID, "userID", session.UserID, "amount", amount, "error", err) return err @@ -208,7 +210,7 @@ func (s *service) ProcessBet(ctx context.Context, req *domain.PopOKBetRequest) ( } _, err = s.walletSvc.DeductFromWallet(ctx, claims.UserID, domain.Currency(amountCents), domain.CustomerWalletType, domain.ValidInt64{}, domain.TRANSFER_DIRECT, - fmt.Sprintf("Deducted %d amount from wallet by system while placing virtual game bet", amountCents)) + fmt.Sprintf("Deducted %v amount from wallet by system while placing virtual game bet", amountCents)) if err != nil { return nil, fmt.Errorf("insufficient balance") } @@ -274,8 +276,11 @@ func (s *service) ProcessWin(ctx context.Context, req *domain.PopOKWinRequest) ( amountCents := int64(req.Amount * 100) // 4. Credit to wallet - - if _, err := s.walletSvc.AddToWallet(ctx, claims.UserID, domain.Currency(amountCents), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{}); err != nil { + _, err = s.walletSvc.AddToWallet(ctx, claims.UserID, domain.Currency(amountCents), domain.ValidInt64{}, + domain.TRANSFER_DIRECT, domain.PaymentDetails{}, + fmt.Sprintf("Added %v to wallet for winning PopOkBet", req.Amount), + ) + if err != nil { s.logger.Error("Failed to credit wallet", "userID", claims.UserID, "error", err) return nil, fmt.Errorf("wallet credit failed") } @@ -342,7 +347,9 @@ func (s *service) ProcessTournamentWin(ctx context.Context, req *domain.PopOKWin amountCents := int64(req.Amount * 100) // 4. Credit user wallet - if _, err := s.walletSvc.AddToWallet(ctx, claims.UserID, domain.Currency(amountCents), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{}); err != nil { + _, err = s.walletSvc.AddToWallet(ctx, claims.UserID, domain.Currency(amountCents), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{}, + fmt.Sprintf("Added %v to wallet for winning Popok Tournament", req.Amount)) + if err != nil { s.logger.Error("Failed to credit wallet for tournament", "userID", claims.UserID, "error", err) return nil, fmt.Errorf("wallet credit failed") } @@ -403,8 +410,9 @@ func (s *service) ProcessPromoWin(ctx context.Context, req *domain.PopOKWinReque } amountCents := int64(req.Amount * 100) - - if _, err := s.walletSvc.AddToWallet(ctx, claims.UserID, domain.Currency(amountCents), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{}); err != nil { + _, err = s.walletSvc.AddToWallet(ctx, claims.UserID, domain.Currency(amountCents), domain.ValidInt64{}, + domain.TRANSFER_DIRECT, domain.PaymentDetails{}, fmt.Sprintf("Added %v to wallet for winning PopOk Promo Win", req.Amount)) + if err != nil { s.logger.Error("Failed to credit wallet for promo", "userID", claims.UserID, "error", err) return nil, fmt.Errorf("wallet credit failed") } @@ -509,8 +517,10 @@ func (s *service) ProcessCancel(ctx context.Context, req *domain.PopOKCancelRequ // 5. Refund the bet amount (absolute value since bet amount is negative) refundAmount := -originalBet.Amount - - if _, err := s.walletSvc.AddToWallet(ctx, claims.UserID, domain.Currency(refundAmount), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{}); err != nil { + _, err = s.walletSvc.AddToWallet(ctx, claims.UserID, domain.Currency(refundAmount), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{}, + fmt.Sprintf("Added %v to wallet as refund for cancelling PopOk bet", refundAmount), + ) + if err != nil { s.logger.Error("Failed to refund bet", "userID", claims.UserID, "error", err) return nil, fmt.Errorf("refund failed") } diff --git a/internal/services/wallet/port.go b/internal/services/wallet/port.go index fb761cb..e47bc65 100644 --- a/internal/services/wallet/port.go +++ b/internal/services/wallet/port.go @@ -25,11 +25,11 @@ type WalletStore interface { } type TransferStore interface { - CreateTransfer(ctx context.Context, transfer domain.CreateTransfer) (domain.Transfer, error) - GetAllTransfers(ctx context.Context) ([]domain.Transfer, error) - GetTransfersByWallet(ctx context.Context, walletID int64) ([]domain.Transfer, error) - GetTransferByReference(ctx context.Context, reference string) (domain.Transfer, error) - GetTransferByID(ctx context.Context, id int64) (domain.Transfer, error) - UpdateTransferVerification(ctx context.Context, id int64, verified bool) error - UpdateTransferStatus(ctx context.Context, id int64, status string) error + CreateTransfer(ctx context.Context, transfer domain.CreateTransfer) (domain.Transfer, error) + GetAllTransfers(ctx context.Context) ([]domain.TransferDetail, error) + GetTransfersByWallet(ctx context.Context, walletID int64) ([]domain.TransferDetail, error) + GetTransferByReference(ctx context.Context, reference string) (domain.TransferDetail, error) + GetTransferByID(ctx context.Context, id int64) (domain.TransferDetail, error) + UpdateTransferVerification(ctx context.Context, id int64, verified bool) error + UpdateTransferStatus(ctx context.Context, id int64, status string) error } diff --git a/internal/services/wallet/transfer.go b/internal/services/wallet/transfer.go index cb7ad67..4a65926 100644 --- a/internal/services/wallet/transfer.go +++ b/internal/services/wallet/transfer.go @@ -9,8 +9,9 @@ import ( ) var ( - ErrWalletNotTransferable = errors.New("wallet is not transferable") - ErrInsufficientBalance = errors.New("wallet balance is insufficient") + ErrSenderWalletNotTransferable = errors.New("sender wallet is not transferable") + ErrReceiverWalletNotTransferable = errors.New("receiver wallet is not transferable") + ErrInsufficientBalance = errors.New("wallet balance is insufficient") ) func (s *Service) CreateTransfer(ctx context.Context, transfer domain.CreateTransfer) (domain.Transfer, error) { @@ -18,19 +19,19 @@ func (s *Service) CreateTransfer(ctx context.Context, transfer domain.CreateTran return s.transferStore.CreateTransfer(ctx, transfer) } -func (s *Service) GetAllTransfers(ctx context.Context) ([]domain.Transfer, error) { +func (s *Service) GetAllTransfers(ctx context.Context) ([]domain.TransferDetail, error) { return s.transferStore.GetAllTransfers(ctx) } -func (s *Service) GetTransferByReference(ctx context.Context, reference string) (domain.Transfer, error) { +func (s *Service) GetTransferByReference(ctx context.Context, reference string) (domain.TransferDetail, error) { return s.transferStore.GetTransferByReference(ctx, reference) } -func (s *Service) GetTransferByID(ctx context.Context, id int64) (domain.Transfer, error) { +func (s *Service) GetTransferByID(ctx context.Context, id int64) (domain.TransferDetail, error) { return s.transferStore.GetTransferByID(ctx, id) } -func (s *Service) GetTransfersByWallet(ctx context.Context, walletID int64) ([]domain.Transfer, error) { +func (s *Service) GetTransfersByWallet(ctx context.Context, walletID int64) ([]domain.TransferDetail, error) { return s.transferStore.GetTransfersByWallet(ctx, walletID) } @@ -44,15 +45,17 @@ func (s *Service) UpdateTransferStatus(ctx context.Context, id int64, status str func (s *Service) TransferToWallet(ctx context.Context, senderID int64, receiverID int64, amount domain.Currency, paymentMethod domain.PaymentMethod, - cashierID domain.ValidInt64) (domain.Transfer, error) { + cashierID domain.ValidInt64, message string) (domain.Transfer, error) { senderWallet, err := s.GetWalletByID(ctx, senderID) if err != nil { + return domain.Transfer{}, err } - if senderWallet.IsTransferable { - return domain.Transfer{}, ErrWalletNotTransferable + if !senderWallet.IsTransferable { + fmt.Printf("Error: %d Sender Wallet is not transferable \n", senderWallet.ID) + return domain.Transfer{}, ErrSenderWalletNotTransferable } receiverWallet, err := s.GetWalletByID(ctx, receiverID) @@ -60,8 +63,9 @@ func (s *Service) TransferToWallet(ctx context.Context, senderID int64, receiver return domain.Transfer{}, err } - if receiverWallet.IsTransferable { - return domain.Transfer{}, ErrWalletNotTransferable + if !receiverWallet.IsTransferable { + fmt.Printf("Error: %d Receiver Wallet is not transferable \n", senderWallet.ID) + return domain.Transfer{}, ErrReceiverWalletNotTransferable } // Deduct from sender @@ -84,7 +88,7 @@ func (s *Service) TransferToWallet(ctx context.Context, senderID int64, receiver // Log the transfer so that if there is a mistake, it can be reverted transfer, err := s.CreateTransfer(ctx, domain.CreateTransfer{ - Message: fmt.Sprintf("Transferring %d to another wallet", amount), + Message: message, SenderWalletID: domain.ValidInt64{ Value: senderID, Valid: true, diff --git a/internal/web_server/cron.go b/internal/web_server/cron.go index 7e39391..9658ad5 100644 --- a/internal/web_server/cron.go +++ b/internal/web_server/cron.go @@ -23,22 +23,22 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S spec string task func() }{ - { - spec: "0 0 * * * *", // Every 1 hour - task: func() { - if err := eventService.FetchUpcomingEvents(context.Background()); err != nil { - log.Printf("FetchUpcomingEvents error: %v", err) - } - }, - }, - { - spec: "0 0 * * * *", // Every 1 hour (since its takes that long to fetch all the events) - task: func() { - if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil { - log.Printf("FetchNonLiveOdds error: %v", err) - } - }, - }, + // { + // spec: "0 0 * * * *", // Every 1 hour + // task: func() { + // if err := eventService.FetchUpcomingEvents(context.Background()); err != nil { + // log.Printf("FetchUpcomingEvents error: %v", err) + // } + // }, + // }, + // { + // spec: "0 0 * * * *", // Every 1 hour (since its takes that long to fetch all the events) + // task: func() { + // if err := oddsService.FetchNonLiveOdds(context.Background()); err != nil { + // log.Printf("FetchNonLiveOdds error: %v", err) + // } + // }, + // }, { spec: "0 */5 * * * *", // Every 5 Minutes task: func() { @@ -66,7 +66,7 @@ func StartDataFetchingCrons(eventService eventsvc.Service, oddsService oddssvc.S } for _, job := range schedule { - job.task() + // job.task() if _, err := c.AddFunc(job.spec, job.task); err != nil { log.Fatalf("Failed to schedule cron job: %v", err) } diff --git a/internal/web_server/handlers/cashier.go b/internal/web_server/handlers/cashier.go index 0155f45..8474cde 100644 --- a/internal/web_server/handlers/cashier.go +++ b/internal/web_server/handlers/cashier.go @@ -7,7 +7,6 @@ import ( "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication" - "github.com/SamuelTariku/FortuneBet-Backend/internal/services/user" "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response" "github.com/gofiber/fiber/v2" ) @@ -178,7 +177,11 @@ func (h *Handler) GetAllCashiers(c *fiber.Ctx) error { return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) } - cashiers, total, err := h.userSvc.GetAllCashiers(c.Context()) + cashiers, total, err := h.userSvc.GetAllCashiers(c.Context(), domain.UserFilter{ + Query: searchString, + CreatedBefore: createdBefore, + CreatedAfter: createdAfter, + }) if err != nil { h.logger.Error("GetAllCashiers failed", "error", err) return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get cashiers", nil, nil) diff --git a/internal/web_server/handlers/chapa.go b/internal/web_server/handlers/chapa.go index ddfb32d..e5107ff 100644 --- a/internal/web_server/handlers/chapa.go +++ b/internal/web_server/handlers/chapa.go @@ -66,7 +66,9 @@ func (h *Handler) InitiateDeposit(c *fiber.Ctx) error { multiplier = bonusMultiplier[0].Multiplier } - _, err = h.walletSvc.AddToWallet(c.Context(), wallet.StaticID, domain.ToCurrency(float32(amount)*multiplier), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{}) + _, err = h.walletSvc.AddToWallet(c.Context(), wallet.StaticID, domain.ToCurrency(float32(amount)*multiplier), domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{}, + fmt.Sprintf("Added %v to static wallet because of deposit bonus using multiplier %v", float32(amount)*multiplier, multiplier), + ) if err != nil { h.logger.Error("Failed to add bonus to static wallet", "walletID", wallet.StaticID, "user id", userID, "error", err) return err diff --git a/internal/web_server/handlers/manager.go b/internal/web_server/handlers/manager.go index 3fec76f..2993a70 100644 --- a/internal/web_server/handlers/manager.go +++ b/internal/web_server/handlers/manager.go @@ -6,7 +6,6 @@ import ( "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/services/authentication" - "github.com/SamuelTariku/FortuneBet-Backend/internal/services/user" "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response" "github.com/gofiber/fiber/v2" ) @@ -173,7 +172,7 @@ func (h *Handler) GetAllManagers(c *fiber.Ctx) error { managers, total, err := h.userSvc.GetAllUsers(c.Context(), filter) if err != nil { h.logger.Error("GetAllManagers failed", "error", err) - return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get Managers", nil, nil) + return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to get Managers", err, nil) } var result []ManagersRes = make([]ManagersRes, len(managers)) diff --git a/internal/web_server/handlers/notification_handler.go b/internal/web_server/handlers/notification_handler.go index 24332d0..8af6fed 100644 --- a/internal/web_server/handlers/notification_handler.go +++ b/internal/web_server/handlers/notification_handler.go @@ -9,7 +9,6 @@ import ( "strconv" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" - "github.com/SamuelTariku/FortuneBet-Backend/internal/services/user" "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/ws" "github.com/gofiber/fiber/v2" "github.com/gofiber/fiber/v2/middleware/adaptor" @@ -183,7 +182,7 @@ func (h *Handler) CreateAndSendNotification(c *fiber.Ctx) error { return c.Status(fiber.StatusCreated).JSON(fiber.Map{"message": "Single notification sent successfully", "notification_id": notification.ID}) case domain.NotificationDeliverySchemeBulk: - recipients, _, err := h.userSvc.GetAllUsers(context.Background(), user.Filter{ + recipients, _, err := h.userSvc.GetAllUsers(context.Background(), domain.UserFilter{ Role: string(req.Reciever), }) if err != nil { diff --git a/internal/web_server/handlers/transfer_handler.go b/internal/web_server/handlers/transfer_handler.go index 54d2454..0d1d74f 100644 --- a/internal/web_server/handlers/transfer_handler.go +++ b/internal/web_server/handlers/transfer_handler.go @@ -8,20 +8,25 @@ import ( "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response" "github.com/gofiber/fiber/v2" + "go.uber.org/zap" ) type TransferWalletRes struct { - ID int64 `json:"id"` - Amount float32 `json:"amount"` - Verified bool `json:"verified"` - Type string `json:"type"` - PaymentMethod string `json:"payment_method"` - ReceiverWalletID *int64 `json:"receiver_wallet_id,omitempty"` - SenderWalletID *int64 `json:"sender_wallet_id,omitempty"` - CashierID *int64 `json:"cashier_id,omitempty"` - ReferenceNumber string `json:"reference_number"` // ← Add this - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` + ID int64 `json:"id"` + Amount float32 `json:"amount"` + Verified bool `json:"verified"` + Message string `json:"message"` + Type string `json:"type"` + PaymentMethod string `json:"payment_method"` + ReceiverWalletID *int64 `json:"receiver_wallet_id,omitempty"` + SenderWalletID *int64 `json:"sender_wallet_id,omitempty"` + DepositorID *int64 `json:"depositor_id,omitempty"` + DepositorFirstName string `json:"depositor_first_name"` + DepositorLastName string `json:"depositor_last_name"` + DepositorPhoneNumber string `json:"depositor_phone_number"` + ReferenceNumber string `json:"reference_number"` // ← Add this + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` } type RefillRes struct { @@ -48,25 +53,60 @@ func convertTransfer(t domain.Transfer) TransferWalletRes { senderID = &t.SenderWalletID.Value } - var cashierID *int64 - if t.CashierID.Valid { - cashierID = &t.CashierID.Value + var depositorID *int64 + if t.DepositorID.Valid { + depositorID = &t.DepositorID.Value } return TransferWalletRes{ ID: t.ID, - Amount: float32(t.Amount), + Amount: t.Amount.Float32(), Verified: t.Verified, + Message: t.Message, Type: string(t.Type), PaymentMethod: string(t.PaymentMethod), ReceiverWalletID: receiverID, SenderWalletID: senderID, - CashierID: cashierID, + DepositorID: depositorID, ReferenceNumber: t.ReferenceNumber, CreatedAt: t.CreatedAt, UpdatedAt: t.UpdatedAt, } } +func convertTransferDetail(t domain.TransferDetail) TransferWalletRes { + var receiverID *int64 + if t.ReceiverWalletID.Valid { + receiverID = &t.ReceiverWalletID.Value + } + + var senderID *int64 + if t.SenderWalletID.Valid { + senderID = &t.SenderWalletID.Value + } + + var depositorID *int64 + if t.DepositorID.Valid { + depositorID = &t.DepositorID.Value + } + + return TransferWalletRes{ + ID: t.ID, + Amount: t.Amount.Float32(), + Verified: t.Verified, + Message: t.Message, + Type: string(t.Type), + PaymentMethod: string(t.PaymentMethod), + ReceiverWalletID: receiverID, + SenderWalletID: senderID, + DepositorID: depositorID, + DepositorFirstName: t.DepositorFirstName, + DepositorLastName: t.DepositorLastName, + DepositorPhoneNumber: t.DepositorPhoneNumber, + ReferenceNumber: t.ReferenceNumber, + CreatedAt: t.CreatedAt, + UpdatedAt: t.UpdatedAt, + } +} type CreateTransferReq struct { Amount float32 `json:"amount" example:"100.0"` @@ -107,7 +147,7 @@ func (h *Handler) GetTransfersByWallet(c *fiber.Ctx) error { var transferResponses []TransferWalletRes for _, transfer := range transfers { - transferResponses = append(transferResponses, convertTransfer(transfer)) + transferResponses = append(transferResponses, convertTransferDetail(transfer)) } return response.WriteJSON(c, fiber.StatusOK, "Transfers retrieved successfully", transferResponses, nil) @@ -140,16 +180,15 @@ func (h *Handler) TransferToWallet(c *fiber.Ctx) error { role := c.Locals("role").(domain.Role) companyID := c.Locals("company_id").(domain.ValidInt64) - fmt.Printf("\n\nCompant ID: %v\n\n", companyID.Value) + fmt.Printf("\n\nCompany ID: %v\n\n", companyID.Value) var senderID int64 - //TODO: check to make sure that the cashiers aren't transferring TO branch wallet switch role { case domain.RoleCustomer: h.logger.Error("Unauthorized access", "userID", userID, "role", role) return response.WriteJSON(c, fiber.StatusUnauthorized, "Unauthorized access", nil, nil) - case domain.RoleBranchManager, domain.RoleAdmin, domain.RoleSuperAdmin: + case domain.RoleAdmin: company, err := h.companySvc.GetCompanyByID(c.Context(), companyID.Value) if err != nil { return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{ @@ -160,13 +199,20 @@ func (h *Handler) TransferToWallet(c *fiber.Ctx) error { } senderID = company.WalletID h.logger.Error("Will", "userID", userID, "role", role) - default: + + case domain.RoleSuperAdmin: + return response.WriteJSON(c, fiber.StatusBadRequest, "Super Admin does not have a wallet", err, nil) + case domain.RoleBranchManager: + return response.WriteJSON(c, fiber.StatusBadRequest, "Branch Manager does not have a wallet", err, nil) + case domain.RoleCashier: cashierBranch, err := h.branchSvc.GetBranchByCashier(c.Context(), userID) if err != nil { h.logger.Error("Failed to get branch", "user ID", userID, "error", err) return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve cashier branch", err, nil) } senderID = cashierBranch.WalletID + default: + return response.WriteJSON(c, fiber.StatusInternalServerError, "Unknown Role", err, nil) } var req CreateTransferReq @@ -181,9 +227,14 @@ func (h *Handler) TransferToWallet(c *fiber.Ctx) error { return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) } - transfer, err := h.walletSvc.TransferToWallet(c.Context(), senderID, receiverID, domain.ToCurrency(req.Amount), domain.PaymentMethod(req.PaymentMethod), domain.ValidInt64{Value: userID, Valid: true}) + transfer, err := h.walletSvc.TransferToWallet(c.Context(), + senderID, receiverID, domain.ToCurrency(req.Amount), domain.PaymentMethod(req.PaymentMethod), + domain.ValidInt64{Value: userID, Valid: true}, + fmt.Sprintf("Transferred %v from wallet to another", req.Amount), + ) - if !ok { + if err != nil { + h.mongoLoggerSvc.Error("Failed to transfer money to wallet", zap.Error(err)) return response.WriteJSON(c, fiber.StatusInternalServerError, "Transfer Failed", err, nil) } @@ -233,7 +284,7 @@ func (h *Handler) RefillWallet(c *fiber.Ctx) error { c.Context(), receiverID, domain.ToCurrency(req.Amount), domain.ValidInt64{ Value: userID, Valid: true, - }, domain.TRANSFER_BANK, domain.PaymentDetails{}, fmt.Sprintf("Added %d to wallet directly by super-admin", req.Amount)) + }, domain.TRANSFER_BANK, domain.PaymentDetails{}, fmt.Sprintf("Added %v to wallet directly by super-admin", req.Amount)) if !ok { return response.WriteJSON(c, fiber.StatusInternalServerError, "Creating Transfer Failed", err, nil) diff --git a/makefile b/makefile index 0f0dcec..e29d29e 100644 --- a/makefile +++ b/makefile @@ -50,7 +50,7 @@ swagger: .PHONY: db-up db-up: - @docker compose up -d postgres migrate mongo + @docker compose up -d postgres migrate mongo redis .PHONY: db-down db-down: