mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 05:21:57 +00:00
Merge branch 'development' of https://gitlab.com/mbugroup/lti-api into FEAT/BE/report_customer_payment
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
ALTER TABLE recording_eggs
|
||||
DROP COLUMN IF EXISTS total_used,
|
||||
DROP COLUMN IF EXISTS total_qty;
|
||||
@@ -0,0 +1,7 @@
|
||||
ALTER TABLE recording_eggs
|
||||
ADD COLUMN total_qty NUMERIC(15, 3) DEFAULT 0 NOT NULL,
|
||||
ADD COLUMN total_used NUMERIC(15, 3) DEFAULT 0 NOT NULL;
|
||||
|
||||
UPDATE recording_eggs
|
||||
SET total_qty = qty
|
||||
WHERE total_qty = 0;
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
-- Rollback: add price back to nonstock_suppliers
|
||||
ALTER TABLE nonstock_suppliers
|
||||
ADD COLUMN IF NOT EXISTS price NUMERIC(15, 3) NOT NULL DEFAULT 0;
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
-- Migration: remove price from nonstock_suppliers
|
||||
ALTER TABLE nonstock_suppliers
|
||||
DROP COLUMN IF EXISTS price;
|
||||
@@ -5,7 +5,6 @@ import "time"
|
||||
type NonstockSupplier struct {
|
||||
NonstockId uint `gorm:"not null"`
|
||||
SupplierId uint `gorm:"not null"`
|
||||
Price float64 `gorm:"type:numeric(15,3);not null;default:0"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime"`
|
||||
|
||||
Nonstock Nonstock `gorm:"foreignKey:NonstockId;references:Id"`
|
||||
|
||||
@@ -7,6 +7,8 @@ type RecordingEgg struct {
|
||||
RecordingId uint `gorm:"column:recording_id;not null;index"`
|
||||
ProductWarehouseId uint `gorm:"column:product_warehouse_id;not null"`
|
||||
Qty int `gorm:"column:qty;not null"`
|
||||
TotalQty float64 `gorm:"column:total_qty"`
|
||||
TotalUsed float64 `gorm:"column:total_used"`
|
||||
Weight *float64 `gorm:"column:weight"`
|
||||
CreatedBy uint `gorm:"column:created_by"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime"`
|
||||
|
||||
@@ -240,3 +240,15 @@ const (
|
||||
P_UserGetAll = "lti.users.list"
|
||||
P_UserGetOne = "lti.users.detail"
|
||||
)
|
||||
|
||||
// daily-checklist
|
||||
const (
|
||||
P_DailyChecklistDashboardList = "lti.daily_checklist.dashboard.list"
|
||||
P_DailyChecklistCreateOne = "lti.daily_checklist.create"
|
||||
P_DailyChecklistGetAll = "lti.daily_checklist.list"
|
||||
P_DailyChecklistGetOne = "lti.daily_checklist.detail"
|
||||
P_DailyChecklistReports = "lti.daily_checklist.reports"
|
||||
P_DailyChecklistEmployee = "lti.daily_checklist.master_data.employee"
|
||||
P_DailyChecklistActivity = "lti.daily_checklist.master_data.activity"
|
||||
P_DailyChecklistActivityConfig = "lti.daily_checklist.master_data.configuration"
|
||||
)
|
||||
|
||||
@@ -15,49 +15,49 @@ func DailyChecklistRoutes(v1 fiber.Router, u user.UserService, s dailyChecklist.
|
||||
route := v1.Group("/daily-checklists")
|
||||
route.Use(m.Auth(u))
|
||||
|
||||
route.Get("/", ctrl.GetAll)
|
||||
route.Get("/report", ctrl.GetReport)
|
||||
route.Get("/", m.RequirePermissions(m.P_DailyChecklistGetAll), ctrl.GetAll)
|
||||
route.Get("/report", m.RequirePermissions(m.P_DailyChecklistReports), ctrl.GetReport)
|
||||
|
||||
route.Get("/summary", ctrl.GetSummary)
|
||||
route.Get("/summary", m.RequirePermissions(m.P_DailyChecklistDashboardList), ctrl.GetSummary)
|
||||
|
||||
route.Get("/report", ctrl.GetReport)
|
||||
// route.Get("/report", ctrl.GetReport)
|
||||
|
||||
// upsert daily checklist
|
||||
route.Post("/", ctrl.CreateOne)
|
||||
route.Post("/", m.RequirePermissions(m.P_DailyChecklistCreateOne), ctrl.CreateOne)
|
||||
|
||||
// get detail data daily checklist by id
|
||||
route.Get("/relation/:idDailyChecklist", ctrl.GetOne)
|
||||
route.Get("/relation/:idDailyChecklist", m.RequirePermissions(m.P_DailyChecklistGetOne), ctrl.GetOne)
|
||||
|
||||
// get phases by daily checklist id
|
||||
route.Get("/phase/:idDailyChecklist", ctrl.GetPhaseByIdChecklist)
|
||||
route.Get("/phase/:idDailyChecklist", m.RequirePermissions(m.P_DailyChecklistCreateOne), ctrl.GetPhaseByIdChecklist)
|
||||
|
||||
// create task
|
||||
/*
|
||||
ketika add phase
|
||||
*/
|
||||
route.Post("/phase/:idDailyChecklist", ctrl.CreateDailyChecklistPhase)
|
||||
route.Post("/phase/:idDailyChecklist", m.RequirePermissions(m.P_DailyChecklistCreateOne), ctrl.CreateDailyChecklistPhase)
|
||||
|
||||
// create assigment
|
||||
/*
|
||||
ketika add ABK
|
||||
*/
|
||||
route.Post("/assignment/:idDailyChecklist", ctrl.CreateAssignment)
|
||||
route.Post("/assignment/:idDailyChecklist", m.RequirePermissions(m.P_DailyChecklistCreateOne), ctrl.CreateAssignment)
|
||||
|
||||
// remove assignment
|
||||
/*
|
||||
ketika remove ABK
|
||||
*/
|
||||
route.Delete("/:idDailyChecklist/assignments/:idEmployee", ctrl.RemoveAssignment)
|
||||
route.Delete("/:idDailyChecklist/assignments/:idEmployee", m.RequirePermissions(m.P_DailyChecklistCreateOne), ctrl.RemoveAssignment)
|
||||
|
||||
//get all tasks
|
||||
route.Get("/tasks", ctrl.GetAllTasks)
|
||||
route.Get("/tasks", m.RequirePermissions(m.P_DailyChecklistCreateOne), ctrl.GetAllTasks)
|
||||
|
||||
// update assignment
|
||||
/*
|
||||
ketika check dan uncheck tugas oleh ABK
|
||||
*/
|
||||
route.Post("/assignment", ctrl.UpdateAssignment)
|
||||
route.Post("/assignment", m.RequirePermissions(m.P_DailyChecklistCreateOne), ctrl.UpdateAssignment)
|
||||
|
||||
route.Patch("/:idDailyChecklist", ctrl.UpdateOne)
|
||||
route.Delete("/:idDailyChecklist", ctrl.DeleteOne)
|
||||
route.Patch("/:idDailyChecklist", m.RequirePermissions(m.P_DailyChecklistCreateOne), ctrl.UpdateOne)
|
||||
route.Delete("/:idDailyChecklist", m.RequirePermissions(m.P_DailyChecklistCreateOne), ctrl.DeleteOne)
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@ func ConfigChecklistRoutes(v1 fiber.Router, u user.UserService, s configChecklis
|
||||
route := v1.Group("/config-checklists")
|
||||
route.Use(m.Auth(u))
|
||||
|
||||
route.Get("/", ctrl.GetAll)
|
||||
route.Post("/", ctrl.CreateOne)
|
||||
route.Get("/:id", ctrl.GetOne)
|
||||
route.Patch("/:id", ctrl.UpdateOne)
|
||||
route.Delete("/:id", ctrl.DeleteOne)
|
||||
route.Get("/", m.RequirePermissions(m.P_DailyChecklistActivityConfig), ctrl.GetAll)
|
||||
route.Post("/", m.RequirePermissions(m.P_DailyChecklistActivityConfig), ctrl.CreateOne)
|
||||
route.Get("/:id", m.RequirePermissions(m.P_DailyChecklistActivityConfig), ctrl.GetOne)
|
||||
route.Patch("/:id", m.RequirePermissions(m.P_DailyChecklistActivityConfig), ctrl.UpdateOne)
|
||||
route.Delete("/:id", m.RequirePermissions(m.P_DailyChecklistActivityConfig), ctrl.DeleteOne)
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@ func EmployeesRoutes(v1 fiber.Router, u user.UserService, s employees.EmployeesS
|
||||
route := v1.Group("/employees")
|
||||
route.Use(m.Auth(u))
|
||||
|
||||
route.Get("/", ctrl.GetAll)
|
||||
route.Post("/", ctrl.CreateOne)
|
||||
route.Get("/:id", ctrl.GetOne)
|
||||
route.Patch("/:id", ctrl.UpdateOne)
|
||||
route.Delete("/:id", ctrl.DeleteOne)
|
||||
route.Get("/", m.RequirePermissions(m.P_DailyChecklistEmployee), ctrl.GetAll)
|
||||
route.Post("/", m.RequirePermissions(m.P_DailyChecklistEmployee), ctrl.CreateOne)
|
||||
route.Get("/:id", m.RequirePermissions(m.P_DailyChecklistEmployee), ctrl.GetOne)
|
||||
route.Patch("/:id", m.RequirePermissions(m.P_DailyChecklistEmployee), ctrl.UpdateOne)
|
||||
route.Delete("/:id", m.RequirePermissions(m.P_DailyChecklistEmployee), ctrl.DeleteOne)
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ type NonstockSupplierDTO struct {
|
||||
Name string `json:"name"`
|
||||
Alias string `json:"alias"`
|
||||
Category string `json:"category"`
|
||||
Price float64 `json:"price"`
|
||||
}
|
||||
|
||||
// === Mapper Functions ===
|
||||
@@ -121,7 +120,6 @@ func toNonstockSupplierDTOs(relations []entity.NonstockSupplier) []NonstockSuppl
|
||||
Name: relation.Supplier.Name,
|
||||
Alias: relation.Supplier.Alias,
|
||||
Category: relation.Supplier.Category,
|
||||
Price: relation.Price,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -61,30 +61,20 @@ func (r *NonstockRepositoryImpl) SyncSuppliersDiff(ctx context.Context, tx *gorm
|
||||
return err
|
||||
}
|
||||
|
||||
existingMap := make(map[uint]entity.NonstockSupplier, len(existing))
|
||||
existingMap := make(map[uint]struct{}, len(existing))
|
||||
for _, rel := range existing {
|
||||
existingMap[rel.SupplierId] = rel
|
||||
existingMap[rel.SupplierId] = struct{}{}
|
||||
}
|
||||
|
||||
incomingMap := make(map[uint]struct{}, len(suppliers))
|
||||
for _, rel := range suppliers {
|
||||
incomingMap[rel.SupplierId] = struct{}{}
|
||||
if existingRel, exists := existingMap[rel.SupplierId]; exists {
|
||||
if existingRel.Price != rel.Price {
|
||||
if err := db.WithContext(ctx).
|
||||
Model(&entity.NonstockSupplier{}).
|
||||
Where("nonstock_id = ? AND supplier_id = ?", nonstockID, rel.SupplierId).
|
||||
Update("price", rel.Price).
|
||||
Error; err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if _, exists := existingMap[rel.SupplierId]; exists {
|
||||
continue
|
||||
}
|
||||
record := entity.NonstockSupplier{
|
||||
NonstockId: nonstockID,
|
||||
SupplierId: rel.SupplierId,
|
||||
Price: rel.Price,
|
||||
}
|
||||
if err := db.WithContext(ctx).Create(&record).Error; err != nil {
|
||||
return err
|
||||
|
||||
@@ -115,19 +115,18 @@ func (s *nonstockService) CreateOne(c *fiber.Ctx, req *validation.Create) (*enti
|
||||
supplierLinks []entity.NonstockSupplier
|
||||
supplierIDs []uint
|
||||
)
|
||||
if len(req.Suppliers) > 0 {
|
||||
seen := make(map[uint]struct{}, len(req.Suppliers))
|
||||
supplierLinks = make([]entity.NonstockSupplier, 0, len(req.Suppliers))
|
||||
supplierIDs = make([]uint, 0, len(req.Suppliers))
|
||||
for _, supplier := range req.Suppliers {
|
||||
if _, exists := seen[supplier.SupplierID]; exists {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Duplicate supplier_id %d", supplier.SupplierID))
|
||||
if len(req.SupplierIDs) > 0 {
|
||||
seen := make(map[uint]struct{}, len(req.SupplierIDs))
|
||||
supplierLinks = make([]entity.NonstockSupplier, 0, len(req.SupplierIDs))
|
||||
supplierIDs = make([]uint, 0, len(req.SupplierIDs))
|
||||
for _, supplierID := range req.SupplierIDs {
|
||||
if _, exists := seen[supplierID]; exists {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Duplicate supplier_id %d", supplierID))
|
||||
}
|
||||
seen[supplier.SupplierID] = struct{}{}
|
||||
supplierIDs = append(supplierIDs, supplier.SupplierID)
|
||||
seen[supplierID] = struct{}{}
|
||||
supplierIDs = append(supplierIDs, supplierID)
|
||||
supplierLinks = append(supplierLinks, entity.NonstockSupplier{
|
||||
SupplierId: supplier.SupplierID,
|
||||
Price: supplier.Price,
|
||||
SupplierId: supplierID,
|
||||
})
|
||||
}
|
||||
supplierList, supplierErr := s.Repository.GetSuppliersByIDs(ctx, supplierIDs)
|
||||
@@ -212,21 +211,20 @@ func (s nonstockService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uint
|
||||
|
||||
var supplierLinks []entity.NonstockSupplier
|
||||
var supplierUpdate bool
|
||||
if req.Suppliers != nil {
|
||||
if req.SupplierIDs != nil {
|
||||
supplierUpdate = true
|
||||
if len(*req.Suppliers) > 0 {
|
||||
seen := make(map[uint]struct{}, len(*req.Suppliers))
|
||||
supplierLinks = make([]entity.NonstockSupplier, 0, len(*req.Suppliers))
|
||||
supplierIDs := make([]uint, 0, len(*req.Suppliers))
|
||||
for _, supplier := range *req.Suppliers {
|
||||
if _, exists := seen[supplier.SupplierID]; exists {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Duplicate supplier_id %d", supplier.SupplierID))
|
||||
if len(*req.SupplierIDs) > 0 {
|
||||
seen := make(map[uint]struct{}, len(*req.SupplierIDs))
|
||||
supplierLinks = make([]entity.NonstockSupplier, 0, len(*req.SupplierIDs))
|
||||
supplierIDs := make([]uint, 0, len(*req.SupplierIDs))
|
||||
for _, supplierID := range *req.SupplierIDs {
|
||||
if _, exists := seen[supplierID]; exists {
|
||||
return nil, fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Duplicate supplier_id %d", supplierID))
|
||||
}
|
||||
seen[supplier.SupplierID] = struct{}{}
|
||||
supplierIDs = append(supplierIDs, supplier.SupplierID)
|
||||
seen[supplierID] = struct{}{}
|
||||
supplierIDs = append(supplierIDs, supplierID)
|
||||
supplierLinks = append(supplierLinks, entity.NonstockSupplier{
|
||||
SupplierId: supplier.SupplierID,
|
||||
Price: supplier.Price,
|
||||
SupplierId: supplierID,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +1,17 @@
|
||||
package validation
|
||||
|
||||
type SupplierPrice struct {
|
||||
SupplierID uint `json:"supplier_id" validate:"required,gt=0"`
|
||||
Price float64 `json:"price" validate:"required,gte=0"`
|
||||
}
|
||||
|
||||
type Create struct {
|
||||
Name string `json:"name" validate:"required_strict,min=3,max=50"`
|
||||
UomID uint `json:"uom_id" validate:"required,gt=0"`
|
||||
Suppliers []SupplierPrice `json:"suppliers,omitempty" validate:"omitempty,dive"`
|
||||
Flags []string `json:"flags" validate:"dive,max=50"`
|
||||
Name string `json:"name" validate:"required_strict,min=3,max=50"`
|
||||
UomID uint `json:"uom_id" validate:"required,gt=0"`
|
||||
SupplierIDs []uint `json:"supplier_ids,omitempty" validate:"omitempty,dive,gt=0"`
|
||||
Flags []string `json:"flags" validate:"dive,max=50"`
|
||||
}
|
||||
|
||||
type Update struct {
|
||||
Name *string `json:"name,omitempty" validate:"omitempty,min=3,max=50"`
|
||||
UomID *uint `json:"uom_id,omitempty" validate:"omitempty,gt=0"`
|
||||
Suppliers *[]SupplierPrice `json:"suppliers,omitempty" validate:"omitempty,dive"`
|
||||
Flags *[]string `json:"flags,omitempty" validate:"omitempty,dive,max=50"`
|
||||
Name *string `json:"name,omitempty" validate:"omitempty,min=3,max=50"`
|
||||
UomID *uint `json:"uom_id,omitempty" validate:"omitempty,gt=0"`
|
||||
SupplierIDs *[]uint `json:"supplier_ids,omitempty" validate:"omitempty,dive,gt=0"`
|
||||
Flags *[]string `json:"flags,omitempty" validate:"omitempty,dive,max=50"`
|
||||
}
|
||||
|
||||
type Query struct {
|
||||
|
||||
@@ -15,9 +15,9 @@ func PhaseActivityRoutes(v1 fiber.Router, u user.UserService, s phaseActivity.Ph
|
||||
route := v1.Group("/phase-activities")
|
||||
route.Use(m.Auth(u))
|
||||
|
||||
route.Get("/", ctrl.GetAll)
|
||||
route.Post("/", ctrl.CreateOne)
|
||||
route.Get("/:id", ctrl.GetOne)
|
||||
route.Patch("/:id", ctrl.UpdateOne)
|
||||
route.Delete("/:id", ctrl.DeleteOne)
|
||||
route.Get("/", m.RequirePermissions(m.P_DailyChecklistActivity), ctrl.GetAll)
|
||||
route.Post("/", m.RequirePermissions(m.P_DailyChecklistActivity), ctrl.CreateOne)
|
||||
route.Get("/:id", m.RequirePermissions(m.P_DailyChecklistActivity), ctrl.GetOne)
|
||||
route.Patch("/:id", m.RequirePermissions(m.P_DailyChecklistActivity), ctrl.UpdateOne)
|
||||
route.Delete("/:id", m.RequirePermissions(m.P_DailyChecklistActivity), ctrl.DeleteOne)
|
||||
}
|
||||
|
||||
@@ -15,9 +15,9 @@ func PhasesRoutes(v1 fiber.Router, u user.UserService, s phases.PhasesService) {
|
||||
route := v1.Group("/phases")
|
||||
route.Use(m.Auth(u))
|
||||
|
||||
route.Get("/", ctrl.GetAll)
|
||||
route.Post("/", ctrl.CreateOne)
|
||||
route.Get("/:id", ctrl.GetOne)
|
||||
route.Patch("/:id", ctrl.UpdateOne)
|
||||
route.Delete("/:id", ctrl.DeleteOne)
|
||||
route.Get("/", m.RequirePermissions(m.P_DailyChecklistActivity), ctrl.GetAll)
|
||||
route.Post("/", m.RequirePermissions(m.P_DailyChecklistActivity), ctrl.CreateOne)
|
||||
route.Get("/:id", m.RequirePermissions(m.P_DailyChecklistActivity), ctrl.GetOne)
|
||||
route.Patch("/:id", m.RequirePermissions(m.P_DailyChecklistActivity), ctrl.UpdateOne)
|
||||
route.Delete("/:id", m.RequirePermissions(m.P_DailyChecklistActivity), ctrl.DeleteOne)
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
type SupplierNonstockDTO struct {
|
||||
Id uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Price float64 `json:"price"`
|
||||
Uom *uomDTO.UomRelationDTO `json:"uom,omitempty"`
|
||||
Flags []string `json:"flags"`
|
||||
}
|
||||
@@ -43,7 +42,6 @@ func toSupplierNonstockDTOs(relations []entity.NonstockSupplier) []SupplierNonst
|
||||
result = append(result, SupplierNonstockDTO{
|
||||
Id: Nonstock.Id,
|
||||
Name: Nonstock.Name,
|
||||
Price: relation.Price,
|
||||
Uom: uomRef,
|
||||
Flags: flags,
|
||||
})
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
warehouseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/dto"
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/dto"
|
||||
service "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/services"
|
||||
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/production/project_flocks/validations"
|
||||
@@ -278,14 +279,22 @@ func (u *ProjectflockController) LookupProjectFlockKandang(c *fiber.Ctx) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_ = availableStock
|
||||
|
||||
dtoResult := dto.ToProjectFlockKandangDTO(*result)
|
||||
dtoResult.AvailableQuantity = float64(availableStock)
|
||||
if population, err := u.ProjectflockService.GetProjectFlockKandangPopulation(c, result.Id); err != nil {
|
||||
return err
|
||||
} else {
|
||||
dtoResult.AvailableQuantity = population
|
||||
}
|
||||
if warehouse, werr := u.ProjectflockService.GetWarehouseByKandangID(c, result.KandangId); werr != nil {
|
||||
return werr
|
||||
} else if warehouse != nil {
|
||||
mapped := warehouseDTO.ToWarehouseRelationDTO(*warehouse)
|
||||
dtoResult.Warehouse = &mapped
|
||||
}
|
||||
if withPopulation {
|
||||
population, err := u.ProjectflockService.GetProjectFlockKandangPopulation(c, result.Id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
population := dtoResult.AvailableQuantity
|
||||
dtoResult.Population = &population
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
kandangDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/kandangs/dto"
|
||||
locationDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/locations/dto"
|
||||
productionStandardDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/production-standards/dto"
|
||||
warehouseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/dto"
|
||||
userDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/users/dto"
|
||||
)
|
||||
|
||||
@@ -17,24 +18,26 @@ type KandangWithPivotDTO struct {
|
||||
|
||||
type ProjectFlockWithPivotDTO struct {
|
||||
ProjectFlockRelationDTO
|
||||
Area *areaDTO.AreaRelationDTO `json:"area,omitempty"`
|
||||
Category string `json:"category"`
|
||||
Fcr *fcrDTO.FcrRelationDTO `json:"fcr,omitempty"`
|
||||
ProductionStandard *productionStandardDTO.ProductionStandardRelationDTO `json:"production_standard,omitempty"`
|
||||
Location *locationDTO.LocationRelationDTO `json:"location,omitempty"`
|
||||
Kandangs []KandangWithPivotDTO `json:"kandangs,omitempty"`
|
||||
CreatedUser *userDTO.UserRelationDTO `json:"created_user,omitempty"`
|
||||
Area *areaDTO.AreaRelationDTO `json:"area,omitempty"`
|
||||
Category string `json:"category"`
|
||||
Fcr *fcrDTO.FcrRelationDTO `json:"fcr,omitempty"`
|
||||
ProductionStandard *productionStandardDTO.ProductionStandardRelationDTO `json:"production_standard,omitempty"`
|
||||
ProductionStandardId uint `json:"production_standard_id"`
|
||||
Location *locationDTO.LocationRelationDTO `json:"location,omitempty"`
|
||||
Kandangs []KandangWithPivotDTO `json:"kandangs,omitempty"`
|
||||
CreatedUser *userDTO.UserRelationDTO `json:"created_user,omitempty"`
|
||||
}
|
||||
|
||||
type ProjectFlockKandangDTO struct {
|
||||
Id uint `json:"id"`
|
||||
ProjectFlockKandangId uint `json:"project_flock_kandang_id"`
|
||||
ProjectFlockId uint `json:"project_flock_id"`
|
||||
KandangId uint `json:"kandang_id"`
|
||||
Kandang *kandangDTO.KandangRelationDTO `json:"kandang,omitempty"`
|
||||
ProjectFlock *ProjectFlockWithPivotDTO `json:"project_flock,omitempty"`
|
||||
AvailableQuantity float64 `json:"available_quantity"`
|
||||
Population *float64 `json:"population,omitempty"`
|
||||
Id uint `json:"id"`
|
||||
ProjectFlockKandangId uint `json:"project_flock_kandang_id"`
|
||||
ProjectFlockId uint `json:"project_flock_id"`
|
||||
KandangId uint `json:"kandang_id"`
|
||||
Kandang *kandangDTO.KandangRelationDTO `json:"kandang,omitempty"`
|
||||
Warehouse *warehouseDTO.WarehouseRelationDTO `json:"warehouse,omitempty"`
|
||||
ProjectFlock *ProjectFlockWithPivotDTO `json:"project_flock,omitempty"`
|
||||
AvailableQuantity float64 `json:"available_quantity"`
|
||||
Population *float64 `json:"population,omitempty"`
|
||||
}
|
||||
|
||||
func ToProjectFlockKandangDTO(e entity.ProjectFlockKandang) ProjectFlockKandangDTO {
|
||||
@@ -53,7 +56,8 @@ func ToProjectFlockKandangDTO(e entity.ProjectFlockKandang) ProjectFlockKandangD
|
||||
Period: e.Period,
|
||||
FlockName: e.ProjectFlock.FlockName,
|
||||
},
|
||||
Category: e.ProjectFlock.Category,
|
||||
Category: e.ProjectFlock.Category,
|
||||
ProductionStandardId: e.ProjectFlock.ProductionStandardId,
|
||||
}
|
||||
|
||||
if e.ProjectFlock.Area.Id != 0 {
|
||||
|
||||
@@ -38,6 +38,7 @@ type ProjectflockService interface {
|
||||
GetOne(ctx *fiber.Ctx, id uint) (*entity.ProjectFlock, *flockDTO.FlockRelationDTO, error)
|
||||
CreateOne(ctx *fiber.Ctx, req *validation.Create) (*entity.ProjectFlock, error)
|
||||
GetAvailableDocQuantity(ctx *fiber.Ctx, kandangID uint) (float64, error)
|
||||
GetWarehouseByKandangID(ctx *fiber.Ctx, kandangID uint) (*entity.Warehouse, error)
|
||||
DeleteOne(ctx *fiber.Ctx, id uint) error
|
||||
GetProjectFlockKandangByProjectAndKandang(ctx *fiber.Ctx, projectFlockID uint, kandangID uint) (*entity.ProjectFlockKandang, float64, error)
|
||||
GetProjectFlockKandangPopulation(ctx *fiber.Ctx, projectFlockKandangID uint) (float64, error)
|
||||
@@ -518,6 +519,31 @@ func (s projectflockService) GetAvailableDocQuantity(ctx *fiber.Ctx, kandangID u
|
||||
return total, nil
|
||||
}
|
||||
|
||||
func (s projectflockService) GetWarehouseByKandangID(ctx *fiber.Ctx, kandangID uint) (*entity.Warehouse, error) {
|
||||
if kandangID == 0 || s.WarehouseRepo == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var warehouse entity.Warehouse
|
||||
err := s.WarehouseRepo.DB().WithContext(ctx.Context()).
|
||||
Preload("Area").
|
||||
Preload("Location").
|
||||
Preload("Kandang").
|
||||
Where("kandang_id = ?", kandangID).
|
||||
Where("deleted_at IS NULL").
|
||||
Order("id DESC").
|
||||
First(&warehouse).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
s.Log.Errorf("Failed to fetch warehouse for kandang %d: %+v", kandangID, err)
|
||||
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch warehouse")
|
||||
}
|
||||
|
||||
return &warehouse, nil
|
||||
}
|
||||
|
||||
func (s projectflockService) GetProjectPeriods(c *fiber.Ctx, projectIDs []uint) (map[uint]int, error) {
|
||||
if len(projectIDs) == 0 {
|
||||
return map[uint]int{}, nil
|
||||
|
||||
@@ -82,11 +82,11 @@ type RecordingListDTO struct {
|
||||
CreatedUser *userDTO.UserRelationDTO `json:"created_user,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
Warehouse *RecordingWarehouseDTO `json:"warehouse,omitempty"`
|
||||
}
|
||||
|
||||
type RecordingDetailDTO struct {
|
||||
RecordingListDTO
|
||||
Warehouse *RecordingWarehouseDTO `json:"warehouse,omitempty"`
|
||||
ProductCategory string `json:"product_category"`
|
||||
Depletions []RecordingDepletionDTO `json:"depletions"`
|
||||
Stocks []RecordingStockDTO `json:"stocks"`
|
||||
@@ -133,7 +133,6 @@ func ToRecordingDetailDTO(e entity.Recording) RecordingDetailDTO {
|
||||
|
||||
return RecordingDetailDTO{
|
||||
RecordingListDTO: listDTO,
|
||||
Warehouse: recordingWarehouseDTO(e),
|
||||
ProductCategory: recordingProductCategory(e),
|
||||
Depletions: ToRecordingDepletionDTOs(e.Depletions),
|
||||
Stocks: ToRecordingStockDTOs(e.Stocks),
|
||||
@@ -203,6 +202,7 @@ func toRecordingListDTO(e entity.Recording) RecordingListDTO {
|
||||
CreatedAt: e.CreatedAt,
|
||||
UpdatedAt: e.UpdatedAt,
|
||||
CreatedUser: createdUser,
|
||||
Warehouse: recordingWarehouseDTO(e),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,6 +43,22 @@ func (RecordingModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate
|
||||
)
|
||||
|
||||
fifoService := commonSvc.NewFifoService(db, stockAllocationRepo, productWarehouseRepo, utils.Log)
|
||||
if err := fifoService.RegisterStockable(fifo.StockableConfig{
|
||||
Key: fifo.StockableKeyRecordingEgg,
|
||||
Table: "recording_eggs",
|
||||
Columns: fifo.StockableColumns{
|
||||
ID: "id",
|
||||
ProductWarehouseID: "product_warehouse_id",
|
||||
TotalQuantity: "total_qty",
|
||||
TotalUsedQuantity: "total_used",
|
||||
CreatedAt: "created_at",
|
||||
},
|
||||
OrderBy: []string{"created_at ASC", "id ASC"},
|
||||
}); err != nil {
|
||||
if !strings.Contains(strings.ToLower(err.Error()), "already registered") {
|
||||
panic(fmt.Sprintf("failed to register recording egg stockable workflow: %v", err))
|
||||
}
|
||||
}
|
||||
if err := fifoService.RegisterUsable(fifo.UsableConfig{
|
||||
Key: fifo.UsableKeyRecordingStock,
|
||||
Table: "recording_stocks",
|
||||
|
||||
@@ -290,8 +290,19 @@ func (s *recordingService) CreateOne(c *fiber.Ctx, req *validation.Create) (*ent
|
||||
s.Log.Errorf("Failed to persist eggs: %+v", err)
|
||||
return err
|
||||
}
|
||||
if s.FifoSvc != nil {
|
||||
if err := s.replenishRecordingEggs(ctx, tx, mappedEggs); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(nil, mappedDepletions, nil, mappedEggs)); err != nil {
|
||||
var warehouseDeltas map[uint]float64
|
||||
if s.FifoSvc != nil {
|
||||
warehouseDeltas = buildWarehouseDeltas(nil, mappedDepletions, nil, nil)
|
||||
} else {
|
||||
warehouseDeltas = buildWarehouseDeltas(nil, mappedDepletions, nil, mappedEggs)
|
||||
}
|
||||
if err := s.adjustProductWarehouseQuantities(ctx, tx, warehouseDeltas); err != nil {
|
||||
s.Log.Errorf("Failed to adjust product warehouses: %+v", err)
|
||||
return err
|
||||
}
|
||||
@@ -438,6 +449,16 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin
|
||||
}
|
||||
|
||||
if hasEggChanges {
|
||||
if s.FifoSvc != nil {
|
||||
if err := ensureRecordingEggsUnused(existingEggs); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(nil, nil, existingEggs, nil)); err != nil {
|
||||
s.Log.Errorf("Failed to adjust product warehouses for eggs: %+v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := s.Repository.DeleteEggs(tx, recordingEntity.Id); err != nil {
|
||||
s.Log.Errorf("Failed to clear eggs: %+v", err)
|
||||
return err
|
||||
@@ -449,9 +470,15 @@ func (s recordingService) UpdateOne(c *fiber.Ctx, req *validation.Update, id uin
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(nil, nil, existingEggs, mappedEggs)); err != nil {
|
||||
s.Log.Errorf("Failed to adjust product warehouses for eggs: %+v", err)
|
||||
return err
|
||||
if s.FifoSvc != nil {
|
||||
if err := s.replenishRecordingEggs(ctx, tx, mappedEggs); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err := s.adjustProductWarehouseQuantities(ctx, tx, buildWarehouseDeltas(nil, nil, existingEggs, mappedEggs)); err != nil {
|
||||
s.Log.Errorf("Failed to adjust product warehouses for eggs: %+v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -626,6 +653,11 @@ func (s recordingService) DeleteOne(c *fiber.Ctx, id uint) error {
|
||||
s.Log.Errorf("Failed to list eggs before delete: %+v", err)
|
||||
return err
|
||||
}
|
||||
if s.FifoSvc != nil {
|
||||
if err := ensureRecordingEggsUnused(oldEggs); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
oldStocks, err := s.Repository.ListStocks(tx, id)
|
||||
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
@@ -802,6 +834,32 @@ func (s *recordingService) adjustProductWarehouseQuantities(ctx context.Context,
|
||||
return s.ProductWarehouseRepo.AdjustQuantities(ctx, deltas, func(*gorm.DB) *gorm.DB { return tx })
|
||||
}
|
||||
|
||||
func (s *recordingService) replenishRecordingEggs(ctx context.Context, tx *gorm.DB, eggs []entity.RecordingEgg) error {
|
||||
if len(eggs) == 0 || s.FifoSvc == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, egg := range eggs {
|
||||
if egg.Id == 0 || egg.ProductWarehouseId == 0 || egg.Qty <= 0 {
|
||||
continue
|
||||
}
|
||||
note := fmt.Sprintf("Recording egg #%d", egg.Id)
|
||||
if _, err := s.FifoSvc.Replenish(ctx, commonSvc.StockReplenishRequest{
|
||||
StockableKey: fifo.StockableKeyRecordingEgg,
|
||||
StockableID: egg.Id,
|
||||
ProductWarehouseID: egg.ProductWarehouseId,
|
||||
Quantity: float64(egg.Qty),
|
||||
Note: ¬e,
|
||||
Tx: tx,
|
||||
}); err != nil {
|
||||
s.Log.Errorf("Failed to replenish FIFO stock for recording egg %d: %+v", egg.Id, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type desiredStock struct {
|
||||
Usage float64
|
||||
Pending float64
|
||||
@@ -922,6 +980,14 @@ type eggTotals struct {
|
||||
Weight float64
|
||||
}
|
||||
|
||||
func ensureRecordingEggsUnused(eggs []entity.RecordingEgg) error {
|
||||
for _, egg := range eggs {
|
||||
if egg.TotalUsed > 0 {
|
||||
return fiber.NewError(fiber.StatusBadRequest, "Recording egg sudah digunakan sehingga tidak dapat diubah")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func stocksMatch(existing []entity.RecordingStock, incoming []validation.Stock) bool {
|
||||
hasPending := false
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
expenseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/expenses/repositories"
|
||||
marketingRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/marketing/repositories"
|
||||
customerRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/master/customers/repositories"
|
||||
productionStandardRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/master/production-standards/repositories"
|
||||
chickinRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/repositories"
|
||||
recordingRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/repositories"
|
||||
purchaseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/purchases/repositories"
|
||||
@@ -37,10 +38,12 @@ func (RepportModule) RegisterRoutes(router fiber.Router, db *gorm.DB, validate *
|
||||
productionResultRepository := repportRepo.NewProductionResultRepository(db)
|
||||
customerPaymentRepository := repportRepo.NewCustomerPaymentRepository(db)
|
||||
customerRepository := customerRepo.NewCustomerRepository(db)
|
||||
standardGrowthDetailRepository := productionStandardRepo.NewStandardGrowthDetailRepository(db)
|
||||
productionStandardDetailRepository := productionStandardRepo.NewProductionStandardDetailRepository(db)
|
||||
userRepository := rUser.NewUserRepository(db)
|
||||
|
||||
approvalSvc := approvalService.NewApprovalService(approvalRepository)
|
||||
repportService := sRepport.NewRepportService(db, validate, expenseRealizationRepository, marketingDeliveryProductRepository, purchaseRepository, chickinRepository, recordingRepository, approvalSvc, purchaseSupplierRepository, debtSupplierRepository, hppPerKandangRepository, productionResultRepository, customerPaymentRepository, customerRepository)
|
||||
repportService := sRepport.NewRepportService(db, validate, expenseRealizationRepository, marketingDeliveryProductRepository, purchaseRepository, chickinRepository, recordingRepository, approvalSvc, purchaseSupplierRepository, debtSupplierRepository, hppPerKandangRepository, productionResultRepository, customerPaymentRepository, customerRepository, standardGrowthDetailRepository, productionStandardDetailRepository)
|
||||
userService := sUser.NewUserService(userRepository, validate)
|
||||
|
||||
RepportRoutes(router, userService, repportService)
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
type ProductionResultRepository interface {
|
||||
GetRecordingsByProjectFlockKandang(ctx context.Context, projectFlockKandangID uint, offset, limit int) ([]entity.Recording, int64, error)
|
||||
GetProductionStandardIDByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) (uint, error)
|
||||
}
|
||||
|
||||
type productionResultRepositoryImpl struct {
|
||||
@@ -76,3 +77,25 @@ func (r *productionResultRepositoryImpl) GetRecordingsByProjectFlockKandang(
|
||||
|
||||
return recordings, total, nil
|
||||
}
|
||||
|
||||
func (r *productionResultRepositoryImpl) GetProductionStandardIDByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) (uint, error) {
|
||||
if projectFlockKandangID == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var row struct {
|
||||
ProductionStandardID uint `gorm:"column:production_standard_id"`
|
||||
}
|
||||
|
||||
err := r.db.WithContext(ctx).
|
||||
Table("project_flock_kandangs pfk").
|
||||
Select("pf.production_standard_id").
|
||||
Joins("JOIN project_flocks pf ON pf.id = pfk.project_flock_id").
|
||||
Where("pfk.id = ?", projectFlockKandangID).
|
||||
Take(&row).Error
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return row.ProductionStandardID, nil
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"sort"
|
||||
@@ -22,6 +23,7 @@ import (
|
||||
customerRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/master/customers/repositories"
|
||||
supplierDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/suppliers/dto"
|
||||
warehouseDTO "gitlab.com/mbugroup/lti-api.git/internal/modules/master/warehouses/dto"
|
||||
productionStandardRepository "gitlab.com/mbugroup/lti-api.git/internal/modules/master/production-standards/repositories"
|
||||
chickinRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/production/chickins/repositories"
|
||||
recordingRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/production/recordings/repositories"
|
||||
purchaseRepo "gitlab.com/mbugroup/lti-api.git/internal/modules/purchases/repositories"
|
||||
@@ -60,6 +62,8 @@ type repportService struct {
|
||||
ProductionResultRepo repportRepo.ProductionResultRepository
|
||||
CustomerPaymentRepo repportRepo.CustomerPaymentRepository
|
||||
CustomerRepo customerRepo.CustomerRepository
|
||||
StandardGrowthDetailRepo productionStandardRepository.StandardGrowthDetailRepository
|
||||
ProductionStandardDetailRepo productionStandardRepository.ProductionStandardDetailRepository
|
||||
}
|
||||
|
||||
type HppCostAggregate struct {
|
||||
@@ -86,6 +90,8 @@ func NewRepportService(
|
||||
productionResultRepo repportRepo.ProductionResultRepository,
|
||||
customerPaymentRepo repportRepo.CustomerPaymentRepository,
|
||||
customerRepo customerRepo.CustomerRepository,
|
||||
standardGrowthDetailRepo productionStandardRepository.StandardGrowthDetailRepository,
|
||||
productionStandardDetailRepo productionStandardRepository.ProductionStandardDetailRepository,
|
||||
) RepportService {
|
||||
return &repportService{
|
||||
Log: utils.Log,
|
||||
@@ -103,6 +109,8 @@ func NewRepportService(
|
||||
ProductionResultRepo: productionResultRepo,
|
||||
CustomerPaymentRepo: customerPaymentRepo,
|
||||
CustomerRepo: customerRepo,
|
||||
StandardGrowthDetailRepo: standardGrowthDetailRepo,
|
||||
ProductionStandardDetailRepo: productionStandardDetailRepo,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -296,6 +304,21 @@ func (s *repportService) GetProductionResult(ctx *fiber.Ctx, params *validation.
|
||||
|
||||
weeklyResults := summarizeProductionResults(dailyResults, recordsPerWeek)
|
||||
|
||||
var productionStandardID uint
|
||||
if s.ProductionResultRepo != nil {
|
||||
standardID, err := s.ProductionResultRepo.GetProductionStandardIDByProjectFlockKandangID(ctx.Context(), params.ProjectFlockKandangID)
|
||||
if err != nil {
|
||||
if !errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
return nil, 0, err
|
||||
}
|
||||
} else {
|
||||
productionStandardID = standardID
|
||||
}
|
||||
}
|
||||
|
||||
standardDetailCache := make(map[int]*entity.ProductionStandardDetail)
|
||||
growthDetailCache := make(map[int]*entity.StandardGrowthDetail)
|
||||
|
||||
var cumulativeButir int64
|
||||
var cumulativeKg float64
|
||||
for i := range weeklyResults {
|
||||
@@ -311,6 +334,66 @@ func (s *repportService) GetProductionResult(ctx *fiber.Ctx, params *validation.
|
||||
|
||||
cumulativeKg += weeklyResults[i].KgJumlah
|
||||
weeklyResults[i].TotalKg = cumulativeKg
|
||||
|
||||
if productionStandardID == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
week := int(weeklyResults[i].Woa)
|
||||
if s.ProductionStandardDetailRepo != nil {
|
||||
detail, ok := standardDetailCache[week]
|
||||
if !ok {
|
||||
fetched, fetchErr := s.ProductionStandardDetailRepo.GetByStandardIDAndWeek(ctx.Context(), productionStandardID, week)
|
||||
if fetchErr != nil {
|
||||
if !errors.Is(fetchErr, gorm.ErrRecordNotFound) {
|
||||
return nil, 0, fetchErr
|
||||
}
|
||||
} else {
|
||||
detail = fetched
|
||||
}
|
||||
standardDetailCache[week] = detail
|
||||
}
|
||||
|
||||
if detail != nil {
|
||||
if detail.TargetHenDayProduction != nil {
|
||||
weeklyResults[i].HdStd = *detail.TargetHenDayProduction
|
||||
}
|
||||
if detail.TargetHenHouseProduction != nil {
|
||||
weeklyResults[i].HhStd = *detail.TargetHenHouseProduction
|
||||
}
|
||||
if detail.TargetEggWeight != nil {
|
||||
weeklyResults[i].EwStd = *detail.TargetEggWeight
|
||||
}
|
||||
if detail.TargetEggMass != nil {
|
||||
weeklyResults[i].EmStd = *detail.TargetEggMass
|
||||
}
|
||||
if detail.StandardFCR != nil {
|
||||
weeklyResults[i].FcrStd = *detail.StandardFCR
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if s.StandardGrowthDetailRepo != nil {
|
||||
detail, ok := growthDetailCache[week]
|
||||
if !ok {
|
||||
fetched, fetchErr := s.StandardGrowthDetailRepo.GetByStandardIDAndWeek(ctx.Context(), productionStandardID, week)
|
||||
if fetchErr != nil {
|
||||
if !errors.Is(fetchErr, gorm.ErrRecordNotFound) {
|
||||
return nil, 0, fetchErr
|
||||
}
|
||||
} else {
|
||||
detail = fetched
|
||||
}
|
||||
growthDetailCache[week] = detail
|
||||
}
|
||||
|
||||
if detail != nil && detail.FeedIntake != nil {
|
||||
weeklyResults[i].FiStd = *detail.FeedIntake
|
||||
}
|
||||
if detail != nil && detail.TargetMeanBw != nil {
|
||||
weeklyResults[i].StdBw = *detail.TargetMeanBw
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
totalWeeks := int64(math.Ceil(float64(totalRecordings) / float64(recordsPerWeek)))
|
||||
@@ -524,17 +607,17 @@ func mapRecordingToProductionResultDTO(record entity.Recording) dto.ProductionRe
|
||||
StdUniformity: "90% up",
|
||||
DepKum: valueOrZero(record.CumDepletionRate),
|
||||
DepStd: valueOrZero(record.TotalDepletionQty),
|
||||
Hd: valueOrZero(record.HenDay),
|
||||
Fi: valueOrZero(record.FeedIntake),
|
||||
Fcr: valueOrZero(record.FcrValue),
|
||||
Hh: valueOrZero(record.TotalChickQty),
|
||||
Hh: valueOrZero(record.HenHouse),
|
||||
Em: valueOrZero(record.EggMass),
|
||||
Ew: valueOrZero(record.EggWeight),
|
||||
}
|
||||
|
||||
if record.Day != nil {
|
||||
result.Woa = float64(*record.Day)
|
||||
}
|
||||
if record.CumIntake != nil {
|
||||
result.Fi = float64(*record.CumIntake)
|
||||
}
|
||||
|
||||
// avgWeight := calculateAverageBodyWeight(record.BodyWeights)
|
||||
avgWeight := 1.0
|
||||
if avgWeight > 0 {
|
||||
@@ -561,8 +644,6 @@ func mapRecordingToProductionResultDTO(record entity.Recording) dto.ProductionRe
|
||||
result.PersenPutih = roundFloat((float64(result.ButiranPutih)/total)*100, 2)
|
||||
result.PersenRetak = roundFloat((float64(result.ButiranRetak)/total)*100, 2)
|
||||
result.PersenPecah = roundFloat((float64(result.ButiranPecah)/total)*100, 2)
|
||||
result.Ew = (eggSummary.TotalKg * 1000) / total
|
||||
result.Em = eggSummary.TotalKg
|
||||
}
|
||||
|
||||
return result
|
||||
@@ -674,13 +755,13 @@ func summarizeProductionResults(daily []dto.ProductionResultDTO, groupSize int)
|
||||
if end > len(daily) {
|
||||
end = len(daily)
|
||||
}
|
||||
result = append(result, aggregateProductionResultGroup(daily[i:end]))
|
||||
result = append(result, aggregateProductionResultGroup(daily[i:end], groupSize))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func aggregateProductionResultGroup(group []dto.ProductionResultDTO) dto.ProductionResultDTO {
|
||||
func aggregateProductionResultGroup(group []dto.ProductionResultDTO, groupSize int) dto.ProductionResultDTO {
|
||||
count := len(group)
|
||||
if count == 0 {
|
||||
return dto.ProductionResultDTO{}
|
||||
@@ -752,6 +833,10 @@ func aggregateProductionResultGroup(group []dto.ProductionResultDTO) dto.Product
|
||||
if divider == 0 {
|
||||
divider = 1
|
||||
}
|
||||
weeklyDivider := float64(groupSize)
|
||||
if weeklyDivider == 0 {
|
||||
weeklyDivider = divider
|
||||
}
|
||||
|
||||
agg.Bw = sumBw / divider
|
||||
agg.StdBw = sumStdBw / divider
|
||||
@@ -780,17 +865,17 @@ func aggregateProductionResultGroup(group []dto.ProductionResultDTO) dto.Product
|
||||
agg.PersenPecah = roundFloat(sumPersenPecah/percentDivider, 2)
|
||||
}
|
||||
|
||||
agg.Hd = sumHd / divider
|
||||
agg.Hd = roundFloat(sumHd/weeklyDivider, 2)
|
||||
agg.HdStd = sumHdStd / divider
|
||||
agg.Fi = sumFi / divider
|
||||
agg.Fi = roundFloat(sumFi/weeklyDivider, 2)
|
||||
agg.FiStd = sumFiStd / divider
|
||||
agg.Em = sumEm / divider
|
||||
agg.Em = group[count-1].Em
|
||||
agg.EmStd = sumEmStd / divider
|
||||
agg.Ew = sumEw / divider
|
||||
agg.Ew = group[count-1].Ew
|
||||
agg.EwStd = sumEwStd / divider
|
||||
agg.Fcr = sumFcr / divider
|
||||
agg.Fcr = roundFloat(sumFcr/weeklyDivider, 2)
|
||||
agg.FcrStd = sumFcrStd / divider
|
||||
agg.Hh = sumHh / divider
|
||||
agg.Hh = roundFloat(sumHh/weeklyDivider, 2)
|
||||
agg.HhStd = sumHhStd / divider
|
||||
|
||||
return agg
|
||||
|
||||
@@ -15,4 +15,5 @@ const (
|
||||
StockableKeyAdjustmentIn StockableKey = "ADJUSTMENT_IN"
|
||||
StockableKeyPurchaseItems StockableKey = "PURCHASE_ITEMS"
|
||||
StockableKeyProjectFlockPopulation StockableKey = "PROJECT_FLOCK_POPULATION"
|
||||
StockableKeyRecordingEgg StockableKey = "RECORDING_EGG"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user