mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-24 07:15:43 +00:00
feat: reimplement with plan hppv2 flow and logics
This commit is contained in:
@@ -2,6 +2,7 @@ package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||
@@ -10,8 +11,61 @@ import (
|
||||
"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)
|
||||
@@ -27,6 +81,33 @@ 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).
|
||||
@@ -41,6 +122,241 @@ func (r *HppV2RepositoryImpl) GetProjectFlockKandangIDs(ctx context.Context, pro
|
||||
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()
|
||||
@@ -122,10 +438,13 @@ func (r *HppV2RepositoryImpl) GetEggProduksiPiecesAndWeightKgByProjectFlockKanda
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
var adjustmentTotalWeight float64
|
||||
var adjustmentTotals struct {
|
||||
TotalQty float64
|
||||
TotalWeight float64
|
||||
}
|
||||
adjustmentSubQuery := r.db.WithContext(ctx).
|
||||
Table("recordings AS r").
|
||||
Select("DISTINCT ast.id AS adjustment_id, ast.price AS price").
|
||||
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(
|
||||
@@ -141,13 +460,14 @@ func (r *HppV2RepositoryImpl) GetEggProduksiPiecesAndWeightKgByProjectFlockKanda
|
||||
|
||||
err = r.db.WithContext(ctx).
|
||||
Table("(?) AS adjustment_sources", adjustmentSubQuery).
|
||||
Select("COALESCE(SUM(adjustment_sources.price), 0)").
|
||||
Scan(&adjustmentTotalWeight).Error
|
||||
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.TotalWeightKg += adjustmentTotalWeight
|
||||
totals.TotalPieces += adjustmentTotals.TotalQty
|
||||
totals.TotalWeightKg += adjustmentTotals.TotalWeight
|
||||
|
||||
return totals.TotalPieces, totals.TotalWeightKg, nil
|
||||
}
|
||||
@@ -200,7 +520,7 @@ sales_kandang AS (
|
||||
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 mdp.delivery_date <= ?
|
||||
AND UPPER(COALESCE(w.type, '')) = 'KANDANG'
|
||||
AND pw.project_flock_kandang_id IN (SELECT id FROM selected_pfk)
|
||||
AND EXISTS (
|
||||
@@ -234,7 +554,7 @@ sales_lokasi AS (
|
||||
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 mdp.delivery_date <= ?
|
||||
AND UPPER(COALESCE(w.type, '')) = 'LOKASI'
|
||||
AND w.location_id IN (SELECT location_id FROM selected_locations)
|
||||
AND EXISTS (
|
||||
@@ -390,10 +710,10 @@ CROSS JOIN lokasi_rec_totals lrt
|
||||
Raw(
|
||||
query,
|
||||
projectFlockKandangIDs,
|
||||
*startDate,
|
||||
*endDate,
|
||||
entity.FlagableTypeProduct,
|
||||
eggFlags,
|
||||
*startDate,
|
||||
*endDate,
|
||||
entity.FlagableTypeProduct,
|
||||
eggFlags,
|
||||
string(utils.AdjustmentTransactionSubtypeRecordingEggIn),
|
||||
|
||||
Reference in New Issue
Block a user