package repository import ( "context" "fmt" "time" entity "gitlab.com/mbugroup/lti-api.git/internal/entities" "gitlab.com/mbugroup/lti-api.git/internal/utils" "gitlab.com/mbugroup/lti-api.git/internal/utils/fifo" "gorm.io/gorm" ) type HppV2ProjectFlockKandangContext struct { ProjectFlockKandangID uint ProjectFlockID uint ProjectFlockCategory string KandangID uint KandangName string LocationID uint HouseType string } type HppV2UsageCostRow struct { StockableType string StockableID uint SourceProductID uint SourceProductName string Qty float64 UnitPrice float64 TotalCost float64 FirstUsedAt time.Time LastUsedAt time.Time } type HppV2AdjustmentCostRow struct { AdjustmentID uint ProjectFlockKandangID *uint ProductWarehouseID uint ProductID uint ProductName string WarehouseID uint WarehouseType string Qty float64 Price float64 GrandTotal float64 CreatedAt time.Time } type HppV2ExpenseCostRow struct { ExpenseRealizationID uint ExpenseNonstockID uint ExpenseID uint NonstockID uint NonstockName string Qty float64 Price float64 TotalCost float64 RealizationDate time.Time } type HppV2CostRepository interface { GetProjectFlockKandangContext(ctx context.Context, projectFlockKandangId uint) (*HppV2ProjectFlockKandangContext, error) GetProjectFlockKandangIDs(ctx context.Context, projectFlockId uint) ([]uint, error) ListUsageCostRowsByProductFlags(ctx context.Context, projectFlockKandangIDs []uint, flagNames []string, date *time.Time) ([]HppV2UsageCostRow, error) ListAdjustmentCostRowsByProductFlags(ctx context.Context, projectFlockKandangIDs []uint, flagNames []string, date *time.Time) ([]HppV2AdjustmentCostRow, error) ListExpenseRealizationRowsByProjectFlockKandangIDs(ctx context.Context, projectFlockKandangIDs []uint, date *time.Time, ekspedisi bool) ([]HppV2ExpenseCostRow, error) ListExpenseRealizationRowsByProjectFlockID(ctx context.Context, projectFlockID uint, date *time.Time, ekspedisi bool) ([]HppV2ExpenseCostRow, error) GetFeedUsageCost(ctx context.Context, projectFlockKandangIDs []uint, date *time.Time) (float64, error) GetTotalPopulation(ctx context.Context, projectFlockKandangIDs []uint) (float64, error) GetEggProduksiPiecesAndWeightKgByProjectFlockKandangIds(ctx context.Context, projectFlockKandangIDs []uint, date *time.Time) (float64, float64, error) GetEggTerjualPiecesAndWeightKgByProjectFlockKandangIds(ctx context.Context, projectFlockKandangIDs []uint, startDate *time.Time, endDate *time.Time) (float64, float64, error) GetTransferSourceSummary(ctx context.Context, projectFlockKandangId uint) (uint, float64, error) } type HppV2RepositoryImpl struct { db *gorm.DB } func NewHppV2CostRepository(db *gorm.DB) HppV2CostRepository { return &HppV2RepositoryImpl{db: db} } func (r *HppV2RepositoryImpl) GetProjectFlockKandangContext(ctx context.Context, projectFlockKandangId uint) (*HppV2ProjectFlockKandangContext, error) { var row HppV2ProjectFlockKandangContext err := r.db.WithContext(ctx). Table("project_flock_kandangs AS pfk"). Select(` pfk.id AS project_flock_kandang_id, pf.id AS project_flock_id, pf.category AS project_flock_category, k.id AS kandang_id, k.name AS kandang_name, k.location_id AS location_id, k.house_type::text AS house_type `). Joins("JOIN project_flocks AS pf ON pf.id = pfk.project_flock_id"). Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id"). Where("pfk.id = ?", projectFlockKandangId). Scan(&row).Error if err != nil { return nil, err } if row.ProjectFlockKandangID == 0 { return nil, gorm.ErrRecordNotFound } return &row, nil } func (r *HppV2RepositoryImpl) GetProjectFlockKandangIDs(ctx context.Context, projectFlockId uint) ([]uint, error) { var ids []uint err := r.db.WithContext(ctx). Table("project_flock_kandangs"). Select("id"). Where("project_flock_id = ?", projectFlockId). Scan(&ids).Error if err != nil { return nil, err } return ids, nil } func (r *HppV2RepositoryImpl) ListUsageCostRowsByProductFlags( ctx context.Context, projectFlockKandangIDs []uint, flagNames []string, date *time.Time, ) ([]HppV2UsageCostRow, error) { if len(projectFlockKandangIDs) == 0 || len(flagNames) == 0 { return []HppV2UsageCostRow{}, nil } if date == nil { now := time.Now() date = &now } stockablePurchase := fifo.StockableKeyPurchaseItems.String() stockableAdjustment := fifo.StockableKeyAdjustmentIn.String() usableRecordingStock := fifo.UsableKeyRecordingStock.String() rows := make([]HppV2UsageCostRow, 0) err := r.db.WithContext(ctx). Table("recordings AS r"). Select(` sa.stockable_type AS stockable_type, sa.stockable_id AS stockable_id, COALESCE(pi.product_id, ast_pw.product_id, 0) AS source_product_id, COALESCE(pi_prod.name, ast_prod.name, '') AS source_product_name, COALESCE(SUM(sa.qty), 0) AS qty, CASE WHEN sa.stockable_type = ? THEN COALESCE(pi.price, 0) WHEN sa.stockable_type = ? THEN COALESCE(ast.price, 0) ELSE 0 END AS unit_price, COALESCE(SUM(sa.qty * CASE WHEN sa.stockable_type = ? THEN COALESCE(pi.price, 0) WHEN sa.stockable_type = ? THEN COALESCE(ast.price, 0) ELSE 0 END), 0) AS total_cost, MIN(r.record_datetime) AS first_used_at, MAX(r.record_datetime) AS last_used_at `, stockablePurchase, stockableAdjustment, stockablePurchase, stockableAdjustment, ). Joins("JOIN recording_stocks AS rs ON rs.recording_id = r.id"). Joins("JOIN product_warehouses AS pw ON pw.id = rs.product_warehouse_id"). Joins( "JOIN stock_allocations AS sa ON sa.usable_type = ? AND sa.usable_id = rs.id AND (sa.stockable_type = ? OR sa.stockable_type = ?) AND sa.status = ? AND sa.allocation_purpose = ?", usableRecordingStock, stockablePurchase, stockableAdjustment, entity.StockAllocationStatusActive, entity.StockAllocationPurposeConsume, ). Joins("LEFT JOIN purchase_items AS pi ON pi.id = sa.stockable_id AND sa.stockable_type = ?", stockablePurchase). Joins("LEFT JOIN products AS pi_prod ON pi_prod.id = pi.product_id"). Joins("LEFT JOIN adjustment_stocks AS ast ON ast.id = sa.stockable_id AND sa.stockable_type = ?", stockableAdjustment). Joins("LEFT JOIN product_warehouses AS ast_pw ON ast_pw.id = ast.product_warehouse_id"). Joins("LEFT JOIN products AS ast_prod ON ast_prod.id = ast_pw.product_id"). Where("r.project_flock_kandangs_id IN ?", projectFlockKandangIDs). Where("r.record_datetime <= ?", *date). Where("EXISTS (SELECT 1 FROM flags f WHERE f.flagable_id = pw.product_id AND f.flagable_type = ? AND f.name IN ?)", entity.FlagableTypeProduct, flagNames). Group(` sa.stockable_type, sa.stockable_id, COALESCE(pi.product_id, ast_pw.product_id, 0), COALESCE(pi_prod.name, ast_prod.name, ''), CASE WHEN sa.stockable_type = '` + stockablePurchase + `' THEN COALESCE(pi.price, 0) WHEN sa.stockable_type = '` + stockableAdjustment + `' THEN COALESCE(ast.price, 0) ELSE 0 END `). Order("MIN(r.record_datetime) ASC, sa.stockable_type ASC, sa.stockable_id ASC"). Scan(&rows).Error if err != nil { return nil, err } return rows, nil } func (r *HppV2RepositoryImpl) ListAdjustmentCostRowsByProductFlags( ctx context.Context, projectFlockKandangIDs []uint, flagNames []string, date *time.Time, ) ([]HppV2AdjustmentCostRow, error) { if len(projectFlockKandangIDs) == 0 || len(flagNames) == 0 { return []HppV2AdjustmentCostRow{}, nil } if date == nil { now := time.Now() date = &now } rows := make([]HppV2AdjustmentCostRow, 0) err := r.db.WithContext(ctx). Table("adjustment_stocks AS ast"). Select(` ast.id AS adjustment_id, pw.project_flock_kandang_id AS project_flock_kandang_id, ast.product_warehouse_id AS product_warehouse_id, pw.product_id AS product_id, p.name AS product_name, w.id AS warehouse_id, w.type AS warehouse_type, COALESCE(ast.total_qty, 0) AS qty, COALESCE(ast.price, 0) AS price, COALESCE(ast.grand_total, 0) AS grand_total, ast.created_at AS created_at `). Joins("JOIN product_warehouses AS pw ON pw.id = ast.product_warehouse_id"). Joins("JOIN products AS p ON p.id = pw.product_id"). Joins("JOIN warehouses AS w ON w.id = pw.warehouse_id"). Where("pw.project_flock_kandang_id IN ?", projectFlockKandangIDs). Where("ast.created_at <= ?", *date). Where("COALESCE(ast.total_qty, 0) > 0"). Where("EXISTS (SELECT 1 FROM flags f WHERE f.flagable_id = pw.product_id AND f.flagable_type = ? AND f.name IN ?)", entity.FlagableTypeProduct, flagNames). Order("ast.created_at ASC, ast.id ASC"). Scan(&rows).Error if err != nil { return nil, err } return rows, nil } func (r *HppV2RepositoryImpl) ListExpenseRealizationRowsByProjectFlockKandangIDs( ctx context.Context, projectFlockKandangIDs []uint, date *time.Time, ekspedisi bool, ) ([]HppV2ExpenseCostRow, error) { if len(projectFlockKandangIDs) == 0 { return []HppV2ExpenseCostRow{}, nil } if date == nil { now := time.Now() date = &now } rows := make([]HppV2ExpenseCostRow, 0) query := r.db.WithContext(ctx). Table("expense_realizations AS er"). Select(` er.id AS expense_realization_id, en.id AS expense_nonstock_id, e.id AS expense_id, COALESCE(n.id, 0) AS nonstock_id, COALESCE(n.name, '') AS nonstock_name, COALESCE(er.qty, 0) AS qty, COALESCE(er.price, 0) AS price, COALESCE(er.qty, 0) * COALESCE(er.price, 0) AS total_cost, COALESCE(e.realization_date, DATE(er.created_at)) AS realization_date `). 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 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("e.deleted_at IS NULL"). Where("e.category = ?", utils.ExpenseCategoryBOP). Where("en.project_flock_kandang_id IN ?", projectFlockKandangIDs). Where("COALESCE(e.realization_date, DATE(er.created_at)) <= ?", *date) if ekspedisi { query = query.Where("f.id IS NOT NULL") } else { query = query.Where("f.id IS NULL") } if err := query. Order("COALESCE(e.realization_date, DATE(er.created_at)) ASC, er.id ASC"). Scan(&rows).Error; err != nil { return nil, err } return rows, nil } func (r *HppV2RepositoryImpl) ListExpenseRealizationRowsByProjectFlockID( ctx context.Context, projectFlockID uint, date *time.Time, ekspedisi bool, ) ([]HppV2ExpenseCostRow, error) { if projectFlockID == 0 { return []HppV2ExpenseCostRow{}, nil } if date == nil { now := time.Now() date = &now } rows := make([]HppV2ExpenseCostRow, 0) query := r.db.WithContext(ctx). Table("expense_realizations AS er"). Select(` er.id AS expense_realization_id, en.id AS expense_nonstock_id, e.id AS expense_id, COALESCE(n.id, 0) AS nonstock_id, COALESCE(n.name, '') AS nonstock_name, COALESCE(er.qty, 0) AS qty, COALESCE(er.price, 0) AS price, COALESCE(er.qty, 0) * COALESCE(er.price, 0) AS total_cost, COALESCE(e.realization_date, DATE(er.created_at)) AS realization_date `). 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 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("e.deleted_at IS NULL"). Where("e.category = ?", utils.ExpenseCategoryBOP). Where("en.project_flock_kandang_id IS NULL"). Where("e.project_flock_id IS NOT NULL"). Where("e.project_flock_id::jsonb @> ?::jsonb", fmt.Sprintf("[%d]", projectFlockID)). Where("COALESCE(e.realization_date, DATE(er.created_at)) <= ?", *date) if ekspedisi { query = query.Where("f.id IS NOT NULL") } else { query = query.Where("f.id IS NULL") } if err := query. Order("COALESCE(e.realization_date, DATE(er.created_at)) ASC, er.id ASC"). Scan(&rows).Error; err != nil { return nil, err } return rows, nil } func (r *HppV2RepositoryImpl) GetFeedUsageCost(ctx context.Context, projectFlockKandangIDs []uint, date *time.Time) (float64, error) { if date == nil { now := time.Now() date = &now } stockablePurchase := fifo.StockableKeyPurchaseItems.String() stockableAdjustment := fifo.StockableKeyAdjustmentIn.String() usableRecordingStock := fifo.UsableKeyRecordingStock.String() var total float64 err := r.db.WithContext(ctx). Table("recordings AS r"). Select(` COALESCE(SUM(sa.qty * CASE WHEN sa.stockable_type = ? THEN COALESCE(pi.price, 0) WHEN sa.stockable_type = ? THEN COALESCE(ast.price, 0) ELSE 0 END), 0)`, stockablePurchase, stockableAdjustment, ). Joins("JOIN recording_stocks AS rs ON rs.recording_id = r.id"). Joins("JOIN product_warehouses AS pw ON pw.id = rs.product_warehouse_id"). Joins("JOIN flags AS f ON f.flagable_id = pw.product_id AND f.flagable_type = ?", entity.FlagableTypeProduct). Joins( "JOIN stock_allocations AS sa ON sa.usable_type = ? AND sa.usable_id = rs.id AND (sa.stockable_type = ? OR sa.stockable_type = ?) AND sa.status = ? AND sa.allocation_purpose = ?", usableRecordingStock, stockablePurchase, stockableAdjustment, entity.StockAllocationStatusActive, entity.StockAllocationPurposeConsume, ). Joins("LEFT JOIN purchase_items AS pi ON pi.id = sa.stockable_id AND sa.stockable_type = ?", stockablePurchase). Joins("LEFT JOIN adjustment_stocks AS ast ON ast.id = sa.stockable_id AND sa.stockable_type = ?", stockableAdjustment). Where("r.project_flock_kandangs_id IN (?)", projectFlockKandangIDs). Where("r.record_datetime <= ?", *date). Where("f.name = ?", utils.FlagPakan). Scan(&total).Error if err != nil { return 0, err } return total, nil } func (r *HppV2RepositoryImpl) GetTotalPopulation(ctx context.Context, projectFlockKandangIDs []uint) (float64, error) { var total float64 err := r.db.WithContext(ctx). Table("project_chickins AS pc"). Select("COALESCE(SUM(pc.usage_qty), 0)"). Where("pc.project_flock_kandang_id IN (?)", projectFlockKandangIDs). Scan(&total).Error if err != nil { return 0, err } return total, nil } func (r *HppV2RepositoryImpl) GetEggProduksiPiecesAndWeightKgByProjectFlockKandangIds(ctx context.Context, projectFlockKandangIDs []uint, date *time.Time) (float64, float64, error) { if date == nil { now := time.Now() date = &now } var totals struct { TotalPieces float64 TotalWeightKg float64 } err := r.db.WithContext(ctx). Table("recordings AS r"). Select("COALESCE(SUM(re.qty), 0) AS total_pieces, COALESCE(SUM(re.weight), 0)AS total_weight_kg"). Joins("JOIN recording_eggs AS re ON re.recording_id = r.id"). Where("r.project_flock_kandangs_id IN (?)", projectFlockKandangIDs). Where("r.record_datetime <= ?", *date). Scan(&totals).Error if err != nil { return 0, 0, err } var adjustmentTotals struct { TotalQty float64 TotalWeight float64 } adjustmentSubQuery := r.db.WithContext(ctx). Table("recordings AS r"). Select("DISTINCT ast.id AS adjustment_id, ast.total_qty AS total_qty, ast.price AS price"). Joins("JOIN recording_eggs AS re ON re.recording_id = r.id"). Joins("JOIN stock_transfer_details AS std ON std.dest_product_warehouse_id = re.product_warehouse_id"). Joins( "JOIN stock_allocations AS sa ON sa.usable_type = ? AND sa.usable_id = std.id AND sa.stockable_type = ? AND sa.status = ? AND sa.allocation_purpose = ?", fifo.UsableKeyStockTransferOut.String(), fifo.StockableKeyAdjustmentIn.String(), entity.StockAllocationStatusActive, entity.StockAllocationPurposeConsume, ). Joins("JOIN adjustment_stocks AS ast ON ast.id = sa.stockable_id AND ast.product_warehouse_id = std.source_product_warehouse_id"). Where("r.project_flock_kandangs_id IN (?)", projectFlockKandangIDs). Where("r.record_datetime <= ?", *date) err = r.db.WithContext(ctx). Table("(?) AS adjustment_sources", adjustmentSubQuery). Select("COALESCE(SUM(adjustment_sources.total_qty), 0) AS total_qty, COALESCE(SUM(adjustment_sources.price), 0) AS total_weight"). Scan(&adjustmentTotals).Error if err != nil { return 0, 0, err } totals.TotalPieces += adjustmentTotals.TotalQty totals.TotalWeightKg += adjustmentTotals.TotalWeight return totals.TotalPieces, totals.TotalWeightKg, nil } func (r *HppV2RepositoryImpl) GetEggTerjualPiecesAndWeightKgByProjectFlockKandangIds( ctx context.Context, projectFlockKandangIDs []uint, startDate *time.Time, endDate *time.Time, ) (float64, float64, error) { if len(projectFlockKandangIDs) == 0 { return 0, 0, nil } if endDate == nil { now := time.Now() endDate = &now } if startDate == nil { startDate = endDate } eggFlags := []string{ string(utils.FlagTelur), string(utils.FlagTelurUtuh), string(utils.FlagTelurPecah), string(utils.FlagTelurPutih), string(utils.FlagTelurRetak), string(utils.FlagTelurPapacal), string(utils.FlagTelurJumbo), } query := ` WITH selected_pfk AS ( SELECT pfk.id, k.location_id FROM project_flock_kandangs pfk JOIN kandangs k ON k.id = pfk.kandang_id WHERE pfk.id IN ? ), selected_locations AS ( SELECT DISTINCT location_id FROM selected_pfk ), sales_kandang AS ( SELECT DISTINCT mdp.id AS mdp_id, COALESCE(mdp.usage_qty, 0) AS usage_qty, COALESCE(mdp.total_weight, 0) AS total_weight FROM marketing_delivery_products mdp JOIN marketing_products mp ON mp.id = mdp.marketing_product_id JOIN product_warehouses pw ON pw.id = mp.product_warehouse_id JOIN warehouses w ON w.id = pw.warehouse_id WHERE mdp.delivery_date IS NOT NULL AND mdp.delivery_date <= ? AND UPPER(COALESCE(w.type, '')) = 'KANDANG' AND pw.project_flock_kandang_id IN (SELECT id FROM selected_pfk) AND EXISTS ( SELECT 1 FROM recording_eggs re JOIN recordings rr ON rr.id = re.recording_id WHERE re.product_warehouse_id = mp.product_warehouse_id AND COALESCE(re.project_flock_kandang_id, rr.project_flock_kandangs_id) IN (SELECT id FROM selected_pfk) AND rr.deleted_at IS NULL AND DATE(rr.record_datetime) <= DATE(mdp.delivery_date) ) AND EXISTS ( SELECT 1 FROM flags f WHERE f.flagable_type = ? AND f.flagable_id = pw.product_id AND f.name IN ? ) ), sales_lokasi AS ( SELECT DISTINCT mdp.id AS mdp_id, COALESCE(mdp.usage_qty, 0) AS usage_qty, COALESCE(mdp.total_weight, 0) AS total_weight, mdp.delivery_date AS delivery_date, pw.id AS lokasi_pw_id, pw.product_id AS product_id, w.location_id AS location_id FROM marketing_delivery_products mdp JOIN marketing_products mp ON mp.id = mdp.marketing_product_id JOIN product_warehouses pw ON pw.id = mp.product_warehouse_id JOIN warehouses w ON w.id = pw.warehouse_id WHERE mdp.delivery_date IS NOT NULL AND mdp.delivery_date <= ? AND UPPER(COALESCE(w.type, '')) = 'LOKASI' AND w.location_id IN (SELECT location_id FROM selected_locations) AND EXISTS ( SELECT 1 FROM flags f WHERE f.flagable_type = ? AND f.flagable_id = pw.product_id AND f.name IN ? ) ), transfer_pairs AS ( SELECT std.source_product_warehouse_id AS source_pw_id, std.dest_product_warehouse_id AS dest_pw_id, MIN(st.transfer_date) AS first_transfer_date FROM stock_transfer_details std JOIN stock_transfers st ON st.id = std.stock_transfer_id WHERE std.source_product_warehouse_id IS NOT NULL AND std.dest_product_warehouse_id IS NOT NULL GROUP BY std.source_product_warehouse_id, std.dest_product_warehouse_id ), adj_pool AS ( SELECT sl.mdp_id, SUM(CASE WHEN spw.project_flock_kandang_id IN (SELECT id FROM selected_pfk) THEN COALESCE(ast.usage_qty, 0) ELSE 0 END) AS sel_usage_qty, SUM(COALESCE(ast.usage_qty, 0)) AS farm_usage_qty, SUM(CASE WHEN spw.project_flock_kandang_id IN (SELECT id FROM selected_pfk) THEN COALESCE(ast.price, 0) ELSE 0 END) AS sel_price_sum, SUM(COALESCE(ast.price, 0)) AS farm_price_sum FROM sales_lokasi sl JOIN transfer_pairs tf ON tf.dest_pw_id = sl.lokasi_pw_id AND DATE(tf.first_transfer_date) <= DATE(sl.delivery_date) JOIN product_warehouses spw ON spw.id = tf.source_pw_id AND spw.product_id = sl.product_id JOIN warehouses sw ON sw.id = spw.warehouse_id JOIN adjustment_stocks ast ON ast.product_warehouse_id = tf.source_pw_id WHERE UPPER(COALESCE(sw.type, '')) = 'KANDANG' AND sw.location_id = sl.location_id AND UPPER(COALESCE(ast.function_code, '')) = UPPER(?) AND UPPER(COALESCE(ast.transaction_type, '')) = UPPER(?) AND DATE(ast.created_at) <= DATE(sl.delivery_date) GROUP BY sl.mdp_id ), sales_lokasi_adj AS ( SELECT sl.* FROM sales_lokasi sl JOIN adj_pool ap ON ap.mdp_id = sl.mdp_id WHERE COALESCE(ap.farm_usage_qty, 0) > 0 OR COALESCE(ap.farm_price_sum, 0) > 0 ), sales_lokasi_rec AS ( SELECT sl.* FROM sales_lokasi sl WHERE NOT EXISTS ( SELECT 1 FROM sales_lokasi_adj sla WHERE sla.mdp_id = sl.mdp_id ) ), rec_pool AS ( SELECT sl.mdp_id, SUM(CASE WHEN COALESCE(re.project_flock_kandang_id, r.project_flock_kandangs_id) IN (SELECT id FROM selected_pfk) THEN COALESCE(re.qty, 0) ELSE 0 END) AS sel_qty, SUM(COALESCE(re.qty, 0)) AS farm_qty, SUM(CASE WHEN COALESCE(re.project_flock_kandang_id, r.project_flock_kandangs_id) IN (SELECT id FROM selected_pfk) THEN COALESCE(re.weight, 0) ELSE 0 END) AS sel_weight, SUM(COALESCE(re.weight, 0)) AS farm_weight FROM sales_lokasi_rec sl JOIN recordings r ON r.deleted_at IS NULL AND DATE(r.record_datetime) <= DATE(sl.delivery_date) JOIN recording_eggs re ON re.recording_id = r.id AND re.product_warehouse_id = sl.lokasi_pw_id JOIN project_flock_kandangs pfk ON pfk.id = COALESCE(re.project_flock_kandang_id, r.project_flock_kandangs_id) JOIN kandangs k ON k.id = pfk.kandang_id WHERE k.location_id = sl.location_id GROUP BY sl.mdp_id ), kandang_totals AS ( SELECT COALESCE(SUM(sk.usage_qty), 0) AS total_pieces, COALESCE(SUM(sk.total_weight), 0) AS total_weight FROM sales_kandang sk ), lokasi_adj_totals AS ( SELECT COALESCE(SUM( sla.usage_qty * CASE WHEN COALESCE(ap.farm_usage_qty, 0) > 0 THEN (COALESCE(ap.sel_usage_qty, 0) * 1.0) / NULLIF(ap.farm_usage_qty, 0) ELSE 0 END ), 0) AS total_pieces, COALESCE(SUM( sla.total_weight * CASE WHEN COALESCE(ap.farm_price_sum, 0) > 0 THEN (COALESCE(ap.sel_price_sum, 0) * 1.0) / NULLIF(ap.farm_price_sum, 0) ELSE 0 END ), 0) AS total_weight FROM sales_lokasi_adj sla JOIN adj_pool ap ON ap.mdp_id = sla.mdp_id ), lokasi_rec_totals AS ( SELECT COALESCE(SUM( slr.usage_qty * CASE WHEN COALESCE(rp.farm_qty, 0) > 0 THEN (COALESCE(rp.sel_qty, 0) * 1.0) / NULLIF(rp.farm_qty, 0) ELSE 0 END ), 0) AS total_pieces, COALESCE(SUM( slr.total_weight * CASE WHEN COALESCE(rp.farm_weight, 0) > 0 THEN (COALESCE(rp.sel_weight, 0) * 1.0) / NULLIF(rp.farm_weight, 0) ELSE 0 END ), 0) AS total_weight FROM sales_lokasi_rec slr LEFT JOIN rec_pool rp ON rp.mdp_id = slr.mdp_id ) SELECT COALESCE(kt.total_pieces, 0) + COALESCE(lat.total_pieces, 0) + COALESCE(lrt.total_pieces, 0) AS total_pieces, COALESCE(kt.total_weight, 0) + COALESCE(lat.total_weight, 0) + COALESCE(lrt.total_weight, 0) AS total_weight FROM kandang_totals kt CROSS JOIN lokasi_adj_totals lat CROSS JOIN lokasi_rec_totals lrt ` var totals struct { TotalPieces float64 TotalWeight float64 } err := r.db.WithContext(ctx). Raw( query, projectFlockKandangIDs, *endDate, entity.FlagableTypeProduct, eggFlags, *endDate, entity.FlagableTypeProduct, eggFlags, string(utils.AdjustmentTransactionSubtypeRecordingEggIn), string(utils.AdjustmentTransactionTypeRecording), ). Scan(&totals).Error if err != nil { return 0, 0, err } return totals.TotalPieces, totals.TotalWeight, nil } func (r *HppV2RepositoryImpl) GetTransferSourceSummary(ctx context.Context, projectFlockKandangId uint) (uint, float64, error) { var summary struct { ProjectFlockID uint TotalQty float64 } err := r.db.WithContext(ctx). Table("laying_transfer_targets AS ltt"). Select("lt.from_project_flock_id AS project_flock_id, COALESCE(SUM(ltt.total_qty), 0) AS total_qty"). Joins("JOIN laying_transfers AS lt ON lt.id = ltt.laying_transfer_id"). Where("lt.deleted_at IS NULL"). Where("ltt.deleted_at IS NULL"). Where("lt.executed_at IS NOT NULL"). Where("ltt.target_project_flock_kandang_id = ?", projectFlockKandangId). Group("lt.from_project_flock_id"). Scan(&summary).Error if err != nil { return 0, 0, err } return summary.ProjectFlockID, summary.TotalQty, nil }