Files
lti-api/internal/modules/dashboards/repositories/dashboard_stats.repository.go
T

708 lines
24 KiB
Go

package repository
import (
"context"
"fmt"
"strings"
"time"
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/dashboards/validations"
"gitlab.com/mbugroup/lti-api.git/internal/utils"
"gorm.io/gorm"
)
type SellingPriceAggregate struct {
TotalPrice float64
TotalWeight float64
}
type FeedUsageByUom struct {
TotalQty float64
UomName string
}
type RecordingWeeklyMetric struct {
Week int
HenDay float64
EggWeight float64
FeedIntake float64
FcrValue float64
CumDepletionRate float64
}
type UniformityWeeklyMetric struct {
Week int
Uniformity float64
AverageWeight float64
}
type StandardWeeklyMetric struct {
Week int
StdLaying float64
StdEggWeight float64
StdFeedIntake float64
StdUniformity float64
StdDepletion float64
StdBodyWeight float64
}
type StandardWeeklyFcrMetric struct {
Week int
StdFcr float64
}
type ComparisonSeries struct {
Id uint
Label string
}
type ComparisonWeeklyMetric struct {
Week int
SeriesId uint
Value float64
}
type ComparisonUniformityMetric struct {
Week int
SeriesId uint
Uniformity float64
AverageWeight float64
}
type EggQualityWeeklyMetric struct {
Week int
NormalQty float64
AbnormalQty float64
TotalQty float64
}
type WeeklyEggWeightMetric struct {
Week int
EggWeightGrams float64
}
type WeeklyFeedUsageMetric struct {
Week int
TotalQty float64
UomName string
}
func applyDashboardFilters(db *gorm.DB, filters *validation.DashboardFilter) *gorm.DB {
if filters == nil {
return db
}
if len(filters.FlockIds) > 0 {
db = db.Where("pfk.project_flock_id IN ?", filters.FlockIds)
}
if len(filters.KandangIds) > 0 {
db = db.Where("k.id IN ?", filters.KandangIds)
}
if len(filters.LokasiIds) > 0 {
db = db.Where("k.location_id IN ?", filters.LokasiIds)
}
return db
}
func (r *DashboardRepositoryImpl) GetRecordingWeeklyMetrics(ctx context.Context, start, end time.Time, filters *validation.DashboardFilter) ([]RecordingWeeklyMetric, error) {
var rows []RecordingWeeklyMetric
weekExpr := `CASE
WHEN r.day IS NULL OR r.day <= 0 THEN 1
WHEN UPPER(pf.category) = 'LAYING' THEN ((r.day - 1) / 7 + 1) + 17
ELSE ((r.day - 1) / 7 + 1)
END`
db := r.DB().WithContext(ctx).
Table("recordings AS r").
Select(fmt.Sprintf(`%s AS week,
COALESCE(AVG(r.hen_day), 0) AS hen_day,
COALESCE(AVG(r.egg_weight), 0) AS egg_weight,
COALESCE(AVG(r.feed_intake), 0) AS feed_intake,
COALESCE(AVG(r.fcr_value), 0) AS fcr_value,
COALESCE(AVG(r.cum_depletion_rate), 0) AS cum_depletion_rate`, weekExpr)).
Joins("JOIN project_flock_kandangs AS pfk ON pfk.id = r.project_flock_kandangs_id").
Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id").
Joins("JOIN project_flocks AS pf ON pf.id = pfk.project_flock_id").
Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end).
Where("r.deleted_at IS NULL").
Where("r.day IS NOT NULL AND r.day > 0")
db = applyDashboardFilters(db, filters)
if err := db.Group("week").Order("week ASC").Scan(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
func (r *DashboardRepositoryImpl) GetUniformityWeeklyMetrics(ctx context.Context, start, end time.Time, filters *validation.DashboardFilter) ([]UniformityWeeklyMetric, error) {
var rows []UniformityWeeklyMetric
db := r.DB().WithContext(ctx).
Table("project_flock_kandang_uniformity AS u").
Select(`u.week AS week,
COALESCE(AVG(u.uniformity), 0) AS uniformity,
COALESCE(AVG((u.chart_data->'statistics'->>'average_weight')::numeric), 0) AS average_weight`).
Joins("JOIN project_flock_kandangs AS pfk ON pfk.id = u.project_flock_kandang_id").
Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id").
Where("u.uniform_date IS NOT NULL").
Where("u.uniform_date >= ? AND u.uniform_date < ?", start, end)
db = applyDashboardFilters(db, filters)
if err := db.Group("u.week").Order("u.week ASC").Scan(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
func (r *DashboardRepositoryImpl) GetStandardWeeklyMetrics(ctx context.Context, weeks []int, filters *validation.DashboardFilter) ([]StandardWeeklyMetric, error) {
if len(weeks) == 0 {
return nil, nil
}
standardIDs := r.standardIDSubquery(filters)
if standardIDs == nil {
return nil, nil
}
var rows []StandardWeeklyMetric
db := r.DB().WithContext(ctx).
Table("standard_growth_details AS sgd").
Select(`sgd.week AS week,
COALESCE(AVG(psd.target_hen_day_production), 0) AS std_laying,
COALESCE(AVG(psd.target_egg_weight), 0) AS std_egg_weight,
COALESCE(AVG(sgd.feed_intake), 0) AS std_feed_intake,
COALESCE(AVG(sgd.min_uniformity), 0) AS std_uniformity,
COALESCE(AVG(sgd.max_depletion), 0) AS std_depletion,
COALESCE(AVG(sgd.target_mean_bw), 0) AS std_body_weight`).
Joins("LEFT JOIN production_standard_details AS psd ON psd.production_standard_id = sgd.production_standard_id AND psd.week = sgd.week").
Where("sgd.week IN ?", weeks).
Where("sgd.production_standard_id IN (?)", standardIDs)
if err := db.Group("sgd.week").Order("sgd.week ASC").Scan(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
func (r *DashboardRepositoryImpl) GetStandardFcrWeekly(ctx context.Context, weeks []int, filters *validation.DashboardFilter) ([]StandardWeeklyFcrMetric, error) {
if len(weeks) == 0 {
return nil, nil
}
standardIDs := r.standardIDSubquery(filters)
if standardIDs == nil {
return nil, nil
}
var rows []StandardWeeklyFcrMetric
db := r.DB().WithContext(ctx).
Table("production_standard_details AS psd").
Select("psd.week AS week, COALESCE(AVG(psd.standard_fcr), 0) AS std_fcr").
Where("psd.week IN ?", weeks).
Where("psd.production_standard_id IN (?)", standardIDs)
if err := db.Group("psd.week").Order("psd.week ASC").Scan(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
func (r *DashboardRepositoryImpl) SumEggProductionWeightGrams(ctx context.Context, start, end time.Time, filters *validation.DashboardFilter) (float64, error) {
var total float64
db := r.DB().WithContext(ctx).
Table("recording_eggs AS re").
Select("COALESCE(SUM(re.weight * 1000), 0)").
Joins("JOIN recordings AS r ON r.id = re.recording_id").
Joins("JOIN project_flock_kandangs AS pfk ON pfk.id = r.project_flock_kandangs_id").
Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id").
Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end).
Where("r.deleted_at IS NULL")
db = applyDashboardFilters(db, filters)
if err := db.Scan(&total).Error; err != nil {
return 0, err
}
return total, nil
}
func (r *DashboardRepositoryImpl) SumEggProductionWeightKg(ctx context.Context, start, end time.Time, filters *validation.DashboardFilter) (float64, error) {
grams, err := r.SumEggProductionWeightGrams(ctx, start, end, filters)
if err != nil {
return 0, err
}
return grams / 1000, nil
}
func (r *DashboardRepositoryImpl) ListProjectFlockKandangIDsByEggProduction(ctx context.Context, start, end time.Time, filters *validation.DashboardFilter) ([]uint, error) {
var ids []uint
db := r.DB().WithContext(ctx).
Table("recording_eggs AS re").
Select("DISTINCT r.project_flock_kandangs_id").
Joins("JOIN recordings AS r ON r.id = re.recording_id").
Joins("JOIN project_flock_kandangs AS pfk ON pfk.id = r.project_flock_kandangs_id").
Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id").
Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end).
Where("r.deleted_at IS NULL")
db = applyDashboardFilters(db, filters)
if err := db.Scan(&ids).Error; err != nil {
return nil, err
}
return ids, nil
}
func (r *DashboardRepositoryImpl) GetFeedUsageByUom(ctx context.Context, start, end time.Time, filters *validation.DashboardFilter) ([]FeedUsageByUom, error) {
var rows []FeedUsageByUom
db := r.DB().WithContext(ctx).
Table("recording_stocks AS rs").
Select("COALESCE(SUM(rs.usage_qty), 0) + COALESCE(SUM(rs.pending_qty), 0) AS total_qty, LOWER(uoms.name) AS uom_name").
Joins("JOIN recordings AS r ON r.id = rs.recording_id").
Joins("JOIN project_flock_kandangs AS pfk ON pfk.id = r.project_flock_kandangs_id").
Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id").
Joins("JOIN product_warehouses AS pw ON pw.id = rs.product_warehouse_id").
Joins("JOIN products AS p ON p.id = pw.product_id").
Joins("JOIN uoms ON uoms.id = p.uom_id").
Joins("JOIN flags AS f ON f.flagable_id = p.id AND f.flagable_type = ? AND UPPER(f.name) = ?", entity.FlagableTypeProduct, "PAKAN").
Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end).
Where("r.deleted_at IS NULL")
db = applyDashboardFilters(db, filters)
if err := db.Group("LOWER(uoms.name)").Scan(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
func (r *DashboardRepositoryImpl) SumDepletions(ctx context.Context, start, end time.Time, filters *validation.DashboardFilter) (float64, error) {
var total float64
db := r.DB().WithContext(ctx).
Table("recording_depletions AS rd").
Select("COALESCE(SUM(rd.qty), 0)").
Joins("JOIN recordings AS r ON r.id = rd.recording_id").
Joins("JOIN project_flock_kandangs AS pfk ON pfk.id = r.project_flock_kandangs_id").
Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id").
Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end).
Where("r.deleted_at IS NULL")
db = applyDashboardFilters(db, filters)
if err := db.Scan(&total).Error; err != nil {
return 0, err
}
return total, nil
}
func (r *DashboardRepositoryImpl) SumInitialPopulation(ctx context.Context, endDate time.Time, filters *validation.DashboardFilter) (float64, error) {
var total float64
endOfDate := endDate.AddDate(0, 0, 1)
db := r.DB().WithContext(ctx).
Table("project_chickins AS pc").
Select("COALESCE(SUM(pc.usage_qty), 0)").
Joins("JOIN project_flock_kandangs AS pfk ON pfk.id = pc.project_flock_kandang_id").
Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id").
Where("pc.chick_in_date < ?", endOfDate).
Where("pc.deleted_at IS NULL")
db = applyDashboardFilters(db, filters)
if err := db.Scan(&total).Error; err != nil {
return 0, err
}
return total, nil
}
func (r *DashboardRepositoryImpl) SumSellingPrice(ctx context.Context, start, end time.Time, filters *validation.DashboardFilter) (SellingPriceAggregate, error) {
var result SellingPriceAggregate
db := r.DB().WithContext(ctx).
Table("marketing_delivery_products AS mdp").
Select("COALESCE(SUM(mdp.total_price), 0) AS total_price, COALESCE(SUM(mdp.total_weight), 0) AS total_weight").
Joins("JOIN marketing_products AS mp ON mp.id = mdp.marketing_product_id").
Joins("JOIN product_warehouses AS pw ON pw.id = mp.product_warehouse_id").
Joins("JOIN project_flock_kandangs AS pfk ON pfk.id = pw.project_flock_kandang_id").
Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id").
Where("mdp.delivery_date IS NOT NULL").
Where("mdp.delivery_date >= ? AND mdp.delivery_date < ?", start, end)
db = applyDashboardFilters(db, filters)
if err := db.Scan(&result).Error; err != nil {
return SellingPriceAggregate{}, err
}
return result, nil
}
func (r *DashboardRepositoryImpl) SumSapronakCost(ctx context.Context, start, end time.Time, filters *validation.DashboardFilter) (float64, error) {
var total float64
db := r.DB().WithContext(ctx).
Table("purchase_items AS pi").
Select("COALESCE(SUM(pi.total_price), 0) AS total").
Joins("JOIN products AS p ON p.id = pi.product_id").
Joins("JOIN flags AS f ON f.flagable_id = p.id AND f.flagable_type = ?", entity.FlagableTypeProduct).
Joins("LEFT JOIN product_warehouses AS pw ON pw.id = pi.product_warehouse_id").
Joins("LEFT JOIN project_flock_kandangs AS pfk ON pfk.id = COALESCE(pi.project_flock_kandang_id, pw.project_flock_kandang_id)").
Joins("LEFT JOIN kandangs AS k ON k.id = pfk.kandang_id").
Where("f.name IN ?", []utils.FlagType{utils.FlagDOC, utils.FlagPakan, utils.FlagOVK}).
Where("pi.received_date IS NOT NULL").
Where("pi.received_date >= ? AND pi.received_date < ?", start, end)
db = applyDashboardFilters(db, filters)
if err := db.Scan(&total).Error; err != nil {
return 0, err
}
return total, nil
}
func (r *DashboardRepositoryImpl) SumBopCost(ctx context.Context, start, end time.Time, filters *validation.DashboardFilter) (float64, error) {
return r.sumExpenseRealization(ctx, start, end, filters, func(db *gorm.DB) *gorm.DB {
return db.
Where("e.category = ?", utils.ExpenseCategoryBOP).
Joins("LEFT JOIN nonstocks AS n ON n.id = en.nonstock_id").
Joins("LEFT JOIN flags AS f ON f.flagable_id = n.id AND f.flagable_type = ? AND f.name = ?", entity.FlagableTypeNonstock, utils.FlagEkspedisi).
Where("f.id IS NULL")
})
}
func (r *DashboardRepositoryImpl) SumEkspedisiCost(ctx context.Context, start, end time.Time, filters *validation.DashboardFilter) (float64, error) {
return r.sumExpenseRealization(ctx, start, end, filters, func(db *gorm.DB) *gorm.DB {
return db.
Joins("JOIN nonstocks AS n ON n.id = en.nonstock_id").
Joins("JOIN flags AS f ON f.flagable_id = n.id AND f.flagable_type = ?", entity.FlagableTypeNonstock).
Where("f.name = ?", utils.FlagEkspedisi)
})
}
func (r *DashboardRepositoryImpl) sumExpenseRealization(ctx context.Context, start, end time.Time, filters *validation.DashboardFilter, modifier func(*gorm.DB) *gorm.DB) (float64, error) {
var total float64
db := r.DB().WithContext(ctx).
Table("expense_realizations AS er").
Select("COALESCE(SUM(er.qty * er.price), 0) AS total").
Joins("JOIN expense_nonstocks AS en ON en.id = er.expense_nonstock_id").
Joins("JOIN expenses AS e ON e.id = en.expense_id").
Joins("LEFT JOIN project_flock_kandangs AS pfk ON pfk.id = en.project_flock_kandang_id").
Joins("LEFT JOIN kandangs AS k ON k.id = COALESCE(en.kandang_id, pfk.kandang_id)").
Where("e.realization_date >= ? AND e.realization_date < ?", start, end)
db = applyDashboardFilters(db, filters)
if modifier != nil {
db = modifier(db)
}
if err := db.Scan(&total).Error; err != nil {
return 0, err
}
return total, nil
}
func (r *DashboardRepositoryImpl) standardIDSubquery(filters *validation.DashboardFilter) *gorm.DB {
db := r.DB().
Table("project_flocks AS pf").
Select("DISTINCT pf.production_standard_id").
Joins("JOIN project_flock_kandangs AS pfk ON pfk.project_flock_id = pf.id").
Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id").
Where("pf.production_standard_id > 0")
if filters != nil {
if len(filters.FlockIds) > 0 {
db = db.Where("pf.id IN ?", filters.FlockIds)
}
if len(filters.KandangIds) > 0 {
db = db.Where("k.id IN ?", filters.KandangIds)
}
if len(filters.LokasiIds) > 0 {
db = db.Where("k.location_id IN ?", filters.LokasiIds)
}
}
return db
}
func (r *DashboardRepositoryImpl) standardSourceSubquery(filters *validation.DashboardFilter) *gorm.DB {
db := r.DB().
Table("project_flocks AS pf").
Select("DISTINCT pf.production_standard_id, pf.fcr_id").
Joins("JOIN project_flock_kandangs AS pfk ON pfk.project_flock_id = pf.id").
Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id").
Where("pf.production_standard_id > 0").
Where("pf.fcr_id > 0")
if filters != nil {
if len(filters.FlockIds) > 0 {
db = db.Where("pf.id IN ?", filters.FlockIds)
}
if len(filters.KandangIds) > 0 {
db = db.Where("k.id IN ?", filters.KandangIds)
}
if len(filters.LokasiIds) > 0 {
db = db.Where("k.location_id IN ?", filters.LokasiIds)
}
}
return db
}
func (r *DashboardRepositoryImpl) GetComparisonSeries(ctx context.Context, start, end time.Time, filters *validation.DashboardFilter, comparisonType string) ([]ComparisonSeries, error) {
seriesExpr, labelExpr, groupExpr, orderExpr, err := comparisonSeriesColumns(comparisonType)
if err != nil {
return nil, err
}
var rows []ComparisonSeries
db := r.DB().WithContext(ctx).
Table("recordings AS r").
Select(fmt.Sprintf("%s AS id, %s AS label", seriesExpr, labelExpr)).
Joins("JOIN project_flock_kandangs AS pfk ON pfk.id = r.project_flock_kandangs_id").
Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id").
Joins("JOIN project_flocks AS pf ON pf.id = pfk.project_flock_id").
Joins("JOIN locations AS loc ON loc.id = k.location_id").
Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end).
Where("r.deleted_at IS NULL")
db = applyDashboardFilters(db, filters)
if err := db.Group(groupExpr).Order(orderExpr).Scan(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
func (r *DashboardRepositoryImpl) GetComparisonWeeklyMetrics(ctx context.Context, start, end time.Time, filters *validation.DashboardFilter, comparisonType, metric string) ([]ComparisonWeeklyMetric, error) {
seriesExpr, _, groupExpr, orderExpr, err := comparisonSeriesColumns(comparisonType)
if err != nil {
return nil, err
}
metricExpr, err := comparisonMetricColumn(metric)
if err != nil {
return nil, err
}
var rows []ComparisonWeeklyMetric
weekExpr := `CASE
WHEN r.day IS NULL OR r.day <= 0 THEN 1
WHEN UPPER(pf.category) = 'LAYING' THEN ((r.day - 1) / 7 + 1) + 17
ELSE ((r.day - 1) / 7 + 1)
END`
db := r.DB().WithContext(ctx).
Table("recordings AS r").
Select(fmt.Sprintf(`%s AS week,
%s AS series_id,
COALESCE(AVG(%s), 0) AS value`, weekExpr, seriesExpr, metricExpr)).
Joins("JOIN project_flock_kandangs AS pfk ON pfk.id = r.project_flock_kandangs_id").
Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id").
Joins("JOIN project_flocks AS pf ON pf.id = pfk.project_flock_id").
Joins("JOIN locations AS loc ON loc.id = k.location_id").
Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end).
Where("r.deleted_at IS NULL")
db = applyDashboardFilters(db, filters)
groupBy := fmt.Sprintf("week, %s", groupExpr)
orderBy := fmt.Sprintf("week ASC, %s", orderExpr)
if err := db.Group(groupBy).Order(orderBy).Scan(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
func (r *DashboardRepositoryImpl) GetComparisonWeeklyUniformityMetrics(ctx context.Context, start, end time.Time, filters *validation.DashboardFilter, comparisonType string) ([]ComparisonUniformityMetric, error) {
seriesExpr, _, groupExpr, orderExpr, err := comparisonSeriesColumns(comparisonType)
if err != nil {
return nil, err
}
var rows []ComparisonUniformityMetric
db := r.DB().WithContext(ctx).
Table("project_flock_kandang_uniformity AS u").
Select(fmt.Sprintf(`u.week AS week,
%s AS series_id,
COALESCE(AVG(u.uniformity), 0) AS uniformity,
COALESCE(AVG((u.chart_data->'statistics'->>'average_weight')::numeric), 0) AS average_weight`, seriesExpr)).
Joins("JOIN project_flock_kandangs AS pfk ON pfk.id = u.project_flock_kandang_id").
Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id").
Joins("JOIN project_flocks AS pf ON pf.id = pfk.project_flock_id").
Joins("JOIN locations AS loc ON loc.id = k.location_id").
Where("u.uniform_date IS NOT NULL").
Where("u.uniform_date >= ? AND u.uniform_date < ?", start, end)
db = applyDashboardFilters(db, filters)
groupBy := fmt.Sprintf("u.week, %s", groupExpr)
orderBy := fmt.Sprintf("u.week ASC, %s", orderExpr)
if err := db.Group(groupBy).Order(orderBy).Scan(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
func (r *DashboardRepositoryImpl) GetEggQualityWeeklyMetrics(ctx context.Context, start, end time.Time, filters *validation.DashboardFilter) ([]EggQualityWeeklyMetric, error) {
var rows []EggQualityWeeklyMetric
weekExpr := `CASE
WHEN r.day IS NULL OR r.day <= 0 THEN 1
WHEN UPPER(pf.category) = 'LAYING' THEN ((r.day - 1) / 7 + 1) + 17
ELSE ((r.day - 1) / 7 + 1)
END`
db := r.DB().WithContext(ctx).
Table("recording_eggs AS re").
Select(fmt.Sprintf(`
%s AS week,
COALESCE(SUM(CASE WHEN f.name = ? THEN re.qty ELSE 0 END), 0) AS normal_qty,
COALESCE(SUM(CASE WHEN f.name IN (?, ?, ?) THEN re.qty ELSE 0 END), 0) AS abnormal_qty,
COALESCE(SUM(re.qty), 0) AS total_qty`,
weekExpr,
utils.FlagTelurUtuh,
utils.FlagTelurPutih,
utils.FlagTelurRetak,
utils.FlagTelurPecah,
)).
Joins("JOIN recordings AS r ON r.id = re.recording_id").
Joins("JOIN project_flock_kandangs AS pfk ON pfk.id = r.project_flock_kandangs_id").
Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id").
Joins("JOIN project_flocks AS pf ON pf.id = pfk.project_flock_id").
Joins("JOIN product_warehouses AS pw ON pw.id = re.product_warehouse_id").
Joins("JOIN products AS p ON p.id = pw.product_id").
Joins("JOIN flags AS f ON f.flagable_id = p.id AND f.flagable_type = ?", entity.FlagableTypeProduct).
Where("f.name IN ?", []utils.FlagType{utils.FlagTelurUtuh, utils.FlagTelurPutih, utils.FlagTelurRetak, utils.FlagTelurPecah}).
Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end).
Where("r.deleted_at IS NULL").
Where("r.day IS NOT NULL AND r.day > 0")
db = applyDashboardFilters(db, filters)
if err := db.Group("week").Order("week ASC").Scan(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
func (r *DashboardRepositoryImpl) GetEggWeightWeeklyGrams(ctx context.Context, start, end time.Time, filters *validation.DashboardFilter) ([]WeeklyEggWeightMetric, error) {
var rows []WeeklyEggWeightMetric
weekExpr := `CASE
WHEN r.day IS NULL OR r.day <= 0 THEN 1
WHEN UPPER(pf.category) = 'LAYING' THEN ((r.day - 1) / 7 + 1) + 17
ELSE ((r.day - 1) / 7 + 1)
END`
db := r.DB().WithContext(ctx).
Table("recording_eggs AS re").
Select(fmt.Sprintf(`
%s AS week,
COALESCE(SUM(re.weight * 1000), 0) AS egg_weight_grams`, weekExpr)).
Joins("JOIN recordings AS r ON r.id = re.recording_id").
Joins("JOIN project_flock_kandangs AS pfk ON pfk.id = r.project_flock_kandangs_id").
Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id").
Joins("JOIN project_flocks AS pf ON pf.id = pfk.project_flock_id").
Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end).
Where("r.deleted_at IS NULL").
Where("r.day IS NOT NULL AND r.day > 0")
db = applyDashboardFilters(db, filters)
if err := db.Group("week").Order("week ASC").Scan(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
func (r *DashboardRepositoryImpl) GetFeedUsageWeeklyByUom(ctx context.Context, start, end time.Time, filters *validation.DashboardFilter) ([]WeeklyFeedUsageMetric, error) {
var rows []WeeklyFeedUsageMetric
weekExpr := `CASE
WHEN r.day IS NULL OR r.day <= 0 THEN 1
WHEN UPPER(pf.category) = 'LAYING' THEN ((r.day - 1) / 7 + 1) + 17
ELSE ((r.day - 1) / 7 + 1)
END`
db := r.DB().WithContext(ctx).
Table("recording_stocks AS rs").
Select(fmt.Sprintf(`
%s AS week,
COALESCE(SUM(rs.usage_qty), 0) + COALESCE(SUM(rs.pending_qty), 0) AS total_qty,
LOWER(uoms.name) AS uom_name`, weekExpr)).
Joins("JOIN recordings AS r ON r.id = rs.recording_id").
Joins("JOIN project_flock_kandangs AS pfk ON pfk.id = r.project_flock_kandangs_id").
Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id").
Joins("JOIN project_flocks AS pf ON pf.id = pfk.project_flock_id").
Joins("JOIN product_warehouses AS pw ON pw.id = rs.product_warehouse_id").
Joins("JOIN products AS p ON p.id = pw.product_id").
Joins("JOIN uoms ON uoms.id = p.uom_id").
Joins("JOIN flags AS f ON f.flagable_id = p.id AND f.flagable_type = ? AND UPPER(f.name) = ?", entity.FlagableTypeProduct, "PAKAN").
Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end).
Where("r.deleted_at IS NULL").
Where("r.day IS NOT NULL AND r.day > 0")
db = applyDashboardFilters(db, filters)
if err := db.Group("week, LOWER(uoms.name)").Order("week ASC").Scan(&rows).Error; err != nil {
return nil, err
}
return rows, nil
}
func comparisonSeriesColumns(comparisonType string) (string, string, string, string, error) {
switch strings.ToUpper(strings.TrimSpace(comparisonType)) {
case validation.ComparisonTypeFarm:
return "loc.id", "loc.name", "loc.id, loc.name", "loc.name", nil
case validation.ComparisonTypeFlock:
return "pf.id", "pf.flock_name", "pf.id, pf.flock_name", "pf.flock_name", nil
case validation.ComparisonTypeKandang:
return "k.id", "k.name", "k.id, k.name", "k.name", nil
default:
return "", "", "", "", fmt.Errorf("invalid comparison_type")
}
}
func comparisonMetricColumn(metric string) (string, error) {
switch strings.ToLower(strings.TrimSpace(metric)) {
case validation.MetricFcr:
return "r.fcr_value", nil
case validation.MetricMortality:
return "r.cum_depletion_rate", nil
case validation.MetricLaying:
return "r.hen_day", nil
case validation.MetricEggWeight:
return "r.egg_weight", nil
case validation.MetricFeedIntake:
return "r.feed_intake", nil
default:
return "", fmt.Errorf("invalid metric")
}
}