feat(BE): enhance ProjectFlockKandang structure and approval fetching methods

This commit is contained in:
aguhh18
2026-01-07 13:39:54 +07:00
parent 0a84e427c1
commit 76d5b6b69a
3 changed files with 94 additions and 57 deletions
+5 -4
View File
@@ -10,8 +10,9 @@ type ProjectFlockKandang struct {
ClosedAt *time.Time `gorm:"index"` ClosedAt *time.Time `gorm:"index"`
CreatedAt time.Time `gorm:"autoCreateTime"` CreatedAt time.Time `gorm:"autoCreateTime"`
ProjectFlock ProjectFlock `gorm:"foreignKey:ProjectFlockId;references:Id"` ProjectFlock ProjectFlock `gorm:"foreignKey:ProjectFlockId;references:Id"`
Kandang Kandang `gorm:"foreignKey:KandangId;references:Id"` Kandang Kandang `gorm:"foreignKey:KandangId;references:Id"`
Chickins []ProjectChickin `gorm:"foreignKey:ProjectFlockKandangId;references:Id"` Chickins []ProjectChickin `gorm:"foreignKey:ProjectFlockKandangId;references:Id"`
LatestApproval *Approval `gorm:"-" json:"-"` LatestProjectFlockApproval *Approval `gorm:"-" json:"-"`
LatestChickinApproval *Approval `gorm:"-" json:"-"`
} }
@@ -28,14 +28,14 @@ type ProjectFlockKandangRelationDTO struct {
type ProjectFlockDTO struct { type ProjectFlockDTO struct {
projectFlockDTO.ProjectFlockRelationDTO projectFlockDTO.ProjectFlockRelationDTO
Area *areaDTO.AreaRelationDTO `json:"area,omitempty"` Area *areaDTO.AreaRelationDTO `json:"area,omitempty"`
Category string `json:"category"` Category string `json:"category"`
Fcr *fcrDTO.FcrRelationDTO `json:"fcr,omitempty"` Fcr *fcrDTO.FcrRelationDTO `json:"fcr,omitempty"`
ProductionStandard *productionStandardDTO.ProductionStandardRelationDTO `json:"production_standard,omitempty"` ProductionStandard *productionStandardDTO.ProductionStandardRelationDTO `json:"production_standard,omitempty"`
Location *locationDTO.LocationRelationDTO `json:"location,omitempty"` Location *locationDTO.LocationRelationDTO `json:"location,omitempty"`
CreatedUser *userDTO.UserRelationDTO `json:"created_user,omitempty"` CreatedUser *userDTO.UserRelationDTO `json:"created_user,omitempty"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"` UpdatedAt time.Time `json:"updated_at"`
} }
type ProductWarehouseDTO struct { type ProductWarehouseDTO struct {
@@ -51,11 +51,12 @@ type AvailableQtyDTO struct {
type ProjectFlockKandangListDTO struct { type ProjectFlockKandangListDTO struct {
ProjectFlockKandangRelationDTO ProjectFlockKandangRelationDTO
ProjectFlock *ProjectFlockDTO `json:"project_flock,omitempty"` ProjectFlock *ProjectFlockDTO `json:"project_flock,omitempty"`
Kandang *kandangDTO.KandangRelationDTO `json:"kandang,omitempty"` Kandang *kandangDTO.KandangRelationDTO `json:"kandang,omitempty"`
CreatedUser *userDTO.UserRelationDTO `json:"created_user,omitempty"` CreatedUser *userDTO.UserRelationDTO `json:"created_user,omitempty"`
CreatedAt time.Time `json:"created_at"` CreatedAt time.Time `json:"created_at"`
Approval *approvalDTO.ApprovalRelationDTO `json:"approval,omitempty"` Approval *approvalDTO.ApprovalRelationDTO `json:"approval,omitempty"`
ChickinApproval *approvalDTO.ApprovalRelationDTO `json:"chickin_approval,omitempty"`
} }
type ProjectFlockKandangDetailDTO struct { type ProjectFlockKandangDetailDTO struct {
@@ -105,7 +106,8 @@ func ToProjectFlockKandangDetailDTOWithAvailableQty(e entity.ProjectFlockKandang
Kandang: toKandangRelation(e.Kandang), Kandang: toKandangRelation(e.Kandang),
CreatedAt: e.CreatedAt, CreatedAt: e.CreatedAt,
CreatedUser: toCreatedUserDTO(e.ProjectFlock), CreatedUser: toCreatedUserDTO(e.ProjectFlock),
Approval: toApprovalDTO(e), Approval: toApprovalDTOSelector(e, func(x entity.ProjectFlockKandang) *entity.Approval { return x.LatestProjectFlockApproval }),
ChickinApproval: toApprovalDTOSelector(e, func(x entity.ProjectFlockKandang) *entity.Approval { return x.LatestChickinApproval }),
} }
return ProjectFlockKandangDetailDTO{ return ProjectFlockKandangDetailDTO{
@@ -124,9 +126,11 @@ func toKandangRelation(kandang entity.Kandang) *kandangDTO.KandangRelationDTO {
return &mapped return &mapped
} }
func toApprovalDTO(e entity.ProjectFlockKandang) *approvalDTO.ApprovalRelationDTO { func toApprovalDTOSelector(
if e.LatestApproval != nil { e entity.ProjectFlockKandang, selector func(entity.ProjectFlockKandang) *entity.Approval) *approvalDTO.ApprovalRelationDTO {
mapped := approvalDTO.ToApprovalDTO(*e.LatestApproval) approval := selector(e)
if approval != nil {
mapped := approvalDTO.ToApprovalDTO(*approval)
return &mapped return &mapped
} }
return nil return nil
@@ -145,18 +149,11 @@ func ToProjectFlockKandangListDTO(e entity.ProjectFlockKandang) ProjectFlockKand
Kandang: toKandangRelation(e.Kandang), Kandang: toKandangRelation(e.Kandang),
CreatedAt: e.CreatedAt, CreatedAt: e.CreatedAt,
CreatedUser: toCreatedUserDTO(e.ProjectFlock), CreatedUser: toCreatedUserDTO(e.ProjectFlock),
Approval: toApprovalDTO(e), Approval: toApprovalDTOSelector(e, func(x entity.ProjectFlockKandang) *entity.Approval { return x.LatestProjectFlockApproval }),
ChickinApproval: toApprovalDTOSelector(e, func(x entity.ProjectFlockKandang) *entity.Approval { return x.LatestChickinApproval }),
} }
} }
func ToProjectFlockKandangListDTOs(e []entity.ProjectFlockKandang) []ProjectFlockKandangListDTO {
result := make([]ProjectFlockKandangListDTO, len(e))
for i, r := range e {
result[i] = ToProjectFlockKandangListDTO(r)
}
return result
}
func toCreatedUserDTO(pf entity.ProjectFlock) *userDTO.UserRelationDTO { func toCreatedUserDTO(pf entity.ProjectFlock) *userDTO.UserRelationDTO {
if pf.CreatedUser.Id != 0 { if pf.CreatedUser.Id != 0 {
mapped := userDTO.ToUserRelationDTO(pf.CreatedUser) mapped := userDTO.ToUserRelationDTO(pf.CreatedUser)
@@ -187,7 +184,6 @@ func toAvailableQtyDTOsFromMap(chickins []entity.ProjectChickin, availableQtyMap
return nil return nil
} }
// First, build map from chickins
pwMap := make(map[uint]*entity.ProductWarehouse) pwMap := make(map[uint]*entity.ProductWarehouse)
for _, chickin := range chickins { for _, chickin := range chickins {
if chickin.ProductWarehouse != nil && chickin.ProductWarehouse.Id != 0 { if chickin.ProductWarehouse != nil && chickin.ProductWarehouse.Id != 0 {
@@ -195,7 +191,6 @@ func toAvailableQtyDTOsFromMap(chickins []entity.ProjectChickin, availableQtyMap
} }
} }
// Then, add productWarehouses that are not in chickins yet
for i := range productWarehouses { for i := range productWarehouses {
if _, exists := pwMap[productWarehouses[i].Id]; !exists { if _, exists := pwMap[productWarehouses[i].Id]; !exists {
pwMap[productWarehouses[i].Id] = &productWarehouses[i] pwMap[productWarehouses[i].Id] = &productWarehouses[i]
@@ -204,7 +199,7 @@ func toAvailableQtyDTOsFromMap(chickins []entity.ProjectChickin, availableQtyMap
result := make([]AvailableQtyDTO, 0, len(availableQtyMap)) result := make([]AvailableQtyDTO, 0, len(availableQtyMap))
for pwId, availableQty := range availableQtyMap { for pwId, availableQty := range availableQtyMap {
// Skip jika available qty = 0
if availableQty <= 0 { if availableQty <= 0 {
continue continue
} }
@@ -98,23 +98,8 @@ func (s projectFlockKandangService) GetAll(c *fiber.Ctx, params *validation.Quer
} }
if s.ApprovalSvc != nil { if s.ApprovalSvc != nil {
projectFlockKandangIDs := make([]uint, len(projectFlockKandangs)) s.fetchProjectFlockApprovals(c, projectFlockKandangs)
for i, pfk := range projectFlockKandangs { s.fetchChickinApprovals(c, projectFlockKandangs)
projectFlockKandangIDs[i] = pfk.Id
}
approvalMap, err := s.ApprovalSvc.LatestByTargets(c.Context(), utils.ApprovalWorkflowProjectFlockKandang, projectFlockKandangIDs, func(db *gorm.DB) *gorm.DB {
return db.Preload("ActionUser")
})
if err != nil {
s.Log.Warnf("Failed to fetch approvals for projectFlockKandangs: %+v", err)
} else {
for i := range projectFlockKandangs {
if approval, ok := approvalMap[projectFlockKandangs[i].Id]; ok {
projectFlockKandangs[i].LatestApproval = approval
}
}
}
} }
return projectFlockKandangs, total, nil return projectFlockKandangs, total, nil
@@ -130,14 +115,8 @@ func (s projectFlockKandangService) GetOne(c *fiber.Ctx, id uint) (*entity.Proje
} }
if len(projectFlockKandang.Chickins) > 0 && s.ApprovalSvc != nil { if len(projectFlockKandang.Chickins) > 0 && s.ApprovalSvc != nil {
latest, err := s.ApprovalSvc.LatestByTarget(c.Context(), utils.ApprovalWorkflowProjectFlockKandang, projectFlockKandang.Id, nil) s.fetchProjectFlockApproval(c, projectFlockKandang)
if err != nil { s.fetchChickinApproval(c, projectFlockKandang)
s.Log.Errorf("Failed to fetch latest kandang approval for projectFlockKandang %d: %+v", projectFlockKandang.Id, err)
}
if latest != nil {
projectFlockKandang.LatestApproval = latest
}
} }
availableQtyMap, err := s.getAvailableQuantities(c, projectFlockKandang) availableQtyMap, err := s.getAvailableQuantities(c, projectFlockKandang)
@@ -164,6 +143,68 @@ func (s projectFlockKandangService) GetOne(c *fiber.Ctx, id uint) (*entity.Proje
return projectFlockKandang, availableQtyMap, productWarehouses, nil return projectFlockKandang, availableQtyMap, productWarehouses, nil
} }
func (s projectFlockKandangService) fetchProjectFlockApprovals(c *fiber.Ctx, projectFlockKandangs []entity.ProjectFlockKandang) {
projectFlockKandangIDs := make([]uint, len(projectFlockKandangs))
for i, pfk := range projectFlockKandangs {
projectFlockKandangIDs[i] = pfk.Id
}
approvalMap, err := s.ApprovalSvc.LatestByTargets(c.Context(), utils.ApprovalWorkflowProjectFlockKandang, projectFlockKandangIDs, func(db *gorm.DB) *gorm.DB {
return db.Preload("ActionUser")
})
if err != nil {
s.Log.Warnf("Failed to fetch approvals for projectFlockKandangs: %+v", err)
} else {
for i := range projectFlockKandangs {
if approval, ok := approvalMap[projectFlockKandangs[i].Id]; ok {
projectFlockKandangs[i].LatestProjectFlockApproval = approval
}
}
}
}
func (s projectFlockKandangService) fetchChickinApprovals(c *fiber.Ctx, projectFlockKandangs []entity.ProjectFlockKandang) {
projectFlockKandangIDs := make([]uint, len(projectFlockKandangs))
for i, pfk := range projectFlockKandangs {
projectFlockKandangIDs[i] = pfk.Id
}
chickinApprovalMap, err := s.ApprovalSvc.LatestByTargets(c.Context(), utils.ApprovalWorkflowChickin, projectFlockKandangIDs, func(db *gorm.DB) *gorm.DB {
return db.Preload("ActionUser")
})
if err != nil {
s.Log.Warnf("Failed to fetch chickin approvals for projectFlockKandangs: %+v", err)
} else {
for i := range projectFlockKandangs {
if approval, ok := chickinApprovalMap[projectFlockKandangs[i].Id]; ok {
projectFlockKandangs[i].LatestChickinApproval = approval
}
}
}
}
func (s projectFlockKandangService) fetchProjectFlockApproval(c *fiber.Ctx, projectFlockKandang *entity.ProjectFlockKandang) {
latest, err := s.ApprovalSvc.LatestByTarget(c.Context(), utils.ApprovalWorkflowProjectFlockKandang, projectFlockKandang.Id, nil)
if err != nil {
s.Log.Errorf("Failed to fetch latest kandang approval for projectFlockKandang %d: %+v", projectFlockKandang.Id, err)
}
if latest != nil {
projectFlockKandang.LatestProjectFlockApproval = latest
}
}
func (s projectFlockKandangService) fetchChickinApproval(c *fiber.Ctx, projectFlockKandang *entity.ProjectFlockKandang) {
latestChickin, err := s.ApprovalSvc.LatestByTarget(c.Context(), utils.ApprovalWorkflowChickin, projectFlockKandang.Id, nil)
if err != nil {
s.Log.Errorf("Failed to fetch latest chickin approval for projectFlockKandang %d: %+v", projectFlockKandang.Id, err)
}
if latestChickin != nil {
projectFlockKandang.LatestChickinApproval = latestChickin
}
}
func (s projectFlockKandangService) getAvailableQuantities(c *fiber.Ctx, projectFlockKandang *entity.ProjectFlockKandang) (map[uint]float64, error) { func (s projectFlockKandangService) getAvailableQuantities(c *fiber.Ctx, projectFlockKandang *entity.ProjectFlockKandang) (map[uint]float64, error) {
if projectFlockKandang.Kandang.Id == 0 || s.WarehouseRepo == nil || s.ProductWarehouseRepo == nil { if projectFlockKandang.Kandang.Id == 0 || s.WarehouseRepo == nil || s.ProductWarehouseRepo == nil {
return nil, nil return nil, nil