mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-20 13:31:56 +00:00
Merge branch 'fix/BE/US-281-adjustment-recording-egg-mass' into 'development'
[FEAT/BE] fix bug recording and closing counting sapronak See merge request mbugroup/lti-api!296
This commit is contained in:
@@ -234,14 +234,14 @@ func ToSapronakProjectAggregatedFromReport(report *SapronakReportDTO, flag strin
|
||||
row.Notes = "TRANSFER STOCK"
|
||||
}
|
||||
}
|
||||
case "pemakaian", "adjustment keluar":
|
||||
case "pemakaian":
|
||||
price := row.UnitPrice
|
||||
if price == 0 {
|
||||
price = item.Harga
|
||||
}
|
||||
row.QtyUsed += item.QtyKeluar
|
||||
row.TotalAmount += item.QtyKeluar * price
|
||||
case "mutasi keluar", "penjualan":
|
||||
case "adjustment keluar", "mutasi keluar", "penjualan":
|
||||
price := row.UnitPrice
|
||||
if price == 0 {
|
||||
price = item.Harga
|
||||
|
||||
@@ -36,6 +36,7 @@ type ClosingRepository interface {
|
||||
FetchSapronakAdjustments(ctx context.Context, kandangID uint) (map[uint][]SapronakDetailRow, map[uint][]SapronakDetailRow, error)
|
||||
FetchSapronakTransfers(ctx context.Context, kandangID uint) (map[uint][]SapronakDetailRow, map[uint][]SapronakDetailRow, error)
|
||||
FetchSapronakSales(ctx context.Context, projectFlockKandangID uint) (map[uint][]SapronakDetailRow, error)
|
||||
FetchSapronakSalesAllocatedDetails(ctx context.Context, projectFlockKandangID uint) (map[uint][]SapronakDetailRow, error)
|
||||
GetProductsWithFlagsByIDs(ctx context.Context, productIDs []uint) ([]entity.Product, error)
|
||||
}
|
||||
|
||||
@@ -939,6 +940,7 @@ func (r *ClosingRepositoryImpl) FetchSapronakUsageAllocatedDetails(ctx context.C
|
||||
Joins("LEFT JOIN project_flock_populations pfp ON pfp.id = sa.stockable_id AND sa.stockable_type = ?", fifo.StockableKeyProjectFlockPopulation.String()).
|
||||
Joins("LEFT JOIN project_chickins pc ON pc.id = pfp.project_chickin_id").
|
||||
Where("sa.status = ?", entity.StockAllocationStatusActive).
|
||||
Where("sa.stockable_type <> ?", fifo.StockableKeyProjectFlockPopulation.String()).
|
||||
Where("f.name IN ?", sapronakFlagsAll).
|
||||
Where(`
|
||||
(sa.usable_type = ? AND r.project_flock_kandangs_id = ?)
|
||||
@@ -1085,12 +1087,75 @@ func splitStockLogs(rows []stockLogSapronakRow, refFn func(stockLogSapronakRow)
|
||||
}
|
||||
|
||||
func (r *ClosingRepositoryImpl) FetchSapronakAdjustments(ctx context.Context, kandangID uint) (map[uint][]SapronakDetailRow, map[uint][]SapronakDetailRow, error) {
|
||||
rows, err := r.fetchStockLogs(ctx, kandangID, string(utils.StockLogTypeAdjustment), false)
|
||||
poByWarehouse := r.DB().
|
||||
Table("purchase_items pi").
|
||||
Select("DISTINCT ON (pi.product_warehouse_id) pi.product_warehouse_id, po.po_number, pi.received_date").
|
||||
Joins("JOIN purchases po ON po.id = pi.purchase_id").
|
||||
Where("pi.received_date IS NOT NULL").
|
||||
Order("pi.product_warehouse_id, pi.received_date ASC")
|
||||
|
||||
incomingQuery := r.withCtx(ctx).
|
||||
Table("adjustment_stocks AS ast").
|
||||
Select(`
|
||||
pw.product_id AS product_id,
|
||||
p.name AS product_name,
|
||||
f.name AS flag,
|
||||
ast.created_at AS date,
|
||||
CONCAT('ADJ-', ast.id) AS reference,
|
||||
COALESCE(ast.total_qty, 0) AS qty_in,
|
||||
0 AS qty_out,
|
||||
COALESCE(p.product_price, 0) AS price
|
||||
`).
|
||||
Joins("JOIN product_warehouses pw ON pw.id = ast.product_warehouse_id").
|
||||
Joins("JOIN warehouses w ON w.id = pw.warehouse_id").
|
||||
Joins("JOIN products p ON p.id = pw.product_id").
|
||||
Where("w.kandang_id = ?", kandangID).
|
||||
Where("f.name IN ?", sapronakFlagsAll).
|
||||
Where("COALESCE(ast.total_qty, 0) > 0")
|
||||
incomingQuery = r.joinSapronakProductFlag(incomingQuery, "p")
|
||||
incoming, err := scanAndGroupDetails(incomingQuery)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
in, out := splitStockLogs(rows, func(row stockLogSapronakRow) string { return fmt.Sprintf("ADJ-%d", row.ID) })
|
||||
return in, out, nil
|
||||
|
||||
outgoingQuery := r.withCtx(ctx).
|
||||
Table("stock_allocations AS sa").
|
||||
Select(`
|
||||
pw.product_id AS product_id,
|
||||
p.name AS product_name,
|
||||
f.name AS flag,
|
||||
COALESCE(pi.received_date, st.transfer_date, lt.transfer_date, pfp_po.received_date, pc.chick_in_date, ast_in.created_at, ast.created_at) AS date,
|
||||
COALESCE(po.po_number, st.movement_number, lt.transfer_number, pfp_po.po_number, CONCAT('CHICKIN-', pc.id), CONCAT('ADJ-', ast_in.id), CONCAT('ADJ-', ast.id)) AS reference,
|
||||
0 AS qty_in,
|
||||
COALESCE(SUM(sa.qty), 0) AS qty_out,
|
||||
COALESCE(p.product_price, 0) AS price
|
||||
`).
|
||||
Joins("JOIN adjustment_stocks ast ON ast.id = sa.usable_id AND sa.usable_type = ?", fifo.UsableKeyAdjustmentOut.String()).
|
||||
Joins("LEFT JOIN purchase_items pi ON pi.id = sa.stockable_id AND sa.stockable_type = ?", fifo.StockableKeyPurchaseItems.String()).
|
||||
Joins("LEFT JOIN purchases po ON po.id = pi.purchase_id").
|
||||
Joins("LEFT JOIN stock_transfer_details std ON std.id = sa.stockable_id AND sa.stockable_type = ?", fifo.StockableKeyStockTransferIn.String()).
|
||||
Joins("LEFT JOIN stock_transfers st ON st.id = std.stock_transfer_id").
|
||||
Joins("LEFT JOIN laying_transfer_targets ltt ON ltt.id = sa.stockable_id AND sa.stockable_type = ?", fifo.StockableKeyTransferToLayingIn.String()).
|
||||
Joins("LEFT JOIN laying_transfers lt ON lt.id = ltt.laying_transfer_id").
|
||||
Joins("LEFT JOIN adjustment_stocks ast_in ON ast_in.id = sa.stockable_id AND sa.stockable_type = ?", fifo.StockableKeyAdjustmentIn.String()).
|
||||
Joins("LEFT JOIN project_flock_populations pfp ON pfp.id = sa.stockable_id AND sa.stockable_type = ?", fifo.StockableKeyProjectFlockPopulation.String()).
|
||||
Joins("LEFT JOIN project_chickins pc ON pc.id = pfp.project_chickin_id").
|
||||
Joins("LEFT JOIN (?) pfp_po ON pfp_po.product_warehouse_id = pfp.product_warehouse_id", poByWarehouse).
|
||||
Joins("JOIN product_warehouses pw ON pw.id = sa.product_warehouse_id").
|
||||
Joins("JOIN warehouses w ON w.id = pw.warehouse_id").
|
||||
Joins("JOIN products p ON p.id = pw.product_id").
|
||||
Where("sa.status = ?", entity.StockAllocationStatusActive).
|
||||
Where("w.kandang_id = ?", kandangID).
|
||||
Where("f.name IN ?", sapronakFlagsAll).
|
||||
Where("f.name NOT IN ?", sapronakFlags(utils.FlagDOC, utils.FlagPullet)).
|
||||
Group("pw.product_id, p.name, f.name, pi.received_date, st.transfer_date, lt.transfer_date, pfp_po.received_date, pc.chick_in_date, ast_in.created_at, ast.created_at, po.po_number, st.movement_number, lt.transfer_number, pfp_po.po_number, pc.id, ast_in.id, ast.id, p.product_price")
|
||||
outgoingQuery = r.joinSapronakProductFlag(outgoingQuery, "p")
|
||||
outgoing, err := scanAndGroupDetails(outgoingQuery)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return incoming, outgoing, nil
|
||||
}
|
||||
|
||||
func (r *ClosingRepositoryImpl) FetchSapronakTransfers(ctx context.Context, kandangID uint) (map[uint][]SapronakDetailRow, map[uint][]SapronakDetailRow, error) {
|
||||
@@ -1286,6 +1351,59 @@ func (r *ClosingRepositoryImpl) FetchSapronakSales(ctx context.Context, projectF
|
||||
return sales, nil
|
||||
}
|
||||
|
||||
func (r *ClosingRepositoryImpl) FetchSapronakSalesAllocatedDetails(ctx context.Context, projectFlockKandangID uint) (map[uint][]SapronakDetailRow, error) {
|
||||
if projectFlockKandangID == 0 {
|
||||
return map[uint][]SapronakDetailRow{}, nil
|
||||
}
|
||||
|
||||
query := r.withCtx(ctx).
|
||||
Table("stock_allocations AS sa").
|
||||
Select(`
|
||||
pw.product_id AS product_id,
|
||||
p.name AS product_name,
|
||||
f.name AS flag,
|
||||
COALESCE(
|
||||
pi.received_date,
|
||||
st.transfer_date,
|
||||
lt.transfer_date,
|
||||
ast.created_at
|
||||
) AS date,
|
||||
COALESCE(
|
||||
po.po_number,
|
||||
st.movement_number,
|
||||
lt.transfer_number,
|
||||
CONCAT('ADJ-', ast.id),
|
||||
''
|
||||
) AS reference,
|
||||
0 AS qty_in,
|
||||
COALESCE(SUM(sa.qty), 0) AS qty_out,
|
||||
COALESCE(pi.price, p.product_price, 0) AS price
|
||||
`).
|
||||
Joins("JOIN product_warehouses pw ON pw.id = sa.product_warehouse_id").
|
||||
Joins("JOIN products p ON p.id = pw.product_id").
|
||||
Joins("JOIN marketing_delivery_products mdp ON mdp.id = sa.usable_id AND sa.usable_type = ?", fifo.UsableKeyMarketingDelivery.String()).
|
||||
Joins("LEFT JOIN purchase_items pi ON pi.id = sa.stockable_id AND sa.stockable_type = ?", fifo.StockableKeyPurchaseItems.String()).
|
||||
Joins("LEFT JOIN purchases po ON po.id = pi.purchase_id").
|
||||
Joins("LEFT JOIN stock_transfer_details std ON std.id = sa.stockable_id AND sa.stockable_type = ?", fifo.StockableKeyStockTransferIn.String()).
|
||||
Joins("LEFT JOIN stock_transfers st ON st.id = std.stock_transfer_id").
|
||||
Joins("LEFT JOIN laying_transfer_targets ltt ON ltt.id = sa.stockable_id AND sa.stockable_type = ?", fifo.StockableKeyTransferToLayingIn.String()).
|
||||
Joins("LEFT JOIN laying_transfers lt ON lt.id = ltt.laying_transfer_id").
|
||||
Joins("LEFT JOIN adjustment_stocks ast ON ast.id = sa.stockable_id AND sa.stockable_type = ?", fifo.StockableKeyAdjustmentIn.String()).
|
||||
Where("sa.status = ?", entity.StockAllocationStatusActive).
|
||||
Where("sa.stockable_type <> ?", fifo.StockableKeyProjectFlockPopulation.String()).
|
||||
Where("pw.project_flock_kandang_id = ?", projectFlockKandangID).
|
||||
Where("f.name IN ?", sapronakFlagsAll).
|
||||
Group(`
|
||||
pw.product_id, p.name, f.name,
|
||||
pi.received_date, st.transfer_date, lt.transfer_date, ast.created_at,
|
||||
po.po_number, st.movement_number, lt.transfer_number, ast.id,
|
||||
pi.price, p.product_price
|
||||
`)
|
||||
|
||||
query = r.joinSapronakProductFlag(query, "p")
|
||||
return scanAndGroupDetails(query)
|
||||
}
|
||||
|
||||
func (r *ClosingRepositoryImpl) GetProductsWithFlagsByIDs(ctx context.Context, productIDs []uint) ([]entity.Product, error) {
|
||||
if len(productIDs) == 0 {
|
||||
return []entity.Product{}, nil
|
||||
|
||||
@@ -363,7 +363,7 @@ func (s sapronakService) buildSapronakItems(ctx context.Context, pfk entity.Proj
|
||||
if err != nil {
|
||||
return nil, nil, 0, 0, err
|
||||
}
|
||||
salesOutRows, err := s.Repository.FetchSapronakSales(ctx, pfk.Id)
|
||||
salesOutRows, err := s.Repository.FetchSapronakSalesAllocatedDetails(ctx, pfk.Id)
|
||||
if err != nil {
|
||||
return nil, nil, 0, 0, err
|
||||
}
|
||||
@@ -570,13 +570,12 @@ func (s sapronakService) buildSapronakItems(ctx context.Context, pfk entity.Proj
|
||||
if existing.ProductName == "" {
|
||||
existing.ProductName = d.ProductName
|
||||
}
|
||||
existing.UsageQty += d.QtyKeluar
|
||||
existing.UsageValue += d.Nilai
|
||||
if existing.IncomingQty >= existing.UsageQty {
|
||||
existing.RemainingQty = existing.IncomingQty - existing.UsageQty
|
||||
} else {
|
||||
existing.RemainingQty = 0
|
||||
// Adjustment keluar should reduce stock without inflating usage-based HPP.
|
||||
remaining := existing.IncomingQty - existing.UsageQty - d.QtyKeluar
|
||||
if remaining < 0 {
|
||||
remaining = 0
|
||||
}
|
||||
existing.RemainingQty = remaining
|
||||
itemMap[productID] = existing
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user