Feat[BE-290]: enhance expense update functionality and validation

This commit is contained in:
aguhh18
2025-12-03 12:02:58 +07:00
parent 31699f4162
commit 1b464884c5
5 changed files with 48 additions and 31 deletions
@@ -151,12 +151,16 @@ func (u *ExpenseController) UpdateOne(c *fiber.Ctx) error {
} }
req.Documents = form.File["documents"] req.Documents = form.File["documents"]
if transactionDate := c.FormValue("transaction_date"); transactionDate != "" {
transactionDate := c.FormValue("transaction_date")
if transactionDate != "" {
req.TransactionDate = &transactionDate req.TransactionDate = &transactionDate
} }
categoryVal := c.FormValue("category") categoryVal := c.FormValue("category")
req.Category = &categoryVal if categoryVal != "" {
req.Category = &categoryVal
}
supplierIDVal := c.FormValue("supplier_id") supplierIDVal := c.FormValue("supplier_id")
if supplierIDVal != "" { if supplierIDVal != "" {
@@ -312,13 +316,18 @@ func (u *ExpenseController) UpdateRealization(c *fiber.Ctx) error {
req.Documents = form.File["documents"] req.Documents = form.File["documents"]
req.RealizationDate = c.FormValue("realization_date") realizationDate := c.FormValue("realization_date")
if realizationDate != "" {
req.RealizationDate = &realizationDate
}
realizationsJSON := c.FormValue("realizations") realizationsJSON := c.FormValue("realizations")
if realizationsJSON != "" { if realizationsJSON != "" {
if err := json.Unmarshal([]byte(realizationsJSON), &req.Realizations); err != nil { var realizations []validation.RealizationItem
if err := json.Unmarshal([]byte(realizationsJSON), &realizations); err != nil {
return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid realizations JSON: %v", err)) return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Invalid realizations JSON: %v", err))
} }
req.Realizations = &realizations
} }
expense, err := u.ExpenseService.UpdateRealization(c, uint(id), &req) expense, err := u.ExpenseService.UpdateRealization(c, uint(id), &req)
+2
View File
@@ -14,6 +14,8 @@ func ExpenseRoutes(v1 fiber.Router, u user.UserService, s expense.ExpenseService
route := v1.Group("/expenses") route := v1.Group("/expenses")
route.Use(m.Auth(u)) route.Use(m.Auth(u))
// route.Use(m.Auth(u))
// route.Get("/", m.Auth(u), ctrl.GetAll) // route.Get("/", m.Auth(u), ctrl.GetAll)
// route.Post("/", m.Auth(u), ctrl.CreateOne) // route.Post("/", m.Auth(u), ctrl.CreateOne)
// route.Get("/:id", m.Auth(u), ctrl.GetOne) // route.Get("/:id", m.Auth(u), ctrl.GetOne)
@@ -732,10 +732,10 @@ func (s *expenseService) UpdateRealization(c *fiber.Ctx, expenseID uint, req *va
expenseRepoTx := repository.NewExpenseRepository(tx) expenseRepoTx := repository.NewExpenseRepository(tx)
// Check if only updating documents // Check if only updating documents
updateDataOnly := len(req.Realizations) == 0 && len(req.Documents) > 0 updateDataOnly := req.Realizations == nil && len(req.Documents) > 0
if len(req.Realizations) > 0 { if req.Realizations != nil {
for _, realizationItem := range req.Realizations { for _, realizationItem := range *req.Realizations {
expenseNonstockID := realizationItem.ExpenseNonstockID expenseNonstockID := realizationItem.ExpenseNonstockID
@@ -770,6 +770,12 @@ func (s *expenseService) UpdateRealization(c *fiber.Ctx, expenseID uint, req *va
} }
if req.RealizationDate != nil {
if err := expenseRepoTx.PatchOne(c.Context(), expenseID, map[string]interface{}{"realization_date": *req.RealizationDate}, nil); err != nil {
return fiber.NewError(fiber.StatusInternalServerError, "Failed to update realization date")
}
}
if len(req.Documents) > 0 { if len(req.Documents) > 0 {
if err := s.processDocuments(c, expenseRepoTx, expenseID, req.Documents, true); err != nil { if err := s.processDocuments(c, expenseRepoTx, expenseID, req.Documents, true); err != nil {
return err return err
@@ -5,11 +5,11 @@ import (
) )
type Create struct { type Create struct {
PoNumber string `form:"po_number" json:"po_number" validate:"omitempty,max=50"` PoNumber string `form:"po_number" json:"po_number" validate:"omitempty,max=50"`
TransactionDate string `form:"transaction_date" json:"transaction_date" validate:"required,datetime=2006-01-02"` TransactionDate string `form:"transaction_date" json:"transaction_date" validate:"required,datetime=2006-01-02"`
Category string `form:"category" json:"category" validate:"required,oneof=BOP NON-BOP"` Category string `form:"category" json:"category" validate:"required,oneof=BOP NON-BOP"`
SupplierID uint64 `form:"supplier_id" json:"supplier_id" validate:"required,gt=0"` SupplierID uint64 `form:"supplier_id" json:"supplier_id" validate:"required,gt=0"`
Documents []*multipart.FileHeader `form:"documents" json:"documents" validate:"omitempty,dive"` Documents []*multipart.FileHeader `form:"documents" json:"documents" validate:"omitempty,dive"`
ExpenseNonstocks []ExpenseNonstock `form:"expense_nonstocks" json:"expense_nonstocks" validate:"required,min=1,dive"` ExpenseNonstocks []ExpenseNonstock `form:"expense_nonstocks" json:"expense_nonstocks" validate:"required,min=1,dive"`
} }
@@ -26,11 +26,11 @@ type CostItem struct {
} }
type Update struct { type Update struct {
TransactionDate *string `form:"transaction_date" json:"transaction_date" validate:"omitempty,datetime=2006-01-02"` TransactionDate *string `form:"transaction_date" json:"transaction_date" validate:"omitempty,datetime=2006-01-02"`
Category *string `form:"category" json:"category" validate:"omitempty,oneof=BOP NON-BOP"` Category *string `form:"category" json:"category" validate:"omitempty,oneof=BOP NON-BOP"`
SupplierID *uint64 `form:"supplier_id" json:"supplier_id" validate:"omitempty,gt=0"` SupplierID *uint64 `form:"supplier_id" json:"supplier_id" validate:"omitempty,gt=0"`
Documents []*multipart.FileHeader `form:"documents" json:"documents" validate:"omitempty,dive"`
ExpenseNonstocks *[]ExpenseNonstock `form:"expense_nonstocks" json:"expense_nonstocks" validate:"omitempty,min=1,dive"` ExpenseNonstocks *[]ExpenseNonstock `form:"expense_nonstocks" json:"expense_nonstocks" validate:"omitempty,min=1,dive"`
Documents []*multipart.FileHeader `form:"documents" json:"documents" validate:"omitempty,dive"`
} }
type Query struct { type Query struct {
@@ -46,9 +46,9 @@ type CreateRealization struct {
} }
type UpdateRealization struct { type UpdateRealization struct {
RealizationDate string `form:"realization_date" json:"realization_date" validate:"omitempty,datetime=2006-01-02"` RealizationDate *string `form:"realization_date" json:"realization_date" validate:"omitempty,datetime=2006-01-02"`
Documents []*multipart.FileHeader `form:"documents" json:"documents" validate:"omitempty,dive"` Documents []*multipart.FileHeader `form:"documents" json:"documents" validate:"omitempty,dive"`
Realizations []RealizationItem `form:"realizations" json:"realizations" validate:"required,min=1,dive"` Realizations *[]RealizationItem `form:"realizations" json:"realizations" validate:"omitempty,min=1,dive"`
} }
type RealizationItem struct { type RealizationItem struct {
@@ -1,22 +1,22 @@
package validation package validation
type Create struct { type Create struct {
FlockName string `json:"flock_name" validate:"required_strict"` FlockName string `form:"flock_name" json:"flock_name" validate:"required_strict"`
AreaId uint `json:"area_id" validate:"required_strict,number,gt=0"` AreaId uint `form:"area_id" json:"area_id" validate:"required_strict,number,gt=0"`
Category string `json:"category" validate:"required_strict"` Category string `form:"category" json:"category" validate:"required_strict,oneof=BOP NON-BOP"`
FcrId uint `json:"fcr_id" validate:"required_strict,number,gt=0"` FcrId uint `form:"fcr_id" json:"fcr_id" validate:"required_strict,number,gt=0"`
LocationId uint `json:"location_id" validate:"required_strict,number,gt=0"` LocationId uint `form:"location_id" json:"location_id" validate:"required_strict,number,gt=0"`
KandangIds []uint `json:"kandang_ids" validate:"required,min=1,dive,gt=0"` KandangIds []uint `form:"kandang_ids" json:"kandang_ids" validate:"required,min=1,dive,gt=0"`
ProjectBudgets []ProjectBudget `json:"project_budgets" validate:"required,min=1,dive"` ProjectBudgets []ProjectBudget `form:"project_budgets" json:"project_budgets" validate:"required,min=1,dive"`
} }
type Update struct { type Update struct {
FlockName *string `json:"flock_name,omitempty" validate:"omitempty"` FlockName *string `form:"flock_name" json:"flock_name,omitempty" validate:"omitempty"`
AreaId *uint `json:"area_id,omitempty" validate:"omitempty,number,gt=0"` AreaId *uint `form:"area_id" json:"area_id,omitempty" validate:"omitempty,number,gt=0"`
Category *string `json:"category,omitempty" validate:"omitempty"` Category *string `form:"category" json:"category,omitempty" validate:"omitempty,oneof=BOP NON-BOP"`
FcrId *uint `json:"fcr_id,omitempty" validate:"omitempty,number,gt=0"` FcrId *uint `form:"fcr_id" json:"fcr_id,omitempty" validate:"omitempty,number,gt=0"`
LocationId *uint `json:"location_id,omitempty" validate:"omitempty,number,gt=0"` LocationId *uint `form:"location_id" json:"location_id,omitempty" validate:"omitempty,number,gt=0"`
KandangIds []uint `json:"kandang_ids,omitempty" validate:"omitempty,min=1,dive,gt=0"` KandangIds []uint `form:"kandang_ids" json:"kandang_ids,omitempty" validate:"omitempty,min=1,dive,gt=0"`
} }
type Query struct { type Query struct {