package handlers import ( "strconv" "time" "github.com/SamuelTariku/FortuneBet-Backend/internal/domain" "github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response" "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 cashierID *int64 if transfer.CashierID.Valid { cashierID = &transfer.CashierID.Value } var receiverID *int64 if transfer.ReceiverWalletID.Valid { receiverID = &transfer.ReceiverWalletID.Value } var senderId *int64 if transfer.SenderWalletID.Valid { senderId = &transfer.SenderWalletID.Value } return TransferWalletRes{ ID: transfer.ID, Amount: transfer.Amount.Float32(), Verified: transfer.Verified, Type: string(transfer.Type), PaymentMethod: string(transfer.PaymentMethod), ReceiverWalletID: receiverID, SenderWalletID: senderId, 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 (h *Handler) GetTransfersByWallet(c *fiber.Ctx) error { walletID := c.Params("id") id, err := strconv.ParseInt(walletID, 10, 64) if err != nil { h.logger.Error("Invalid wallet ID", "walletID", walletID, "error", err) return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid wallet ID", err, nil) } transfers, err := h.walletSvc.GetTransfersByWallet(c.Context(), int64(id)) if err != nil { h.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 (h *Handler) TransferToWallet(c *fiber.Ctx) error { receiverIDString := c.Params("id") receiverID, err := strconv.ParseInt(receiverIDString, 10, 64) if err != nil { h.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 := c.Locals("role").(domain.Role) companyID := c.Locals("company_id").(int64) var senderID int64 //TODO: check to make sure that the cashiers aren't transferring TO branch wallet if role == domain.RoleCustomer { h.logger.Error("Unauthorized access", "userID", userID, "role", role) return response.WriteJSON(c, fiber.StatusUnauthorized, "Unauthorized access", nil, nil) } else if role == domain.RoleBranchManager || role == domain.RoleAdmin || role == domain.RoleSuperAdmin { company, err := h.companySvc.GetCompanyByID(c.Context(), companyID) if err != nil { return response.WriteJSON(c, fiber.StatusInternalServerError, "Error fetching company", err, nil) } senderID = company.WalletID h.logger.Error("Will", "userID", userID, "role", role) } else { 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 } var req CreateTransferReq if err := c.BodyParser(&req); err != nil { h.logger.Error("CreateTransferReq failed", "error", err) return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) } valErrs, ok := h.validator.Validate(c, req) if !ok { 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}) 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 (h *Handler) RefillWallet(c *fiber.Ctx) error { receiverIDString := c.Params("id") userID := c.Locals("user_id").(int64) receiverID, err := strconv.ParseInt(receiverIDString, 10, 64) if err != nil { h.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 var req CreateRefillReq if err := c.BodyParser(&req); err != nil { h.logger.Error("CreateRefillReq failed", "error", err) return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil) } valErrs, ok := h.validator.Validate(c, req) if !ok { return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) } transfer, err := h.walletSvc.AddToWallet( c.Context(), receiverID, domain.ToCurrency(req.Amount), domain.ValidInt64{ Value: userID, Valid: true, }, domain.TRANSFER_BANK, domain.PaymentDetails{}) 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) }