package controller import ( "encoding/json" "fmt" "math" "strconv" "strings" "gitlab.com/mbugroup/lti-api.git/internal/modules/expenses/dto" service "gitlab.com/mbugroup/lti-api.git/internal/modules/expenses/services" validation "gitlab.com/mbugroup/lti-api.git/internal/modules/expenses/validations" "gitlab.com/mbugroup/lti-api.git/internal/response" "github.com/gofiber/fiber/v2" ) type ExpenseController struct { ExpenseService service.ExpenseService } func NewExpenseController(expenseService service.ExpenseService) *ExpenseController { return &ExpenseController{ ExpenseService: expenseService, } } func (u *ExpenseController) GetAll(c *fiber.Ctx) error { query := &validation.Query{ Page: c.QueryInt("page", 1), Limit: c.QueryInt("limit", 10), Search: c.Query("search", ""), } if query.Page < 1 || query.Limit < 1 { return fiber.NewError(fiber.StatusBadRequest, "page and limit must be greater than 0") } result, totalResults, err := u.ExpenseService.GetAll(c, query) if err != nil { return err } return c.Status(fiber.StatusOK). JSON(response.SuccessWithPaginate[dto.ExpenseListDTO]{ Code: fiber.StatusOK, Status: "success", Message: "Get all expenses successfully", Meta: response.Meta{ Page: query.Page, Limit: query.Limit, TotalPages: int64(math.Ceil(float64(totalResults) / float64(query.Limit))), TotalResults: totalResults, }, Data: result, }) } func (u *ExpenseController) GetOne(c *fiber.Ctx) error { param := c.Params("id") id, err := strconv.Atoi(param) if err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid Id") } result, err := u.ExpenseService.GetOne(c, uint(id)) if err != nil { return err } return c.Status(fiber.StatusOK). JSON(response.Success{ Code: fiber.StatusOK, Status: "success", Message: "Get expense successfully", Data: result, }) } func (u *ExpenseController) CreateOne(c *fiber.Ctx) error { req := new(validation.Create) req.TransactionDate = c.FormValue("transaction_date") req.Category = c.FormValue("category") supplierID, err := strconv.ParseUint(c.FormValue("supplier_id"), 10, 64) if err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid supplier_id format") } req.SupplierID = supplierID form, err := c.MultipartForm() if err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid multipart form") } req.Documents = form.File["documents"] costPerKandangJSON := c.FormValue("cost_per_kandangs") if costPerKandangJSON != "" { if err := json.Unmarshal([]byte(costPerKandangJSON), &req.CostPerKandangs); err != nil { var singleCostPerKandang validation.CostPerKandang if err := json.Unmarshal([]byte(costPerKandangJSON), &singleCostPerKandang); err != nil { return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid cost_per_kandang JSON: %v", err)) } req.CostPerKandangs = []validation.CostPerKandang{singleCostPerKandang} } } result, err := u.ExpenseService.CreateOne(c, req) if err != nil { return err } return c.Status(fiber.StatusCreated). JSON(response.Success{ Code: fiber.StatusCreated, Status: "success", Message: "Create expense successfully", Data: result, }) } func (u *ExpenseController) UpdateOne(c *fiber.Ctx) error { req := new(validation.Update) param := c.Params("id") id, err := strconv.Atoi(param) if err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid Id") } if err := c.BodyParser(req); err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") } result, err := u.ExpenseService.UpdateOne(c, req, uint(id)) if err != nil { return err } return c.Status(fiber.StatusOK). JSON(response.Success{ Code: fiber.StatusOK, Status: "success", Message: "Update expense successfully", Data: result, }) } func (u *ExpenseController) DeleteOne(c *fiber.Ctx) error { param := c.Params("id") id, err := strconv.Atoi(param) if err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid Id") } if err := u.ExpenseService.DeleteOne(c, uint(id)); err != nil { return err } return c.Status(fiber.StatusOK). JSON(response.Common{ Code: fiber.StatusOK, Status: "success", Message: "Delete expense successfully", }) } func (u *ExpenseController) ApproveExpense(c *fiber.Ctx) error { expenseID := c.Params("id") id, err := strconv.Atoi(expenseID) if err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid expense ID") } // Extract step from URL path (manager or finance) path := c.Path() var step string if strings.Contains(path, "/approvals/manager") { step = "Manager" } else if strings.Contains(path, "/approvals/finance") { step = "Finance" } else { return fiber.NewError(fiber.StatusBadRequest, "Invalid approval step") } // Parse approval request var req validation.ApprovalRequest if err := c.BodyParser(&req); err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") } // Approve expense expense, err := u.ExpenseService.ApproveExpense(c, uint(id), step, req.Action, req.Notes) if err != nil { return err } return c.Status(fiber.StatusOK). JSON(response.Success{ Code: fiber.StatusOK, Status: "success", Message: "Approve expense successfully", Data: expense, }) } func (u *ExpenseController) CreateRealization(c *fiber.Ctx) error { expenseID := c.Params("id") id, err := strconv.Atoi(expenseID) if err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid expense ID") } req := new(validation.CreateRealization) form, err := c.MultipartForm() if err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid multipart form") } req.Documents = form.File["documents"] // Parse realizations JSON realizationsJSON := c.FormValue("realizations") if realizationsJSON != "" { if err := json.Unmarshal([]byte(realizationsJSON), &req.Realizations); err != nil { return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid realizations JSON: %v", err)) } } expense, err := u.ExpenseService.CreateRealization(c, uint(id), req) if err != nil { return err } return c.Status(fiber.StatusCreated). JSON(response.Success{ Code: fiber.StatusCreated, Status: "success", Message: "Create realization successfully", Data: expense, }) } func (u *ExpenseController) UpdateRealization(c *fiber.Ctx) error { expenseID := c.Params("id") id, err := strconv.Atoi(expenseID) if err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid expense ID") } var req validation.UpdateRealization if err := c.BodyParser(&req); err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") } expense, err := u.ExpenseService.UpdateRealization(c, uint(id), &req) if err != nil { return err } return c.Status(fiber.StatusOK). JSON(response.Success{ Code: fiber.StatusOK, Status: "success", Message: "Update realization successfully", Data: expense, }) } func (u *ExpenseController) CompleteExpense(c *fiber.Ctx) error { expenseID := c.Params("id") id, err := strconv.Atoi(expenseID) if err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid expense ID") } expense, err := u.ExpenseService.CompleteExpense(c, uint(id), nil) if err != nil { return err } return c.Status(fiber.StatusOK). JSON(response.Success{ Code: fiber.StatusOK, Status: "success", Message: "Complete expense successfully", Data: expense, }) }