mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-23 06:45:43 +00:00
add restrict for expense,purchase,adjustment transfer: unfinished
This commit is contained in:
@@ -11,7 +11,6 @@ import (
|
||||
commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service"
|
||||
rExpense "gitlab.com/mbugroup/lti-api.git/internal/modules/expenses/repositories"
|
||||
sExpense "gitlab.com/mbugroup/lti-api.git/internal/modules/expenses/services"
|
||||
|
||||
rUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/repositories"
|
||||
sUser "gitlab.com/mbugroup/lti-api.git/internal/modules/users/services"
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ func (r *ExpenseRepositoryImpl) CountUnfinishedByProjectFlockKandang(ctx context
|
||||
if err := r.DB().WithContext(ctx).
|
||||
Table("expenses").
|
||||
Scopes(r.WithProjectFlockKandangFilter(pfkID, kandangID)).
|
||||
Group("expenses.id").
|
||||
Group("expenses.id").Where("expenses.deleted_at IS NULL").
|
||||
Pluck("expenses.id", &ids).Error; err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
@@ -360,6 +360,9 @@ func (s expenseService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get expense")
|
||||
}
|
||||
|
||||
if err := s.ensureProjectFlockNotClosedForExpense(c.Context(), currentExpense); err != nil {
|
||||
return err
|
||||
}
|
||||
categoryChanged := false
|
||||
var newCategory string
|
||||
if req.Category != nil && *req.Category != currentExpense.Category {
|
||||
@@ -404,6 +407,9 @@ func (s expenseService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint)
|
||||
if ens.KandangId != nil {
|
||||
projectFlockKandang, err := projectFlockKandangRepoTx.GetActiveByKandangID(c.Context(), uint(*ens.KandangId))
|
||||
if err != nil {
|
||||
if err := s.ensureProjectFlockNotClosedForExpense(c.Context(), currentExpense); err != nil {
|
||||
return err
|
||||
}
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fiber.NewError(fiber.StatusNotFound, "No active project flock kandang found for this kandang")
|
||||
}
|
||||
@@ -543,7 +549,21 @@ func (s expenseService) DeleteOne(c *fiber.Ctx, id uint) error {
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
expense, err := s.Repository.GetByID(c.Context(), id, func(db *gorm.DB) *gorm.DB {
|
||||
return db.Preload("Nonstocks")
|
||||
})
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
s.Log.Errorf("Expense not found for ID %d: %+v", id, err)
|
||||
return fiber.NewError(fiber.StatusNotFound, "Expense not found")
|
||||
}
|
||||
s.Log.Errorf("Failed to get expense for ID %d: %+v", id, err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to get expense")
|
||||
}
|
||||
|
||||
if err := s.ensureProjectFlockNotClosedForExpense(c.Context(), expense); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.Repository.DeleteOne(c.Context(), id); err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
s.Log.Errorf("Expense not found for ID %d: %+v", id, err)
|
||||
@@ -572,6 +592,20 @@ func (s *expenseService) CreateRealization(c *fiber.Ctx, expenseID uint, req *va
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid realization_date format")
|
||||
}
|
||||
|
||||
expense, err := s.Repository.GetByID(c.Context(), expenseID, func(db *gorm.DB) *gorm.DB {
|
||||
return db.Preload("Nonstocks")
|
||||
})
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fiber.NewError(fiber.StatusNotFound, "Expense not found")
|
||||
}
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to get expense")
|
||||
}
|
||||
|
||||
if err := s.ensureProjectFlockNotClosedForExpense(c.Context(), expense); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := s.Repository.DB().WithContext(c.Context()).Transaction(func(tx *gorm.DB) error {
|
||||
|
||||
approvalSvc := commonSvc.NewApprovalService(commonRepo.NewApprovalRepository(tx))
|
||||
@@ -712,7 +746,19 @@ func (s *expenseService) UpdateRealization(c *fiber.Ctx, expenseID uint, req *va
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
expense, err := s.Repository.GetByID(c.Context(), expenseID, func(db *gorm.DB) *gorm.DB {
|
||||
return db.Preload("Nonstocks")
|
||||
})
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fiber.NewError(fiber.StatusNotFound, "Expense not found")
|
||||
}
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to get expense")
|
||||
}
|
||||
|
||||
if err := s.ensureProjectFlockNotClosedForExpense(c.Context(), expense); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
latestApproval, err := s.ApprovalSvc.LatestByTarget(c.Context(), utils.ApprovalWorkflowExpense, expenseID, nil)
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to validate workflow")
|
||||
@@ -1010,6 +1056,21 @@ func (s *expenseService) Approval(c *fiber.Ctx, req *validation.ApprovalRequest,
|
||||
} else {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid approval action")
|
||||
}
|
||||
if approvalAction == entity.ApprovalActionApproved {
|
||||
expense, err := expenseRepoTx.GetByID(c.Context(), id, func(db *gorm.DB) *gorm.DB {
|
||||
return db.Preload("Nonstocks")
|
||||
})
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fiber.NewError(fiber.StatusNotFound, "Expense not found")
|
||||
}
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to load expense")
|
||||
}
|
||||
|
||||
if err := s.ensureProjectFlockNotClosedForExpense(c.Context(), expense); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := approvalSvcTx.CreateApproval(
|
||||
c.Context(),
|
||||
@@ -1079,13 +1140,45 @@ func (s *expenseService) validateExpenseNonstockRelation(ctx *fiber.Ctx, expense
|
||||
return nil
|
||||
}
|
||||
|
||||
// func actorIDFromContext(c *fiber.Ctx) (uint, error) {
|
||||
// user, ok := authmiddleware.AuthenticatedUser(c)
|
||||
// if !ok || user == nil || user.Id == 0 {
|
||||
// return 0, fiber.NewError(fiber.StatusUnauthorized, "Please authenticate")
|
||||
// }
|
||||
// return user.Id, nil
|
||||
// }
|
||||
func (s *expenseService) ensureProjectFlockNotClosedForExpense(
|
||||
ctx context.Context,
|
||||
expense *entity.Expense,
|
||||
) error {
|
||||
// Kalau repo belum di-wire atau expense kosong → gak usah ngecek apa-apa
|
||||
if s.ProjectFlockKandangRepo == nil || expense == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// return user.Id, nil
|
||||
// }
|
||||
seen := make(map[uint]struct{})
|
||||
|
||||
for _, ens := range expense.Nonstocks {
|
||||
// Field ini pointer, bisa nil
|
||||
if ens.ProjectFlockKandangId == nil || *ens.ProjectFlockKandangId == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
pfkID := uint(*ens.ProjectFlockKandangId)
|
||||
if _, ok := seen[pfkID]; ok {
|
||||
continue
|
||||
}
|
||||
seen[pfkID] = struct{}{}
|
||||
|
||||
pfk, err := s.ProjectFlockKandangRepo.GetByID(ctx, pfkID)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fiber.NewError(
|
||||
fiber.StatusBadRequest,
|
||||
fmt.Sprintf("Project flock %d tidak ditemukan", pfkID),
|
||||
)
|
||||
}
|
||||
s.Log.Errorf("Failed to validate project flock %d for expense %d: %+v", pfkID, expense.Id, err)
|
||||
return fiber.NewError(fiber.StatusInternalServerError, "Failed to validate project flock")
|
||||
}
|
||||
// ❗ RULE: kalau ClosedAt tidak nil → project sudah closing
|
||||
if pfk.ClosedAt != nil {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Project sudah closing")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user