mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
Merge branch 'feat/informasi-umum' into 'development'
adjust api informasi umum filter per kandang See merge request mbugroup/lti-api!177
This commit is contained in:
@@ -116,7 +116,17 @@ func (u *ClosingController) GetClosingSummary(c *fiber.Ctx) error {
|
|||||||
return fiber.NewError(fiber.StatusBadRequest, "Invalid projectFlockId")
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid projectFlockId")
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := u.ClosingService.GetClosingSummary(c, uint(id))
|
var kandangID *uint
|
||||||
|
if raw := c.Query("kandang_id"); raw != "" {
|
||||||
|
kandangInt, convErr := strconv.Atoi(raw)
|
||||||
|
if convErr != nil || kandangInt <= 0 {
|
||||||
|
return fiber.NewError(fiber.StatusBadRequest, "Invalid kandang_id")
|
||||||
|
}
|
||||||
|
kandangUint := uint(kandangInt)
|
||||||
|
kandangID = &kandangUint
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := u.ClosingService.GetClosingSummary(c, uint(id), kandangID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,6 +59,21 @@ type ClosingSummaryDTO struct {
|
|||||||
StatusClosing string `json:"closing_status"`
|
StatusClosing string `json:"closing_status"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ClosingSummaryKandangDTO struct {
|
||||||
|
FlockID uint `json:"flock_id"`
|
||||||
|
Period int `json:"period"`
|
||||||
|
LocationName string `json:"location_name"`
|
||||||
|
Population int `json:"population"`
|
||||||
|
PopulationFormatted string `json:"population_formatted"`
|
||||||
|
ProjectType string `json:"project_type"`
|
||||||
|
ClosingDate string `json:"closing_date"`
|
||||||
|
KandangName string `json:"kandang_name"`
|
||||||
|
ChickInDate string `json:"chick_in_date"`
|
||||||
|
PicName string `json:"pic_name"`
|
||||||
|
ApprovalDate string `json:"approval_date"`
|
||||||
|
ProjectStatus string `json:"project_status"`
|
||||||
|
}
|
||||||
|
|
||||||
type ClosingPurchaseDTO struct {
|
type ClosingPurchaseDTO struct {
|
||||||
InitialPopulation int `json:"initial_population"`
|
InitialPopulation int `json:"initial_population"`
|
||||||
ClaimCulling int `json:"claim_culling"`
|
ClaimCulling int `json:"claim_culling"`
|
||||||
@@ -83,18 +98,18 @@ type ClosingEggSalesDTO struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ClosingPerformanceDTO struct {
|
type ClosingPerformanceDTO struct {
|
||||||
Depletion float64 `json:"depletion"`
|
Depletion float64 `json:"depletion"`
|
||||||
Age float64 `json:"age_day"`
|
Age float64 `json:"age_day"`
|
||||||
MortalityStd float64 `json:"mor_std"`
|
MortalityStd float64 `json:"mor_std"`
|
||||||
MortalityAct float64 `json:"mor_act"`
|
MortalityAct float64 `json:"mor_act"`
|
||||||
DeffMortality float64 `json:"mor_diff"`
|
DeffMortality float64 `json:"mor_diff"`
|
||||||
FcrStd float64 `json:"fcr_std"`
|
FcrStd float64 `json:"fcr_std"`
|
||||||
FcrAct float64 `json:"fcr_act"`
|
FcrAct float64 `json:"fcr_act"`
|
||||||
DeffFcr float64 `json:"fcr_diff"`
|
DeffFcr float64 `json:"fcr_diff"`
|
||||||
AwgAct float64 `json:"awg_act"`
|
AwgAct float64 `json:"awg_act"`
|
||||||
AwgStd float64 `json:"awg_std"`
|
AwgStd float64 `json:"awg_std"`
|
||||||
FeedIntake float64 `json:"feed_intake"`
|
FeedIntake float64 `json:"feed_intake"`
|
||||||
FeedIntakeStd float64 `json:"feed_intake_std"`
|
FeedIntakeStd float64 `json:"feed_intake_std"`
|
||||||
HenDayAct *float64 `json:"hen_day_act,omitempty"`
|
HenDayAct *float64 `json:"hen_day_act,omitempty"`
|
||||||
HendayStd *float64 `json:"hen_day_std,omitempty"`
|
HendayStd *float64 `json:"hen_day_std,omitempty"`
|
||||||
EggMass *float64 `json:"egg_mass,omitempty"`
|
EggMass *float64 `json:"egg_mass,omitempty"`
|
||||||
@@ -175,7 +190,7 @@ func sumPopulation(history []entity.ProjectFlockKandang) float64 {
|
|||||||
var total float64
|
var total float64
|
||||||
for _, h := range history {
|
for _, h := range history {
|
||||||
for _, chickin := range h.Chickins {
|
for _, chickin := range h.Chickins {
|
||||||
total += chickin.UsageQty + chickin.PendingUsageQty
|
total += chickin.UsageQty
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return total
|
return total
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -35,7 +36,7 @@ type ClosingService interface {
|
|||||||
GetAll(ctx *fiber.Ctx, params *validation.Query) ([]dto.ClosingListItemDTO, int64, error)
|
GetAll(ctx *fiber.Ctx, params *validation.Query) ([]dto.ClosingListItemDTO, int64, error)
|
||||||
GetProjectFlockByID(ctx *fiber.Ctx, id uint) (*entity.ProjectFlock, error)
|
GetProjectFlockByID(ctx *fiber.Ctx, id uint) (*entity.ProjectFlock, error)
|
||||||
GetPenjualan(ctx *fiber.Ctx, projectFlockID uint, projectFlockKandangID *uint) ([]entity.MarketingDeliveryProduct, error)
|
GetPenjualan(ctx *fiber.Ctx, projectFlockID uint, projectFlockKandangID *uint) ([]entity.MarketingDeliveryProduct, error)
|
||||||
GetClosingSummary(ctx *fiber.Ctx, projectFlockID uint) (*dto.ClosingSummaryDTO, error)
|
GetClosingSummary(ctx *fiber.Ctx, projectFlockID uint, kandangID *uint) (any, error)
|
||||||
GetClosingDataProduksi(ctx *fiber.Ctx, projectFlockID uint, kandangID *uint) (*dto.ClosingProductionReportDTO, error)
|
GetClosingDataProduksi(ctx *fiber.Ctx, projectFlockID uint, kandangID *uint) (*dto.ClosingProductionReportDTO, error)
|
||||||
GetOverhead(ctx *fiber.Ctx, projectFlockID uint, projectFlockKandangID *uint) (*dto.OverheadListDTO, error)
|
GetOverhead(ctx *fiber.Ctx, projectFlockID uint, projectFlockKandangID *uint) (*dto.OverheadListDTO, error)
|
||||||
GetClosingSapronak(ctx *fiber.Ctx, projectFlockID uint, params *validation.ClosingSapronakQuery) ([]dto.ClosingSapronakItemDTO, int64, error)
|
GetClosingSapronak(ctx *fiber.Ctx, projectFlockID uint, params *validation.ClosingSapronakQuery) ([]dto.ClosingSapronakItemDTO, int64, error)
|
||||||
@@ -150,11 +151,15 @@ func (s closingService) GetPenjualan(c *fiber.Ctx, projectFlockID uint, projectF
|
|||||||
return realisasi, nil
|
return realisasi, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s closingService) GetClosingSummary(c *fiber.Ctx, projectFlockID uint) (*dto.ClosingSummaryDTO, error) {
|
func (s closingService) GetClosingSummary(c *fiber.Ctx, projectFlockID uint, kandangID *uint) (any, error) {
|
||||||
if projectFlockID == 0 {
|
if projectFlockID == 0 {
|
||||||
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid project flock id")
|
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid project flock id")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if kandangID != nil {
|
||||||
|
return s.getClosingSummaryByKandang(c.Context(), projectFlockID, *kandangID)
|
||||||
|
}
|
||||||
|
|
||||||
project, err := s.Repository.GetByID(c.Context(), projectFlockID, s.withClosingRelations)
|
project, err := s.Repository.GetByID(c.Context(), projectFlockID, s.withClosingRelations)
|
||||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
return nil, fiber.NewError(fiber.StatusNotFound, "Project flock not found")
|
return nil, fiber.NewError(fiber.StatusNotFound, "Project flock not found")
|
||||||
@@ -175,6 +180,124 @@ func (s closingService) GetClosingSummary(c *fiber.Ctx, projectFlockID uint) (*d
|
|||||||
return &summary, nil
|
return &summary, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s closingService) getClosingSummaryByKandang(ctx context.Context, projectFlockID uint, kandangID uint) (*dto.ClosingSummaryKandangDTO, error) {
|
||||||
|
if projectFlockID == 0 || kandangID == 0 {
|
||||||
|
return nil, fiber.NewError(fiber.StatusBadRequest, "Invalid project flock id or kandang id")
|
||||||
|
}
|
||||||
|
|
||||||
|
db := s.Repository.DB().WithContext(ctx)
|
||||||
|
|
||||||
|
var kandang entity.ProjectFlockKandang
|
||||||
|
if err := db.
|
||||||
|
Preload("Kandang").
|
||||||
|
Preload("Kandang.Location").
|
||||||
|
Preload("Kandang.Pic").
|
||||||
|
Where("project_flock_id = ?", projectFlockID).
|
||||||
|
Where("kandang_id = ?", kandangID).
|
||||||
|
First(&kandang).Error; err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, fiber.NewError(fiber.StatusNotFound, "Project flock kandang not found")
|
||||||
|
}
|
||||||
|
s.Log.Errorf("Failed get project flock kandang %d/%d: %+v", projectFlockID, kandangID, err)
|
||||||
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch project flock kandang")
|
||||||
|
}
|
||||||
|
|
||||||
|
var project entity.ProjectFlock
|
||||||
|
if err := db.
|
||||||
|
Select("id", "category").
|
||||||
|
First(&project, projectFlockID).Error; err != nil {
|
||||||
|
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||||
|
return nil, fiber.NewError(fiber.StatusNotFound, "Project flock not found")
|
||||||
|
}
|
||||||
|
s.Log.Errorf("Failed get project flock %d: %+v", projectFlockID, err)
|
||||||
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch project flock")
|
||||||
|
}
|
||||||
|
|
||||||
|
var population float64
|
||||||
|
if err := db.
|
||||||
|
Table("project_flock_populations pfp").
|
||||||
|
Joins("JOIN project_chickins pc ON pc.id = pfp.project_chickin_id").
|
||||||
|
Where("pc.project_flock_kandang_id = ?", kandang.Id).
|
||||||
|
Select("COALESCE(SUM(pfp.total_qty), 0)").
|
||||||
|
Scan(&population).Error; err != nil {
|
||||||
|
s.Log.Errorf("Failed to sum population for project flock kandang %d: %+v", kandang.Id, err)
|
||||||
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch population data")
|
||||||
|
}
|
||||||
|
|
||||||
|
var chickInDate time.Time
|
||||||
|
if err := db.
|
||||||
|
Table("project_chickins").
|
||||||
|
Where("project_flock_kandang_id = ?", kandang.Id).
|
||||||
|
Select("MIN(chick_in_date)").
|
||||||
|
Scan(&chickInDate).Error; err != nil {
|
||||||
|
s.Log.Errorf("Failed to fetch chick in date for project flock kandang %d: %+v", kandang.Id, err)
|
||||||
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch chick in date")
|
||||||
|
}
|
||||||
|
|
||||||
|
statusProject := "Belum Selesai"
|
||||||
|
var approvalDate string
|
||||||
|
if s.ApprovalSvc != nil {
|
||||||
|
records, _, err := s.ApprovalSvc.List(ctx, utils.ApprovalWorkflowProjectFlockKandang.String(), &kandang.Id, 1, 1000, "")
|
||||||
|
if err != nil {
|
||||||
|
s.Log.Errorf("Failed to fetch approvals for project flock kandang %d: %+v", kandang.Id, err)
|
||||||
|
return nil, fiber.NewError(fiber.StatusInternalServerError, "Failed to fetch approval data")
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
minStep uint16
|
||||||
|
latestActionAt time.Time
|
||||||
|
)
|
||||||
|
|
||||||
|
for _, rec := range records {
|
||||||
|
if minStep == 0 || rec.StepNumber < minStep {
|
||||||
|
minStep = rec.StepNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
if latestActionAt.IsZero() || rec.ActionAt.After(latestActionAt) {
|
||||||
|
latestActionAt = rec.ActionAt
|
||||||
|
statusProject = rec.StepName
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if statusProject == "" && minStep > 0 {
|
||||||
|
if label, ok := approvalutils.ApprovalStepName(utils.ApprovalWorkflowProjectFlockKandang, approvalutils.ApprovalStep(minStep)); ok {
|
||||||
|
statusProject = label
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !latestActionAt.IsZero() {
|
||||||
|
approvalDate = latestActionAt.Format("2006-01-02")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
closingDate := ""
|
||||||
|
if kandang.ClosedAt != nil {
|
||||||
|
closingDate = kandang.ClosedAt.Format("2006-01-02")
|
||||||
|
}
|
||||||
|
|
||||||
|
chickInDateStr := ""
|
||||||
|
if !chickInDate.IsZero() {
|
||||||
|
chickInDateStr = chickInDate.Format("2006-01-02")
|
||||||
|
}
|
||||||
|
|
||||||
|
populationInt := int(population)
|
||||||
|
|
||||||
|
return &dto.ClosingSummaryKandangDTO{
|
||||||
|
FlockID: projectFlockID,
|
||||||
|
Period: kandang.Period,
|
||||||
|
LocationName: kandang.Kandang.Location.Name,
|
||||||
|
Population: populationInt,
|
||||||
|
PopulationFormatted: fmt.Sprintf("%d Ekor", populationInt),
|
||||||
|
ProjectType: project.Category,
|
||||||
|
ClosingDate: closingDate,
|
||||||
|
KandangName: kandang.Kandang.Name,
|
||||||
|
ChickInDate: chickInDateStr,
|
||||||
|
PicName: kandang.Kandang.Pic.Name,
|
||||||
|
ApprovalDate: approvalDate,
|
||||||
|
ProjectStatus: statusProject,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s closingService) GetClosingSapronak(c *fiber.Ctx, projectFlockID uint, params *validation.ClosingSapronakQuery) ([]dto.ClosingSapronakItemDTO, int64, error) {
|
func (s closingService) GetClosingSapronak(c *fiber.Ctx, projectFlockID uint, params *validation.ClosingSapronakQuery) ([]dto.ClosingSapronakItemDTO, int64, error) {
|
||||||
if projectFlockID == 0 {
|
if projectFlockID == 0 {
|
||||||
return nil, 0, fiber.NewError(fiber.StatusBadRequest, "Invalid project flock id")
|
return nil, 0, fiber.NewError(fiber.StatusBadRequest, "Invalid project flock id")
|
||||||
|
|||||||
Reference in New Issue
Block a user