mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-24 07:15:43 +00:00
Merge branch 'feat/hpp-harian' into 'development'
[FEAT][BE]: add hpp harian See merge request mbugroup/lti-api!195
This commit is contained in:
@@ -25,14 +25,12 @@ type HppPerKandangResponseData struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type HppPerKandangRowDTO struct {
|
type HppPerKandangRowDTO struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
Kandang HppPerKandangRowKandangDTO `json:"kandang"`
|
Kandang HppPerKandangRowKandangDTO `json:"kandang"`
|
||||||
WeightRange HppPerKandangWeightRangeDTO `json:"weight_range"`
|
WeightRange HppPerKandangWeightRangeDTO `json:"weight_range"`
|
||||||
RemainingChickenBirds int64 `json:"remaining_chicken_birds"`
|
AvgWeightKg float64 `json:"avg_weight_kg"`
|
||||||
RemainingChickenWeightKg float64 `json:"remaining_chicken_weight_kg"`
|
EggProductionPieces int64 `json:"egg_production_pieces"`
|
||||||
AvgWeightKg float64 `json:"avg_weight_kg"`
|
EggProductionKg float64 `json:"egg_production_kg"`
|
||||||
EggProductionPieces int64 `json:"egg_production_pieces"`
|
|
||||||
EggProductionKg float64 `json:"egg_production_kg"`
|
|
||||||
// FeedCostRp float64 `json:"feed_cost_rp"`
|
// FeedCostRp float64 `json:"feed_cost_rp"`
|
||||||
// OvkCostRp float64 `json:"ovk_cost_rp"`
|
// OvkCostRp float64 `json:"ovk_cost_rp"`
|
||||||
EggHppRpPerKg float64 `json:"egg_hpp_rp_per_kg"`
|
EggHppRpPerKg float64 `json:"egg_hpp_rp_per_kg"`
|
||||||
@@ -80,34 +78,28 @@ type HppPerKandangSummaryDTO struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type HppPerKandangSummaryWeightRangeDTO struct {
|
type HppPerKandangSummaryWeightRangeDTO struct {
|
||||||
ID int `json:"id"`
|
ID int `json:"id"`
|
||||||
WeightRange HppPerKandangWeightRangeDTO `json:"weight_range"`
|
WeightRange HppPerKandangWeightRangeDTO `json:"weight_range"`
|
||||||
Label string `json:"label"`
|
Label string `json:"label"`
|
||||||
RemainingChickenBirds int64 `json:"remaining_chicken_birds"`
|
AvgWeightKg float64 `json:"avg_weight_kg"`
|
||||||
RemainingChickenWeightKg float64 `json:"remaining_chicken_weight_kg"`
|
EggProductionPieces int64 `json:"egg_production_pieces"`
|
||||||
AvgWeightKg float64 `json:"avg_weight_kg"`
|
EggProductionKg float64 `json:"egg_production_kg"`
|
||||||
EggProductionPieces int64 `json:"egg_production_pieces"`
|
EggHppRpPerKg float64 `json:"egg_hpp_rp_per_kg"`
|
||||||
EggProductionKg float64 `json:"egg_production_kg"`
|
EggValueRp int64 `json:"egg_value_rp"`
|
||||||
EggHppRpPerKg float64 `json:"egg_hpp_rp_per_kg"`
|
FeedSuppliers []HppPerKandangSupplierDTO `json:"feed_suppliers"`
|
||||||
EggValueRp int64 `json:"egg_value_rp"`
|
DocSuppliers []HppPerKandangSupplierDTO `json:"doc_suppliers"`
|
||||||
FeedSuppliers []HppPerKandangSupplierDTO `json:"feed_suppliers"`
|
AverageDocPriceRp float64 `json:"average_doc_price_rp"`
|
||||||
DocSuppliers []HppPerKandangSupplierDTO `json:"doc_suppliers"`
|
HppRp float64 `json:"hpp_rp"`
|
||||||
AverageDocPriceRp float64 `json:"average_doc_price_rp"`
|
RemainingValueRp int64 `json:"remaining_value_rp"`
|
||||||
HppRp float64 `json:"hpp_rp"`
|
|
||||||
RemainingValueRp int64 `json:"remaining_value_rp"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type HppPerKandangSummaryTotalDTO struct {
|
type HppPerKandangSummaryTotalDTO struct {
|
||||||
TotalRemainingChickenBirds int64 `json:"total_remaining_chicken_birds"`
|
AverageWeightKg float64 `json:"average_weight_kg"`
|
||||||
TotalRemainingChickenWeightKg float64 `json:"total_remaining_chicken_weight_kg"`
|
TotalEggProductionPieces int64 `json:"total_egg_production_pieces"`
|
||||||
AverageWeightKg float64 `json:"average_weight_kg"`
|
TotalEggProductionKg float64 `json:"total_egg_production_kg"`
|
||||||
TotalRemainingValueRp int64 `json:"total_remaining_value_rp"`
|
AverageEggHppRpPerKg float64 `json:"average_egg_hpp_rp_per_kg"`
|
||||||
TotalEggProductionPieces int64 `json:"total_egg_production_pieces"`
|
TotalEggValueRp int64 `json:"total_egg_value_rp"`
|
||||||
TotalEggProductionKg float64 `json:"total_egg_production_kg"`
|
TotalAverageDocPriceRp float64 `json:"total_average_doc_price_rp"`
|
||||||
AverageEggHppRpPerKg float64 `json:"average_egg_hpp_rp_per_kg"`
|
|
||||||
TotalEggValueRp int64 `json:"total_egg_value_rp"`
|
|
||||||
TotalHppRp float64 `json:"total_hpp_rp"`
|
|
||||||
TotalAverageDocPriceRp float64 `json:"total_average_doc_price_rp"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHppPerKandangFiltersDTO(area, location, kandang, weightMin, weightMax, period, showUnrecorded string) HppPerKandangFiltersDTO {
|
func NewHppPerKandangFiltersDTO(area, location, kandang, weightMin, weightMax, period, showUnrecorded string) HppPerKandangFiltersDTO {
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type HppPerKandangRow struct {
|
type HppPerKandangRow struct {
|
||||||
|
ProjectFlockKandangID uint
|
||||||
KandangID uint
|
KandangID uint
|
||||||
KandangName string
|
KandangName string
|
||||||
KandangStatus string
|
KandangStatus string
|
||||||
@@ -18,6 +19,7 @@ type HppPerKandangRow struct {
|
|||||||
LocationName string
|
LocationName string
|
||||||
PicID uint
|
PicID uint
|
||||||
PicName string
|
PicName string
|
||||||
|
RecordingCount int64
|
||||||
RemainingChickenBirds float64
|
RemainingChickenBirds float64
|
||||||
RemainingChickenWeight float64
|
RemainingChickenWeight float64
|
||||||
EggProductionWeightKg float64
|
EggProductionWeightKg float64
|
||||||
@@ -44,7 +46,8 @@ type HppPerKandangSupplierRow struct {
|
|||||||
|
|
||||||
type HppPerKandangRepository interface {
|
type HppPerKandangRepository interface {
|
||||||
GetRowsByPeriod(ctx context.Context, start, end time.Time, areaIDs, locationIDs, kandangIDs []int64) ([]HppPerKandangRow, error)
|
GetRowsByPeriod(ctx context.Context, start, end time.Time, areaIDs, locationIDs, kandangIDs []int64) ([]HppPerKandangRow, error)
|
||||||
GetFeedOvkDocCostByPeriod(ctx context.Context, start, end time.Time, areaIDs, locationIDs, kandangIDs []int64) ([]HppPerKandangCostRow, []HppPerKandangSupplierRow, error)
|
GetFeedOvkDocCostByPeriod(ctx context.Context, start, end time.Time, projectFlockKandangIDs []uint) ([]HppPerKandangCostRow, []HppPerKandangSupplierRow, error)
|
||||||
|
GetEggProductionByProjectFlockKandangIDs(ctx context.Context, start, end time.Time, projectFlockKandangIDs []uint) (map[uint]HppPerKandangRow, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type hppPerKandangRepository struct {
|
type hppPerKandangRepository struct {
|
||||||
@@ -58,9 +61,31 @@ func NewHppPerKandangRepository(db *gorm.DB) HppPerKandangRepository {
|
|||||||
func (r *hppPerKandangRepository) GetRowsByPeriod(ctx context.Context, start, end time.Time, areaIDs, locationIDs, kandangIDs []int64) ([]HppPerKandangRow, error) {
|
func (r *hppPerKandangRepository) GetRowsByPeriod(ctx context.Context, start, end time.Time, areaIDs, locationIDs, kandangIDs []int64) ([]HppPerKandangRow, error) {
|
||||||
var rows []HppPerKandangRow
|
var rows []HppPerKandangRow
|
||||||
|
|
||||||
query := r.db.WithContext(ctx).
|
latestApproval := r.db.WithContext(ctx).
|
||||||
|
Table("approvals AS a").
|
||||||
|
Select("a.approvable_id, a.action").
|
||||||
|
Joins(`
|
||||||
|
JOIN (
|
||||||
|
SELECT approvable_id, MAX(action_at) AS latest_action_at
|
||||||
|
FROM approvals
|
||||||
|
WHERE approvable_type = ?
|
||||||
|
GROUP BY approvable_id
|
||||||
|
) AS la ON la.approvable_id = a.approvable_id AND la.latest_action_at = a.action_at`,
|
||||||
|
string(utils.ApprovalWorkflowRecording),
|
||||||
|
)
|
||||||
|
|
||||||
|
validRecordings := r.db.WithContext(ctx).
|
||||||
Table("recordings AS r").
|
Table("recordings AS r").
|
||||||
|
Select("r.id, r.project_flock_kandangs_id, r.total_chick_qty").
|
||||||
|
Joins("LEFT JOIN (?) AS la ON la.approvable_id = r.id", latestApproval).
|
||||||
|
Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end).
|
||||||
|
Where("r.deleted_at IS NULL").
|
||||||
|
Where("(la.action IS NULL OR la.action != ?)", string(entity.ApprovalActionRejected))
|
||||||
|
|
||||||
|
query := r.db.WithContext(ctx).
|
||||||
|
Table("project_flocks AS pf").
|
||||||
Select(`
|
Select(`
|
||||||
|
pfk.id AS project_flock_kandang_id,
|
||||||
k.id AS kandang_id,
|
k.id AS kandang_id,
|
||||||
k.name AS kandang_name,
|
k.name AS kandang_name,
|
||||||
k.status AS kandang_status,
|
k.status AS kandang_status,
|
||||||
@@ -68,22 +93,21 @@ func (r *hppPerKandangRepository) GetRowsByPeriod(ctx context.Context, start, en
|
|||||||
loc.name AS location_name,
|
loc.name AS location_name,
|
||||||
pic.id AS pic_id,
|
pic.id AS pic_id,
|
||||||
pic.name AS pic_name,
|
pic.name AS pic_name,
|
||||||
COALESCE(MAX(r.total_chick_qty), 0) AS remaining_chicken_birds,
|
COALESCE(COUNT(vr.id), 0) AS recording_count,
|
||||||
COALESCE(SUM(rbw.total_weight), 0) AS remaining_chicken_weight,
|
COALESCE(MAX(vr.total_chick_qty), 0) AS remaining_chicken_birds,
|
||||||
COALESCE(SUM(re.weight), 0) AS egg_production_weight_kg,
|
0 AS remaining_chicken_weight,
|
||||||
COALESCE(SUM(re.qty), 0) AS egg_production_pieces`).
|
0 AS egg_production_weight_kg,
|
||||||
Joins("JOIN project_flock_kandangs AS pfk ON pfk.id = r.project_flock_kandangs_id").
|
0 AS egg_production_pieces`).
|
||||||
|
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").
|
Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id").
|
||||||
Joins("JOIN locations AS loc ON loc.id = k.location_id").
|
Joins("JOIN locations AS loc ON loc.id = k.location_id").
|
||||||
Joins("JOIN users AS pic ON pic.id = k.pic_id").
|
Joins("JOIN users AS pic ON pic.id = k.pic_id").
|
||||||
Joins("LEFT JOIN recording_bws AS rbw ON rbw.recording_id = r.id").
|
Joins("LEFT JOIN (?) AS vr ON vr.project_flock_kandangs_id = pfk.id", validRecordings).
|
||||||
Joins("LEFT JOIN recording_eggs AS re ON re.recording_id = r.id").
|
Where("pfk.closed_at IS NULL")
|
||||||
Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end).
|
|
||||||
Where("r.deleted_at IS NULL")
|
|
||||||
|
|
||||||
query = applyLocationFilters(query, areaIDs, locationIDs, kandangIDs)
|
query = applyLocationFilters(query, areaIDs, locationIDs, kandangIDs)
|
||||||
|
|
||||||
query = query.Group("k.id, k.name, k.status, loc.id, loc.name, pic.id, pic.name").
|
query = query.Group("pfk.id, k.id, k.name, k.status, loc.id, loc.name, pic.id, pic.name").
|
||||||
Order("k.id ASC")
|
Order("k.id ASC")
|
||||||
|
|
||||||
if err := query.Scan(&rows).Error; err != nil {
|
if err := query.Scan(&rows).Error; err != nil {
|
||||||
@@ -93,41 +117,44 @@ func (r *hppPerKandangRepository) GetRowsByPeriod(ctx context.Context, start, en
|
|||||||
return rows, nil
|
return rows, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context, start, end time.Time, areaIDs, locationIDs, kandangIDs []int64) ([]HppPerKandangCostRow, []HppPerKandangSupplierRow, error) {
|
func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context, start, end time.Time, projectFlockKandangIDs []uint) ([]HppPerKandangCostRow, []HppPerKandangSupplierRow, error) {
|
||||||
var rows []HppPerKandangCostRow
|
var rows []HppPerKandangCostRow
|
||||||
|
|
||||||
recordingPfk := r.db.WithContext(ctx).
|
|
||||||
Table("recordings AS r").
|
|
||||||
Select("DISTINCT pfk.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 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")
|
|
||||||
recordingPfk = applyLocationFilters(recordingPfk, areaIDs, locationIDs, kandangIDs)
|
|
||||||
|
|
||||||
purchaseStockableKey := fifo.StockableKeyPurchaseItems.String()
|
purchaseStockableKey := fifo.StockableKeyPurchaseItems.String()
|
||||||
transferStockableKey := fifo.StockableKeyStockTransferIn.String()
|
transferStockableKey := fifo.StockableKeyStockTransferIn.String()
|
||||||
|
|
||||||
|
latestApproval := r.db.WithContext(ctx).
|
||||||
|
Table("approvals AS a").
|
||||||
|
Select("a.approvable_id, a.action").
|
||||||
|
Joins(`
|
||||||
|
JOIN (
|
||||||
|
SELECT approvable_id, MAX(action_at) AS latest_action_at
|
||||||
|
FROM approvals
|
||||||
|
WHERE approvable_type = ?
|
||||||
|
GROUP BY approvable_id
|
||||||
|
) AS la ON la.approvable_id = a.approvable_id AND la.latest_action_at = a.action_at`,
|
||||||
|
string(utils.ApprovalWorkflowRecording),
|
||||||
|
)
|
||||||
|
|
||||||
query := r.db.WithContext(ctx).
|
query := r.db.WithContext(ctx).
|
||||||
Table("recordings AS r").
|
Table("recordings AS r").
|
||||||
Select(`
|
Select(`
|
||||||
k.id AS kandang_id,
|
k.id AS kandang_id,
|
||||||
COALESCE(SUM(CASE
|
COALESCE(SUM(CASE
|
||||||
WHEN f.name = ? THEN COALESCE(sa.qty, 0) * COALESCE(pi.price, 0)
|
WHEN f.name = ? THEN COALESCE(sa.qty, 0) * COALESCE(pi.price, 0)
|
||||||
WHEN sa.stockable_type = ? AND tf.name = ? THEN COALESCE(std.quantity, 0) * COALESCE(tpi.price, 0)
|
WHEN sa.stockable_type = ? AND tf.name = ? THEN COALESCE(std.total_qty, 0) * COALESCE(tpi.price, 0)
|
||||||
ELSE 0
|
ELSE 0
|
||||||
END), 0) AS feed_cost,
|
END), 0) AS feed_cost,
|
||||||
COALESCE(SUM(CASE
|
COALESCE(SUM(CASE
|
||||||
WHEN f.name = ? THEN COALESCE(sa.qty, 0) * COALESCE(pi.price, 0)
|
WHEN f.name = ? THEN COALESCE(sa.qty, 0) * COALESCE(pi.price, 0)
|
||||||
WHEN sa.stockable_type = ? AND tf.name = ? THEN COALESCE(std.quantity, 0) * COALESCE(tpi.price, 0)
|
WHEN sa.stockable_type = ? AND tf.name = ? THEN COALESCE(std.total_qty, 0) * COALESCE(tpi.price, 0)
|
||||||
ELSE 0
|
ELSE 0
|
||||||
END), 0) AS ovk_cost`,
|
END), 0) AS ovk_cost`,
|
||||||
utils.FlagPakan, transferStockableKey, utils.FlagPakan,
|
utils.FlagPakan, transferStockableKey, utils.FlagPakan,
|
||||||
utils.FlagOVK, transferStockableKey, utils.FlagOVK).
|
utils.FlagOVK, transferStockableKey, utils.FlagOVK).
|
||||||
Joins("JOIN project_flock_kandangs AS pfk ON pfk.id = r.project_flock_kandangs_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 kandangs AS k ON k.id = pfk.kandang_id").
|
||||||
Joins("JOIN locations AS loc ON loc.id = k.location_id").
|
Joins("LEFT JOIN (?) AS la ON la.approvable_id = r.id", latestApproval).
|
||||||
Joins("LEFT JOIN recording_stocks AS rs ON rs.recording_id = r.id").
|
Joins("LEFT JOIN recording_stocks AS rs ON rs.recording_id = r.id").
|
||||||
Joins("LEFT JOIN stock_allocations AS sa ON sa.usable_type = ? AND sa.usable_id = rs.id AND sa.status = ?", fifo.UsableKeyRecordingStock.String(), entity.StockAllocationStatusActive).
|
Joins("LEFT JOIN stock_allocations AS sa ON sa.usable_type = ? AND sa.usable_id = rs.id AND sa.status = ?", fifo.UsableKeyRecordingStock.String(), entity.StockAllocationStatusActive).
|
||||||
Joins("LEFT JOIN purchase_items AS pi ON pi.id = sa.stockable_id AND sa.stockable_type = ?", purchaseStockableKey).
|
Joins("LEFT JOIN purchase_items AS pi ON pi.id = sa.stockable_id AND sa.stockable_type = ?", purchaseStockableKey).
|
||||||
@@ -136,11 +163,10 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context,
|
|||||||
Joins("LEFT JOIN purchase_items AS tpi ON tpi.product_id = std.product_id AND tpi.warehouse_id = st.from_warehouse_id").
|
Joins("LEFT JOIN purchase_items AS tpi ON tpi.product_id = std.product_id AND tpi.warehouse_id = st.from_warehouse_id").
|
||||||
Joins("LEFT JOIN flags AS f ON f.flagable_id = pi.product_id AND f.flagable_type = ?", entity.FlagableTypeProduct).
|
Joins("LEFT JOIN flags AS f ON f.flagable_id = pi.product_id AND f.flagable_type = ?", entity.FlagableTypeProduct).
|
||||||
Joins("LEFT JOIN flags AS tf ON tf.flagable_id = std.product_id AND tf.flagable_type = ?", entity.FlagableTypeProduct).
|
Joins("LEFT JOIN flags AS tf ON tf.flagable_id = std.product_id AND tf.flagable_type = ?", entity.FlagableTypeProduct).
|
||||||
Where("r.project_flock_kandangs_id IN (?)", recordingPfk.Session(&gorm.Session{NewDB: true})).
|
Where("r.project_flock_kandangs_id IN ?", projectFlockKandangIDs).
|
||||||
Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end).
|
// Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end).
|
||||||
Where("r.deleted_at IS NULL")
|
Where("r.deleted_at IS NULL").
|
||||||
|
Where("(la.action IS NULL OR la.action != ?)", string(entity.ApprovalActionRejected))
|
||||||
query = applyLocationFilters(query, areaIDs, locationIDs, kandangIDs)
|
|
||||||
|
|
||||||
query = query.Group("k.id").Order("k.id ASC")
|
query = query.Group("k.id").Order("k.id ASC")
|
||||||
|
|
||||||
@@ -172,9 +198,8 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context,
|
|||||||
Joins("LEFT JOIN purchase_items AS pi ON pi.product_warehouse_id = pc.product_warehouse_id").
|
Joins("LEFT JOIN purchase_items AS pi ON pi.product_warehouse_id = pc.product_warehouse_id").
|
||||||
Joins("LEFT JOIN purchases AS pur ON pur.id = pi.purchase_id").
|
Joins("LEFT JOIN purchases AS pur ON pur.id = pi.purchase_id").
|
||||||
Joins("LEFT JOIN suppliers AS s ON s.id = pur.supplier_id").
|
Joins("LEFT JOIN suppliers AS s ON s.id = pur.supplier_id").
|
||||||
Where("pc.project_flock_kandang_id IN (?)", recordingPfk.Session(&gorm.Session{NewDB: true})).
|
Where("pc.project_flock_kandang_id IN ?", projectFlockKandangIDs).
|
||||||
Group("pfk.kandang_id, s.id, s.name, s.alias")
|
Group("pfk.kandang_id, s.id, s.name, s.alias")
|
||||||
docQuery = applyLocationFilters(docQuery, areaIDs, locationIDs, kandangIDs)
|
|
||||||
|
|
||||||
if err := docQuery.Scan(&docRows).Error; err != nil {
|
if err := docQuery.Scan(&docRows).Error; err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@@ -254,9 +279,9 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context,
|
|||||||
Joins("JOIN project_budgets AS pb ON pb.project_flock_id = pfk.project_flock_id").
|
Joins("JOIN project_budgets AS pb ON pb.project_flock_id = pfk.project_flock_id").
|
||||||
Joins("LEFT JOIN (?) AS k_usage ON k_usage.project_flock_kandang_id = pfk.id", pfkUsageSub).
|
Joins("LEFT JOIN (?) AS k_usage ON k_usage.project_flock_kandang_id = pfk.id", pfkUsageSub).
|
||||||
Joins("LEFT JOIN (?) AS p_usage ON p_usage.project_flock_id = pfk.project_flock_id", projectUsageSub).
|
Joins("LEFT JOIN (?) AS p_usage ON p_usage.project_flock_id = pfk.project_flock_id", projectUsageSub).
|
||||||
Where("pfk.id IN (?)", recordingPfk.Session(&gorm.Session{NewDB: true})).
|
Where("pfk.id IN (?)", projectFlockKandangIDs).
|
||||||
Group("k.id")
|
Group("k.id")
|
||||||
budgetQuery = applyLocationFilters(budgetQuery, areaIDs, locationIDs, kandangIDs)
|
// budgetQuery = applyLocationFilters(budgetQuery, areaIDs, locationIDs, kandangIDs)
|
||||||
|
|
||||||
if err := budgetQuery.Scan(&budgetRows).Error; err != nil {
|
if err := budgetQuery.Scan(&budgetRows).Error; err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@@ -288,9 +313,9 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context,
|
|||||||
Joins("JOIN locations AS loc ON loc.id = k.location_id").
|
Joins("JOIN locations AS loc ON loc.id = k.location_id").
|
||||||
Joins("JOIN expense_nonstocks AS en ON en.project_flock_kandang_id = pfk.id").
|
Joins("JOIN expense_nonstocks AS en ON en.project_flock_kandang_id = pfk.id").
|
||||||
Joins("JOIN expense_realizations AS er ON er.expense_nonstock_id = en.id").
|
Joins("JOIN expense_realizations AS er ON er.expense_nonstock_id = en.id").
|
||||||
Where("pfk.id IN (?)", recordingPfk.Session(&gorm.Session{NewDB: true})).
|
Where("pfk.id IN (?)", projectFlockKandangIDs).
|
||||||
Group("k.id")
|
Group("k.id")
|
||||||
expenseQuery = applyLocationFilters(expenseQuery, areaIDs, locationIDs, kandangIDs)
|
// expenseQuery = applyLocationFilters(expenseQuery, areaIDs, locationIDs, kandangIDs)
|
||||||
|
|
||||||
if err := expenseQuery.Scan(&expenseRows).Error; err != nil {
|
if err := expenseQuery.Scan(&expenseRows).Error; err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@@ -323,10 +348,10 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context,
|
|||||||
Joins("LEFT JOIN suppliers AS s ON s.id = pur.supplier_id").
|
Joins("LEFT JOIN suppliers AS s ON s.id = pur.supplier_id").
|
||||||
Joins("LEFT JOIN flags AS f ON f.flagable_id = pi.product_id AND f.flagable_type = ?", entity.FlagableTypeProduct).
|
Joins("LEFT JOIN flags AS f ON f.flagable_id = pi.product_id AND f.flagable_type = ?", entity.FlagableTypeProduct).
|
||||||
Where("f.name IN ?", []utils.FlagType{utils.FlagPakan, utils.FlagOVK}).
|
Where("f.name IN ?", []utils.FlagType{utils.FlagPakan, utils.FlagOVK}).
|
||||||
Where("r.project_flock_kandangs_id IN (?)", recordingPfk.Session(&gorm.Session{NewDB: true})).
|
Where("r.project_flock_kandangs_id IN (?)", projectFlockKandangIDs).
|
||||||
Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end).
|
// Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end).
|
||||||
Where("r.deleted_at IS NULL")
|
Where("r.deleted_at IS NULL")
|
||||||
feedQuery = applyLocationFilters(feedQuery, areaIDs, locationIDs, kandangIDs)
|
// feedQuery = applyLocationFilters(feedQuery, areaIDs, locationIDs, kandangIDs)
|
||||||
|
|
||||||
if err := feedQuery.Scan(&feedSuppliers).Error; err != nil {
|
if err := feedQuery.Scan(&feedSuppliers).Error; err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
@@ -347,6 +372,61 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context,
|
|||||||
return rows, supplierRows, nil
|
return rows, supplierRows, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *hppPerKandangRepository) GetEggProductionByProjectFlockKandangIDs(ctx context.Context, start, end time.Time, projectFlockKandangIDs []uint) (map[uint]HppPerKandangRow, error) {
|
||||||
|
if len(projectFlockKandangIDs) == 0 {
|
||||||
|
return map[uint]HppPerKandangRow{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
latestApproval := r.db.WithContext(ctx).
|
||||||
|
Table("approvals AS a").
|
||||||
|
Select("a.approvable_id, a.action").
|
||||||
|
Joins(`
|
||||||
|
JOIN (
|
||||||
|
SELECT approvable_id, MAX(action_at) AS latest_action_at
|
||||||
|
FROM approvals
|
||||||
|
WHERE approvable_type = ?
|
||||||
|
GROUP BY approvable_id
|
||||||
|
) AS la ON la.approvable_id = a.approvable_id AND la.latest_action_at = a.action_at`,
|
||||||
|
string(utils.ApprovalWorkflowRecording),
|
||||||
|
)
|
||||||
|
|
||||||
|
type eggRow struct {
|
||||||
|
ProjectFlockKandangID uint
|
||||||
|
EggProductionWeightKg float64
|
||||||
|
EggProductionPieces float64
|
||||||
|
}
|
||||||
|
|
||||||
|
eggRows := make([]eggRow, 0)
|
||||||
|
query := r.db.WithContext(ctx).
|
||||||
|
Table("recordings AS r").
|
||||||
|
Select(`
|
||||||
|
r.project_flock_kandangs_id AS project_flock_kandang_id,
|
||||||
|
COALESCE(SUM(re.weight), 0) AS egg_production_weight_kg,
|
||||||
|
COALESCE(SUM(re.qty), 0) AS egg_production_pieces`).
|
||||||
|
Joins("LEFT JOIN (?) AS la ON la.approvable_id = r.id", latestApproval).
|
||||||
|
Joins("LEFT JOIN recording_eggs AS re ON re.recording_id = r.id").
|
||||||
|
Where("r.project_flock_kandangs_id IN ?", projectFlockKandangIDs).
|
||||||
|
// Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end).
|
||||||
|
Where("r.deleted_at IS NULL").
|
||||||
|
Where("(la.action IS NULL OR la.action != ?)", string(entity.ApprovalActionRejected)).
|
||||||
|
Group("r.project_flock_kandangs_id")
|
||||||
|
|
||||||
|
if err := query.Scan(&eggRows).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make(map[uint]HppPerKandangRow, len(eggRows))
|
||||||
|
for _, row := range eggRows {
|
||||||
|
result[row.ProjectFlockKandangID] = HppPerKandangRow{
|
||||||
|
ProjectFlockKandangID: row.ProjectFlockKandangID,
|
||||||
|
EggProductionWeightKg: row.EggProductionWeightKg,
|
||||||
|
EggProductionPieces: row.EggProductionPieces,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
|
||||||
func applyLocationFilters(query *gorm.DB, areaIDs, locationIDs, kandangIDs []int64) *gorm.DB {
|
func applyLocationFilters(query *gorm.DB, areaIDs, locationIDs, kandangIDs []int64) *gorm.DB {
|
||||||
if len(areaIDs) > 0 {
|
if len(areaIDs) > 0 {
|
||||||
query = query.Where("loc.area_id IN ?", areaIDs)
|
query = query.Where("loc.area_id IN ?", areaIDs)
|
||||||
|
|||||||
@@ -1267,10 +1267,37 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
costRows, supplierRows, err := s.HppPerKandangRepo.GetFeedOvkDocCostByPeriod(ctx.Context(), startOfDay, endOfDay, params.AreaIDs, params.LocationIDs, params.KandangIDs)
|
|
||||||
if err != nil {
|
validPfkIDs := make([]uint, 0, len(repoRows))
|
||||||
return nil, nil, err
|
pfkIndex := make(map[uint]int, len(repoRows))
|
||||||
|
for idx := range repoRows {
|
||||||
|
row := repoRows[idx]
|
||||||
|
pfkIndex[row.ProjectFlockKandangID] = idx
|
||||||
|
if row.RecordingCount > 0 {
|
||||||
|
validPfkIDs = append(validPfkIDs, row.ProjectFlockKandangID)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
costRows := make([]repportRepo.HppPerKandangCostRow, 0)
|
||||||
|
supplierRows := make([]repportRepo.HppPerKandangSupplierRow, 0)
|
||||||
|
if len(validPfkIDs) > 0 {
|
||||||
|
costRows, supplierRows, err = s.HppPerKandangRepo.GetFeedOvkDocCostByPeriod(ctx.Context(), startOfDay, endOfDay, validPfkIDs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
eggMap, err := s.HppPerKandangRepo.GetEggProductionByProjectFlockKandangIDs(ctx.Context(), startOfDay, endOfDay, validPfkIDs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
for pfkID, egg := range eggMap {
|
||||||
|
if rowIdx, ok := pfkIndex[pfkID]; ok {
|
||||||
|
repoRows[rowIdx].EggProductionWeightKg = egg.EggProductionWeightKg
|
||||||
|
repoRows[rowIdx].EggProductionPieces = egg.EggProductionPieces
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
costMap := make(map[uint]HppCostAggregate, len(costRows))
|
costMap := make(map[uint]HppCostAggregate, len(costRows))
|
||||||
for _, row := range costRows {
|
for _, row := range costRows {
|
||||||
costMap[row.KandangID] = HppCostAggregate{
|
costMap[row.KandangID] = HppCostAggregate{
|
||||||
@@ -1323,9 +1350,15 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes
|
|||||||
Max float64
|
Max float64
|
||||||
}
|
}
|
||||||
type weightRangeAggregate struct {
|
type weightRangeAggregate struct {
|
||||||
Summary *dto.HppPerKandangSummaryWeightRangeDTO
|
Summary *dto.HppPerKandangSummaryWeightRangeDTO
|
||||||
EggHppSum float64
|
RemainingBirds int64
|
||||||
EggHppCount int
|
RemainingWeightKg float64
|
||||||
|
AvgWeightSum float64
|
||||||
|
AvgWeightCount int64
|
||||||
|
EggHppSum float64
|
||||||
|
EggHppCount int
|
||||||
|
FeedSuppliers map[int64]dto.HppPerKandangSupplierDTO
|
||||||
|
DocSuppliers map[int64]dto.HppPerKandangSupplierDTO
|
||||||
}
|
}
|
||||||
|
|
||||||
dataRows := make([]dto.HppPerKandangRowDTO, 0, len(repoRows))
|
dataRows := make([]dto.HppPerKandangRowDTO, 0, len(repoRows))
|
||||||
@@ -1342,8 +1375,14 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes
|
|||||||
var totalDocPriceCount int
|
var totalDocPriceCount int
|
||||||
var totalEggHppSum float64
|
var totalEggHppSum float64
|
||||||
var totalEggHppCount int
|
var totalEggHppCount int
|
||||||
|
var totalAvgWeightSum float64
|
||||||
|
var totalAvgWeightCount int64
|
||||||
|
|
||||||
for _, row := range repoRows {
|
for _, row := range repoRows {
|
||||||
|
if !params.ShowUnrecorded && row.RecordingCount == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
birdsFloat := row.RemainingChickenBirds
|
birdsFloat := row.RemainingChickenBirds
|
||||||
if math.IsNaN(birdsFloat) || math.IsInf(birdsFloat, 0) {
|
if math.IsNaN(birdsFloat) || math.IsInf(birdsFloat, 0) {
|
||||||
birdsFloat = 0
|
birdsFloat = 0
|
||||||
@@ -1362,9 +1401,16 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes
|
|||||||
}
|
}
|
||||||
|
|
||||||
avgWeight := 0.0
|
avgWeight := 0.0
|
||||||
if birdsFloat > 0 {
|
if eggPiecesFloat > 0 {
|
||||||
avgWeight = weightFloat / birdsFloat
|
avgWeight = eggWeightFloat / eggPiecesFloat
|
||||||
}
|
}
|
||||||
|
if params.WeightMin != nil && avgWeight < *params.WeightMin {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if params.WeightMax != nil && avgWeight > *params.WeightMax {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
weightMin := math.Floor(avgWeight*10) / 10
|
weightMin := math.Floor(avgWeight*10) / 10
|
||||||
if weightMin < 0 {
|
if weightMin < 0 {
|
||||||
weightMin = 0
|
weightMin = 0
|
||||||
@@ -1411,9 +1457,7 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes
|
|||||||
WeightMin: weightMin,
|
WeightMin: weightMin,
|
||||||
WeightMax: weightMax,
|
WeightMax: weightMax,
|
||||||
},
|
},
|
||||||
RemainingChickenBirds: rowBirds,
|
AvgWeightKg: avgWeight,
|
||||||
RemainingChickenWeightKg: weightFloat,
|
|
||||||
AvgWeightKg: avgWeight,
|
|
||||||
// FeedCostRp: costEntry.FeedCost,
|
// FeedCostRp: costEntry.FeedCost,
|
||||||
// OvkCostRp: costEntry.OvkCost,
|
// OvkCostRp: costEntry.OvkCost,
|
||||||
DocSuppliers: docSupplierMap[row.KandangID],
|
DocSuppliers: docSupplierMap[row.KandangID],
|
||||||
@@ -1421,10 +1465,10 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes
|
|||||||
EggProductionPieces: rowEggPieces,
|
EggProductionPieces: rowEggPieces,
|
||||||
EggProductionKg: eggWeightFloat,
|
EggProductionKg: eggWeightFloat,
|
||||||
AverageDocPriceRp: avgDocPrice,
|
AverageDocPriceRp: avgDocPrice,
|
||||||
HppRp: hppRp,
|
// HppRp: hppRp,
|
||||||
EggHppRpPerKg: eggHpp,
|
EggHppRpPerKg: eggHpp,
|
||||||
RemainingValueRp: rowRemainingValue,
|
RemainingValueRp: rowRemainingValue,
|
||||||
EggValueRp: rowEggValue,
|
EggValueRp: rowEggValue,
|
||||||
})
|
})
|
||||||
|
|
||||||
totalBirds += rowBirds
|
totalBirds += rowBirds
|
||||||
@@ -1433,6 +1477,8 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes
|
|||||||
totalEggKg += eggWeightFloat
|
totalEggKg += eggWeightFloat
|
||||||
totalRemainingValueRp += rowRemainingValue
|
totalRemainingValueRp += rowRemainingValue
|
||||||
totalEggValueRp += rowEggValue
|
totalEggValueRp += rowEggValue
|
||||||
|
totalAvgWeightSum += avgWeight
|
||||||
|
totalAvgWeightCount++
|
||||||
if weightFloat > 0 {
|
if weightFloat > 0 {
|
||||||
totalHppSum += hppRp
|
totalHppSum += hppRp
|
||||||
totalHppCount++
|
totalHppCount++
|
||||||
@@ -1456,13 +1502,27 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes
|
|||||||
},
|
},
|
||||||
Label: fmt.Sprintf("%.2f - %.2f", weightMin, weightMax),
|
Label: fmt.Sprintf("%.2f - %.2f", weightMin, weightMax),
|
||||||
},
|
},
|
||||||
|
FeedSuppliers: make(map[int64]dto.HppPerKandangSupplierDTO),
|
||||||
|
DocSuppliers: make(map[int64]dto.HppPerKandangSupplierDTO),
|
||||||
}
|
}
|
||||||
perRangeMap[rangeKey] = rangeAgg
|
perRangeMap[rangeKey] = rangeAgg
|
||||||
}
|
}
|
||||||
|
|
||||||
rangeSummary := rangeAgg.Summary
|
rangeSummary := rangeAgg.Summary
|
||||||
rangeSummary.RemainingChickenBirds += rowBirds
|
rangeAgg.RemainingBirds += rowBirds
|
||||||
rangeSummary.RemainingChickenWeightKg += row.RemainingChickenWeight
|
rangeAgg.RemainingWeightKg += row.RemainingChickenWeight
|
||||||
|
rangeAgg.AvgWeightSum += avgWeight
|
||||||
|
rangeAgg.AvgWeightCount++
|
||||||
|
for _, supplier := range feedSupplierMap[row.KandangID] {
|
||||||
|
if _, ok := rangeAgg.FeedSuppliers[supplier.ID]; !ok {
|
||||||
|
rangeAgg.FeedSuppliers[supplier.ID] = supplier
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, supplier := range docSupplierMap[row.KandangID] {
|
||||||
|
if _, ok := rangeAgg.DocSuppliers[supplier.ID]; !ok {
|
||||||
|
rangeAgg.DocSuppliers[supplier.ID] = supplier
|
||||||
|
}
|
||||||
|
}
|
||||||
rangeSummary.EggProductionPieces += rowEggPieces
|
rangeSummary.EggProductionPieces += rowEggPieces
|
||||||
rangeSummary.EggProductionKg += eggWeightFloat
|
rangeSummary.EggProductionKg += eggWeightFloat
|
||||||
rangeSummary.RemainingValueRp += rowRemainingValue
|
rangeSummary.RemainingValueRp += rowRemainingValue
|
||||||
@@ -1489,31 +1549,37 @@ func (s *repportService) GetHppPerKandang(ctx *fiber.Ctx) (*dto.HppPerKandangRes
|
|||||||
agg := perRangeMap[key]
|
agg := perRangeMap[key]
|
||||||
entry := agg.Summary
|
entry := agg.Summary
|
||||||
entry.ID = idx + 1
|
entry.ID = idx + 1
|
||||||
if entry.RemainingChickenBirds > 0 {
|
if agg.AvgWeightCount > 0 {
|
||||||
entry.AvgWeightKg = entry.RemainingChickenWeightKg / float64(entry.RemainingChickenBirds)
|
entry.AvgWeightKg = agg.AvgWeightSum / float64(agg.AvgWeightCount)
|
||||||
}
|
}
|
||||||
if agg.EggHppCount > 0 {
|
if agg.EggHppCount > 0 {
|
||||||
entry.EggHppRpPerKg = agg.EggHppSum / float64(agg.EggHppCount)
|
entry.EggHppRpPerKg = agg.EggHppSum / float64(agg.EggHppCount)
|
||||||
}
|
}
|
||||||
|
entry.FeedSuppliers = make([]dto.HppPerKandangSupplierDTO, 0, len(agg.FeedSuppliers))
|
||||||
|
for _, supplier := range agg.FeedSuppliers {
|
||||||
|
entry.FeedSuppliers = append(entry.FeedSuppliers, supplier)
|
||||||
|
}
|
||||||
|
entry.DocSuppliers = make([]dto.HppPerKandangSupplierDTO, 0, len(agg.DocSuppliers))
|
||||||
|
for _, supplier := range agg.DocSuppliers {
|
||||||
|
entry.DocSuppliers = append(entry.DocSuppliers, supplier)
|
||||||
|
}
|
||||||
perRangeSummary = append(perRangeSummary, *entry)
|
perRangeSummary = append(perRangeSummary, *entry)
|
||||||
}
|
}
|
||||||
|
|
||||||
totalSummary := dto.HppPerKandangSummaryTotalDTO{
|
totalSummary := dto.HppPerKandangSummaryTotalDTO{
|
||||||
TotalRemainingChickenBirds: totalBirds,
|
TotalEggProductionPieces: totalEggPieces,
|
||||||
TotalRemainingChickenWeightKg: totalWeight,
|
TotalEggProductionKg: totalEggKg,
|
||||||
TotalEggProductionPieces: totalEggPieces,
|
TotalEggValueRp: totalEggValueRp,
|
||||||
TotalEggProductionKg: totalEggKg,
|
|
||||||
TotalRemainingValueRp: totalRemainingValueRp,
|
|
||||||
TotalEggValueRp: totalEggValueRp,
|
|
||||||
}
|
}
|
||||||
if totalBirds > 0 {
|
if totalBirds > 0 {
|
||||||
totalSummary.AverageWeightKg = totalWeight / float64(totalBirds)
|
}
|
||||||
|
if totalAvgWeightCount > 0 {
|
||||||
|
totalSummary.AverageWeightKg = totalAvgWeightSum / float64(totalAvgWeightCount)
|
||||||
}
|
}
|
||||||
if totalEggHppCount > 0 {
|
if totalEggHppCount > 0 {
|
||||||
totalSummary.AverageEggHppRpPerKg = totalEggHppSum / float64(totalEggHppCount)
|
totalSummary.AverageEggHppRpPerKg = totalEggHppSum / float64(totalEggHppCount)
|
||||||
}
|
}
|
||||||
if totalHppCount > 0 {
|
if totalHppCount > 0 {
|
||||||
totalSummary.TotalHppRp = totalHppSum / float64(totalHppCount)
|
|
||||||
}
|
}
|
||||||
if totalDocPriceCount > 0 {
|
if totalDocPriceCount > 0 {
|
||||||
totalSummary.TotalAverageDocPriceRp = totalDocPriceSum / float64(totalDocPriceCount)
|
totalSummary.TotalAverageDocPriceRp = totalDocPriceSum / float64(totalDocPriceCount)
|
||||||
|
|||||||
Reference in New Issue
Block a user