fix: added message to transfer and more filter routes

This commit is contained in:
Samuel Tariku 2025-06-29 18:00:23 +03:00
parent 56bcdeffaa
commit 10a49b4571
29 changed files with 453 additions and 126 deletions

View File

@ -119,11 +119,16 @@ CREATE TABLE IF NOT EXISTS banks (
name VARCHAR(255) NOT NULL,
acct_length INT NOT NULL,
country_id INT NOT NULL,
is_mobilemoney INT, -- nullable integer (0 or 1)
is_active INT NOT NULL, -- 0 or 1
is_rtgs INT NOT NULL, -- 0 or 1
active INT NOT NULL, -- 0 or 1
is_24hrs INT, -- nullable integer (0 or 1)
is_mobilemoney INT,
-- nullable integer (0 or 1)
is_active INT NOT NULL,
-- 0 or 1
is_rtgs INT NOT NULL,
-- 0 or 1
active INT NOT NULL,
-- 0 or 1
is_24hrs INT,
-- nullable integer (0 or 1)
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL,
currency VARCHAR(10) NOT NULL,
@ -151,6 +156,7 @@ CREATE TABLE IF NOT EXISTS customer_wallets (
CREATE TABLE IF NOT EXISTS wallet_transfer (
id BIGSERIAL PRIMARY KEY,
amount BIGINT,
message VARCHAR(255) NOT NULL,
type VARCHAR(255),
receiver_wallet_id BIGINT,
sender_wallet_id BIGINT,

View File

@ -12,7 +12,20 @@ SELECT users.*,
branches.location As branch_location
FROM branch_cashiers
JOIN users ON branch_cashiers.user_id = users.id
JOIN branches ON branches.id = branch_id;
JOIN branches ON branches.id = branch_id
WHERE (
full_name ILIKE '%' || sqlc.narg('query') || '%'
OR phone_number ILIKE '%' || sqlc.narg('query') || '%'
OR sqlc.narg('query') IS NULL
)
AND (
users.created_at > sqlc.narg('created_before')
OR sqlc.narg('created_before') IS NULL
)
AND (
users.created_at < sqlc.narg('created_after')
OR sqlc.narg('created_after') IS NULL
);
-- name: GetCashierByID :one
SELECT users.*,
branch_id,

View File

@ -54,6 +54,19 @@ wHERE (
AND (
cashier_id = sqlc.narg('cashier_id')
OR sqlc.narg('cashier_id') IS NULL
)
AND (
full_name ILIKE '%' || sqlc.narg('query') || '%'
OR phone_number ILIKE '%' || sqlc.narg('query') || '%'
OR sqlc.narg('query') IS NULL
)
AND (
created_at > sqlc.narg('created_before')
OR sqlc.narg('created_before') IS NULL
)
AND (
created_at < sqlc.narg('created_after')
OR sqlc.narg('created_after') IS NULL
);
-- name: GetTransactionByID :one
SELECT *

View File

@ -1,6 +1,7 @@
-- name: CreateTransfer :one
INSERT INTO wallet_transfer (
amount,
message,
type,
receiver_wallet_id,
sender_wallet_id,
@ -10,7 +11,7 @@ INSERT INTO wallet_transfer (
status,
payment_method
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
RETURNING *;
-- name: GetAllTransfers :many
SELECT *
@ -33,18 +34,15 @@ UPDATE wallet_transfer
SET verified = $1,
updated_at = CURRENT_TIMESTAMP
WHERE id = $2;
-- name: UpdateTransferStatus :exec
UPDATE wallet_transfer
SET status = $1,
updated_at = CURRENT_TIMESTAMP
WHERE id = $2;
-- name: GetWalletTransactionsInRange :many
SELECT type, COUNT(*) as count, SUM(amount) as total_amount
SELECT type,
COUNT(*) as count,
SUM(amount) as total_amount
FROM wallet_transfer
WHERE created_at BETWEEN $1 AND $2
GROUP BY type;

View File

@ -14,8 +14,18 @@ INSERT INTO users (
company_id
)
VALUES (
$1, $2, $3, $4, $5, $6,
$7, $8, $9, $10, $11, $12
$1,
$2,
$3,
$4,
$5,
$6,
$7,
$8,
$9,
$10,
$11,
$12
)
RETURNING id,
first_name,
@ -29,7 +39,6 @@ RETURNING id,
updated_at,
suspended,
company_id;
-- name: GetUserByID :one
SELECT *
FROM users
@ -57,6 +66,19 @@ wHERE (
company_id = $2
OR $2 IS NULL
)
AND (
full_name ILIKE '%' || sqlc.narg('query') || '%'
OR phone_number ILIKE '%' || sqlc.narg('query') || '%'
OR sqlc.narg('query') IS NULL
)
AND (
created_at > sqlc.narg('created_before')
OR sqlc.narg('created_before') IS NULL
)
AND (
created_at < sqlc.narg('created_after')
OR sqlc.narg('created_after') IS NULL
)
LIMIT sqlc.narg('limit') OFFSET sqlc.narg('offset');
-- name: GetTotalUsers :one
SELECT COUNT(*)

View File

@ -20,8 +20,27 @@ SELECT users.id, users.first_name, users.last_name, users.email, users.phone_num
FROM branch_cashiers
JOIN users ON branch_cashiers.user_id = users.id
JOIN branches ON branches.id = branch_id
WHERE (
full_name ILIKE '%' || $1 || '%'
OR phone_number ILIKE '%' || $1 || '%'
OR $1 IS NULL
)
AND (
users.created_at > $2
OR $2 IS NULL
)
AND (
users.created_at < $3
OR $3 IS NULL
)
`
type GetAllCashiersParams struct {
Query pgtype.Text `json:"query"`
CreatedBefore pgtype.Timestamptz `json:"created_before"`
CreatedAfter pgtype.Timestamptz `json:"created_after"`
}
type GetAllCashiersRow struct {
ID int64 `json:"id"`
FirstName string `json:"first_name"`
@ -45,8 +64,8 @@ type GetAllCashiersRow struct {
BranchLocation string `json:"branch_location"`
}
func (q *Queries) GetAllCashiers(ctx context.Context) ([]GetAllCashiersRow, error) {
rows, err := q.db.Query(ctx, GetAllCashiers)
func (q *Queries) GetAllCashiers(ctx context.Context, arg GetAllCashiersParams) ([]GetAllCashiersRow, error) {
rows, err := q.db.Query(ctx, GetAllCashiers, arg.Query, arg.CreatedBefore, arg.CreatedAfter)
if err != nil {
return nil, err
}

View File

@ -580,6 +580,7 @@ type WalletThresholdNotification struct {
type WalletTransfer 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"`

View File

@ -142,16 +142,39 @@ wHERE (
cashier_id = $3
OR $3 IS NULL
)
AND (
full_name ILIKE '%' || $4 || '%'
OR phone_number ILIKE '%' || $4 || '%'
OR $4 IS NULL
)
AND (
created_at > $5
OR $5 IS NULL
)
AND (
created_at < $6
OR $6 IS NULL
)
`
type GetAllTransactionsParams struct {
BranchID pgtype.Int8 `json:"branch_id"`
CompanyID pgtype.Int8 `json:"company_id"`
CashierID pgtype.Int8 `json:"cashier_id"`
Query pgtype.Text `json:"query"`
CreatedBefore pgtype.Timestamp `json:"created_before"`
CreatedAfter pgtype.Timestamp `json:"created_after"`
}
func (q *Queries) GetAllTransactions(ctx context.Context, arg GetAllTransactionsParams) ([]Transaction, error) {
rows, err := q.db.Query(ctx, GetAllTransactions, arg.BranchID, arg.CompanyID, arg.CashierID)
rows, err := q.db.Query(ctx, GetAllTransactions,
arg.BranchID,
arg.CompanyID,
arg.CashierID,
arg.Query,
arg.CreatedBefore,
arg.CreatedAfter,
)
if err != nil {
return nil, err
}

View File

@ -14,6 +14,7 @@ import (
const CreateTransfer = `-- name: CreateTransfer :one
INSERT INTO wallet_transfer (
amount,
message,
type,
receiver_wallet_id,
sender_wallet_id,
@ -23,12 +24,13 @@ INSERT INTO wallet_transfer (
status,
payment_method
)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
RETURNING id, amount, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, reference_number, status, payment_method, created_at, updated_at
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10)
RETURNING id, amount, message, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, reference_number, status, payment_method, created_at, updated_at
`
type CreateTransferParams struct {
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"`
@ -42,6 +44,7 @@ type CreateTransferParams struct {
func (q *Queries) CreateTransfer(ctx context.Context, arg CreateTransferParams) (WalletTransfer, error) {
row := q.db.QueryRow(ctx, CreateTransfer,
arg.Amount,
arg.Message,
arg.Type,
arg.ReceiverWalletID,
arg.SenderWalletID,
@ -55,6 +58,7 @@ func (q *Queries) CreateTransfer(ctx context.Context, arg CreateTransferParams)
err := row.Scan(
&i.ID,
&i.Amount,
&i.Message,
&i.Type,
&i.ReceiverWalletID,
&i.SenderWalletID,
@ -70,7 +74,7 @@ func (q *Queries) CreateTransfer(ctx context.Context, arg CreateTransferParams)
}
const GetAllTransfers = `-- name: GetAllTransfers :many
SELECT id, amount, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, reference_number, status, payment_method, created_at, updated_at
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
`
@ -86,6 +90,7 @@ func (q *Queries) GetAllTransfers(ctx context.Context) ([]WalletTransfer, error)
if err := rows.Scan(
&i.ID,
&i.Amount,
&i.Message,
&i.Type,
&i.ReceiverWalletID,
&i.SenderWalletID,
@ -108,7 +113,7 @@ func (q *Queries) GetAllTransfers(ctx context.Context) ([]WalletTransfer, error)
}
const GetTransferByID = `-- name: GetTransferByID :one
SELECT id, amount, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, reference_number, status, payment_method, created_at, updated_at
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
WHERE id = $1
`
@ -119,6 +124,7 @@ func (q *Queries) GetTransferByID(ctx context.Context, id int64) (WalletTransfer
err := row.Scan(
&i.ID,
&i.Amount,
&i.Message,
&i.Type,
&i.ReceiverWalletID,
&i.SenderWalletID,
@ -134,7 +140,7 @@ func (q *Queries) GetTransferByID(ctx context.Context, id int64) (WalletTransfer
}
const GetTransferByReference = `-- name: GetTransferByReference :one
SELECT id, amount, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, reference_number, status, payment_method, created_at, updated_at
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
WHERE reference_number = $1
`
@ -145,6 +151,7 @@ func (q *Queries) GetTransferByReference(ctx context.Context, referenceNumber st
err := row.Scan(
&i.ID,
&i.Amount,
&i.Message,
&i.Type,
&i.ReceiverWalletID,
&i.SenderWalletID,
@ -160,7 +167,7 @@ func (q *Queries) GetTransferByReference(ctx context.Context, referenceNumber st
}
const GetTransfersByWallet = `-- name: GetTransfersByWallet :many
SELECT id, amount, type, receiver_wallet_id, sender_wallet_id, cashier_id, verified, reference_number, status, payment_method, created_at, updated_at
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
WHERE receiver_wallet_id = $1
OR sender_wallet_id = $1
@ -178,6 +185,7 @@ func (q *Queries) GetTransfersByWallet(ctx context.Context, receiverWalletID pgt
if err := rows.Scan(
&i.ID,
&i.Amount,
&i.Message,
&i.Type,
&i.ReceiverWalletID,
&i.SenderWalletID,
@ -200,7 +208,9 @@ func (q *Queries) GetTransfersByWallet(ctx context.Context, receiverWalletID pgt
}
const GetWalletTransactionsInRange = `-- name: GetWalletTransactionsInRange :many
SELECT type, COUNT(*) as count, SUM(amount) as total_amount
SELECT type,
COUNT(*) as count,
SUM(amount) as total_amount
FROM wallet_transfer
WHERE created_at BETWEEN $1 AND $2
GROUP BY type

View File

@ -59,8 +59,18 @@ INSERT INTO users (
company_id
)
VALUES (
$1, $2, $3, $4, $5, $6,
$7, $8, $9, $10, $11, $12
$1,
$2,
$3,
$4,
$5,
$6,
$7,
$8,
$9,
$10,
$11,
$12
)
RETURNING id,
first_name,
@ -172,12 +182,28 @@ wHERE (
company_id = $2
OR $2 IS NULL
)
LIMIT $4 OFFSET $3
AND (
full_name ILIKE '%' || $3 || '%'
OR phone_number ILIKE '%' || $3 || '%'
OR $3 IS NULL
)
AND (
created_at > $4
OR $4 IS NULL
)
AND (
created_at < $5
OR $5 IS NULL
)
LIMIT $7 OFFSET $6
`
type GetAllUsersParams struct {
Role string `json:"role"`
CompanyID pgtype.Int8 `json:"company_id"`
Query pgtype.Text `json:"query"`
CreatedBefore pgtype.Timestamptz `json:"created_before"`
CreatedAfter pgtype.Timestamptz `json:"created_after"`
Offset pgtype.Int4 `json:"offset"`
Limit pgtype.Int4 `json:"limit"`
}
@ -202,6 +228,9 @@ func (q *Queries) GetAllUsers(ctx context.Context, arg GetAllUsersParams) ([]Get
rows, err := q.db.Query(ctx, GetAllUsers,
arg.Role,
arg.CompanyID,
arg.Query,
arg.CreatedBefore,
arg.CreatedAfter,
arg.Offset,
arg.Limit,
)

View File

@ -52,6 +52,9 @@ type TransactionFilter struct {
CompanyID ValidInt64
BranchID ValidInt64
CashierID ValidInt64
Query ValidString
CreatedBefore ValidTime
CreatedAfter ValidTime
}
type CreateTransaction struct {
Amount Currency

View File

@ -36,6 +36,7 @@ type Transfer 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"`
@ -50,6 +51,7 @@ type Transfer struct {
type CreateTransfer struct {
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"`

View File

@ -30,6 +30,20 @@ type User struct {
CompanyID ValidInt64
}
type UserFilter struct {
Role string
CompanyID ValidInt64
Page ValidInt
PageSize ValidInt
Query ValidString
CreatedBefore ValidTime
CreatedAfter ValidTime
}
type ValidRole struct {
Value Role
Valid bool
}
type RegisterUserReq struct {
FirstName string
LastName string

View File

@ -99,6 +99,18 @@ func (s *Store) GetAllTransactions(ctx context.Context, filter domain.Transactio
Int64: filter.CashierID.Value,
Valid: filter.CashierID.Valid,
},
Query: pgtype.Text{
String: filter.Query.Value,
Valid: filter.Query.Valid,
},
CreatedBefore: pgtype.Timestamp{
Time: filter.CreatedBefore.Value,
Valid: filter.CreatedBefore.Valid,
},
CreatedAfter: pgtype.Timestamp{
Time: filter.CreatedAfter.Value,
Valid: filter.CreatedAfter.Valid,
},
})
if err != nil {

View File

@ -36,6 +36,7 @@ func convertDBTransfer(transfer dbgen.WalletTransfer) domain.Transfer {
func convertCreateTransfer(transfer domain.CreateTransfer) dbgen.CreateTransferParams {
return dbgen.CreateTransferParams{
Message: transfer.Message,
Amount: pgtype.Int8{Int64: int64(transfer.Amount), Valid: true},
Type: pgtype.Text{String: string(transfer.Type), Valid: true},
ReceiverWalletID: pgtype.Int8{

View File

@ -9,7 +9,6 @@ import (
dbgen "github.com/SamuelTariku/FortuneBet-Backend/gen/db"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/user"
"github.com/jackc/pgx/v5/pgtype"
)
@ -88,7 +87,7 @@ func (s *Store) GetUserByID(ctx context.Context, id int64) (domain.User, error)
},
}, nil
}
func (s *Store) GetAllUsers(ctx context.Context, filter user.Filter) ([]domain.User, int64, error) {
func (s *Store) GetAllUsers(ctx context.Context, filter domain.UserFilter) ([]domain.User, int64, error) {
users, err := s.queries.GetAllUsers(ctx, dbgen.GetAllUsersParams{
Role: filter.Role,
CompanyID: pgtype.Int8{
@ -103,6 +102,18 @@ func (s *Store) GetAllUsers(ctx context.Context, filter user.Filter) ([]domain.U
Int32: int32(filter.Page.Value),
Valid: filter.Page.Valid,
},
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

View File

@ -275,7 +275,8 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID
branch.WalletID, domain.ToCurrency(deductedAmount), domain.BranchWalletType, domain.ValidInt64{
Value: userID,
Valid: true,
}, domain.TRANSFER_DIRECT)
}, domain.TRANSFER_DIRECT,
fmt.Sprintf("Deducted %d 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),
@ -311,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)
}, domain.TRANSFER_DIRECT, fmt.Sprintf("Deducted %d amount from wallet by system while placing bet", deductedAmount))
if err != nil {
s.mongoLogger.Error("wallet deduction failed",
zap.Int64("wallet_id", branch.WalletID),
@ -337,7 +338,8 @@ 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)
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))
if err != nil {
s.mongoLogger.Error("wallet deduction failed for customer regular wallet",
zap.Int64("customer_id", wallets.CustomerID),
@ -355,7 +357,8 @@ 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)
wallets.RegularBalance, domain.CustomerWalletType, domain.ValidInt64{}, domain.TRANSFER_DIRECT,
fmt.Sprintf("Deducted %d 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),
@ -369,7 +372,8 @@ func (s *Service) PlaceBet(ctx context.Context, req domain.CreateBetReq, userID
// Empty remaining from static balance
remainingAmount := wallets.RegularBalance - domain.Currency(req.Amount)
_, err = s.walletSvc.DeductFromWallet(ctx, wallets.StaticID,
remainingAmount, domain.CustomerWalletType, domain.ValidInt64{}, domain.TRANSFER_DIRECT)
remainingAmount, domain.CustomerWalletType, domain.ValidInt64{}, domain.TRANSFER_DIRECT,
fmt.Sprintf("Deducted %d 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),
@ -754,7 +758,8 @@ func (s *Service) UpdateStatus(ctx context.Context, id int64, status domain.Outc
amount = bet.Amount
}
_, err = s.walletSvc.AddToWallet(ctx, customerWallet.RegularID, amount, domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{})
_, 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()))
if err != nil {
s.mongoLogger.Error("failed to add winnings to wallet",

View File

@ -83,6 +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),
Amount: amount,
Type: domain.DEPOSIT,
PaymentMethod: domain.TRANSFER_CHAPA,
@ -167,6 +168,7 @@ func (s *Service) InitiateWithdrawal(ctx context.Context, userID int64, req doma
reference := uuid.New().String()
createTransfer := domain.CreateTransfer{
Message: fmt.Sprintf("Withdrawing %d into wallet using chapa. Reference Number %s", amount, reference),
Amount: domain.Currency(amount),
Type: domain.WITHDRAW,
SenderWalletID: domain.ValidInt64{
@ -265,7 +267,10 @@ func (s *Service) ManuallyVerify(ctx context.Context, txRef string) (*domain.Cha
}
// Credit wallet
if _, err := s.walletStore.AddToWallet(ctx, transfer.SenderWalletID.Value, transfer.Amount, domain.ValidInt64{}, domain.TRANSFER_CHAPA, domain.PaymentDetails{}); err != nil {
_, 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()))
if err != nil {
return nil, fmt.Errorf("failed to credit wallet: %w", err)
}
}
@ -325,7 +330,7 @@ func (s *Service) HandleVerifyDepositWebhook(ctx context.Context, transfer domai
ReferenceNumber: domain.ValidString{
Value: transfer.Reference,
},
}); err != nil {
}, fmt.Sprintf("Added %d to wallet using Chapa")); err != nil {
return fmt.Errorf("failed to credit user wallet: %w", err)
}
}
@ -361,7 +366,10 @@ func (s *Service) HandleVerifyWithdrawWebhook(ctx context.Context, payment domai
return fmt.Errorf("failed to update payment status: %w", err)
} // If payment is completed, credit user's walle
} else {
if _, err := s.walletStore.AddToWallet(ctx, transfer.SenderWalletID.Value, transfer.Amount, domain.ValidInt64{}, domain.TRANSFER_DIRECT, domain.PaymentDetails{}); err != nil {
_, 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"))
if err != nil {
return fmt.Errorf("failed to credit user wallet: %w", err)
}
}

View File

@ -43,22 +43,9 @@ func (s *Service) DeleteUser(ctx context.Context, id int64) error {
return s.userStore.DeleteUser(ctx, id)
}
type Filter struct {
Role string
CompanyID domain.ValidInt64
Page domain.ValidInt
PageSize domain.ValidInt
}
type ValidRole struct {
Value domain.Role
Valid bool
}
type ValidBranchId struct {
Value int64
Valid bool
}
func (s *Service) GetAllUsers(ctx context.Context, filter Filter) ([]domain.User, int64, error) {
func (s *Service) GetAllUsers(ctx context.Context, filter domain.UserFilter) ([]domain.User, int64, error) {
// Get all Users
return s.userStore.GetAllUsers(ctx, filter)
}

View File

@ -206,8 +206,10 @@ func (s *service) ProcessBet(ctx context.Context, req *domain.PopOKBetRequest) (
if err != nil {
return &domain.PopOKBetResponse{}, fmt.Errorf("Failed to read user wallets")
}
if _, err := s.walletSvc.DeductFromWallet(ctx, claims.UserID, domain.Currency(amountCents), domain.CustomerWalletType, domain.ValidInt64{}, domain.TRANSFER_DIRECT); err != nil {
_, 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))
if err != nil {
return nil, fmt.Errorf("insufficient balance")
}

View File

@ -42,7 +42,6 @@ func (s *Service) UpdateTransferStatus(ctx context.Context, id int64, status str
return s.transferStore.UpdateTransferStatus(ctx, id, status)
}
func (s *Service) TransferToWallet(ctx context.Context, senderID int64, receiverID int64,
amount domain.Currency, paymentMethod domain.PaymentMethod,
cashierID domain.ValidInt64) (domain.Transfer, error) {
@ -85,6 +84,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),
SenderWalletID: domain.ValidInt64{
Value: senderID,
Valid: true,

View File

@ -84,7 +84,7 @@ func (s *Service) UpdateBalance(ctx context.Context, id int64, balance domain.Cu
}
func (s *Service) AddToWallet(
ctx context.Context, id int64, amount domain.Currency, cashierID domain.ValidInt64, paymentMethod domain.PaymentMethod, paymentDetails domain.PaymentDetails) (domain.Transfer, error) {
ctx context.Context, id int64, amount domain.Currency, cashierID domain.ValidInt64, paymentMethod domain.PaymentMethod, paymentDetails domain.PaymentDetails, message string) (domain.Transfer, error) {
wallet, err := s.GetWalletByID(ctx, id)
if err != nil {
return domain.Transfer{}, err
@ -99,6 +99,7 @@ func (s *Service) AddToWallet(
// Log the transfer here for reference
newTransfer, err := s.transferStore.CreateTransfer(ctx, domain.CreateTransfer{
Message: message,
Amount: amount,
Verified: true,
ReceiverWalletID: domain.ValidInt64{
@ -114,7 +115,7 @@ func (s *Service) AddToWallet(
return newTransfer, err
}
func (s *Service) DeductFromWallet(ctx context.Context, id int64, amount domain.Currency, walletType domain.WalletType, cashierID domain.ValidInt64, paymentMethod domain.PaymentMethod) (domain.Transfer, error) {
func (s *Service) DeductFromWallet(ctx context.Context, id int64, amount domain.Currency, walletType domain.WalletType, cashierID domain.ValidInt64, paymentMethod domain.PaymentMethod, message string) (domain.Transfer, error) {
wallet, err := s.GetWalletByID(ctx, id)
if err != nil {
return domain.Transfer{}, err
@ -138,6 +139,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,
Amount: amount,
Verified: true,
SenderWalletID: domain.ValidInt64{

View File

@ -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)
}

View File

@ -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"
"go.uber.org/zap"
@ -155,7 +154,41 @@ type AdminRes struct {
// @Failure 500 {object} response.APIResponse
// @Router /admin [get]
func (h *Handler) GetAllAdmins(c *fiber.Ctx) error {
filter := user.Filter{
searchQuery := c.Query("query")
searchString := domain.ValidString{
Value: searchQuery,
Valid: searchQuery != "",
}
createdBeforeQuery := c.Query("created_before")
var createdBefore domain.ValidTime
if createdBeforeQuery != "" {
createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery)
if err != nil {
h.logger.Error("invalid start_time format", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil)
}
createdBefore = domain.ValidTime{
Value: createdBeforeParsed,
Valid: true,
}
}
createdAfterQuery := c.Query("created_after")
var createdAfter domain.ValidTime
if createdAfterQuery != "" {
createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery)
if err != nil {
h.logger.Error("invalid start_time format", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil)
}
createdAfter = domain.ValidTime{
Value: createdAfterParsed,
Valid: true,
}
}
filter := domain.UserFilter{
Role: string(domain.RoleAdmin),
CompanyID: domain.ValidInt64{
Value: int64(c.QueryInt("company_id")),
@ -169,6 +202,9 @@ func (h *Handler) GetAllAdmins(c *fiber.Ctx) error {
Value: c.QueryInt("page_size", 10),
Valid: true,
},
Query: searchString,
CreatedBefore: createdBefore,
CreatedAfter: createdAfter,
}
valErrs, ok := h.validator.Validate(c, filter)

View File

@ -124,7 +124,40 @@ func (h *Handler) GetAllCashiers(c *fiber.Ctx) error {
if role != domain.RoleSuperAdmin && !companyId.Valid {
return fiber.NewError(fiber.StatusInternalServerError, "Cannot get company ID")
}
filter := user.Filter{
searchQuery := c.Query("query")
searchString := domain.ValidString{
Value: searchQuery,
Valid: searchQuery != "",
}
createdBeforeQuery := c.Query("created_before")
var createdBefore domain.ValidTime
if createdBeforeQuery != "" {
createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery)
if err != nil {
h.logger.Error("invalid start_time format", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil)
}
createdBefore = domain.ValidTime{
Value: createdBeforeParsed,
Valid: true,
}
}
createdAfterQuery := c.Query("created_after")
var createdAfter domain.ValidTime
if createdAfterQuery != "" {
createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery)
if err != nil {
h.logger.Error("invalid start_time format", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil)
}
createdAfter = domain.ValidTime{
Value: createdAfterParsed,
Valid: true,
}
}
filter := domain.UserFilter{
Role: string(domain.RoleCashier),
CompanyID: companyId,
Page: domain.ValidInt{
@ -135,6 +168,9 @@ func (h *Handler) GetAllCashiers(c *fiber.Ctx) error {
Value: c.QueryInt("page_size", 10),
Valid: true,
},
Query: searchString,
CreatedBefore: createdBefore,
CreatedAfter: createdAfter,
}
valErrs, ok := h.validator.Validate(c, filter)

View File

@ -116,7 +116,42 @@ func (h *Handler) GetAllManagers(c *fiber.Ctx) error {
if role != domain.RoleSuperAdmin && !companyId.Valid {
return fiber.NewError(fiber.StatusInternalServerError, "Cannot get company ID")
}
filter := user.Filter{
searchQuery := c.Query("query")
searchString := domain.ValidString{
Value: searchQuery,
Valid: searchQuery != "",
}
createdBeforeQuery := c.Query("created_before")
var createdBefore domain.ValidTime
if createdBeforeQuery != "" {
createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery)
if err != nil {
h.logger.Error("invalid start_time format", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil)
}
createdBefore = domain.ValidTime{
Value: createdBeforeParsed,
Valid: true,
}
}
createdAfterQuery := c.Query("created_after")
var createdAfter domain.ValidTime
if createdAfterQuery != "" {
createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery)
if err != nil {
h.logger.Error("invalid start_time format", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil)
}
createdAfter = domain.ValidTime{
Value: createdAfterParsed,
Valid: true,
}
}
filter := domain.UserFilter{
Role: string(domain.RoleBranchManager),
CompanyID: companyId,
Page: domain.ValidInt{
@ -127,6 +162,9 @@ func (h *Handler) GetAllManagers(c *fiber.Ctx) error {
Value: c.QueryInt("page_size", 10),
Valid: true,
},
Query: searchString,
CreatedBefore: createdBefore,
CreatedAfter: createdAfter,
}
valErrs, ok := h.validator.Validate(c, filter)
if !ok {

View File

@ -230,12 +230,47 @@ func (h *Handler) GetAllTransactions(c *fiber.Ctx) error {
companyID := c.Locals("company_id").(domain.ValidInt64)
branchID := c.Locals("branch_id").(domain.ValidInt64)
var transactions []domain.Transaction
searchQuery := c.Query("query")
searchString := domain.ValidString{
Value: searchQuery,
Valid: searchQuery != "",
}
createdBeforeQuery := c.Query("created_before")
var createdBefore domain.ValidTime
if createdBeforeQuery != "" {
createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery)
if err != nil {
h.logger.Error("invalid start_time format", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil)
}
createdBefore = domain.ValidTime{
Value: createdBeforeParsed,
Valid: true,
}
}
createdAfterQuery := c.Query("created_after")
var createdAfter domain.ValidTime
if createdAfterQuery != "" {
createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery)
if err != nil {
h.logger.Error("invalid start_time format", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil)
}
createdAfter = domain.ValidTime{
Value: createdAfterParsed,
Valid: true,
}
}
// Check user role and fetch transactions accordingly
transactions, err := h.transactionSvc.GetAllTransactions(c.Context(), domain.TransactionFilter{
CompanyID: companyID,
BranchID: branchID,
Query: searchString,
CreatedBefore: createdBefore,
CreatedAfter: createdAfter,
})
if err != nil {

View File

@ -233,7 +233,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{})
}, domain.TRANSFER_BANK, domain.PaymentDetails{}, fmt.Sprintf("Added %d to wallet directly by super-admin", req.Amount))
if !ok {
return response.WriteJSON(c, fiber.StatusInternalServerError, "Creating Transfer Failed", err, nil)

View File

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