246 lines
8.8 KiB
Go
246 lines
8.8 KiB
Go
package handlers
|
|
|
|
import (
|
|
"log/slog"
|
|
"strconv"
|
|
"time"
|
|
|
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
|
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/branch"
|
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/services/wallet"
|
|
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
|
|
customvalidator "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/validator"
|
|
"github.com/gofiber/fiber/v2"
|
|
)
|
|
|
|
type TransferWalletRes struct {
|
|
ID int64 `json:"id" example:"1"`
|
|
Amount float32 `json:"amount" example:"100.0"`
|
|
Verified bool `json:"verified" example:"true"`
|
|
Type string `json:"type" example:"transfer"`
|
|
PaymentMethod string `json:"payment_method" example:"bank"`
|
|
ReceiverWalletID int64 `json:"receiver_wallet_id" example:"1"`
|
|
SenderWalletID *int64 `json:"sender_wallet_id" example:"1"`
|
|
CashierID *int64 `json:"cashier_id" example:"789"`
|
|
CreatedAt time.Time `json:"created_at" example:"2025-04-08T12:00:00Z"`
|
|
UpdatedAt time.Time `json:"updated_at" example:"2025-04-08T12:30:00Z"`
|
|
}
|
|
type RefillRes struct {
|
|
ID int64 `json:"id" example:"1"`
|
|
Amount float32 `json:"amount" example:"100.0"`
|
|
Verified bool `json:"verified" example:"true"`
|
|
Type string `json:"type" example:"transfer"`
|
|
PaymentMethod string `json:"payment_method" example:"bank"`
|
|
ReceiverWalletID int64 `json:"receiver_wallet_id" example:"1"`
|
|
SenderWalletID *int64 `json:"sender_wallet_id" example:"1"`
|
|
CashierID *int64 `json:"cashier_id" example:"789"`
|
|
CreatedAt time.Time `json:"created_at" example:"2025-04-08T12:00:00Z"`
|
|
UpdatedAt time.Time `json:"updated_at" example:"2025-04-08T12:30:00Z"`
|
|
}
|
|
|
|
func convertTransfer(transfer domain.Transfer) TransferWalletRes {
|
|
var senderWalletID *int64
|
|
if transfer.SenderWalletID.Valid {
|
|
senderWalletID = &transfer.SenderWalletID.Value
|
|
}
|
|
|
|
var cashierID *int64
|
|
if transfer.CashierID.Valid {
|
|
cashierID = &transfer.CashierID.Value
|
|
}
|
|
|
|
return TransferWalletRes{
|
|
ID: transfer.ID,
|
|
Amount: transfer.Amount.Float64(),
|
|
Verified: transfer.Verified,
|
|
Type: string(transfer.Type),
|
|
PaymentMethod: string(transfer.PaymentMethod),
|
|
ReceiverWalletID: transfer.ReceiverWalletID,
|
|
SenderWalletID: senderWalletID,
|
|
CashierID: cashierID,
|
|
CreatedAt: transfer.CreatedAt,
|
|
UpdatedAt: transfer.UpdatedAt,
|
|
}
|
|
}
|
|
|
|
type CreateTransferReq struct {
|
|
Amount float32 `json:"amount" example:"100.0"`
|
|
PaymentMethod string `json:"payment_method" example:"cash"`
|
|
}
|
|
|
|
type CreateRefillReq struct {
|
|
Amount float32 `json:"amount" example:"100.0"`
|
|
}
|
|
|
|
// GetTransfersByWallet godoc
|
|
// @Summary Get transfer by wallet
|
|
// @Description Get transfer by wallet
|
|
// @Tags transfer
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param transferToWallet body CreateTransferReq true "Create Transfer"
|
|
// @Success 200 {object} TransferWalletRes
|
|
// @Failure 400 {object} response.APIResponse
|
|
// @Failure 500 {object} response.APIResponse
|
|
// @Router /transfer/wallet/{id} [get]
|
|
func GetTransfersByWallet(logger *slog.Logger, walletSvc *wallet.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
|
return func(c *fiber.Ctx) error {
|
|
walletID := c.Params("id")
|
|
|
|
id, err := strconv.ParseInt(walletID, 10, 64)
|
|
|
|
if err != nil {
|
|
logger.Error("Invalid wallet ID", "walletID", walletID, "error", err)
|
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid wallet ID", err, nil)
|
|
}
|
|
|
|
transfers, err := walletSvc.GetTransfersByWallet(c.Context(), int64(id))
|
|
if err != nil {
|
|
logger.Error("Failed to get transfers by wallet", "walletID", walletID, "error", err)
|
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve transfers", err, nil)
|
|
}
|
|
|
|
var transferResponses []TransferWalletRes
|
|
for _, transfer := range transfers {
|
|
transferResponses = append(transferResponses, convertTransfer(transfer))
|
|
}
|
|
|
|
return response.WriteJSON(c, fiber.StatusOK, "Transfers retrieved successfully", transferResponses, nil)
|
|
}
|
|
}
|
|
|
|
// TransferToWallet godoc
|
|
// @Summary Create a transfer to wallet
|
|
// @Description Create a transfer to wallet
|
|
// @Tags transfer
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param transferToWallet body CreateTransferReq true "Create Transfer"
|
|
// @Success 200 {object} TransferWalletRes
|
|
// @Failure 400 {object} response.APIResponse
|
|
// @Failure 500 {object} response.APIResponse
|
|
// @Router /transfer/wallet/:id [post]
|
|
func TransferToWallet(logger *slog.Logger, walletSvc *wallet.Service, branchSvc *branch.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
|
return func(c *fiber.Ctx) error {
|
|
|
|
receiverIDString := c.Params("id")
|
|
|
|
receiverID, err := strconv.ParseInt(receiverIDString, 10, 64)
|
|
|
|
if err != nil {
|
|
logger.Error("Invalid wallet ID", "walletID", receiverID, "error", err)
|
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid wallet ID", err, nil)
|
|
}
|
|
// Get sender ID from the cashier
|
|
userID := c.Locals("user_id").(int64)
|
|
role := string(c.Locals("role").(domain.Role))
|
|
|
|
var senderID int64
|
|
|
|
if role == string(domain.RoleCustomer) {
|
|
logger.Error("Unauthorized access", "userID", userID, "role", role)
|
|
return response.WriteJSON(c, fiber.StatusUnauthorized, "Unauthorized access", nil, nil)
|
|
} else if role == string(domain.RoleBranchManager) || role == string(domain.RoleAdmin) || role == string(domain.RoleSuperAdmin) {
|
|
// TODO Add a way for admins to reference branch wallet
|
|
senderID = 0
|
|
logger.Error("Will", "userID", userID, "role", role)
|
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Unauthorized access", nil, nil)
|
|
} else {
|
|
cashierBranch, err := branchSvc.GetBranchByCashier(c.Context(), userID)
|
|
if err != nil {
|
|
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
|
|
}
|
|
|
|
var req CreateTransferReq
|
|
|
|
if err := c.BodyParser(&req); err != nil {
|
|
logger.Error("CreateTransferReq failed", "error", err)
|
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
|
}
|
|
|
|
valErrs, ok := validator.Validate(c, req)
|
|
if !ok {
|
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
|
}
|
|
|
|
transfer, err := walletSvc.TransferToWallet(c.Context(), senderID, receiverID, domain.ToCurrency(req.Amount), domain.PaymentMethod(req.PaymentMethod), domain.ValidInt64{Value: userID, Valid: true})
|
|
|
|
if !ok {
|
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Transfer Failed", err, nil)
|
|
}
|
|
|
|
res := convertTransfer(transfer)
|
|
|
|
return response.WriteJSON(c, fiber.StatusOK, "Transfer Successful", res, nil)
|
|
|
|
}
|
|
}
|
|
|
|
// RefillWallet godoc
|
|
// @Summary Refill wallet
|
|
// @Description Super Admin route to refill a wallet
|
|
// @Tags transfer
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param refillWallet body CreateTransferReq true "Create Transfer"
|
|
// @Success 200 {object} TransferWalletRes
|
|
// @Failure 400 {object} response.APIResponse
|
|
// @Failure 500 {object} response.APIResponse
|
|
// @Router /transfer/refill/:id [post]
|
|
func RefillWallet(logger *slog.Logger, walletSvc *wallet.Service, validator *customvalidator.CustomValidator) fiber.Handler {
|
|
return func(c *fiber.Ctx) error {
|
|
|
|
receiverIDString := c.Params("id")
|
|
|
|
receiverID, err := strconv.ParseInt(receiverIDString, 10, 64)
|
|
|
|
if err != nil {
|
|
logger.Error("Invalid wallet ID", "walletID", receiverID, "error", err)
|
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid wallet ID", err, nil)
|
|
}
|
|
// Get sender ID from the cashier
|
|
userID := c.Locals("user_id").(int64)
|
|
role := string(c.Locals("role").(domain.Role))
|
|
|
|
if role != string(domain.RoleSuperAdmin) {
|
|
logger.Error("Unauthorized access", "userID", userID, "role", role)
|
|
return response.WriteJSON(c, fiber.StatusUnauthorized, "Unauthorized access", nil, nil)
|
|
}
|
|
|
|
var req CreateRefillReq
|
|
|
|
if err := c.BodyParser(&req); err != nil {
|
|
logger.Error("CreateRefillReq failed", "error", err)
|
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
|
|
}
|
|
|
|
valErrs, ok := validator.Validate(c, req)
|
|
if !ok {
|
|
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
|
|
}
|
|
|
|
transfer, err := walletSvc.RefillWallet(c.Context(), domain.CreateTransfer{
|
|
Amount: domain.ToCurrency(req.Amount),
|
|
PaymentMethod: domain.TRANSFER_BANK,
|
|
ReceiverWalletID: receiverID,
|
|
CashierID: domain.ValidInt64{
|
|
Value: userID,
|
|
Valid: true,
|
|
},
|
|
Type: domain.TransferType("deposit"),
|
|
})
|
|
|
|
if !ok {
|
|
return response.WriteJSON(c, fiber.StatusInternalServerError, "Creating Transfer Failed", err, nil)
|
|
}
|
|
|
|
res := convertTransfer(transfer)
|
|
|
|
return response.WriteJSON(c, fiber.StatusOK, "Transfer Successful", res, nil)
|
|
|
|
}
|
|
}
|