mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-24 15:25:43 +00:00
389 lines
13 KiB
Go
389 lines
13 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
"time"
|
|
|
|
"gitlab.com/mbugroup/lti-api.git/internal/common/repository"
|
|
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
|
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/closings/validations"
|
|
"gitlab.com/mbugroup/lti-api.git/internal/utils"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type ClosingRepository interface {
|
|
repository.BaseRepository[entity.ProjectFlock]
|
|
GetSapronak(ctx context.Context, params SapronakQueryParams) ([]SapronakRow, int64, error)
|
|
SumFeedPurchaseAndUsedByProjectFlockKandangIDs(ctx context.Context, projectFlockKandangIDs []uint) (float64, float64, error)
|
|
SumClaimCullingByProjectFlockKandangIDs(ctx context.Context, projectFlockKandangIDs []uint) (float64, error)
|
|
SumMarketingWeightAndQtyByProjectFlockKandangIDs(ctx context.Context, projectFlockKandangIDs []uint) (float64, float64, float64, error)
|
|
SumMarketingWeightAndQtyByProjectFlockKandangIDsAndFlagNames(ctx context.Context, projectFlockKandangIDs []uint, flagNames []string) (float64, float64, float64, error)
|
|
SumRecordingEggQtyByProjectFlockKandangIDsAndFlagNames(ctx context.Context, projectFlockKandangIDs []uint, flagNames []string) (float64, error)
|
|
GetFcrStandardsByFcrID(ctx context.Context, fcrID uint) ([]entity.FcrStandard, error)
|
|
}
|
|
|
|
type ClosingRepositoryImpl struct {
|
|
*repository.BaseRepositoryImpl[entity.ProjectFlock]
|
|
}
|
|
|
|
func NewClosingRepository(db *gorm.DB) ClosingRepository {
|
|
return &ClosingRepositoryImpl{
|
|
BaseRepositoryImpl: repository.NewBaseRepository[entity.ProjectFlock](db),
|
|
}
|
|
}
|
|
|
|
type SapronakRow struct {
|
|
Id uint64 `gorm:"column:id"`
|
|
SortDate time.Time `gorm:"column:sort_date"`
|
|
DateText string `gorm:"column:date_text"`
|
|
ReferenceNumber string `gorm:"column:reference_number"`
|
|
TransactionType string `gorm:"column:transaction_type"`
|
|
ProductName string `gorm:"column:product_name"`
|
|
ProductCategory string `gorm:"column:product_category"`
|
|
ProductSubCategory string `gorm:"column:product_sub_category"`
|
|
SourceWarehouse string `gorm:"column:source_warehouse"`
|
|
DestinationWarehouse string `gorm:"column:destination_warehouse"`
|
|
Destination string `gorm:"column:destination"`
|
|
Quantity float64 `gorm:"column:quantity"`
|
|
Unit string `gorm:"column:unit"`
|
|
Notes string `gorm:"column:notes"`
|
|
}
|
|
|
|
type SapronakQueryParams struct {
|
|
Type string
|
|
WarehouseIDs []uint
|
|
ProjectFlockKandangIDs []uint
|
|
Limit int
|
|
Offset int
|
|
}
|
|
|
|
func (r *ClosingRepositoryImpl) GetSapronak(ctx context.Context, params SapronakQueryParams) ([]SapronakRow, int64, error) {
|
|
db := r.DB().WithContext(ctx)
|
|
|
|
var (
|
|
unionParts []string
|
|
args []any
|
|
)
|
|
|
|
switch params.Type {
|
|
case validation.SapronakTypeIncoming:
|
|
if len(params.WarehouseIDs) == 0 {
|
|
return []SapronakRow{}, 0, nil
|
|
}
|
|
unionParts = append(unionParts, sapronakIncomingPurchasesSQL, sapronakIncomingTransfersSQL)
|
|
args = append(args, params.WarehouseIDs, params.WarehouseIDs)
|
|
case validation.SapronakTypeOutgoing:
|
|
if len(params.WarehouseIDs) > 0 {
|
|
unionParts = append(unionParts, sapronakOutgoingTransfersSQL)
|
|
args = append(args, params.WarehouseIDs)
|
|
}
|
|
if len(params.ProjectFlockKandangIDs) > 0 {
|
|
unionParts = append(unionParts, sapronakOutgoingMarketingsSQL)
|
|
args = append(args, params.ProjectFlockKandangIDs)
|
|
}
|
|
if len(unionParts) == 0 {
|
|
return []SapronakRow{}, 0, nil
|
|
}
|
|
default:
|
|
return nil, 0, fmt.Errorf("invalid sapronak type: %s", params.Type)
|
|
}
|
|
|
|
unionSQL := strings.Join(unionParts, " UNION ALL ")
|
|
|
|
var totalResults int64
|
|
countSQL := fmt.Sprintf("SELECT COUNT(*) FROM (%s) AS combined", unionSQL)
|
|
if err := db.Raw(countSQL, args...).Scan(&totalResults).Error; err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
dataArgs := append(append([]any{}, args...), params.Limit, params.Offset)
|
|
dataSQL := fmt.Sprintf("SELECT * FROM (%s) AS combined ORDER BY sort_date ASC, id ASC LIMIT ? OFFSET ?", unionSQL)
|
|
|
|
var rows []SapronakRow
|
|
if err := db.Raw(dataSQL, dataArgs...).Scan(&rows).Error; err != nil {
|
|
return nil, 0, err
|
|
}
|
|
|
|
return rows, totalResults, nil
|
|
}
|
|
|
|
func (r *ClosingRepositoryImpl) SumFeedPurchaseAndUsedByProjectFlockKandangIDs(ctx context.Context, projectFlockKandangIDs []uint) (float64, float64, error) {
|
|
if len(projectFlockKandangIDs) == 0 {
|
|
return 0, 0, nil
|
|
}
|
|
|
|
var purchaseAgg struct {
|
|
TotalIn float64 `gorm:"column:total_in"`
|
|
}
|
|
|
|
err := r.DB().WithContext(ctx).
|
|
Table("purchase_items pi").
|
|
Joins("JOIN flags f ON f.flagable_id = pi.product_id AND f.flagable_type = 'products'").
|
|
Where("f.name = ?", "PAKAN").
|
|
Where("pi.project_flock_kandang_id IN ?", projectFlockKandangIDs).
|
|
Select("COALESCE(SUM(pi.total_qty), 0) AS total_in").
|
|
Scan(&purchaseAgg).Error
|
|
if err != nil {
|
|
return 0, 0, err
|
|
}
|
|
|
|
var usageAgg struct {
|
|
TotalUsed float64 `gorm:"column:total_used"`
|
|
}
|
|
|
|
err = r.DB().WithContext(ctx).
|
|
Table("recording_stocks rs").
|
|
Joins("JOIN product_warehouses pw ON pw.id = rs.product_warehouse_id").
|
|
Joins("JOIN products prod ON prod.id = pw.product_id").
|
|
Joins("JOIN flags f ON f.flagable_id = prod.id AND f.flagable_type = ?", "products").
|
|
Where("pw.project_flock_kandang_id IN ?", projectFlockKandangIDs).
|
|
Where("f.name = ?", "PAKAN").
|
|
Select("COALESCE(SUM(COALESCE(rs.usage_qty, 0) + COALESCE(rs.pending_qty, 0)), 0) AS total_used").
|
|
Scan(&usageAgg).Error
|
|
if err != nil {
|
|
return 0, 0, err
|
|
}
|
|
|
|
return purchaseAgg.TotalIn, usageAgg.TotalUsed, nil
|
|
}
|
|
|
|
func (r *ClosingRepositoryImpl) SumClaimCullingByProjectFlockKandangIDs(ctx context.Context, projectFlockKandangIDs []uint) (float64, error) {
|
|
if len(projectFlockKandangIDs) == 0 {
|
|
return 0, nil
|
|
}
|
|
|
|
var agg struct {
|
|
Total float64 `gorm:"column:total_culling"`
|
|
}
|
|
|
|
err := r.DB().WithContext(ctx).
|
|
Table("recording_depletions rd").
|
|
Joins("JOIN product_warehouses pw ON pw.id = rd.product_warehouse_id").
|
|
Joins("JOIN products prod ON prod.id = pw.product_id").
|
|
Joins("JOIN flags f ON f.flagable_id = prod.id AND f.flagable_type = ?", "products").
|
|
Where("pw.project_flock_kandang_id IN ?", projectFlockKandangIDs).
|
|
Where("f.name = ?", utils.FlagAyamCulling).
|
|
Select("COALESCE(SUM(rd.qty), 0) AS total_culling").
|
|
Scan(&agg).Error
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
return agg.Total, nil
|
|
}
|
|
|
|
func (r *ClosingRepositoryImpl) SumMarketingWeightAndQtyByProjectFlockKandangIDs(ctx context.Context, projectFlockKandangIDs []uint) (float64, float64, float64, error) {
|
|
if len(projectFlockKandangIDs) == 0 {
|
|
return 0, 0, 0, nil
|
|
}
|
|
|
|
var agg struct {
|
|
TotalWeight float64 `gorm:"column:total_weight"`
|
|
TotalQty float64 `gorm:"column:total_qty"`
|
|
TotalPrice float64 `gorm:"column:total_price"`
|
|
}
|
|
|
|
err := r.DB().WithContext(ctx).
|
|
Table("marketing_products mp").
|
|
Joins("JOIN product_warehouses pw ON pw.id = mp.product_warehouse_id").
|
|
Where("pw.project_flock_kandang_id IN ?", projectFlockKandangIDs).
|
|
Select("COALESCE(SUM(mp.total_weight), 0) AS total_weight, COALESCE(SUM(mp.qty), 0) AS total_qty, COALESCE(SUM(mp.total_price), 0) AS total_price").
|
|
Scan(&agg).Error
|
|
if err != nil {
|
|
return 0, 0, 0, err
|
|
}
|
|
|
|
return agg.TotalWeight, agg.TotalQty, agg.TotalPrice, nil
|
|
}
|
|
|
|
func (r *ClosingRepositoryImpl) SumMarketingWeightAndQtyByProjectFlockKandangIDsAndFlagNames(ctx context.Context, projectFlockKandangIDs []uint, flagNames []string) (float64, float64, float64, error) {
|
|
if len(projectFlockKandangIDs) == 0 || len(flagNames) == 0 {
|
|
return 0, 0, 0, nil
|
|
}
|
|
|
|
var agg struct {
|
|
TotalWeight float64 `gorm:"column:total_weight"`
|
|
TotalQty float64 `gorm:"column:total_qty"`
|
|
TotalPrice float64 `gorm:"column:total_price"`
|
|
}
|
|
|
|
err := r.DB().WithContext(ctx).
|
|
Table("marketing_products mp").
|
|
Joins("JOIN product_warehouses pw ON pw.id = mp.product_warehouse_id").
|
|
Joins("JOIN products prod ON prod.id = pw.product_id").
|
|
Joins("JOIN flags f ON f.flagable_id = prod.id AND f.flagable_type = ?", "products").
|
|
Where("pw.project_flock_kandang_id IN ?", projectFlockKandangIDs).
|
|
Where("f.name IN ?", flagNames).
|
|
Select("COALESCE(SUM(mp.total_weight), 0) AS total_weight, COALESCE(SUM(mp.qty), 0) AS total_qty, COALESCE(SUM(mp.total_price), 0) AS total_price").
|
|
Scan(&agg).Error
|
|
if err != nil {
|
|
return 0, 0, 0, err
|
|
}
|
|
|
|
return agg.TotalWeight, agg.TotalQty, agg.TotalPrice, nil
|
|
}
|
|
|
|
func (r *ClosingRepositoryImpl) SumRecordingEggQtyByProjectFlockKandangIDsAndFlagNames(ctx context.Context, projectFlockKandangIDs []uint, flagNames []string) (float64, error) {
|
|
if len(projectFlockKandangIDs) == 0 || len(flagNames) == 0 {
|
|
return 0, nil
|
|
}
|
|
|
|
var agg struct {
|
|
TotalQty float64 `gorm:"column:total_qty"`
|
|
}
|
|
|
|
err := r.DB().WithContext(ctx).
|
|
Table("recording_eggs re").
|
|
Joins("JOIN product_warehouses pw ON pw.id = re.product_warehouse_id").
|
|
Joins("JOIN products prod ON prod.id = pw.product_id").
|
|
Joins("JOIN flags f ON f.flagable_id = prod.id AND f.flagable_type = ?", "products").
|
|
Where("pw.project_flock_kandang_id IN ?", projectFlockKandangIDs).
|
|
Where("f.name IN ?", flagNames).
|
|
Select("COALESCE(SUM(re.qty), 0) AS total_qty").
|
|
Scan(&agg).Error
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
return agg.TotalQty, nil
|
|
}
|
|
|
|
func (r *ClosingRepositoryImpl) GetFcrStandardsByFcrID(ctx context.Context, fcrID uint) ([]entity.FcrStandard, error) {
|
|
if fcrID == 0 {
|
|
return []entity.FcrStandard{}, nil
|
|
}
|
|
|
|
var standards []entity.FcrStandard
|
|
if err := r.DB().WithContext(ctx).
|
|
Where("fcr_id = ?", fcrID).
|
|
Order("weight ASC").
|
|
Find(&standards).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return standards, nil
|
|
}
|
|
|
|
const (
|
|
sapronakIncomingPurchasesSQL = `
|
|
SELECT
|
|
CAST(pi.id AS BIGINT) AS id,
|
|
COALESCE(pi.received_date, '1970-01-01') AS sort_date,
|
|
COALESCE(TO_CHAR(pi.received_date, 'DD-Mon-YYYY'), '') AS date_text,
|
|
COALESCE(p.po_number, '') AS reference_number,
|
|
'Purchase' AS transaction_type,
|
|
prod.name AS product_name,
|
|
pc.name AS product_category,
|
|
COALESCE((
|
|
SELECT string_agg(f.name, ' ')
|
|
FROM flags f
|
|
WHERE f.flagable_type = 'products' AND f.flagable_id = prod.id
|
|
), '') AS product_sub_category,
|
|
'External Supplier' AS source_warehouse,
|
|
w.name AS destination_warehouse,
|
|
'' AS destination,
|
|
pi.total_qty AS quantity,
|
|
u.name AS unit,
|
|
COALESCE(p.notes, '') AS notes
|
|
FROM purchase_items pi
|
|
JOIN purchases p ON p.id = pi.purchase_id
|
|
JOIN products prod ON prod.id = pi.product_id
|
|
JOIN product_categories pc ON pc.id = prod.product_category_id
|
|
JOIN uoms u ON u.id = prod.uom_id
|
|
JOIN warehouses w ON w.id = pi.warehouse_id
|
|
WHERE pi.warehouse_id IN ?
|
|
`
|
|
|
|
sapronakIncomingTransfersSQL = `
|
|
SELECT
|
|
CAST(st.id AS BIGINT) AS id,
|
|
st.transfer_date AS sort_date,
|
|
TO_CHAR(st.transfer_date, 'DD-Mon-YYYY') AS date_text,
|
|
st.movement_number AS reference_number,
|
|
'Internal Transfer In' AS transaction_type,
|
|
prod.name AS product_name,
|
|
pc.name AS product_category,
|
|
COALESCE((
|
|
SELECT string_agg(f.name, ' ')
|
|
FROM flags f
|
|
WHERE f.flagable_type = 'products' AND f.flagable_id = prod.id
|
|
), '') AS product_sub_category,
|
|
COALESCE(fw.name, '') AS source_warehouse,
|
|
COALESCE(tw.name, '') AS destination_warehouse,
|
|
'' AS destination,
|
|
std.quantity AS quantity,
|
|
u.name AS unit,
|
|
'Stock Refill' AS notes
|
|
FROM stock_transfer_details std
|
|
JOIN stock_transfers st ON st.id = std.stock_transfer_id
|
|
LEFT JOIN warehouses fw ON fw.id = st.from_warehouse_id
|
|
LEFT JOIN warehouses tw ON tw.id = st.to_warehouse_id
|
|
JOIN products prod ON prod.id = std.product_id
|
|
JOIN product_categories pc ON pc.id = prod.product_category_id
|
|
JOIN uoms u ON u.id = prod.uom_id
|
|
WHERE st.to_warehouse_id IN ?
|
|
`
|
|
|
|
sapronakOutgoingTransfersSQL = `
|
|
SELECT
|
|
CAST(st.id AS BIGINT) AS id,
|
|
st.transfer_date AS sort_date,
|
|
TO_CHAR(st.transfer_date, 'DD-Mon-YYYY') AS date_text,
|
|
st.movement_number AS reference_number,
|
|
'Internal Transfer Out' AS transaction_type,
|
|
prod.name AS product_name,
|
|
pc.name AS product_category,
|
|
COALESCE((
|
|
SELECT string_agg(f.name, ' ')
|
|
FROM flags f
|
|
WHERE f.flagable_type = 'products' AND f.flagable_id = prod.id
|
|
), '') AS product_sub_category,
|
|
COALESCE(fw.name, '') AS source_warehouse,
|
|
'' AS destination_warehouse,
|
|
COALESCE(tw.name, '') AS destination,
|
|
std.quantity AS quantity,
|
|
u.name AS unit,
|
|
'Transfer to other unit' AS notes
|
|
FROM stock_transfer_details std
|
|
JOIN stock_transfers st ON st.id = std.stock_transfer_id
|
|
LEFT JOIN warehouses fw ON fw.id = st.from_warehouse_id
|
|
LEFT JOIN warehouses tw ON tw.id = st.to_warehouse_id
|
|
JOIN products prod ON prod.id = std.product_id
|
|
JOIN product_categories pc ON pc.id = prod.product_category_id
|
|
JOIN uoms u ON u.id = prod.uom_id
|
|
WHERE st.from_warehouse_id IN ?
|
|
`
|
|
|
|
sapronakOutgoingMarketingsSQL = `
|
|
SELECT
|
|
CAST(mp.id AS BIGINT) AS id,
|
|
m.so_date AS sort_date,
|
|
TO_CHAR(m.so_date, 'DD-Mon-YYYY') AS date_text,
|
|
m.so_number AS reference_number,
|
|
'Trading Sales' AS transaction_type,
|
|
prod.name AS product_name,
|
|
pc.name AS product_category,
|
|
COALESCE((
|
|
SELECT string_agg(f.name, ' ')
|
|
FROM flags f
|
|
WHERE f.flagable_type = 'products' AND f.flagable_id = prod.id
|
|
), '') AS product_sub_category,
|
|
w.name AS source_warehouse,
|
|
'' AS destination_warehouse,
|
|
'RETAIL CUSTOMER' AS destination,
|
|
mp.qty AS quantity,
|
|
u.name AS unit,
|
|
m.notes AS notes
|
|
FROM marketing_products mp
|
|
JOIN marketings m ON m.id = mp.marketing_id
|
|
JOIN product_warehouses pw ON pw.id = mp.product_warehouse_id
|
|
JOIN products prod ON prod.id = pw.product_id
|
|
JOIN product_categories pc ON pc.id = prod.product_category_id
|
|
JOIN uoms u ON u.id = prod.uom_id
|
|
JOIN warehouses w ON w.id = pw.warehouse_id
|
|
WHERE pw.project_flock_kandang_id IN ?
|
|
`
|
|
)
|