Yimaru-BackEnd/internal/web_server/handlers/shop_handler.go

383 lines
13 KiB
Go

package handlers
import (
"log/slog"
"strconv"
"time"
"github.com/SamuelTariku/FortuneBet-Backend/internal/domain"
"github.com/SamuelTariku/FortuneBet-Backend/internal/web_server/response"
"github.com/gofiber/fiber/v2"
)
// CreateShopBet godoc
// @Summary Create bet at branch
// @Description Create bet at branch
// @Tags transaction
// @Accept json
// @Produce json
// @Param createBet body domain.ShopBetReq true "create bet"
// @Success 200 {object} TransactionRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /shop/bet [post]
func (h *Handler) CreateShopBet(c *fiber.Ctx) error {
userID := c.Locals("user_id").(int64)
role := c.Locals("role").(domain.Role)
company_id := c.Locals("company_id").(domain.ValidInt64)
var req domain.ShopBetReq
if err := c.BodyParser(&req); err != nil {
h.logger.Error("CreateBetReq 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("CreateBetReq failed v", "error", valErrs)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
}
shopBet, err := h.transactionSvc.CreateShopBet(c.Context(), userID, role, company_id, req)
if err != nil {
return response.WriteJSON(c, fiber.StatusBadRequest, "Failed to cashout bet", err, nil)
}
res := domain.ConvertShopBet(shopBet)
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 cashoutBet body domain.CashoutReq true "cashout bet"
// @Success 200 {object} TransactionRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /shop/bet/{id}/cashout [post]
func (h *Handler) CashoutBet(c *fiber.Ctx) error {
betIDStr := c.Params("id")
betID, err := strconv.ParseInt(betIDStr, 10, 64)
if err != nil {
h.logger.Error("CashoutReq invalid bet id", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid bet id", err, nil)
}
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)
}
transaction, err := h.transactionSvc.CashoutBet(c.Context(), 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)
}
// 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
// @Summary Shop deposit into customer wallet
// @Description Transfers money from branch wallet to customer wallet
// @Tags transaction
// @Accept json
// @Produce json
// @Param transferToWallet body domain.ShopDepositReq true "ShopDepositReq"
// @Success 200 {object} TransferWalletRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /shop/deposit [post]
func (h *Handler) DepositForCustomer(c *fiber.Ctx) error {
// Get sender ID from the cashier
userID := c.Locals("user_id").(int64)
role := c.Locals("role").(domain.Role)
var req domain.ShopDepositReq
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)
}
deposit, err := h.transactionSvc.CreateShopDeposit(c.Context(), userID, role, req)
if err != nil {
return response.WriteJSON(c, fiber.StatusBadRequest, "Failed to create shop deposit", err, nil)
}
res := domain.ConvertShopDeposit(deposit)
return response.WriteJSON(c, fiber.StatusOK, "Transfer Successful", res, nil)
}
// GetAllTransactions godoc
// @Summary Gets all transactions
// @Description Gets all the transactions
// @Tags transaction
// @Accept json
// @Produce json
// @Success 200 {array} TransactionRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /shop/transaction [get]
func (h *Handler) GetAllTransactions(c *fiber.Ctx) error {
// Get user_id from middleware
// userID := c.Locals("user_id").(int64)
// role := c.Locals("role").(domain.Role)
companyID := c.Locals("company_id").(domain.ValidInt64)
branchID := c.Locals("branch_id").(domain.ValidInt64)
searchQuery := c.Query("query")
searchString := domain.ValidString{
Value: searchQuery,
Valid: searchQuery != "",
}
createdBeforeQuery := c.Query("created_before")
var createdBefore domain.ValidTime
if createdBeforeQuery != "" {
createdBeforeParsed, err := time.Parse(time.RFC3339, createdBeforeQuery)
if err != nil {
h.logger.Error("invalid start_time format", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil)
}
createdBefore = domain.ValidTime{
Value: createdBeforeParsed,
Valid: true,
}
}
createdAfterQuery := c.Query("created_after")
var createdAfter domain.ValidTime
if createdAfterQuery != "" {
createdAfterParsed, err := time.Parse(time.RFC3339, createdAfterQuery)
if err != nil {
h.logger.Error("invalid start_time format", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid start_time format", nil, nil)
}
createdAfter = domain.ValidTime{
Value: createdAfterParsed,
Valid: true,
}
}
// Check user role and fetch transactions accordingly
transactions, err := h.transactionSvc.GetAllShopTransactions(c.Context(), domain.ShopTransactionFilter{
CompanyID: companyID,
BranchID: branchID,
Query: searchString,
CreatedBefore: createdBefore,
CreatedAfter: createdAfter,
})
if err != nil {
h.logger.Error("Failed to get transactions", "error", err)
return response.WriteJSON(c, fiber.StatusInternalServerError, "Failed to retrieve transactions", err, nil)
}
res := make([]domain.ShopTransactionRes, len(transactions))
for i, transaction := range transactions {
res[i] = domain.ConvertShopTransactionDetail(transaction)
}
return response.WriteJSON(c, fiber.StatusOK, "Transactions retrieved successfully", res, nil)
}
// GetTransactionByID godoc
// @Summary Gets transaction by id
// @Description Gets a single transaction by id
// @Tags transaction
// @Accept json
// @Produce json
// @Param id path int true "Transaction ID"
// @Success 200 {object} TransactionRes
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /shop/transaction/{id} [get]
func (h *Handler) GetTransactionByID(c *fiber.Ctx) error {
transactionID := c.Params("id")
id, err := strconv.ParseInt(transactionID, 10, 64)
if err != nil {
h.logger.Error("Invalid transaction ID", "transactionID", transactionID, "error", err)
return fiber.NewError(fiber.StatusBadRequest, "Invalid transaction ID")
}
transaction, err := h.transactionSvc.GetShopTransactionByID(c.Context(), id)
if err != nil {
h.logger.Error("Failed to get transaction by ID", "transactionID", id, "error", err)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to retrieve transaction")
}
res := domain.ConvertShopTransactionDetail(transaction)
return response.WriteJSON(c, fiber.StatusOK, "Transaction retrieved successfully", res, nil)
}
type UpdateTransactionVerifiedReq struct {
Verified bool `json:"verified" example:"true"`
}
// UpdateTransactionVerified godoc
// @Summary Updates the verified field of a transaction
// @Description Updates the verified status of a transaction
// @Tags transaction
// @Accept json
// @Produce json
// @Param id path int true "Transaction ID"
// @Param updateVerified body UpdateTransactionVerifiedReq true "Updates Transaction Verification"
// @Success 200 {object} response.APIResponse
// @Failure 400 {object} response.APIResponse
// @Failure 500 {object} response.APIResponse
// @Router /shop/transaction/{id} [put]
func (h *Handler) UpdateTransactionVerified(c *fiber.Ctx) error {
transactionID := c.Params("id")
userID := c.Locals("user_id").(int64)
companyID := c.Locals("company_id").(domain.ValidInt64)
role := c.Locals("role").(domain.Role)
id, err := strconv.ParseInt(transactionID, 10, 64)
if err != nil {
h.logger.Error("Invalid transaction ID", "transactionID", transactionID, "error", err)
return fiber.NewError(fiber.StatusBadRequest, "Invalid transaction ID")
}
var req UpdateTransactionVerifiedReq
if err := c.BodyParser(&req); err != nil {
h.logger.Error("Failed to parse UpdateTransactionVerified request", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
}
h.logger.Info("Update Transaction Verified", slog.Bool("verified", req.Verified))
if valErrs, ok := h.validator.Validate(c, req); !ok {
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", valErrs, nil)
}
transaction, err := h.transactionSvc.GetShopTransactionByID(c.Context(), id)
if role != domain.RoleSuperAdmin {
if !companyID.Valid || companyID.Value != transaction.CompanyID {
h.logger.Error("Failed to parse UpdateTransactionVerified request", "error", err)
return response.WriteJSON(c, fiber.StatusBadRequest, "Invalid request", err, nil)
}
}
user, err := h.userSvc.GetUserById(c.Context(), userID)
if err != nil {
h.logger.Error("Invalid user ID", "userID", userID, "error", err)
return fiber.NewError(fiber.StatusBadRequest, "Invalid user ID")
}
err = h.transactionSvc.UpdateShopTransactionVerified(c.Context(), id, req.Verified, userID, user.FirstName+" "+user.LastName)
if err != nil {
h.logger.Error("Failed to update transaction verification", "transactionID", id, "error", err)
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update transaction verification")
}
return response.WriteJSON(c, fiber.StatusOK, "Transaction updated successfully", nil, nil)
}