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 WalletRes struct { ID int64 `json:"id" example:"1"` Balance float32 `json:"amount" example:"100.0"` IsWithdraw bool `json:"is_withdraw" example:"true"` IsBettable bool `json:"is_bettable" example:"true"` IsTransferable bool `json:"is_transferable" example:"true"` IsActive bool `json:"is_active" example:"true"` UserID int64 `json:"user_id" example:"1"` UpdatedAt time.Time `json:"updated_at"` CreatedAt time.Time `json:"created_at"` } func convertWallet(wallet domain.Wallet) WalletRes { return WalletRes{ ID: wallet.ID, Balance: wallet.Balance.Float32(), IsWithdraw: wallet.IsWithdraw, IsBettable: wallet.IsBettable, IsTransferable: wallet.IsTransferable, IsActive: wallet.IsActive, UserID: wallet.UserID, UpdatedAt: wallet.UpdatedAt, CreatedAt: wallet.CreatedAt, } } type CustomerWalletRes struct { ID int64 `json:"id" example:"1"` RegularID int64 `json:"regular_id" example:"1"` RegularBalance float32 `json:"regular_balance" example:"100.0"` StaticID int64 `json:"static_id" example:"1"` StaticBalance float32 `json:"static_balance" example:"100.0"` CustomerID int64 `json:"customer_id" example:"1"` RegularIsActive bool `json:"regular_is_active" example:"true"` StaticIsActive bool `json:"static_is_active" example:"true"` RegularUpdatedAt time.Time `json:"regular_updated_at"` StaticUpdatedAt time.Time `json:"static_updated_at"` CreatedAt time.Time `json:"created_at"` FirstName string `json:"first_name" example:"John"` LastName string `json:"last_name" example:"Smith"` PhoneNumber string `json:"phone_number" example:"0911111111"` } func ConvertCustomerWallet(wallet domain.GetCustomerWallet) CustomerWalletRes { return CustomerWalletRes{ ID: wallet.ID, RegularID: wallet.RegularID, RegularBalance: wallet.RegularBalance.Float32(), StaticID: wallet.StaticID, StaticBalance: wallet.StaticBalance.Float32(), CustomerID: wallet.CustomerID, RegularIsActive: wallet.RegularIsActive, StaticIsActive: wallet.StaticIsActive, RegularUpdatedAt: wallet.RegularUpdatedAt, StaticUpdatedAt: wallet.StaticUpdatedAt, CreatedAt: wallet.CreatedAt, FirstName: wallet.FirstName, LastName: wallet.LastName, PhoneNumber: wallet.PhoneNumber, } } type BranchWalletRes struct { ID int64 `json:"id" example:"1"` Balance float32 `json:"balance" example:"100.0"` IsActive bool `json:"is_active" example:"true"` Name string `json:"name" example:"true"` Location string `json:"location" example:"somewhere"` BranchManagerID int64 `json:"branch_manager_id" example:"1"` CompanyID int64 `json:"company_id" example:"1"` IsSelfOwned bool `json:"is_self_owned" example:"false"` UpdatedAt time.Time `json:"updated_at"` CreatedAt time.Time `json:"created_at"` } // GetWalletByID godoc // @Summary Get wallet by ID // @Description Retrieve wallet details by wallet ID // @Tags wallet // @Accept json // @Produce json // @Param id path int true "Wallet ID" // @Success 200 {object} WalletRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /wallet/{id} [get] func (h *Handler) GetWalletByID(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 fiber.NewError(fiber.StatusBadRequest, "Invalid wallet ID") } wallet, err := h.walletSvc.GetWalletByID(c.Context(), id) if err != nil { h.logger.Error("Failed to get wallet by ID", "walletID", id, "error", err) return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve wallet") } res := convertWallet(wallet) return response.WriteJSON(c, fiber.StatusOK, "Wallet retrieved successfully", res, nil) } // GetAllWallets godoc // @Summary Get all wallets // @Description Retrieve all wallets // @Tags wallet // @Accept json // @Produce json // @Success 200 {array} WalletRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /wallet [get] func (h *Handler) GetAllWallets(c *fiber.Ctx) error { wallets, err := h.walletSvc.GetAllWallets(c.Context()) if err != nil { h.logger.Error("Failed to get wallets", "error", err) return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve wallets", err, nil) } var res []WalletRes = make([]WalletRes, 0, len(wallets)) for _, wallet := range wallets { res = append(res, convertWallet(wallet)) } return response.WriteJSON(c, fiber.StatusOK, "All wallets retrieved successfully", res, nil) } // GetAllBranchWallets godoc // @Summary Get all branch wallets // @Description Retrieve all branch wallets // @Tags wallet // @Accept json // @Produce json // @Success 200 {array} WalletRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /branchWallet [get] func (h *Handler) GetAllBranchWallets(c *fiber.Ctx) error { wallets, err := h.walletSvc.GetAllBranchWallets(c.Context()) if err != nil { h.logger.Error("Failed to get wallets", "error", err) return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve wallets", err, nil) } var res []BranchWalletRes = make([]BranchWalletRes, 0, len(wallets)) for _, wallet := range wallets { res = append(res, BranchWalletRes{ ID: wallet.ID, Balance: wallet.Balance.Float32(), IsActive: wallet.IsActive, Name: wallet.Name, Location: wallet.Location, BranchManagerID: wallet.BranchManagerID, CompanyID: wallet.CompanyID, IsSelfOwned: wallet.IsSelfOwned, UpdatedAt: wallet.UpdatedAt, CreatedAt: wallet.CreatedAt, }) } return response.WriteJSON(c, fiber.StatusOK, "All Wallets retrieved", res, nil) } // GetAllCustomerWallets godoc // @Summary Get all customer wallets // @Description Retrieve all customer wallets // @Tags wallet // @Accept json // @Produce json // @Success 200 {array} CustomerWalletRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /customerWallet [get] func (h *Handler) GetAllCustomerWallets(c *fiber.Ctx) error { wallets, err := h.walletSvc.GetAllCustomerWallet(c.Context()) if err != nil { h.logger.Error("Failed to get wallets", "error", err) return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve wallets", err, nil) } var res []CustomerWalletRes = make([]CustomerWalletRes, 0, len(wallets)) for _, wallet := range wallets { res = append(res, ConvertCustomerWallet(wallet)) } return response.WriteJSON(c, fiber.StatusOK, "All Wallets retrieved", res, nil) } type UpdateWalletActiveReq struct { IsActive bool `json:"is_active" validate:"required" example:"true"` } // UpdateWalletActive godoc // @Summary Activate and Deactivate Wallet // @Description Can activate and deactivate wallet // @Tags wallet // @Accept json // @Produce json // @Param id path int true "Wallet ID" // @Param updateCashOut body UpdateWalletActiveReq true "Update Wallet Active" // @Success 200 {object} response.APIResponse // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /wallet/{id} [patch] func (h *Handler) UpdateWalletActive(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 fiber.NewError(fiber.StatusBadRequest, "Invalid wallet ID") } var req UpdateWalletActiveReq if err := c.BodyParser(&req); err != nil { h.logger.Error("Failed to parse UpdateWalletActive request", "error", err) return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") } if valErrs, ok := h.validator.Validate(c, req); !ok { return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil) } err = h.walletSvc.UpdateWalletActive(c.Context(), id, req.IsActive) if err != nil { h.logger.Error("Failed to update wallet active status", "walletID", id, "error", err) return fiber.NewError(fiber.StatusInternalServerError, "Failed to update wallet") } return response.WriteJSON(c, fiber.StatusOK, "Wallet successfully updated", nil, nil) } // GetCustomerWallet godoc // @Summary Get customer wallet // @Description Retrieve customer wallet details // @Tags wallet // @Accept json // @Produce json // @Param company_id header int true "Company ID" // @Security Bearer // @Success 200 {object} CustomerWalletRes // @Failure 400 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /user/wallet [get] func (h *Handler) GetCustomerWallet(c *fiber.Ctx) error { userID, ok := c.Locals("user_id").(int64) if !ok || userID == 0 { h.logger.Error("Invalid user ID in context") return fiber.NewError(fiber.StatusUnauthorized, "Invalid user identification") } role, ok := c.Locals("role").(domain.Role) if !ok { h.logger.Error("Invalid role in context", "userID", userID) return fiber.NewError(fiber.StatusUnauthorized, "Invalid role") } if role != domain.RoleCustomer { h.logger.Error("Unauthorized access", "userID", userID, "role", role) return fiber.NewError(fiber.StatusUnauthorized, "Unauthorized access") } // companyID, err := strconv.ParseInt(c.Get("company_id"), 10, 64) // if err != nil { // h.logger.Error("Invalid company_id header", "value", c.Get("company_id"), "error", err) // return fiber.NewError(fiber.StatusBadRequest, "Invalid company_id") // } // h.logger.Info("Fetching customer wallet", "userID", userID) wallet, err := h.walletSvc.GetCustomerWallet(c.Context(), userID) if err != nil { h.logger.Error("Failed to get customer wallet", "userID", userID, "error", err) return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve wallet") } res := ConvertCustomerWallet(wallet) return response.WriteJSON(c, fiber.StatusOK, "Wallet retrieved successfully", res, nil) } // GetWalletForCashier godoc // @Summary Get wallet for cashier // @Description Get wallet for cashier // @Tags cashier // @Accept json // @Produce json // @Param id path int true "User ID" // @Success 200 {object} UserProfileRes // @Failure 400 {object} response.APIResponse // @Failure 401 {object} response.APIResponse // @Failure 500 {object} response.APIResponse // @Router /cashierWallet [get] func (h *Handler) GetWalletForCashier(c *fiber.Ctx) error { cashierID, ok := c.Locals("user_id").(int64) if !ok || cashierID == 0 { h.logger.Error("Invalid cashier ID in context") return response.WriteJSON(c, fiber.StatusUnauthorized, "Invalid cashier identification", nil, nil) } role, ok := c.Locals("role").(domain.Role) if !ok || role != domain.RoleCashier { h.logger.Error("Unauthorized access", "cashierID", cashierID, "role", role) return response.WriteJSON(c, fiber.StatusUnauthorized, "Unauthorized access", nil, nil) } branchID, ok := c.Locals("branch_id").(domain.ValidInt64) if !ok || !branchID.Valid { h.logger.Error("Invalid branch ID in context", "cashierID", cashierID) return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid branch ID", nil, nil) } branch, err := h.branchSvc.GetBranchByID(c.Context(), branchID.Value) if err != nil { h.logger.Error("Failed to get branch by ID", "branchID", branchID.Value, "error", err) return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve branch", err, nil) } wallet, err := h.walletSvc.GetWalletByID(c.Context(), branch.WalletID) if err != nil { h.logger.Error("Failed to get wallet for cashier", "cashierID", cashierID, "error", err) return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve wallet", err, nil) } res := WalletRes{ ID: wallet.ID, Balance: wallet.Balance.Float32(), IsWithdraw: wallet.IsWithdraw, IsBettable: wallet.IsBettable, IsTransferable: wallet.IsTransferable, IsActive: wallet.IsActive, UserID: wallet.UserID, UpdatedAt: wallet.UpdatedAt, CreatedAt: wallet.CreatedAt, } return response.WriteJSON(c, fiber.StatusOK, "Wallet retrieved successfully", res, nil) }