diff --git a/internal/modules/master/kandangs/services/kandang.service.go b/internal/modules/master/kandangs/services/kandang.service.go index 9ece8898..6e836170 100644 --- a/internal/modules/master/kandangs/services/kandang.service.go +++ b/internal/modules/master/kandangs/services/kandang.service.go @@ -101,7 +101,11 @@ func (s *kandangService) CreateOne(c *fiber.Ctx, req *validation.Create) (*entit ); err != nil { return nil, err } - status := strings.ToUpper(req.Status) + + status := strings.ToUpper(strings.TrimSpace(req.Status)) + if status == "" { + status = string(utils.KandangStatusNonActive) + } if !utils.IsValidKandangStatus(status) { return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid kandang status") } diff --git a/internal/modules/master/kandangs/validations/kandang.validation.go b/internal/modules/master/kandangs/validations/kandang.validation.go index 0dc89212..f6886991 100644 --- a/internal/modules/master/kandangs/validations/kandang.validation.go +++ b/internal/modules/master/kandangs/validations/kandang.validation.go @@ -2,7 +2,7 @@ package validation type Create struct { Name string `json:"name" validate:"required_strict,min=3"` - Status string `json:"status" validate:"required_strict,min=3"` + Status string `json:"status,omitempty" validate:"omitempty,min=3"` LocationId uint `json:"location_id" validate:"required_strict,number,gt=0"` PicId uint `json:"pic_id" validate:"required_strict,number,gt=0"` ProjectFlockId *uint `json:"project_flock_id" validate:"omitempty,number,gt=0"` diff --git a/internal/modules/production/project_flocks/repositories/projectflock.repository.go b/internal/modules/production/project_flocks/repositories/projectflock.repository.go index dde9ed35..476b061b 100644 --- a/internal/modules/production/project_flocks/repositories/projectflock.repository.go +++ b/internal/modules/production/project_flocks/repositories/projectflock.repository.go @@ -7,6 +7,7 @@ import ( "gitlab.com/mbugroup/lti-api.git/internal/common/repository" entity "gitlab.com/mbugroup/lti-api.git/internal/entities" "gorm.io/gorm" + "gorm.io/gorm/clause" ) type ProjectflockRepository interface { @@ -14,6 +15,7 @@ type ProjectflockRepository interface { GetAllByFlock(ctx context.Context, flockID uint) ([]entity.ProjectFlock, error) GetActiveByFlock(ctx context.Context, flockID uint) (*entity.ProjectFlock, error) GetMaxPeriodByFlock(ctx context.Context, flockID uint) (int, error) + GetNextPeriodForFlock(ctx context.Context, flockID uint) (int, error) } type ProjectflockRepositoryImpl struct { @@ -64,3 +66,23 @@ func (r *ProjectflockRepositoryImpl) GetMaxPeriodByFlock(ctx context.Context, fl } return max, nil } + +func (r *ProjectflockRepositoryImpl) GetNextPeriodForFlock(ctx context.Context, flockID uint) (int, error) { + var payload struct { + Period int + } + if err := r.DB().WithContext(ctx). + Model(&entity.ProjectFlock{}). + Where("flock_id = ?", flockID). + Clauses(clause.Locking{Strength: "UPDATE"}). + Order("period DESC"). + Limit(1). + Select("period"). + Scan(&payload).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + return 1, nil + } + return 0, err + } + return payload.Period + 1, nil +} diff --git a/internal/modules/production/project_flocks/services/projectflock.service.go b/internal/modules/production/project_flocks/services/projectflock.service.go index 4ad9d21d..e9ad3ddb 100644 --- a/internal/modules/production/project_flocks/services/projectflock.service.go +++ b/internal/modules/production/project_flocks/services/projectflock.service.go @@ -1,9 +1,12 @@ package service import ( + "context" "errors" "fmt" + commonRepo "gitlab.com/mbugroup/lti-api.git/internal/common/repository" + common "gitlab.com/mbugroup/lti-api.git/internal/common/service" entity "gitlab.com/mbugroup/lti-api.git/internal/entities" flockRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/master/flocks/repositories" kandangRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/repositories" @@ -15,7 +18,6 @@ import ( "github.com/gofiber/fiber/v2" "github.com/sirupsen/logrus" "gorm.io/gorm" - "gorm.io/gorm/clause" ) type ProjectflockService interface { @@ -106,6 +108,16 @@ func (s *projectflockService) CreateOne(c *fiber.Ctx, req *validation.Create) (* return nil, fiber.NewError(fiber.StatusBadRequest, "kandang_ids is required") } + if err := common.EnsureRelations(c.Context(), + common.RelationCheck{Name: "Flock", ID: &req.FlockId, Exists: relationExistsChecker[entity.Flock](s.Repository.DB())}, + common.RelationCheck{Name: "Area", ID: &req.AreaId, Exists: relationExistsChecker[entity.Area](s.Repository.DB())}, + common.RelationCheck{Name: "Product category", ID: &req.ProductCategoryId, Exists: relationExistsChecker[entity.ProductCategory](s.Repository.DB())}, + common.RelationCheck{Name: "FCR", ID: &req.FcrId, Exists: relationExistsChecker[entity.Fcr](s.Repository.DB())}, + common.RelationCheck{Name: "Location", ID: &req.LocationId, Exists: relationExistsChecker[entity.Location](s.Repository.DB())}, + ); err != nil { + return nil, err + } + kandangIDs := uniqueUintSlice(req.KandangIds) kandangs, err := s.KandangRepo.GetByIDs(c.Context(), kandangIDs, nil) if err != nil { @@ -128,18 +140,14 @@ func (s *projectflockService) CreateOne(c *fiber.Ctx, req *validation.Create) (* return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to start transaction") } - var nextPeriod int - periodQuery := tx.Model(&entity.ProjectFlock{}). - Where("flock_id = ?", req.FlockId). - Clauses(clause.Locking{Strength: "UPDATE"}) - if err := periodQuery.Select("COALESCE(MAX(period), 0)").Scan(&nextPeriod).Error; err != nil { + projectRepo := repository.NewProjectflockRepository(tx) + nextPeriod, err := projectRepo.GetNextPeriodForFlock(c.Context(), req.FlockId) + if err != nil { tx.Rollback() s.Log.Errorf("Failed to determine next period for flock %d: %+v", req.FlockId, err) return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to determine next period") } - nextPeriod++ - projectRepo := s.Repository.WithTx(tx) createBody := &entity.ProjectFlock{ FlockId: req.FlockId, AreaId: req.AreaId, @@ -190,26 +198,58 @@ func (s projectflockService) UpdateOne(c *fiber.Ctx, req *validation.Update, id } updateBody := make(map[string]any) + var relationChecks []common.RelationCheck if req.FlockId != nil { updateBody["flock_id"] = *req.FlockId + relationChecks = append(relationChecks, common.RelationCheck{ + Name: "Flock", + ID: req.FlockId, + Exists: relationExistsChecker[entity.Flock](s.Repository.DB()), + }) } if req.AreaId != nil { updateBody["area_id"] = *req.AreaId + relationChecks = append(relationChecks, common.RelationCheck{ + Name: "Area", + ID: req.AreaId, + Exists: relationExistsChecker[entity.Area](s.Repository.DB()), + }) } if req.ProductCategoryId != nil { updateBody["product_category_id"] = *req.ProductCategoryId + relationChecks = append(relationChecks, common.RelationCheck{ + Name: "Product category", + ID: req.ProductCategoryId, + Exists: relationExistsChecker[entity.ProductCategory](s.Repository.DB()), + }) } if req.FcrId != nil { updateBody["fcr_id"] = *req.FcrId + relationChecks = append(relationChecks, common.RelationCheck{ + Name: "FCR", + ID: req.FcrId, + Exists: relationExistsChecker[entity.Fcr](s.Repository.DB()), + }) } if req.LocationId != nil { updateBody["location_id"] = *req.LocationId + relationChecks = append(relationChecks, common.RelationCheck{ + Name: "Location", + ID: req.LocationId, + Exists: relationExistsChecker[entity.Location](s.Repository.DB()), + }) } if req.Period != nil { updateBody["period"] = *req.Period } + if len(relationChecks) > 0 { + if err := common.EnsureRelations(c.Context(), relationChecks...); err != nil { + return nil, err + } + } + var newKandangIDs []uint if req.KandangIds != nil { if len(req.KandangIds) == 0 { @@ -238,7 +278,7 @@ func (s projectflockService) UpdateOne(c *fiber.Ctx, req *validation.Update, id return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to start transaction") } - projectRepo := s.Repository.WithTx(tx) + projectRepo := repository.NewProjectflockRepository(tx) if len(updateBody) > 0 { if err := projectRepo.PatchOne(c.Context(), id, updateBody, nil); err != nil { tx.Rollback() @@ -332,7 +372,7 @@ func (s projectflockService) DeleteOne(c *fiber.Ctx, id uint) error { } } - if err := s.Repository.WithTx(tx).DeleteOne(c.Context(), id); err != nil { + if err := repository.NewProjectflockRepository(tx).DeleteOne(c.Context(), id); err != nil { tx.Rollback() if errors.Is(err, gorm.ErrRecordNotFound) { return fiber.NewError(fiber.StatusNotFound, "Projectflock not found") @@ -385,3 +425,9 @@ func uniqueUintSlice(values []uint) []uint { } return result } + +func relationExistsChecker[T any](db *gorm.DB) func(context.Context, uint) (bool, error) { + return func(ctx context.Context, id uint) (bool, error) { + return commonRepo.Exists[T](ctx, db, id) + } +}