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_kandangs JSON: %v", err)) } if singleCostPerKandang.KandangID == 0 { return fiber.NewError(fiber.StatusBadRequest, "Field KandangID is required") } req.CostPerKandangs = []validation.CostPerKandang{singleCostPerKandang} } else { for i, costPerKandang := range req.CostPerKandangs { if costPerKandang.KandangID == 0 { return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Field KandangID is required for cost_per_kandangs[%d]", i)) } } } } else { return fiber.NewError(fiber.StatusBadRequest, "Field cost_per_kandangs is required") } 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") } form, err := c.MultipartForm() if err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid multipart form") } req.Documents = form.File["documents"] if transactionDate := c.FormValue("transaction_date"); transactionDate != "" { req.TransactionDate = &transactionDate } costPerKandangJSON := c.FormValue("cost_per_kandang") if costPerKandangJSON != "" { var costPerKandang []validation.CostPerKandang if err := json.Unmarshal([]byte(costPerKandangJSON), &costPerKandang); err != nil { return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid cost_per_kandang JSON: %v", err)) } for i, costPerKandang := range costPerKandang { if costPerKandang.KandangID == 0 { return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Field KandangID is required for cost_per_kandang[%d]", i)) } } req.CostPerKandang = &costPerKandang } 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) Approval(c *fiber.Ctx) error { req := new(validation.ApprovalRequest) if err := c.BodyParser(req); err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid request body") } path := c.Path() approvalType := "" if strings.Contains(path, "/approvals/manager") { approvalType = "manager" } else if strings.Contains(path, "/approvals/finance") { approvalType = "finance" } else { return fiber.NewError(fiber.StatusBadRequest, "Invalid approval path") } results, err := u.ExpenseService.Approval(c, req, approvalType) if err != nil { return err } var ( data interface{} message = "Submit expense approval successfully" ) if len(results) == 1 { data = results[0] } else { message = "Submit expense approvals successfully" data = results } return c.Status(fiber.StatusOK). JSON(response.Success{ Code: fiber.StatusOK, Status: "success", Message: message, Data: data, }) } 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"] req.RealizationDate = c.FormValue("realization_date") 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 form, err := c.MultipartForm() if err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid multipart form") } req.Documents = form.File["documents"] req.RealizationDate = c.FormValue("realization_date") 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.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, }) } func (u *ExpenseController) DeleteDocument(c *fiber.Ctx) error { expenseID, err := strconv.Atoi(c.Params("id")) if err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid expense ID") } documentID, err := strconv.ParseUint(c.Params("documentId"), 10, 64) if err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid document ID") } if err := u.ExpenseService.DeleteDocument(c, uint(expenseID), documentID, false); err != nil { return err } return c.Status(fiber.StatusOK). JSON(response.Common{ Code: fiber.StatusOK, Status: "success", Message: "Delete document successfully", }) } func (u *ExpenseController) DeleteRealizationDocument(c *fiber.Ctx) error { expenseID, err := strconv.Atoi(c.Params("id")) if err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid expense ID") } documentID, err := strconv.ParseUint(c.Params("documentId"), 10, 64) if err != nil { return fiber.NewError(fiber.StatusBadRequest, "Invalid document ID") } if err := u.ExpenseService.DeleteDocument(c, uint(expenseID), documentID, true); err != nil { return err } return c.Status(fiber.StatusOK). JSON(response.Common{ Code: fiber.StatusOK, Status: "success", Message: "Delete realization document successfully", }) }