mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-23 14:55:42 +00:00
[FEAT/BE]Fix add new response depletions_rate
This commit is contained in:
@@ -12,7 +12,9 @@ type Recording struct {
|
|||||||
RecordDatetime time.Time `gorm:"column:record_datetime;not null"`
|
RecordDatetime time.Time `gorm:"column:record_datetime;not null"`
|
||||||
Day *int `gorm:"column:day"`
|
Day *int `gorm:"column:day"`
|
||||||
TotalDepletionQty *float64 `gorm:"column:total_depletion_qty"`
|
TotalDepletionQty *float64 `gorm:"column:total_depletion_qty"`
|
||||||
|
TotalDepletionCumQty *float64 `gorm:"-"`
|
||||||
CumDepletionRate *float64 `gorm:"column:cum_depletion_rate"`
|
CumDepletionRate *float64 `gorm:"column:cum_depletion_rate"`
|
||||||
|
DepletionRate *float64 `gorm:"-"`
|
||||||
CumIntake *int `gorm:"column:cum_intake"`
|
CumIntake *int `gorm:"column:cum_intake"`
|
||||||
FcrValue *float64 `gorm:"column:fcr_value"`
|
FcrValue *float64 `gorm:"column:fcr_value"`
|
||||||
TotalChickQty *float64 `gorm:"column:total_chick_qty"`
|
TotalChickQty *float64 `gorm:"column:total_chick_qty"`
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package dto
|
package dto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"math"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -73,7 +74,9 @@ type RecordingRelationDTO struct {
|
|||||||
RecordDatetime time.Time `json:"record_datetime"`
|
RecordDatetime time.Time `json:"record_datetime"`
|
||||||
Day int `json:"day"`
|
Day int `json:"day"`
|
||||||
TotalDepletionQty float64 `json:"total_depletion_qty"`
|
TotalDepletionQty float64 `json:"total_depletion_qty"`
|
||||||
|
TotalDepletionCumQty float64 `json:"total_depletion_cum_qty"`
|
||||||
CumDepletionRate float64 `json:"cum_depletion_rate"`
|
CumDepletionRate float64 `json:"cum_depletion_rate"`
|
||||||
|
DepletionRate float64 `json:"depletion_rate"`
|
||||||
CumIntake int `json:"cum_intake"`
|
CumIntake int `json:"cum_intake"`
|
||||||
FcrValue float64 `json:"fcr_value"`
|
FcrValue float64 `json:"fcr_value"`
|
||||||
HenDay float64 `json:"hen_day"`
|
HenDay float64 `json:"hen_day"`
|
||||||
@@ -230,7 +233,9 @@ func toRecordingRelationDTO(e entity.Recording) RecordingRelationDTO {
|
|||||||
RecordDatetime: e.RecordDatetime,
|
RecordDatetime: e.RecordDatetime,
|
||||||
Day: intValue(e.Day),
|
Day: intValue(e.Day),
|
||||||
TotalDepletionQty: floatValue(e.TotalDepletionQty),
|
TotalDepletionQty: floatValue(e.TotalDepletionQty),
|
||||||
CumDepletionRate: floatValue(e.CumDepletionRate),
|
TotalDepletionCumQty: floatValue(e.TotalDepletionCumQty),
|
||||||
|
CumDepletionRate: roundFloatValue(e.CumDepletionRate, 2),
|
||||||
|
DepletionRate: roundFloatValue(e.DepletionRate, 2),
|
||||||
CumIntake: intValue(e.CumIntake),
|
CumIntake: intValue(e.CumIntake),
|
||||||
FcrValue: floatValue(e.FcrValue),
|
FcrValue: floatValue(e.FcrValue),
|
||||||
HenDay: floatValue(e.HenDay),
|
HenDay: floatValue(e.HenDay),
|
||||||
@@ -426,6 +431,17 @@ func floatValue(value *float64) float64 {
|
|||||||
return *value
|
return *value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func roundFloatValue(value *float64, places int) float64 {
|
||||||
|
if value == nil {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
if places <= 0 {
|
||||||
|
return math.Round(*value)
|
||||||
|
}
|
||||||
|
factor := math.Pow(10, float64(places))
|
||||||
|
return math.Round(*value*factor) / factor
|
||||||
|
}
|
||||||
|
|
||||||
func intValue(value *int) int {
|
func intValue(value *int) int {
|
||||||
if value == nil {
|
if value == nil {
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ type RecordingRepository interface {
|
|||||||
ExistsOnDate(ctx context.Context, projectFlockKandangId uint, recordTime time.Time) (bool, error)
|
ExistsOnDate(ctx context.Context, projectFlockKandangId uint, recordTime time.Time) (bool, error)
|
||||||
|
|
||||||
SumRecordingDepletions(tx *gorm.DB, recordingID uint) (float64, error)
|
SumRecordingDepletions(tx *gorm.DB, recordingID uint) (float64, error)
|
||||||
|
GetCumulativeDepletionByProjectFlockKandangUntil(tx *gorm.DB, projectFlockKandangId uint, recordTime time.Time) (float64, error)
|
||||||
FindPreviousRecording(tx *gorm.DB, projectFlockKandangId uint, currentDay int) (*entity.Recording, error)
|
FindPreviousRecording(tx *gorm.DB, projectFlockKandangId uint, currentDay int) (*entity.Recording, error)
|
||||||
GetTotalChick(tx *gorm.DB, projectFlockKandangId uint) (int64, error)
|
GetTotalChick(tx *gorm.DB, projectFlockKandangId uint) (int64, error)
|
||||||
GetTotalChickinByProjectFlockKandang(tx *gorm.DB, projectFlockKandangId uint) (float64, error)
|
GetTotalChickinByProjectFlockKandang(tx *gorm.DB, projectFlockKandangId uint) (float64, error)
|
||||||
@@ -314,6 +315,23 @@ func (r *RecordingRepositoryImpl) SumRecordingDepletions(tx *gorm.DB, recordingI
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *RecordingRepositoryImpl) GetCumulativeDepletionByProjectFlockKandangUntil(tx *gorm.DB, projectFlockKandangId uint, recordTime time.Time) (float64, error) {
|
||||||
|
if projectFlockKandangId == 0 || recordTime.IsZero() {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var total float64
|
||||||
|
err := tx.
|
||||||
|
Table("recording_depletions rd").
|
||||||
|
Select("COALESCE(SUM(rd.qty),0)").
|
||||||
|
Joins("JOIN recordings r ON r.id = rd.recording_id").
|
||||||
|
Where("r.project_flock_kandangs_id = ?", projectFlockKandangId).
|
||||||
|
Where("r.record_datetime <= ?", recordTime).
|
||||||
|
Where("r.deleted_at IS NULL").
|
||||||
|
Scan(&total).Error
|
||||||
|
return total, err
|
||||||
|
}
|
||||||
|
|
||||||
func (r *RecordingRepositoryImpl) FindPreviousRecording(tx *gorm.DB, projectFlockKandangId uint, currentDay int) (*entity.Recording, error) {
|
func (r *RecordingRepositoryImpl) FindPreviousRecording(tx *gorm.DB, projectFlockKandangId uint, currentDay int) (*entity.Recording, error) {
|
||||||
if currentDay <= 1 {
|
if currentDay <= 1 {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|||||||
@@ -128,6 +128,12 @@ func (s recordingService) GetAll(c *fiber.Ctx, params *validation.Query) ([]enti
|
|||||||
if err := s.attachProductionStandards(c.Context(), recordings); err != nil {
|
if err := s.attachProductionStandards(c.Context(), recordings); err != nil {
|
||||||
return nil, 0, err
|
return nil, 0, err
|
||||||
}
|
}
|
||||||
|
if err := s.attachCumulativeDepletions(c.Context(), recordings); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
|
if err := s.attachDepletionRates(c.Context(), recordings); err != nil {
|
||||||
|
return nil, 0, err
|
||||||
|
}
|
||||||
return recordings, total, nil
|
return recordings, total, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,6 +158,12 @@ func (s recordingService) GetOne(c *fiber.Ctx, id uint) (*entity.Recording, erro
|
|||||||
if err := s.attachProductionStandard(c.Context(), recording); err != nil {
|
if err := s.attachProductionStandard(c.Context(), recording); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if err := s.attachCumulativeDepletion(c.Context(), recording); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := s.attachDepletionRate(c.Context(), recording); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
return recording, nil
|
return recording, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1026,12 +1038,8 @@ func (s *recordingService) computeAndUpdateMetrics(ctx context.Context, tx *gorm
|
|||||||
return fmt.Errorf("getPreviousRecording: %w", err)
|
return fmt.Errorf("getPreviousRecording: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var prevCumDepletionQty float64
|
|
||||||
var prevCumIntake float64
|
var prevCumIntake float64
|
||||||
if prevRecording != nil {
|
if prevRecording != nil {
|
||||||
if prevRecording.TotalDepletionQty != nil {
|
|
||||||
prevCumDepletionQty = *prevRecording.TotalDepletionQty
|
|
||||||
}
|
|
||||||
if prevRecording.CumIntake != nil {
|
if prevRecording.CumIntake != nil {
|
||||||
prevCumIntake = float64(*prevRecording.CumIntake)
|
prevCumIntake = float64(*prevRecording.CumIntake)
|
||||||
}
|
}
|
||||||
@@ -1063,12 +1071,16 @@ func (s *recordingService) computeAndUpdateMetrics(ctx context.Context, tx *gorm
|
|||||||
}
|
}
|
||||||
|
|
||||||
currentDepletion := float64(totalDepletionQty)
|
currentDepletion := float64(totalDepletionQty)
|
||||||
cumDepletionQty := prevCumDepletionQty + currentDepletion
|
cumDepletionQty, err := s.Repository.GetCumulativeDepletionByProjectFlockKandangUntil(tx, recording.ProjectFlockKandangId, recording.RecordDatetime)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("getCumulativeDepletionByProjectFlockKandangUntil: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
updates := map[string]any{
|
updates := map[string]any{
|
||||||
"total_depletion_qty": cumDepletionQty,
|
"total_depletion_qty": currentDepletion,
|
||||||
}
|
}
|
||||||
recording.TotalDepletionQty = &cumDepletionQty
|
recording.TotalDepletionQty = ¤tDepletion
|
||||||
|
recording.TotalDepletionCumQty = &cumDepletionQty
|
||||||
|
|
||||||
var remainingChick float64
|
var remainingChick float64
|
||||||
if totalChick > 0 {
|
if totalChick > 0 {
|
||||||
@@ -1111,6 +1123,9 @@ func (s *recordingService) computeAndUpdateMetrics(ctx context.Context, tx *gorm
|
|||||||
recording.CumDepletionRate = nil
|
recording.CumDepletionRate = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
depletionRate := computeDepletionRate(prevRecording, currentDepletion, totalChick)
|
||||||
|
recording.DepletionRate = &depletionRate
|
||||||
|
|
||||||
var feedIntake float64
|
var feedIntake float64
|
||||||
if remainingChick > 0 && usageInGrams > 0 {
|
if remainingChick > 0 && usageInGrams > 0 {
|
||||||
feedIntake = (usageInGrams / remainingChick) * 1000
|
feedIntake = (usageInGrams / remainingChick) * 1000
|
||||||
@@ -1201,6 +1216,81 @@ func (s *recordingService) computeAndUpdateMetrics(ctx context.Context, tx *gorm
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func computeDepletionRate(prevRecording *entity.Recording, currentDepletion float64, totalChick int64) float64 {
|
||||||
|
base := 0.0
|
||||||
|
if prevRecording != nil && prevRecording.TotalChickQty != nil && *prevRecording.TotalChickQty > 0 {
|
||||||
|
base = *prevRecording.TotalChickQty
|
||||||
|
} else if totalChick > 0 {
|
||||||
|
// totalChick is already remaining after today's depletion; add back current to approximate previous population.
|
||||||
|
base = float64(totalChick) + currentDepletion
|
||||||
|
}
|
||||||
|
if base <= 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return (currentDepletion / base) * 100
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *recordingService) attachCumulativeDepletion(ctx context.Context, recording *entity.Recording) error {
|
||||||
|
if recording == nil || recording.ProjectFlockKandangId == 0 || recording.RecordDatetime.IsZero() {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
total, err := s.Repository.GetCumulativeDepletionByProjectFlockKandangUntil(s.Repository.DB().WithContext(ctx), recording.ProjectFlockKandangId, recording.RecordDatetime)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
recording.TotalDepletionCumQty = &total
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *recordingService) attachCumulativeDepletions(ctx context.Context, recordings []entity.Recording) error {
|
||||||
|
if len(recordings) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for i := range recordings {
|
||||||
|
if err := s.attachCumulativeDepletion(ctx, &recordings[i]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *recordingService) attachDepletionRate(ctx context.Context, recording *entity.Recording) error {
|
||||||
|
if recording == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
current := 0.0
|
||||||
|
if recording.TotalDepletionQty != nil {
|
||||||
|
current = *recording.TotalDepletionQty
|
||||||
|
}
|
||||||
|
day := 0
|
||||||
|
if recording.Day != nil {
|
||||||
|
day = *recording.Day
|
||||||
|
}
|
||||||
|
prev, err := s.Repository.FindPreviousRecording(s.Repository.DB().WithContext(ctx), recording.ProjectFlockKandangId, day)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
totalChick, err := s.Repository.GetTotalChick(s.Repository.DB().WithContext(ctx), recording.ProjectFlockKandangId)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
rate := computeDepletionRate(prev, current, totalChick)
|
||||||
|
recording.DepletionRate = &rate
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *recordingService) attachDepletionRates(ctx context.Context, recordings []entity.Recording) error {
|
||||||
|
if len(recordings) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
for i := range recordings {
|
||||||
|
if err := s.attachDepletionRate(ctx, &recordings[i]); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *recordingService) createRecordingApproval(
|
func (s *recordingService) createRecordingApproval(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
db *gorm.DB,
|
db *gorm.DB,
|
||||||
|
|||||||
Reference in New Issue
Block a user