feat(BE-281):add dto standart mean bw and uniformity

This commit is contained in:
ragilap
2025-12-30 12:07:28 +07:00
parent 9a094b8bfe
commit 90125ffe1a
4 changed files with 253 additions and 20 deletions
@@ -32,6 +32,10 @@ func (u *UniformityController) GetAll(c *fiber.Ctx) error {
if err != nil {
return err
}
standards, err := u.UniformityService.MapStandards(c, result)
if err != nil {
return err
}
return c.Status(fiber.StatusOK).
JSON(response.SuccessWithPaginate[dto.UniformityListDTO]{
@@ -49,7 +53,7 @@ func (u *UniformityController) GetAll(c *fiber.Ctx) error {
"status": "Pengajuan",
},
},
Data: dto.ToUniformityListDTOs(result),
Data: dto.ToUniformityListDTOsWithStandard(result, standards),
})
}
@@ -90,12 +94,24 @@ func (u *UniformityController) GetOne(c *fiber.Ctx) error {
}
}
standard, err := u.UniformityService.GetStandard(c, result)
if err != nil {
return err
}
var standardDTO *dto.UniformityStandardDTO
if standard != nil {
standardDTO = &dto.UniformityStandardDTO{
MeanWeight: standard.MeanWeight,
Uniformity: standard.Uniformity,
}
}
return c.Status(fiber.StatusOK).
JSON(response.Success{
Code: fiber.StatusOK,
Status: "success",
Message: "Get production uniformity successfully",
Data: dto.ToUniformityDetailDTO(*result, calculation, document),
Data: dto.ToUniformityDetailDTO(*result, calculation, document, standardDTO),
})
}
@@ -121,13 +137,24 @@ func (u *UniformityController) CreateOne(c *fiber.Ctx) error {
}
document := dto.NewDocumentForResponse(file.Filename)
standard, err := u.UniformityService.GetStandard(c, result)
if err != nil {
return err
}
var standardDTO *dto.UniformityStandardDTO
if standard != nil {
standardDTO = &dto.UniformityStandardDTO{
MeanWeight: standard.MeanWeight,
Uniformity: standard.Uniformity,
}
}
return c.Status(fiber.StatusCreated).
JSON(response.Success{
Code: fiber.StatusCreated,
Status: "success",
Message: "Create uniformity successfully",
Data: dto.ToUniformityDetailDTO(*result, calculation, document),
Data: dto.ToUniformityDetailDTO(*result, calculation, document, standardDTO),
})
}
@@ -181,17 +208,36 @@ func (u *UniformityController) UpdateOne(c *fiber.Ctx) error {
return err
}
calculation, document, err := u.UniformityService.CalculateUniformityFromDocument(c, id)
standard, err := u.UniformityService.GetStandard(c, result)
if err != nil {
return err
}
var standardDTO *dto.UniformityStandardDTO
if standard != nil {
standardDTO = &dto.UniformityStandardDTO{
MeanWeight: standard.MeanWeight,
Uniformity: standard.Uniformity,
}
}
calculation := service.UniformityCalculation{
ChickQtyOfWeight: result.ChickQtyOfWeight,
MeanWeight: math.Round(result.MeanUp / 1.10),
MeanDown: result.MeanDown,
MeanUp: result.MeanUp,
UniformQty: result.UniformQty,
OutsideQty: result.NotUniformQty,
Uniformity: result.Uniformity,
Cv: result.Cv,
}
var document *entity.Document
return c.Status(fiber.StatusOK).
JSON(response.Success{
Code: fiber.StatusOK,
Status: "success",
Message: "Update uniformity successfully",
Data: dto.ToUniformityDetailDTO(*result, calculation, document),
Data: dto.ToUniformityDetailDTO(*result, calculation, document, standardDTO),
})
}
@@ -22,6 +22,11 @@ type UniformityResultDTO struct {
Cv float64 `json:"cv"`
}
type UniformityStandardDTO struct {
MeanWeight *float64 `json:"mean_weight"`
Uniformity *float64 `json:"uniformity"`
}
type UniformityDetailItemDTO struct {
Id int `json:"id"`
Weight float64 `json:"weight"`
@@ -47,6 +52,7 @@ type UniformityDetailDTO struct {
InfoUmum UniformityInfoDTO `json:"info_umum"`
Sampling UniformitySamplingDTO `json:"sampling"`
Result UniformityResultDTO `json:"result"`
Standard *UniformityStandardDTO `json:"standard"`
UniformityDetails []UniformityDetailItemDTO `json:"uniformity_details"`
}
@@ -65,6 +71,8 @@ type UniformityListDTO struct {
UniformQty float64 `json:"uniform_qty"`
MeanUp float64 `json:"mean_up"`
MeanDown float64 `json:"mean_down"`
StandardMeanWeight *float64 `json:"standard_mean_weight"`
StandardUniformity *float64 `json:"standard_uniformity"`
CreatedAt time.Time `json:"created_at"`
CreatedBy uint `json:"created_by"`
LatestApproval *approvalDTO.ApprovalRelationDTO `json:"latest_approval"`
@@ -89,6 +97,7 @@ func ToUniformityDetailDTO(
entityData entity.ProjectFlockKandangUniformity,
calc service.UniformityCalculation,
document *entity.Document,
standard *UniformityStandardDTO,
) UniformityDetailDTO {
info := UniformityInfoDTO{
Tanggal: formatUniformityDate(entityData.UniformDate),
@@ -106,6 +115,7 @@ func ToUniformityDetailDTO(
InfoUmum: info,
Sampling: toUniformitySamplingDTO(calc),
Result: toUniformityResultDTO(calc),
Standard: standard,
UniformityDetails: toUniformityDetailItemsDTO(calc),
}
}
@@ -146,6 +156,24 @@ func ToUniformityListDTOs(items []entity.ProjectFlockKandangUniformity) []Unifor
return result
}
func ToUniformityListDTOsWithStandard(
items []entity.ProjectFlockKandangUniformity,
standards map[uint]service.UniformityStandard,
) []UniformityListDTO {
result := ToUniformityListDTOs(items)
if len(result) == 0 || len(standards) == 0 {
return result
}
for i := range result {
if std, ok := standards[result[i].Id]; ok {
result[i].StandardMeanWeight = std.MeanWeight
result[i].StandardUniformity = std.Uniformity
}
}
return result
}
func toUniformitySamplingDTO(calc service.UniformityCalculation) UniformitySamplingDTO {
return UniformitySamplingDTO{
ChickQtyOfWeight: calc.ChickQtyOfWeight,
@@ -10,6 +10,7 @@ import (
commonRepo "gitlab.com/mbugroup/lti-api.git/internal/common/repository"
commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service"
rProductionStandard "gitlab.com/mbugroup/lti-api.git/internal/modules/master/production-standards/repositories"
rProjectFlock "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
rUniformity "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/repositories"
sUniformity "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/services"
@@ -26,6 +27,8 @@ func (UniformityModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validat
documentRepo := commonRepo.NewDocumentRepository(db)
approvalRepo := commonRepo.NewApprovalRepository(db)
projectFlockKandangRepo := rProjectFlock.NewProjectFlockKandangRepository(db)
productionStandardRepo := rProductionStandard.NewProductionStandardRepository(db)
standardGrowthDetailRepo := rProductionStandard.NewStandardGrowthDetailRepository(db)
userRepo := rUser.NewUserRepository(db)
documentSvc, err := commonSvc.NewDocumentServiceFromConfig(context.Background(), documentRepo)
@@ -38,7 +41,16 @@ func (UniformityModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validat
panic(fmt.Sprintf("failed to register uniformity approval workflow: %v", err))
}
uniformityService := sUniformity.NewUniformityService(uniformityRepo, documentSvc, approvalRepo, approvalSvc, projectFlockKandangRepo, validate)
uniformityService := sUniformity.NewUniformityService(
uniformityRepo,
documentSvc,
approvalRepo,
approvalSvc,
projectFlockKandangRepo,
productionStandardRepo,
standardGrowthDetailRepo,
validate,
)
userService := sUser.NewUserService(userRepo, validate)
UniformityRoutes(router, userService, uniformityService)
@@ -14,6 +14,7 @@ import (
commonSvc "gitlab.com/mbugroup/lti-api.git/internal/common/service"
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
m "gitlab.com/mbugroup/lti-api.git/internal/middleware"
rProductionStandard "gitlab.com/mbugroup/lti-api.git/internal/modules/master/production-standards/repositories"
rProjectFlock "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/repositories"
repository "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/repositories"
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/uniformities/validations"
@@ -30,6 +31,8 @@ type UniformityService interface {
GetAll(ctx *fiber.Ctx, params *validation.Query) ([]entity.ProjectFlockKandangUniformity, int64, error)
GetOne(ctx *fiber.Ctx, id uint) (*entity.ProjectFlockKandangUniformity, error)
GetSummary(ctx *fiber.Ctx, id uint) (*entity.ProjectFlockKandangUniformity, error)
GetStandard(ctx *fiber.Ctx, uniformity *entity.ProjectFlockKandangUniformity) (*UniformityStandard, error)
MapStandards(ctx *fiber.Ctx, items []entity.ProjectFlockKandangUniformity) (map[uint]UniformityStandard, error)
CreateOne(ctx *fiber.Ctx, req *validation.Create, file *multipart.FileHeader, rows []BodyWeightExcelRow) (*entity.ProjectFlockKandangUniformity, error)
UpdateOne(ctx *fiber.Ctx, req *validation.Update, id uint, file *multipart.FileHeader, rows []BodyWeightExcelRow) (*entity.ProjectFlockKandangUniformity, error)
DeleteOne(ctx *fiber.Ctx, id uint) error
@@ -40,13 +43,15 @@ type UniformityService interface {
}
type uniformityService struct {
Log *logrus.Logger
Validate *validator.Validate
Repository repository.UniformityRepository
DocumentSvc commonSvc.DocumentService
ApprovalRepo commonRepo.ApprovalRepository
ApprovalSvc commonSvc.ApprovalService
ProjectFlockKandangRepo rProjectFlock.ProjectFlockKandangRepository
Log *logrus.Logger
Validate *validator.Validate
Repository repository.UniformityRepository
DocumentSvc commonSvc.DocumentService
ApprovalRepo commonRepo.ApprovalRepository
ApprovalSvc commonSvc.ApprovalService
ProjectFlockKandangRepo rProjectFlock.ProjectFlockKandangRepository
ProductionStandardRepo rProductionStandard.ProductionStandardRepository
StandardGrowthDetailRepo rProductionStandard.StandardGrowthDetailRepository
}
func NewUniformityService(
@@ -55,16 +60,20 @@ func NewUniformityService(
approvalRepo commonRepo.ApprovalRepository,
approvalSvc commonSvc.ApprovalService,
projectFlockKandangRepo rProjectFlock.ProjectFlockKandangRepository,
productionStandardRepo rProductionStandard.ProductionStandardRepository,
standardGrowthDetailRepo rProductionStandard.StandardGrowthDetailRepository,
validate *validator.Validate,
) UniformityService {
return &uniformityService{
Log: utils.Log,
Validate: validate,
Repository: repo,
DocumentSvc: documentSvc,
ApprovalRepo: approvalRepo,
ApprovalSvc: approvalSvc,
ProjectFlockKandangRepo: projectFlockKandangRepo,
Log: utils.Log,
Validate: validate,
Repository: repo,
DocumentSvc: documentSvc,
ApprovalRepo: approvalRepo,
ApprovalSvc: approvalSvc,
ProjectFlockKandangRepo: projectFlockKandangRepo,
ProductionStandardRepo: productionStandardRepo,
StandardGrowthDetailRepo: standardGrowthDetailRepo,
}
}
@@ -121,6 +130,64 @@ func (s uniformityService) GetSummary(c *fiber.Ctx, id uint) (*entity.ProjectFlo
return s.GetOne(c, id)
}
func (s uniformityService) GetStandard(c *fiber.Ctx, uniformity *entity.ProjectFlockKandangUniformity) (*UniformityStandard, error) {
if uniformity == nil {
return nil, nil
}
return s.resolveUniformityStandard(c.Context(), *uniformity)
}
func (s uniformityService) MapStandards(c *fiber.Ctx, items []entity.ProjectFlockKandangUniformity) (map[uint]UniformityStandard, error) {
if len(items) == 0 {
return nil, nil
}
if s.ProductionStandardRepo == nil || s.StandardGrowthDetailRepo == nil {
return nil, nil
}
categoryStandard := make(map[string]*entity.ProductionStandard)
detailCache := make(map[uint]map[int]entity.StandardGrowthDetail)
result := make(map[uint]UniformityStandard, len(items))
for _, item := range items {
if item.Id == 0 {
continue
}
standard, err := s.resolveCategoryStandard(c.Context(), item.ProjectFlockKandang.ProjectFlock.Category, categoryStandard)
if err != nil {
return nil, err
}
if standard == nil {
continue
}
weekMap, ok := detailCache[standard.Id]
if !ok {
details, err := s.StandardGrowthDetailRepo.GetByProductionStandardID(c.Context(), standard.Id)
if err != nil {
return nil, err
}
weekMap = make(map[int]entity.StandardGrowthDetail, len(details))
for _, detail := range details {
weekMap[detail.Week] = detail
}
detailCache[standard.Id] = weekMap
}
detail, ok := weekMap[item.Week]
if !ok {
continue
}
standardDTO := UniformityStandard{
MeanWeight: cloneFloat64(detail.TargetMeanBw),
Uniformity: float64Ptr(detail.MinUniformity),
}
result[item.Id] = standardDTO
}
return result, nil
}
func (s *uniformityService) CreateOne(c *fiber.Ctx, req *validation.Create, file *multipart.FileHeader, rows []BodyWeightExcelRow) (*entity.ProjectFlockKandangUniformity, error) {
if err := s.Validate.Struct(req); err != nil {
return nil, err
@@ -516,6 +583,11 @@ type UniformityCalculation struct {
Details []UniformityDetailItem
}
type UniformityStandard struct {
MeanWeight *float64
Uniformity *float64
}
func (s uniformityService) ComputeUniformity(rows []BodyWeightExcelRow) (UniformityCalculation, error) {
return computeUniformity(rows)
}
@@ -664,6 +736,81 @@ func (s *uniformityService) attachLatestApproval(ctx context.Context, item *enti
return nil
}
func (s *uniformityService) resolveUniformityStandard(ctx context.Context, item entity.ProjectFlockKandangUniformity) (*UniformityStandard, error) {
if s.ProductionStandardRepo == nil || s.StandardGrowthDetailRepo == nil {
return nil, nil
}
standard, err := s.resolveCategoryStandard(ctx, item.ProjectFlockKandang.ProjectFlock.Category, nil)
if err != nil || standard == nil {
return nil, err
}
detail, err := s.StandardGrowthDetailRepo.GetByStandardIDAndWeek(ctx, standard.Id, item.Week)
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, nil
}
return nil, err
}
return &UniformityStandard{
MeanWeight: cloneFloat64(detail.TargetMeanBw),
Uniformity: float64Ptr(detail.MinUniformity),
}, nil
}
func (s *uniformityService) resolveCategoryStandard(
ctx context.Context,
category string,
cache map[string]*entity.ProductionStandard,
) (*entity.ProductionStandard, error) {
category = strings.TrimSpace(category)
if category == "" {
return nil, nil
}
if cache != nil {
if cached, ok := cache[category]; ok {
return cached, nil
}
}
var standard entity.ProductionStandard
err := s.ProductionStandardRepo.DB().WithContext(ctx).
Where("project_category = ?", category).
Where("deleted_at IS NULL").
Order("created_at DESC").
First(&standard).Error
if err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
if cache != nil {
cache[category] = nil
}
return nil, nil
}
return nil, err
}
standardCopy := standard
if cache != nil {
cache[category] = &standardCopy
}
return &standardCopy, nil
}
func cloneFloat64(value *float64) *float64 {
if value == nil {
return nil
}
copy := *value
return &copy
}
func float64Ptr(value float64) *float64 {
copy := value
return &copy
}
func (s *uniformityService) rollbackUniformityCreate(ctx context.Context, uniformityID uint) {
if uniformityID == 0 {
return