mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-24 07:15:43 +00:00
deleted edit function in project-flock, and must retest closing feat after fixing product warehouse
This commit is contained in:
@@ -32,7 +32,6 @@ type ProjectflockService interface {
|
||||
GetAll(ctx *fiber.Ctx, params *validation.Query) ([]entity.ProjectFlock, int64, map[uint]*flockDTO.FlockRelationDTO, error)
|
||||
GetOne(ctx *fiber.Ctx, id uint) (*entity.ProjectFlock, *flockDTO.FlockRelationDTO, error)
|
||||
CreateOne(ctx *fiber.Ctx, req *validation.Create) (*entity.ProjectFlock, error)
|
||||
UpdateOne(ctx *fiber.Ctx, req *validation.Update, id uint) (*entity.ProjectFlock, error)
|
||||
GetAvailableDocQuantity(ctx *fiber.Ctx, kandangID uint) (float64, error)
|
||||
DeleteOne(ctx *fiber.Ctx, id uint) error
|
||||
GetProjectFlockKandangByProjectAndKandang(ctx *fiber.Ctx, projectFlockID uint, kandangID uint) (*entity.ProjectFlockKandang, float64, error)
|
||||
@@ -337,365 +336,6 @@ func (s *projectflockService) CreateOne(c *fiber.Ctx, req *validation.Create) (*
|
||||
return s.getOneEntityOnly(c, createBody.Id)
|
||||
}
|
||||
|
||||
func (s projectflockService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint) (*entity.ProjectFlock, error) {
|
||||
if err := s.Validate.Struct(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
actorID, err := m.ActorIDFromContext(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
existing, err := s.Repository.GetByID(c.Context(), id, s.Repository.WithDefaultRelations())
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fiber.NewError(fiber.StatusNotFound, "Projectflock not found")
|
||||
}
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to fetch projectflock %d before update: %+v", id, err)
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch project flock")
|
||||
}
|
||||
updateBody := make(map[string]any)
|
||||
hasBodyChanges := false
|
||||
var relationChecks []commonSvc.RelationCheck
|
||||
existingBase := pfutils.DeriveBaseName(existing.FlockName)
|
||||
targetBaseName := existingBase
|
||||
needFlockNameRegenerate := false
|
||||
|
||||
if req.FlockName != nil {
|
||||
trimmed := strings.TrimSpace(*req.FlockName)
|
||||
if trimmed == "" {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Flock name cannot be empty")
|
||||
}
|
||||
canonicalBase := trimmed
|
||||
if s.FlockRepo != nil {
|
||||
flockEntity, err := s.ensureFlockByName(c.Context(), actorID, trimmed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
canonicalBase = flockEntity.Name
|
||||
}
|
||||
if !strings.EqualFold(canonicalBase, existingBase) {
|
||||
needFlockNameRegenerate = true
|
||||
targetBaseName = canonicalBase
|
||||
hasBodyChanges = true
|
||||
}
|
||||
}
|
||||
if req.AreaId != nil {
|
||||
updateBody["area_id"] = *req.AreaId
|
||||
hasBodyChanges = true
|
||||
relationChecks = append(relationChecks, commonSvc.RelationCheck{
|
||||
Name: "Area",
|
||||
ID: req.AreaId,
|
||||
Exists: s.Repository.AreaExists,
|
||||
})
|
||||
}
|
||||
if req.Category != nil {
|
||||
cat := strings.ToUpper(*req.Category)
|
||||
if !utils.IsValidProjectFlockCategory(cat) {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid category")
|
||||
}
|
||||
|
||||
updateBody["category"] = cat
|
||||
}
|
||||
if req.FcrId != nil {
|
||||
updateBody["fcr_id"] = *req.FcrId
|
||||
hasBodyChanges = true
|
||||
relationChecks = append(relationChecks, commonSvc.RelationCheck{
|
||||
Name: "FCR",
|
||||
ID: req.FcrId,
|
||||
Exists: s.Repository.FcrExists,
|
||||
})
|
||||
}
|
||||
if req.LocationId != nil {
|
||||
updateBody["location_id"] = *req.LocationId
|
||||
hasBodyChanges = true
|
||||
relationChecks = append(relationChecks, commonSvc.RelationCheck{
|
||||
Name: "Location",
|
||||
ID: req.LocationId,
|
||||
Exists: s.Repository.LocationExists,
|
||||
})
|
||||
}
|
||||
|
||||
if len(relationChecks) > 0 {
|
||||
if err := commonSvc.EnsureRelations(c.Context(), relationChecks...); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var newKandangIDs []uint
|
||||
hasKandangChanges := false
|
||||
if req.KandangIds != nil {
|
||||
hasKandangChanges = true
|
||||
if len(req.KandangIds) == 0 {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "kandang_ids cannot be empty")
|
||||
}
|
||||
newKandangIDs = uniqueUintSlice(req.KandangIds)
|
||||
kandangs, err := s.KandangRepo.GetByIDs(c.Context(), newKandangIDs, nil)
|
||||
if err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fiber.NewError(fiber.StatusNotFound, "Some kandangs not found")
|
||||
}
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch kandangs")
|
||||
}
|
||||
if len(kandangs) != len(newKandangIDs) {
|
||||
return nil, fiber.NewError(fiber.StatusNotFound, "Some kandangs not found")
|
||||
}
|
||||
targetLocationID := existing.LocationId
|
||||
if req.LocationId != nil && *req.LocationId > 0 {
|
||||
targetLocationID = *req.LocationId
|
||||
}
|
||||
for _, kandang := range kandangs {
|
||||
if kandang.LocationId != targetLocationID {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Kandang %d tidak berada pada lokasi yang sama dengan project flock", kandang.Id))
|
||||
}
|
||||
}
|
||||
if linked, err := s.pivotRepo().HasKandangsLinkedToOtherProject(c.Context(), newKandangIDs, &id); err != nil {
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to validate kandangs linkage")
|
||||
} else if linked {
|
||||
return nil, fiber.NewError(fiber.StatusConflict, "Beberapa kandang sudah terikat dengan project flock lain")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
hasChanges := hasBodyChanges || hasKandangChanges
|
||||
if !hasChanges {
|
||||
return s.getOneEntityOnly(c, id)
|
||||
}
|
||||
|
||||
err = s.Repository.DB().WithContext(c.Context()).Transaction(func(dbTransaction *gorm.DB) error {
|
||||
projectRepo := repository.NewProjectflockRepository(dbTransaction)
|
||||
|
||||
baseForGeneration := targetBaseName
|
||||
if strings.TrimSpace(baseForGeneration) == "" {
|
||||
baseForGeneration = existingBase
|
||||
}
|
||||
if strings.TrimSpace(baseForGeneration) == "" {
|
||||
baseForGeneration = strings.TrimSpace(existing.FlockName)
|
||||
}
|
||||
|
||||
if needFlockNameRegenerate {
|
||||
newName, _, err := s.generateSequentialFlockName(c.Context(), projectRepo, baseForGeneration, 1, &id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
updateBody["flock_name"] = newName
|
||||
}
|
||||
|
||||
if len(updateBody) > 0 {
|
||||
if err := projectRepo.PatchOne(c.Context(), id, updateBody, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if _, err := projectRepo.GetByID(c.Context(), id, nil); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if req.KandangIds != nil {
|
||||
existingIDs := make(map[uint]struct{}, len(existing.Kandangs))
|
||||
for _, k := range existing.Kandangs {
|
||||
existingIDs[k.Id] = struct{}{}
|
||||
}
|
||||
newSet := make(map[uint]struct{}, len(newKandangIDs))
|
||||
for _, kid := range newKandangIDs {
|
||||
newSet[kid] = struct{}{}
|
||||
}
|
||||
|
||||
var toDetach []uint
|
||||
for kid := range existingIDs {
|
||||
if _, ok := newSet[kid]; !ok {
|
||||
toDetach = append(toDetach, kid)
|
||||
}
|
||||
}
|
||||
|
||||
var toAttach []uint
|
||||
for kid := range newSet {
|
||||
if _, ok := existingIDs[kid]; !ok {
|
||||
toAttach = append(toAttach, kid)
|
||||
}
|
||||
}
|
||||
|
||||
if len(toDetach) > 0 {
|
||||
if err := s.detachKandangs(c.Context(), dbTransaction, id, toDetach, true); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if len(toAttach) > 0 {
|
||||
currentPeriod, err := projectRepo.GetCurrentProjectPeriod(c.Context(), id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
periods := make(map[uint]int, len(toAttach))
|
||||
if currentPeriod > 0 {
|
||||
for _, kid := range toAttach {
|
||||
periods[kid] = currentPeriod
|
||||
}
|
||||
} else {
|
||||
periods, err = projectRepo.GetNextPeriodsForKandangs(c.Context(), toAttach)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.attachKandangs(c.Context(), dbTransaction, id, toAttach, periods); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if hasChanges {
|
||||
approvalSvc := commonSvc.NewApprovalService(commonRepo.NewApprovalRepository(dbTransaction))
|
||||
if approvalSvc != nil {
|
||||
latestBeforeReset, err := approvalSvc.LatestByTarget(c.Context(), s.approvalWorkflow, id, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
shouldRecordUpdate := latestBeforeReset == nil ||
|
||||
latestBeforeReset.StepNumber != uint16(utils.ProjectFlockStepPengajuan) ||
|
||||
latestBeforeReset.Action == nil ||
|
||||
(latestBeforeReset.Action != nil && *latestBeforeReset.Action != entity.ApprovalActionUpdated)
|
||||
|
||||
if shouldRecordUpdate {
|
||||
action := entity.ApprovalActionUpdated
|
||||
if _, err := approvalSvc.CreateApproval(
|
||||
c.Context(),
|
||||
utils.ApprovalWorkflowProjectFlock,
|
||||
id,
|
||||
utils.ProjectFlockStepPengajuan,
|
||||
&action,
|
||||
actorID,
|
||||
nil,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
if fiberErr, ok := err.(*fiber.Error); ok {
|
||||
return nil, fiberErr
|
||||
}
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fiber.NewError(fiber.StatusNotFound, "Projectflock not found")
|
||||
}
|
||||
s.Log.Errorf("Failed to update projectflock %d: %+v", id, err)
|
||||
if errors.Is(err, gorm.ErrDuplicatedKey) {
|
||||
return nil, fiber.NewError(fiber.StatusConflict, "Project flock period already exists")
|
||||
}
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to update project flock")
|
||||
}
|
||||
|
||||
return s.getOneEntityOnly(c, id)
|
||||
}
|
||||
|
||||
func (s projectflockService) Approval(c *fiber.Ctx, req *validation.Approve) ([]entity.ProjectFlock, error) {
|
||||
if err := s.Validate.Struct(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
actorID, err := m.ActorIDFromContext(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var action entity.ApprovalAction
|
||||
switch strings.ToUpper(strings.TrimSpace(req.Action)) {
|
||||
case string(entity.ApprovalActionRejected):
|
||||
action = entity.ApprovalActionRejected
|
||||
case string(entity.ApprovalActionApproved):
|
||||
action = entity.ApprovalActionApproved
|
||||
default:
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "action must be APPROVED or REJECTED")
|
||||
}
|
||||
|
||||
approvableIDs := uniqueUintSlice(req.ApprovableIds)
|
||||
if len(approvableIDs) == 0 {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "approvable_ids must contain at least one id")
|
||||
}
|
||||
|
||||
step := utils.ProjectFlockStepPengajuan
|
||||
if action == entity.ApprovalActionApproved {
|
||||
step = utils.ProjectFlockStepAktif
|
||||
}
|
||||
|
||||
err = s.Repository.DB().WithContext(c.Context()).Transaction(func(dbTransaction *gorm.DB) error {
|
||||
approvalSvc := commonSvc.NewApprovalService(commonRepo.NewApprovalRepository(dbTransaction))
|
||||
kandangRepoTx := kandangRepository.NewKandangRepository(dbTransaction)
|
||||
projectRepoTx := repository.NewProjectflockRepository(dbTransaction)
|
||||
|
||||
for _, approvableID := range approvableIDs {
|
||||
if _, err := projectRepoTx.GetByID(c.Context(), approvableID, nil); err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("Projectflock %d not found", approvableID))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := approvalSvc.CreateApproval(
|
||||
c.Context(),
|
||||
utils.ApprovalWorkflowProjectFlock,
|
||||
approvableID,
|
||||
step,
|
||||
&action,
|
||||
actorID,
|
||||
req.Notes,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch action {
|
||||
case entity.ApprovalActionApproved:
|
||||
if err := kandangRepoTx.UpdateStatusByProjectFlockID(
|
||||
c.Context(),
|
||||
approvableID,
|
||||
utils.KandangStatusActive,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
case entity.ApprovalActionRejected:
|
||||
if err := kandangRepoTx.UpdateStatusByProjectFlockID(
|
||||
c.Context(),
|
||||
approvableID,
|
||||
utils.KandangStatusNonActive,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
if fiberErr, ok := err.(*fiber.Error); ok {
|
||||
return nil, fiberErr
|
||||
}
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fiber.NewError(fiber.StatusNotFound, "Projectflock not found")
|
||||
}
|
||||
s.Log.Errorf("Failed to record approval for projectflocks %+v: %+v", approvableIDs, err)
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to record approval")
|
||||
}
|
||||
|
||||
updated := make([]entity.ProjectFlock, 0, len(approvableIDs))
|
||||
for _, approvableID := range approvableIDs {
|
||||
project, err := s.getOneEntityOnly(c, approvableID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
updated = append(updated, *project)
|
||||
}
|
||||
|
||||
return updated, nil
|
||||
}
|
||||
|
||||
func (s projectflockService) DeleteOne(c *fiber.Ctx, id uint) error {
|
||||
existing, err := s.Repository.GetByID(c.Context(), id, s.Repository.WithDefaultRelations())
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
@@ -823,6 +463,133 @@ func (s projectflockService) GetProjectPeriods(c *fiber.Ctx, projectIDs []uint)
|
||||
return s.pivotRepo().ProjectPeriodsByProjectIDs(c.Context(), projectIDs)
|
||||
}
|
||||
|
||||
func (s projectflockService) Approval(c *fiber.Ctx, req *validation.Approve) ([]entity.ProjectFlock, error) {
|
||||
if err := s.Validate.Struct(req); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
actorID, err := m.ActorIDFromContext(c)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var action entity.ApprovalAction
|
||||
switch strings.ToUpper(strings.TrimSpace(req.Action)) {
|
||||
case string(entity.ApprovalActionRejected):
|
||||
action = entity.ApprovalActionRejected
|
||||
case string(entity.ApprovalActionApproved):
|
||||
action = entity.ApprovalActionApproved
|
||||
default:
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "action must be APPROVED or REJECTED")
|
||||
}
|
||||
|
||||
approvableIDs := uniqueUintSlice(req.ApprovableIds)
|
||||
if len(approvableIDs) == 0 {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "approvable_ids must contain at least one id")
|
||||
}
|
||||
|
||||
step := utils.ProjectFlockStepPengajuan
|
||||
if action == entity.ApprovalActionApproved {
|
||||
step = utils.ProjectFlockStepAktif
|
||||
}
|
||||
|
||||
err = s.Repository.DB().WithContext(c.Context()).Transaction(func(dbTransaction *gorm.DB) error {
|
||||
approvalSvc := commonSvc.NewApprovalService(commonRepo.NewApprovalRepository(dbTransaction))
|
||||
kandangRepoTx := kandangRepository.NewKandangRepository(dbTransaction)
|
||||
projectRepoTx := repository.NewProjectflockRepository(dbTransaction)
|
||||
projectFlockKandangRepoTx := repository.NewProjectFlockKandangRepository(dbTransaction)
|
||||
|
||||
for _, approvableID := range approvableIDs {
|
||||
if _, err := projectRepoTx.GetByID(c.Context(), approvableID, nil); err != nil {
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return fiber.NewError(fiber.StatusNotFound, fmt.Sprintf("Projectflock %d not found", approvableID))
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err := approvalSvc.CreateApproval(
|
||||
c.Context(),
|
||||
utils.ApprovalWorkflowProjectFlock,
|
||||
approvableID,
|
||||
step,
|
||||
&action,
|
||||
actorID,
|
||||
req.Notes,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch action {
|
||||
case entity.ApprovalActionApproved:
|
||||
if err := kandangRepoTx.UpdateStatusByProjectFlockID(
|
||||
c.Context(),
|
||||
approvableID,
|
||||
utils.KandangStatusActive,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pfks, err := projectFlockKandangRepoTx.GetByProjectFlockID(c.Context(), approvableID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, pfk := range pfks {
|
||||
latest, lerr := approvalSvc.LatestByTarget(c.Context(), utils.ApprovalWorkflowProjectFlockKandang, pfk.Id, nil)
|
||||
if lerr != nil {
|
||||
return lerr
|
||||
}
|
||||
if latest != nil && latest.StepNumber == uint16(utils.ProjectFlockKandangStepDisetujui) {
|
||||
continue
|
||||
}
|
||||
if _, aerr := approvalSvc.CreateApproval(
|
||||
c.Context(),
|
||||
utils.ApprovalWorkflowProjectFlockKandang,
|
||||
pfk.Id,
|
||||
utils.ProjectFlockKandangStepDisetujui,
|
||||
&action,
|
||||
actorID,
|
||||
req.Notes,
|
||||
); aerr != nil && !errors.Is(aerr, gorm.ErrDuplicatedKey) {
|
||||
return aerr
|
||||
}
|
||||
}
|
||||
case entity.ApprovalActionRejected:
|
||||
if err := kandangRepoTx.UpdateStatusByProjectFlockID(
|
||||
c.Context(),
|
||||
approvableID,
|
||||
utils.KandangStatusNonActive,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
if fiberErr, ok := err.(*fiber.Error); ok {
|
||||
return nil, fiberErr
|
||||
}
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, fiber.NewError(fiber.StatusNotFound, "Projectflock not found")
|
||||
}
|
||||
s.Log.Errorf("Failed to record approval for projectflocks %+v: %+v", approvableIDs, err)
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to record approval")
|
||||
}
|
||||
|
||||
updated := make([]entity.ProjectFlock, 0, len(approvableIDs))
|
||||
for _, approvableID := range approvableIDs {
|
||||
project, err := s.getOneEntityOnly(c, approvableID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
updated = append(updated, *project)
|
||||
}
|
||||
|
||||
return updated, nil
|
||||
}
|
||||
|
||||
func (s projectflockService) GetPeriodSummary(c *fiber.Ctx, locationID uint) ([]KandangPeriodSummary, error) {
|
||||
if locationID == 0 {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, "location_id is required")
|
||||
|
||||
Reference in New Issue
Block a user