fix: get bet using cashout id

This commit is contained in:
Samuel Tariku 2025-07-02 17:48:16 +03:00
parent d678b4e9d3
commit c4328dedf0
10 changed files with 137 additions and 340 deletions

View File

@ -152,7 +152,7 @@ func main() {
cfg.FIXER_API_KEY, cfg.FIXER_API_KEY,
cfg.FIXER_BASE_URL, cfg.FIXER_BASE_URL,
) )
transactionSvc := transaction.NewService(store, *branchSvc) transactionSvc := transaction.NewService(store, *branchSvc, *betSvc, *walletSvc)
reportSvc := report.NewService( reportSvc := report.NewService(
bet.BetStore(store), bet.BetStore(store),

View File

@ -113,6 +113,10 @@ WHERE id = $1;
SELECT * SELECT *
FROM shop_bet_detail FROM shop_bet_detail
WHERE bet_id = $1; WHERE bet_id = $1;
-- name: GetShopBetByCashoutID :one
SELECT *
FROM shop_bet_detail
WHERE cashout_id = $1;
-- name: GetShopBetByShopTransactionID :one -- name: GetShopBetByShopTransactionID :one
SELECT * SELECT *
FROM shop_bet_detail FROM shop_bet_detail

View File

@ -448,6 +448,38 @@ func (q *Queries) GetShopBetByBetID(ctx context.Context, betID int64) (ShopBetDe
return i, err return i, err
} }
const GetShopBetByCashoutID = `-- name: GetShopBetByCashoutID :one
SELECT id, shop_transaction_id, cashout_id, cashed_out_by, bet_id, number_of_outcomes, cashed_out, created_at, updated_at, customer_full_name, customer_phone_number, branch_id, company_id, amount, transaction_verified, status, total_odds, outcomes
FROM shop_bet_detail
WHERE cashout_id = $1
`
func (q *Queries) GetShopBetByCashoutID(ctx context.Context, cashoutID string) (ShopBetDetail, error) {
row := q.db.QueryRow(ctx, GetShopBetByCashoutID, cashoutID)
var i ShopBetDetail
err := row.Scan(
&i.ID,
&i.ShopTransactionID,
&i.CashoutID,
&i.CashedOutBy,
&i.BetID,
&i.NumberOfOutcomes,
&i.CashedOut,
&i.CreatedAt,
&i.UpdatedAt,
&i.CustomerFullName,
&i.CustomerPhoneNumber,
&i.BranchID,
&i.CompanyID,
&i.Amount,
&i.TransactionVerified,
&i.Status,
&i.TotalOdds,
&i.Outcomes,
)
return i, err
}
const GetShopBetByID = `-- name: GetShopBetByID :one const GetShopBetByID = `-- name: GetShopBetByID :one
SELECT id, shop_transaction_id, cashout_id, cashed_out_by, bet_id, number_of_outcomes, cashed_out, created_at, updated_at, customer_full_name, customer_phone_number, branch_id, company_id, amount, transaction_verified, status, total_odds, outcomes SELECT id, shop_transaction_id, cashout_id, cashed_out_by, bet_id, number_of_outcomes, cashed_out, created_at, updated_at, customer_full_name, customer_phone_number, branch_id, company_id, amount, transaction_verified, status, total_odds, outcomes
FROM shop_bet_detail FROM shop_bet_detail

View File

@ -1,334 +0,0 @@
// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.29.0
// source: transactions.sql
package dbgen
import (
"context"
"github.com/jackc/pgx/v5/pgtype"
)
const CreateShopTransaction = `-- name: CreateShopTransaction :one
INSERT INTO shop_transactions (
amount,
branch_id,
cashier_id,
bet_id,
type,
payment_option,
full_name,
phone_number,
bank_code,
beneficiary_name,
account_name,
account_number,
reference_number,
number_of_outcomes,
branch_name,
branch_location,
company_id,
cashier_name
)
VALUES (
$1,
$2,
$3,
$4,
$5,
$6,
$7,
$8,
$9,
$10,
$11,
$12,
$13,
$14,
$15,
$16,
$17,
$18
)
RETURNING id, amount, branch_id, company_id, cashier_id, cashier_name, bet_id, number_of_outcomes, type, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, approved_by, approver_name, branch_location, branch_name, created_at, updated_at
`
type CreateShopTransactionParams struct {
Amount int64 `json:"amount"`
BranchID int64 `json:"branch_id"`
CashierID pgtype.Int8 `json:"cashier_id"`
BetID pgtype.Int8 `json:"bet_id"`
Type pgtype.Int8 `json:"type"`
PaymentOption pgtype.Int8 `json:"payment_option"`
FullName pgtype.Text `json:"full_name"`
PhoneNumber pgtype.Text `json:"phone_number"`
BankCode pgtype.Text `json:"bank_code"`
BeneficiaryName pgtype.Text `json:"beneficiary_name"`
AccountName pgtype.Text `json:"account_name"`
AccountNumber pgtype.Text `json:"account_number"`
ReferenceNumber pgtype.Text `json:"reference_number"`
NumberOfOutcomes pgtype.Int8 `json:"number_of_outcomes"`
BranchName pgtype.Text `json:"branch_name"`
BranchLocation pgtype.Text `json:"branch_location"`
CompanyID pgtype.Int8 `json:"company_id"`
CashierName pgtype.Text `json:"cashier_name"`
}
func (q *Queries) CreateShopTransaction(ctx context.Context, arg CreateShopTransactionParams) (ShopTransaction, error) {
row := q.db.QueryRow(ctx, CreateShopTransaction,
arg.Amount,
arg.BranchID,
arg.CashierID,
arg.BetID,
arg.Type,
arg.PaymentOption,
arg.FullName,
arg.PhoneNumber,
arg.BankCode,
arg.BeneficiaryName,
arg.AccountName,
arg.AccountNumber,
arg.ReferenceNumber,
arg.NumberOfOutcomes,
arg.BranchName,
arg.BranchLocation,
arg.CompanyID,
arg.CashierName,
)
var i ShopTransaction
err := row.Scan(
&i.ID,
&i.Amount,
&i.BranchID,
&i.CompanyID,
&i.CashierID,
&i.CashierName,
&i.BetID,
&i.NumberOfOutcomes,
&i.Type,
&i.PaymentOption,
&i.FullName,
&i.PhoneNumber,
&i.BankCode,
&i.BeneficiaryName,
&i.AccountName,
&i.AccountNumber,
&i.ReferenceNumber,
&i.Verified,
&i.ApprovedBy,
&i.ApproverName,
&i.BranchLocation,
&i.BranchName,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const GetAllShopTransactions = `-- name: GetAllShopTransactions :many
SELECT id, amount, branch_id, company_id, cashier_id, cashier_name, bet_id, number_of_outcomes, type, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, approved_by, approver_name, branch_location, branch_name, created_at, updated_at
FROM shop_transactions
wHERE (
branch_id = $1
OR $1 IS NULL
)
AND (
company_id = $2
OR $2 IS NULL
)
AND (
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 GetAllShopTransactionsParams 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) GetAllShopTransactions(ctx context.Context, arg GetAllShopTransactionsParams) ([]ShopTransaction, error) {
rows, err := q.db.Query(ctx, GetAllShopTransactions,
arg.BranchID,
arg.CompanyID,
arg.CashierID,
arg.Query,
arg.CreatedBefore,
arg.CreatedAfter,
)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ShopTransaction
for rows.Next() {
var i ShopTransaction
if err := rows.Scan(
&i.ID,
&i.Amount,
&i.BranchID,
&i.CompanyID,
&i.CashierID,
&i.CashierName,
&i.BetID,
&i.NumberOfOutcomes,
&i.Type,
&i.PaymentOption,
&i.FullName,
&i.PhoneNumber,
&i.BankCode,
&i.BeneficiaryName,
&i.AccountName,
&i.AccountNumber,
&i.ReferenceNumber,
&i.Verified,
&i.ApprovedBy,
&i.ApproverName,
&i.BranchLocation,
&i.BranchName,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetShopTransactionByBranch = `-- name: GetShopTransactionByBranch :many
SELECT id, amount, branch_id, company_id, cashier_id, cashier_name, bet_id, number_of_outcomes, type, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, approved_by, approver_name, branch_location, branch_name, created_at, updated_at
FROM shop_transactions
WHERE branch_id = $1
`
func (q *Queries) GetShopTransactionByBranch(ctx context.Context, branchID int64) ([]ShopTransaction, error) {
rows, err := q.db.Query(ctx, GetShopTransactionByBranch, branchID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ShopTransaction
for rows.Next() {
var i ShopTransaction
if err := rows.Scan(
&i.ID,
&i.Amount,
&i.BranchID,
&i.CompanyID,
&i.CashierID,
&i.CashierName,
&i.BetID,
&i.NumberOfOutcomes,
&i.Type,
&i.PaymentOption,
&i.FullName,
&i.PhoneNumber,
&i.BankCode,
&i.BeneficiaryName,
&i.AccountName,
&i.AccountNumber,
&i.ReferenceNumber,
&i.Verified,
&i.ApprovedBy,
&i.ApproverName,
&i.BranchLocation,
&i.BranchName,
&i.CreatedAt,
&i.UpdatedAt,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const GetShopTransactionByID = `-- name: GetShopTransactionByID :one
SELECT id, amount, branch_id, company_id, cashier_id, cashier_name, bet_id, number_of_outcomes, type, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, approved_by, approver_name, branch_location, branch_name, created_at, updated_at
FROM shop_transactions
WHERE id = $1
`
func (q *Queries) GetShopTransactionByID(ctx context.Context, id int64) (ShopTransaction, error) {
row := q.db.QueryRow(ctx, GetShopTransactionByID, id)
var i ShopTransaction
err := row.Scan(
&i.ID,
&i.Amount,
&i.BranchID,
&i.CompanyID,
&i.CashierID,
&i.CashierName,
&i.BetID,
&i.NumberOfOutcomes,
&i.Type,
&i.PaymentOption,
&i.FullName,
&i.PhoneNumber,
&i.BankCode,
&i.BeneficiaryName,
&i.AccountName,
&i.AccountNumber,
&i.ReferenceNumber,
&i.Verified,
&i.ApprovedBy,
&i.ApproverName,
&i.BranchLocation,
&i.BranchName,
&i.CreatedAt,
&i.UpdatedAt,
)
return i, err
}
const UpdateShopTransactionVerified = `-- name: UpdateShopTransactionVerified :exec
UPDATE shop_transactions
SET verified = $2,
approved_by = $3,
approver_name = $4,
updated_at = CURRENT_TIMESTAMP
WHERE id = $1
`
type UpdateShopTransactionVerifiedParams struct {
ID int64 `json:"id"`
Verified bool `json:"verified"`
ApprovedBy pgtype.Int8 `json:"approved_by"`
ApproverName pgtype.Text `json:"approver_name"`
}
func (q *Queries) UpdateShopTransactionVerified(ctx context.Context, arg UpdateShopTransactionVerifiedParams) error {
_, err := q.db.Exec(ctx, UpdateShopTransactionVerified,
arg.ID,
arg.Verified,
arg.ApprovedBy,
arg.ApproverName,
)
return err
}

View File

@ -116,6 +116,14 @@ func (s *Store) GetShopBetByBetID(ctx context.Context, betID int64) (domain.Shop
} }
return convertDBShopBetDetail(bet), nil return convertDBShopBetDetail(bet), nil
} }
func (s *Store) GetShopBetByCashoutID(ctx context.Context, cashoutID string) (domain.ShopBetDetail, error) {
bet, err := s.queries.GetShopBetByCashoutID(ctx, cashoutID)
if err != nil {
return domain.ShopBetDetail{}, err
}
return convertDBShopBetDetail(bet), nil
}
func (s *Store) GetShopBetByShopTransactionID(ctx context.Context, shopTransactionID int64) (domain.ShopBetDetail, error) { func (s *Store) GetShopBetByShopTransactionID(ctx context.Context, shopTransactionID int64) (domain.ShopBetDetail, error) {
bet, err := s.queries.GetShopBetByShopTransactionID(ctx, shopTransactionID) bet, err := s.queries.GetShopBetByShopTransactionID(ctx, shopTransactionID)
if err != nil { if err != nil {

View File

@ -88,6 +88,7 @@ func (s *Store) GetUserByID(ctx context.Context, id int64) (domain.User, error)
}, nil }, nil
} }
func (s *Store) GetAllUsers(ctx context.Context, filter domain.UserFilter) ([]domain.User, int64, error) { func (s *Store) GetAllUsers(ctx context.Context, filter domain.UserFilter) ([]domain.User, int64, error) {
fmt.Printf("\n\nuser_filter %v \n\n", filter)
users, err := s.queries.GetAllUsers(ctx, dbgen.GetAllUsersParams{ users, err := s.queries.GetAllUsers(ctx, dbgen.GetAllUsersParams{
Role: filter.Role, Role: filter.Role,
CompanyID: pgtype.Int8{ CompanyID: pgtype.Int8{

View File

@ -19,6 +19,7 @@ type TransactionStore interface {
GetAllShopBet(ctx context.Context, filter domain.ShopBetFilter) ([]domain.ShopBetDetail, error) GetAllShopBet(ctx context.Context, filter domain.ShopBetFilter) ([]domain.ShopBetDetail, error)
GetShopBetByID(ctx context.Context, id int64) (domain.ShopBetDetail, error) GetShopBetByID(ctx context.Context, id int64) (domain.ShopBetDetail, error)
GetShopBetByBetID(ctx context.Context, betID int64) (domain.ShopBetDetail, error) GetShopBetByBetID(ctx context.Context, betID int64) (domain.ShopBetDetail, error)
GetShopBetByCashoutID(ctx context.Context, cashoutID string) (domain.ShopBetDetail, error)
GetShopBetByShopTransactionID(ctx context.Context, shopTransactionID int64) (domain.ShopBetDetail, error) GetShopBetByShopTransactionID(ctx context.Context, shopTransactionID int64) (domain.ShopBetDetail, error)
UpdateShopBetCashOut(ctx context.Context, id int64, cashedOut bool) error UpdateShopBetCashOut(ctx context.Context, id int64, cashedOut bool) error
UpdateShopBetCashoutID(ctx context.Context, id int64, cashoutID string) error UpdateShopBetCashoutID(ctx context.Context, id int64, cashoutID string) error

View File

@ -111,8 +111,8 @@ func (s *Service) CreateShopBet(ctx context.Context, userID int64, role domain.R
// return s.transactionStore.CreateShopBet(ctx, bet) // return s.transactionStore.CreateShopBet(ctx, bet)
// } // }
func (s *Service) CashoutBet(ctx context.Context, betID int64, userID int64, role domain.Role, req domain.CashoutReq) (domain.ShopTransaction, error) { func (s *Service) CashoutBet(ctx context.Context, betID int64, userID int64, role domain.Role, req domain.CashoutReq, userCompanyID domain.ValidInt64) (domain.ShopTransaction, error) {
branchID, companyID, err := s.GetBranchByRole(ctx, req.BranchID, role, userID) branchID, companyID, err := s.GetBranchByRole(ctx, req.BranchID, role, userID, userCompanyID)
if err != nil { if err != nil {
return domain.ShopTransaction{}, nil return domain.ShopTransaction{}, nil
@ -194,6 +194,10 @@ func (s *Service) GetShopBetByBetID(ctx context.Context, betID int64) (domain.Sh
return s.transactionStore.GetShopBetByBetID(ctx, betID) return s.transactionStore.GetShopBetByBetID(ctx, betID)
} }
func (s *Service) GetShopBetByCashoutID(ctx context.Context, cashoutID string) (domain.ShopBetDetail, error) {
return s.transactionStore.GetShopBetByCashoutID(ctx, cashoutID)
}
func (s *Service) GetShopBetByShopTransactionID(ctx context.Context, shopTransactionID int64) (domain.ShopBetDetail, error) { func (s *Service) GetShopBetByShopTransactionID(ctx context.Context, shopTransactionID int64) (domain.ShopBetDetail, error) {
return s.transactionStore.GetShopBetByShopTransactionID(ctx, shopTransactionID) return s.transactionStore.GetShopBetByShopTransactionID(ctx, shopTransactionID)
} }

View File

@ -55,7 +55,7 @@ func (h *Handler) CreateShopBet(c *fiber.Ctx) error {
// @Tags transaction // @Tags transaction
// @Accept json // @Accept json
// @Produce json // @Produce json
// @Param createBet body domain.CashoutReq true "cashout bet" // @Param cashoutBet body domain.CashoutReq true "cashout bet"
// @Success 200 {object} TransactionRes // @Success 200 {object} TransactionRes
// @Failure 400 {object} response.APIResponse // @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse // @Failure 500 {object} response.APIResponse
@ -73,6 +73,7 @@ func (h *Handler) CashoutBet(c *fiber.Ctx) error {
userID := c.Locals("user_id").(int64) userID := c.Locals("user_id").(int64)
role := c.Locals("role").(domain.Role) role := c.Locals("role").(domain.Role)
companyID := c.Locals("company_id").(domain.ValidInt64)
var req domain.CashoutReq var req domain.CashoutReq
if err := c.BodyParser(&req); err != nil { if err := c.BodyParser(&req); err != nil {
@ -86,7 +87,7 @@ func (h *Handler) CashoutBet(c *fiber.Ctx) error {
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
} }
transaction, err := h.transactionSvc.CashoutBet(c.Context(), betID, userID, role, req) transaction, err := h.transactionSvc.CashoutBet(c.Context(), betID, userID, role, req, companyID)
if err != nil { if err != nil {
return response.WriteJSON(c, fiber.StatusBadRequest, "Failed to cashout bet", err, nil) return response.WriteJSON(c, fiber.StatusBadRequest, "Failed to cashout bet", err, nil)
@ -96,6 +97,84 @@ func (h *Handler) CashoutBet(c *fiber.Ctx) error {
return response.WriteJSON(c, fiber.StatusOK, "Transaction created successfully", res, nil) return response.WriteJSON(c, fiber.StatusOK, "Transaction created successfully", res, nil)
} }
// CashoutByCashoutID godoc
// @Summary Cashout bet by cashoutID
// @Description Cashout bet by cashoutID
// @Tags transaction
// @Accept json
// @Produce json
// @Param cashoutBet body domain.CashoutReq true "cashout bet"
// @Success 200 {object} TransactionRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /shop/cashout [post]
func (h *Handler) CashoutByCashoutID(c *fiber.Ctx) error {
userID := c.Locals("user_id").(int64)
role := c.Locals("role").(domain.Role)
companyID := c.Locals("company_id").(domain.ValidInt64)
var req domain.CashoutReq
if err := c.BodyParser(&req); err != nil {
h.logger.Error("CashoutReq failed to parse request", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
}
valErrs, ok := h.validator.Validate(c, req)
if !ok {
h.logger.Error("CashoutReq failed v", "error", valErrs)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
}
bet, err := h.transactionSvc.GetShopBetByCashoutID(c.Context(), req.CashoutID)
if err != nil {
h.logger.Error("CashoutReq failed invalid cashout id", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid cashout ID", err, nil)
}
transaction, err := h.transactionSvc.CashoutBet(c.Context(), bet.BetID, userID, role, req, companyID)
if err != nil {
return response.WriteJSON(c, fiber.StatusBadRequest, "Failed to cashout bet", err, nil)
}
res := domain.ConvertShopTransaction(transaction)
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/cashout/{id} [get]
func (h *Handler) GetShopBetByCashoutID(c *fiber.Ctx) error {
cashoutID := c.Params("id")
if cashoutID == "" {
h.logger.Error("CashoutReq failed cashout id is required", "error", nil)
return response.WriteJSON(c, fiber.StatusBadRequest, "cashout ID is required", nil, nil)
}
bet, err := h.transactionSvc.GetShopBetByCashoutID(c.Context(), cashoutID)
if err != nil {
h.logger.Error("CashoutReq failed invalid cashout id", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid cashout ID", err, nil)
}
res := domain.ConvertShopBetDetail(bet)
return response.WriteJSON(c, fiber.StatusOK, "Transaction created successfully", res, nil)
}
// DepositForCustomer godoc // DepositForCustomer godoc
// @Summary Shop deposit into customer wallet // @Summary Shop deposit into customer wallet
// @Description Transfers money from branch wallet to customer wallet // @Description Transfers money from branch wallet to customer wallet

View File

@ -275,6 +275,8 @@ func (a *App) initAppRoutes() {
// Transactions /shop/transactions // Transactions /shop/transactions
a.fiber.Post("/shop/bet", a.authMiddleware, a.CompanyOnly, h.CreateShopBet) a.fiber.Post("/shop/bet", a.authMiddleware, a.CompanyOnly, h.CreateShopBet)
a.fiber.Post("/shop/bet/:id/cashout", a.authMiddleware, a.CompanyOnly, h.CashoutBet) a.fiber.Post("/shop/bet/:id/cashout", a.authMiddleware, a.CompanyOnly, h.CashoutBet)
a.fiber.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.Post("/shop/deposit", a.authMiddleware, a.CompanyOnly, h.DepositForCustomer)
a.fiber.Get("/shop/transaction", a.authMiddleware, h.GetAllTransactions) a.fiber.Get("/shop/transaction", a.authMiddleware, h.GetAllTransactions)
a.fiber.Get("/shop/transaction/:id", a.authMiddleware, h.GetTransactionByID) a.fiber.Get("/shop/transaction/:id", a.authMiddleware, h.GetTransactionByID)