diff --git a/db/migrations/000001_fortune.up.sql b/db/migrations/000001_fortune.up.sql index 91e589f..ddfe56a 100644 --- a/db/migrations/000001_fortune.up.sql +++ b/db/migrations/000001_fortune.up.sql @@ -46,14 +46,15 @@ CREATE TABLE IF NOT EXISTS bets ( phone_number VARCHAR(255) NOT NULL, branch_id BIGINT, user_id BIGINT, - cashed_out BOOLEAN DEFAULT FALSE, + cashed_out BOOLEAN DEFAULT FALSE NOT NULL, + cashout_id VARCHAR(255) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, is_shop_bet BOOLEAN NOT NULL, CHECK (user_id IS NOT NULL OR branch_id IS NOT NULL) ); -CREATE TABLE IF NOT EXISTS tickets ( +CREATE TABLE IF NOT EXISTS `tickets` ( id BIGSERIAL PRIMARY KEY, amount BIGINT NULL, total_odds REAL NOT NULL, @@ -118,6 +119,7 @@ CREATE TABLE IF NOT EXISTS transactions ( branch_id BIGINT NOT NULL, cashier_id BIGINT NOT NULL, bet_id BIGINT NOT NULL, + type BIGINT NOT NULL, payment_option BIGINT NOT NULL, full_name VARCHAR(255) NOT NULL, phone_number VARCHAR(255) NOT NULL, diff --git a/db/query/bet.sql b/db/query/bet.sql index bf0d466..2d1d098 100644 --- a/db/query/bet.sql +++ b/db/query/bet.sql @@ -1,6 +1,6 @@ -- name: CreateBet :one -INSERT INTO bets (amount, total_odds, status, full_name, phone_number, branch_id, user_id, is_shop_bet) -VALUES ($1, $2, $3, $4, $5, $6, $7, $8) +INSERT INTO bets (amount, total_odds, status, full_name, phone_number, branch_id, user_id, is_shop_bet, cashout_id) +VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING *; -- name: GetAllBets :many diff --git a/db/query/transactions.sql b/db/query/transactions.sql index 75adba4..a5d21b0 100644 --- a/db/query/transactions.sql +++ b/db/query/transactions.sql @@ -1,5 +1,5 @@ -- name: CreateTransaction :one -INSERT INTO transactions (amount, branch_id, cashier_id, bet_id, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) RETURNING *; +INSERT INTO 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) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) RETURNING *; -- name: GetAllTransactions :many SELECT * FROM transactions; diff --git a/docs/docs.go b/docs/docs.go index cd7719d..f36102b 100644 --- a/docs/docs.go +++ b/docs/docs.go @@ -2165,6 +2165,10 @@ const docTemplate = `{ }, "reference_number": { "type": "string" + }, + "type": { + "type": "integer", + "example": 1 } } }, @@ -2406,6 +2410,10 @@ const docTemplate = `{ "reference_number": { "type": "string" }, + "type": { + "type": "integer", + "example": 1 + }, "verified": { "type": "boolean", "example": true diff --git a/docs/swagger.json b/docs/swagger.json index 7ecbb4f..bad0c85 100644 --- a/docs/swagger.json +++ b/docs/swagger.json @@ -2157,6 +2157,10 @@ }, "reference_number": { "type": "string" + }, + "type": { + "type": "integer", + "example": 1 } } }, @@ -2398,6 +2402,10 @@ "reference_number": { "type": "string" }, + "type": { + "type": "integer", + "example": 1 + }, "verified": { "type": "boolean", "example": true diff --git a/docs/swagger.yaml b/docs/swagger.yaml index 69e4307..8b92636 100644 --- a/docs/swagger.yaml +++ b/docs/swagger.yaml @@ -267,6 +267,9 @@ definitions: type: string reference_number: type: string + type: + example: 1 + type: integer type: object handlers.CreateTransferReq: properties: @@ -434,6 +437,9 @@ definitions: type: string reference_number: type: string + type: + example: 1 + type: integer verified: example: true type: boolean diff --git a/gen/db/bet.sql.go b/gen/db/bet.sql.go index f3667c6..79b5cf3 100644 --- a/gen/db/bet.sql.go +++ b/gen/db/bet.sql.go @@ -12,9 +12,9 @@ import ( ) const CreateBet = `-- name: CreateBet :one -INSERT INTO bets (amount, total_odds, status, full_name, phone_number, branch_id, user_id, is_shop_bet) -VALUES ($1, $2, $3, $4, $5, $6, $7, $8) -RETURNING id, amount, total_odds, status, full_name, phone_number, branch_id, user_id, cashed_out, created_at, updated_at, is_shop_bet +INSERT INTO bets (amount, total_odds, status, full_name, phone_number, branch_id, user_id, is_shop_bet, cashout_id) +VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) +RETURNING id, amount, total_odds, status, full_name, phone_number, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet ` type CreateBetParams struct { @@ -26,6 +26,7 @@ type CreateBetParams struct { BranchID pgtype.Int8 UserID pgtype.Int8 IsShopBet bool + CashoutID string } func (q *Queries) CreateBet(ctx context.Context, arg CreateBetParams) (Bet, error) { @@ -38,6 +39,7 @@ func (q *Queries) CreateBet(ctx context.Context, arg CreateBetParams) (Bet, erro arg.BranchID, arg.UserID, arg.IsShopBet, + arg.CashoutID, ) var i Bet err := row.Scan( @@ -50,6 +52,7 @@ func (q *Queries) CreateBet(ctx context.Context, arg CreateBetParams) (Bet, erro &i.BranchID, &i.UserID, &i.CashedOut, + &i.CashoutID, &i.CreatedAt, &i.UpdatedAt, &i.IsShopBet, @@ -67,7 +70,7 @@ func (q *Queries) DeleteBet(ctx context.Context, id int64) error { } const GetAllBets = `-- name: GetAllBets :many -SELECT id, amount, total_odds, status, full_name, phone_number, branch_id, user_id, cashed_out, created_at, updated_at, is_shop_bet FROM bets +SELECT id, amount, total_odds, status, full_name, phone_number, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet FROM bets ` func (q *Queries) GetAllBets(ctx context.Context) ([]Bet, error) { @@ -89,6 +92,7 @@ func (q *Queries) GetAllBets(ctx context.Context) ([]Bet, error) { &i.BranchID, &i.UserID, &i.CashedOut, + &i.CashoutID, &i.CreatedAt, &i.UpdatedAt, &i.IsShopBet, @@ -104,7 +108,7 @@ func (q *Queries) GetAllBets(ctx context.Context) ([]Bet, error) { } const GetBetByID = `-- name: GetBetByID :one -SELECT id, amount, total_odds, status, full_name, phone_number, branch_id, user_id, cashed_out, created_at, updated_at, is_shop_bet FROM bets WHERE id = $1 +SELECT id, amount, total_odds, status, full_name, phone_number, branch_id, user_id, cashed_out, cashout_id, created_at, updated_at, is_shop_bet FROM bets WHERE id = $1 ` func (q *Queries) GetBetByID(ctx context.Context, id int64) (Bet, error) { @@ -120,6 +124,7 @@ func (q *Queries) GetBetByID(ctx context.Context, id int64) (Bet, error) { &i.BranchID, &i.UserID, &i.CashedOut, + &i.CashoutID, &i.CreatedAt, &i.UpdatedAt, &i.IsShopBet, @@ -133,7 +138,7 @@ UPDATE bets SET cashed_out = $2, updated_at = CURRENT_TIMESTAMP WHERE id = $1 type UpdateCashOutParams struct { ID int64 - CashedOut pgtype.Bool + CashedOut bool } func (q *Queries) UpdateCashOut(ctx context.Context, arg UpdateCashOutParams) error { diff --git a/gen/db/models.go b/gen/db/models.go index 8e449a6..e96ee34 100644 --- a/gen/db/models.go +++ b/gen/db/models.go @@ -17,7 +17,8 @@ type Bet struct { PhoneNumber string BranchID pgtype.Int8 UserID pgtype.Int8 - CashedOut pgtype.Bool + CashedOut bool + CashoutID string CreatedAt pgtype.Timestamp UpdatedAt pgtype.Timestamp IsShopBet bool @@ -125,6 +126,7 @@ type Transaction struct { BranchID int64 CashierID int64 BetID int64 + Type int64 PaymentOption int64 FullName string PhoneNumber string diff --git a/gen/db/transactions.sql.go b/gen/db/transactions.sql.go index 4f5fbe1..8f15071 100644 --- a/gen/db/transactions.sql.go +++ b/gen/db/transactions.sql.go @@ -10,7 +10,7 @@ import ( ) const CreateTransaction = `-- name: CreateTransaction :one -INSERT INTO transactions (amount, branch_id, cashier_id, bet_id, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) RETURNING id, amount, branch_id, cashier_id, bet_id, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, created_at, updated_at +INSERT INTO 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) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) RETURNING id, amount, branch_id, cashier_id, bet_id, type, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, created_at, updated_at ` type CreateTransactionParams struct { @@ -18,6 +18,7 @@ type CreateTransactionParams struct { BranchID int64 CashierID int64 BetID int64 + Type int64 PaymentOption int64 FullName string PhoneNumber string @@ -34,6 +35,7 @@ func (q *Queries) CreateTransaction(ctx context.Context, arg CreateTransactionPa arg.BranchID, arg.CashierID, arg.BetID, + arg.Type, arg.PaymentOption, arg.FullName, arg.PhoneNumber, @@ -50,6 +52,7 @@ func (q *Queries) CreateTransaction(ctx context.Context, arg CreateTransactionPa &i.BranchID, &i.CashierID, &i.BetID, + &i.Type, &i.PaymentOption, &i.FullName, &i.PhoneNumber, @@ -66,7 +69,7 @@ func (q *Queries) CreateTransaction(ctx context.Context, arg CreateTransactionPa } const GetAllTransactions = `-- name: GetAllTransactions :many -SELECT id, amount, branch_id, cashier_id, bet_id, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, created_at, updated_at FROM transactions +SELECT id, amount, branch_id, cashier_id, bet_id, type, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, created_at, updated_at FROM transactions ` func (q *Queries) GetAllTransactions(ctx context.Context) ([]Transaction, error) { @@ -84,6 +87,7 @@ func (q *Queries) GetAllTransactions(ctx context.Context) ([]Transaction, error) &i.BranchID, &i.CashierID, &i.BetID, + &i.Type, &i.PaymentOption, &i.FullName, &i.PhoneNumber, @@ -107,7 +111,7 @@ func (q *Queries) GetAllTransactions(ctx context.Context) ([]Transaction, error) } const GetTransactionByBranch = `-- name: GetTransactionByBranch :many -SELECT id, amount, branch_id, cashier_id, bet_id, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, created_at, updated_at FROM transactions WHERE branch_id = $1 +SELECT id, amount, branch_id, cashier_id, bet_id, type, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, created_at, updated_at FROM transactions WHERE branch_id = $1 ` func (q *Queries) GetTransactionByBranch(ctx context.Context, branchID int64) ([]Transaction, error) { @@ -125,6 +129,7 @@ func (q *Queries) GetTransactionByBranch(ctx context.Context, branchID int64) ([ &i.BranchID, &i.CashierID, &i.BetID, + &i.Type, &i.PaymentOption, &i.FullName, &i.PhoneNumber, @@ -148,7 +153,7 @@ func (q *Queries) GetTransactionByBranch(ctx context.Context, branchID int64) ([ } const GetTransactionByID = `-- name: GetTransactionByID :one -SELECT id, amount, branch_id, cashier_id, bet_id, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, created_at, updated_at FROM transactions WHERE id = $1 +SELECT id, amount, branch_id, cashier_id, bet_id, type, payment_option, full_name, phone_number, bank_code, beneficiary_name, account_name, account_number, reference_number, verified, created_at, updated_at FROM transactions WHERE id = $1 ` func (q *Queries) GetTransactionByID(ctx context.Context, id int64) (Transaction, error) { @@ -160,6 +165,7 @@ func (q *Queries) GetTransactionByID(ctx context.Context, id int64) (Transaction &i.BranchID, &i.CashierID, &i.BetID, + &i.Type, &i.PaymentOption, &i.FullName, &i.PhoneNumber, diff --git a/internal/domain/bet.go b/internal/domain/bet.go index e36ee62..cc8175d 100644 --- a/internal/domain/bet.go +++ b/internal/domain/bet.go @@ -36,6 +36,7 @@ type CreateBet struct { BranchID ValidInt64 // Can Be Nullable UserID ValidInt64 // Can Be Nullable IsShopBet bool + CashoutID string } func (b BetStatus) String() string { diff --git a/internal/domain/transaction.go b/internal/domain/transaction.go index 3ff096e..f47c34a 100644 --- a/internal/domain/transaction.go +++ b/internal/domain/transaction.go @@ -1,5 +1,12 @@ package domain +type TransactionType int + +const ( + TRANSACTION_CASHOUT TransactionType = iota + TRANSACTION_DEPOSIT +) + type PaymentOption int64 const ( @@ -8,6 +15,7 @@ const ( ARIFPAY_TRANSACTION 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 type Transaction struct { @@ -16,6 +24,7 @@ type Transaction struct { BranchID int64 CashierID int64 BetID int64 + Type TransactionType PaymentOption PaymentOption FullName string PhoneNumber string @@ -33,6 +42,7 @@ type CreateTransaction struct { BranchID int64 CashierID int64 BetID int64 + Type TransactionType PaymentOption PaymentOption FullName string PhoneNumber string diff --git a/internal/repository/bet.go b/internal/repository/bet.go index 2ddef36..210fcbd 100644 --- a/internal/repository/bet.go +++ b/internal/repository/bet.go @@ -25,6 +25,8 @@ func convertDBBet(bet dbgen.Bet) domain.Bet { Valid: bet.UserID.Valid, }, IsShopBet: bet.IsShopBet, + CashedOut: bet.CashedOut, + CashoutID: bet.CashoutID, } } @@ -44,6 +46,7 @@ func convertCreateBet(bet domain.CreateBet) dbgen.CreateBetParams { Valid: bet.UserID.Valid, }, IsShopBet: bet.IsShopBet, + CashoutID: bet.CashoutID, } } @@ -83,10 +86,8 @@ func (s *Store) GetAllBets(ctx context.Context) ([]domain.Bet, error) { func (s *Store) UpdateCashOut(ctx context.Context, id int64, cashedOut bool) error { err := s.queries.UpdateCashOut(ctx, dbgen.UpdateCashOutParams{ - ID: id, - CashedOut: pgtype.Bool{ - Bool: cashedOut, - }, + ID: id, + CashedOut: cashedOut, }) return err } diff --git a/internal/repository/transaction.go b/internal/repository/transaction.go index e7f3e4f..24cf9e0 100644 --- a/internal/repository/transaction.go +++ b/internal/repository/transaction.go @@ -13,6 +13,7 @@ func convertDBTransaction(transaction dbgen.Transaction) domain.Transaction { BranchID: transaction.BranchID, CashierID: transaction.CashierID, BetID: transaction.BetID, + Type: domain.TransactionType(transaction.Type), PaymentOption: domain.PaymentOption(transaction.PaymentOption), FullName: transaction.FullName, PhoneNumber: transaction.PhoneNumber, @@ -30,6 +31,7 @@ func convertCreateTransaction(transaction domain.CreateTransaction) dbgen.Create BranchID: transaction.BranchID, CashierID: transaction.CashierID, BetID: transaction.BetID, + Type: int64(transaction.Type), PaymentOption: int64(transaction.PaymentOption), FullName: transaction.FullName, PhoneNumber: transaction.PhoneNumber, diff --git a/internal/web_server/handlers/bet_handler.go b/internal/web_server/handlers/bet_handler.go index 5c9678f..dab2e1d 100644 --- a/internal/web_server/handlers/bet_handler.go +++ b/internal/web_server/handlers/bet_handler.go @@ -9,6 +9,7 @@ import ( "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response" customvalidator "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/validator" "github.com/gofiber/fiber/v2" + "github.com/google/uuid" ) type CreateBetReq struct { @@ -64,7 +65,6 @@ func CreateBet(logger *slog.Logger, betSvc *bet.Service, validator *customvalida // TODO if user is customer, get id from the token then get the wallet id from there // TODO: If user is a cashier, check the token, and find the role and get the branch id from there. Reduce amount from the branch wallet - var isShopBet bool = true var branchID int64 = 1 @@ -87,6 +87,8 @@ func CreateBet(logger *slog.Logger, betSvc *bet.Service, validator *customvalida // TODO Validate Outcomes Here and make sure they didn't expire + cashoutUUID := uuid.New() + bet, err := betSvc.CreateBet(c.Context(), domain.CreateBet{ Outcomes: req.Outcomes, Amount: domain.Currency(req.Amount), @@ -104,6 +106,7 @@ func CreateBet(logger *slog.Logger, betSvc *bet.Service, validator *customvalida Valid: !isShopBet, }, IsShopBet: req.IsShopBet, + CashoutID: cashoutUUID.String(), }) if err != nil { diff --git a/internal/web_server/handlers/branch_handler.go b/internal/web_server/handlers/branch_handler.go index 8e0552e..6a2bf16 100644 --- a/internal/web_server/handlers/branch_handler.go +++ b/internal/web_server/handlers/branch_handler.go @@ -151,9 +151,22 @@ func CreateBranch(logger *slog.Logger, branchSvc *branch.Service, walletSvc *wal }) } + for _, operation := range req.Operations { + err := branchSvc.CreateBranchOperation(c.Context(), domain.CreateBranchOperation{ + BranchID: branch.ID, + OperationID: operation, + }) + if err != nil { + logger.Error("Failed to create branch operations", "BranchID", branch.ID, "operation", operation, "error", err) + return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{ + "error": "Internal server error", + }) + } + } + res := convertBranch(branch) - return response.WriteJSON(c, fiber.StatusOK, "Branch Created", res, nil) + return response.WriteJSON(c, fiber.StatusCreated, "Branch Created", res, nil) } diff --git a/internal/web_server/handlers/transaction_handler.go b/internal/web_server/handlers/transaction_handler.go index 77f80c9..cd441fb 100644 --- a/internal/web_server/handlers/transaction_handler.go +++ b/internal/web_server/handlers/transaction_handler.go @@ -1,6 +1,7 @@ package handlers import ( + // "fmt" "log/slog" "strconv" @@ -13,12 +14,12 @@ import ( ) type TransactionRes struct { - ID int64 `json:"id" example:"1"` - Amount float32 `json:"amount" example:"100.0"` - BranchID int64 `json:"branch_id" example:"1"` - CashierID int64 `json:"cashier_id" example:"1"` - BetID int64 `json:"bet_id" example:"1"` - + ID int64 `json:"id" example:"1"` + Amount float32 `json:"amount" example:"100.0"` + BranchID int64 `json:"branch_id" example:"1"` + CashierID int64 `json:"cashier_id" example:"1"` + BetID int64 `json:"bet_id" example:"1"` + Type int64 `json:"type" example:"1"` PaymentOption domain.PaymentOption `json:"payment_option" example:"1"` FullName string `json:"full_name" example:"John Smith"` PhoneNumber string `json:"phone_number" example:"0911111111"` @@ -35,6 +36,7 @@ type CreateTransactionReq struct { BranchID int64 `json:"branch_id" example:"1"` CashierID int64 `json:"cashier_id" example:"1"` BetID int64 `json:"bet_id" example:"1"` + Type int64 `json:"type" example:"1"` PaymentOption domain.PaymentOption `json:"payment_option" example:"1"` FullName string `json:"full_name" example:"John Smith"` PhoneNumber string `json:"phone_number" example:"0911111111"` @@ -53,6 +55,7 @@ func convertTransaction(transaction domain.Transaction) TransactionRes { BranchID: transaction.BranchID, CashierID: transaction.CashierID, BetID: transaction.BetID, + Type: int64(transaction.Type), PaymentOption: transaction.PaymentOption, FullName: transaction.FullName, PhoneNumber: transaction.PhoneNumber, @@ -97,6 +100,7 @@ func CreateTransaction(logger *slog.Logger, transactionSvc *transaction.Service, BranchID: req.BranchID, CashierID: req.CashierID, BetID: req.BetID, + Type: domain.TransactionType(req.Type), PaymentOption: domain.PaymentOption(req.PaymentOption), FullName: req.FullName, PhoneNumber: req.PhoneNumber, diff --git a/internal/web_server/middleware.go b/internal/web_server/middleware.go index 46e248b..217a2bf 100644 --- a/internal/web_server/middleware.go +++ b/internal/web_server/middleware.go @@ -2,6 +2,7 @@ package httpserver import ( "errors" + "fmt" "strings" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" @@ -13,10 +14,12 @@ func (a *App) authMiddleware(c *fiber.Ctx) error { authHeader := c.Get("Authorization") if authHeader == "" { + fmt.Println("Auth Header Missing") return fiber.NewError(fiber.StatusUnauthorized, "Authorization header missing") } if !strings.HasPrefix(authHeader, "Bearer ") { + fmt.Println("Invalid authorization header format") return fiber.NewError(fiber.StatusUnauthorized, "Invalid authorization header format") } @@ -25,8 +28,10 @@ func (a *App) authMiddleware(c *fiber.Ctx) error { claim, err := jwtutil.ParseJwt(accessToken, a.JwtConfig.JwtAccessKey) if err != nil { if errors.Is(err, jwtutil.ErrExpiredToken) { + fmt.Println("Token Expired") return fiber.NewError(fiber.StatusUnauthorized, "Access token expired") } + fmt.Println("Invalid Token") return fiber.NewError(fiber.StatusUnauthorized, "Invalid access token") }