mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-25 07:45:44 +00:00
codex/fix: show farm stock usage on closing page
This commit is contained in:
@@ -25,8 +25,8 @@ type ClosingRepository interface {
|
||||
SumMarketingWeightAndQtyByProjectFlockKandangIDsAndFlagNames(ctx context.Context, projectFlockKandangIDs []uint, flagNames []string) (float64, float64, float64, error)
|
||||
SumRecordingEggQtyByProjectFlockKandangIDsAndFlagNames(ctx context.Context, projectFlockKandangIDs []uint, flagNames []string) (float64, error)
|
||||
GetExpeditionHPP(ctx context.Context, projectFlockID uint, projectFlockKandangID *uint) ([]ExpeditionHPPRow, error)
|
||||
FetchSapronakIncoming(ctx context.Context, kandangID uint, start, end *time.Time) ([]SapronakIncomingRow, error)
|
||||
FetchSapronakIncomingDetails(ctx context.Context, kandangID uint, start, end *time.Time) (map[uint][]SapronakDetailRow, error)
|
||||
FetchSapronakIncoming(ctx context.Context, projectFlockKandangID uint, kandangID uint, start, end *time.Time) ([]SapronakIncomingRow, error)
|
||||
FetchSapronakIncomingDetails(ctx context.Context, projectFlockKandangID uint, kandangID uint, start, end *time.Time) (map[uint][]SapronakDetailRow, error)
|
||||
FetchSapronakUsage(ctx context.Context, pfkID uint, start, end *time.Time) ([]SapronakUsageRow, error)
|
||||
FetchSapronakUsageDetails(ctx context.Context, pfkID uint, start, end *time.Time) (map[uint][]SapronakDetailRow, error)
|
||||
FetchSapronakChickinUsage(ctx context.Context, pfkID uint, start, end *time.Time) ([]SapronakUsageRow, error)
|
||||
@@ -90,6 +90,23 @@ type SapronakQueryParams struct {
|
||||
EndDate *time.Time
|
||||
}
|
||||
|
||||
func sapronakIncomingPurchaseQueryParts(params SapronakQueryParams) (string, []any) {
|
||||
if len(params.ProjectFlockKandangIDs) > 0 {
|
||||
return sapronakIncomingPurchasesScopedSQL(), []any{
|
||||
fifo.UsableKeyRecordingStock.String(),
|
||||
fifo.UsableKeyProjectChickin.String(),
|
||||
fifo.StockableKeyPurchaseItems.String(),
|
||||
entity.StockAllocationStatusActive,
|
||||
entity.StockAllocationPurposeConsume,
|
||||
params.ProjectFlockKandangIDs,
|
||||
params.ProjectFlockKandangIDs,
|
||||
params.WarehouseIDs,
|
||||
}
|
||||
}
|
||||
|
||||
return sapronakIncomingPurchasesSQL, []any{params.WarehouseIDs}
|
||||
}
|
||||
|
||||
func (r *ClosingRepositoryImpl) GetSapronak(ctx context.Context, params SapronakQueryParams) ([]SapronakRow, int64, error) {
|
||||
db := r.DB().WithContext(ctx)
|
||||
|
||||
@@ -103,8 +120,10 @@ func (r *ClosingRepositoryImpl) GetSapronak(ctx context.Context, params Sapronak
|
||||
if len(params.WarehouseIDs) == 0 {
|
||||
return []SapronakRow{}, 0, nil
|
||||
}
|
||||
unionParts = append(unionParts, sapronakIncomingPurchasesSQL, sapronakIncomingTransfersSQL, sapronakIncomingAdjustmentsSQL)
|
||||
args = append(args, params.WarehouseIDs, params.WarehouseIDs, params.WarehouseIDs)
|
||||
purchasesSQL, purchaseArgs := sapronakIncomingPurchaseQueryParts(params)
|
||||
unionParts = append(unionParts, purchasesSQL, sapronakIncomingTransfersSQL, sapronakIncomingAdjustmentsSQL)
|
||||
args = append(args, purchaseArgs...)
|
||||
args = append(args, params.WarehouseIDs, params.WarehouseIDs)
|
||||
case validation.SapronakTypeOutgoing:
|
||||
if len(params.WarehouseIDs) > 0 {
|
||||
unionParts = append(unionParts, sapronakOutgoingTransfersSQL, sapronakOutgoingAdjustmentsSQL)
|
||||
@@ -193,8 +212,10 @@ func (r *ClosingRepositoryImpl) GetSapronakSummary(ctx context.Context, params S
|
||||
if len(params.WarehouseIDs) == 0 {
|
||||
return []SapronakSummaryRow{}, nil
|
||||
}
|
||||
unionParts = append(unionParts, sapronakIncomingPurchasesSQL, sapronakIncomingTransfersSQL, sapronakIncomingAdjustmentsSQL)
|
||||
args = append(args, params.WarehouseIDs, params.WarehouseIDs, params.WarehouseIDs)
|
||||
purchasesSQL, purchaseArgs := sapronakIncomingPurchaseQueryParts(params)
|
||||
unionParts = append(unionParts, purchasesSQL, sapronakIncomingTransfersSQL, sapronakIncomingAdjustmentsSQL)
|
||||
args = append(args, purchaseArgs...)
|
||||
args = append(args, params.WarehouseIDs, params.WarehouseIDs)
|
||||
case validation.SapronakTypeOutgoing:
|
||||
if len(params.WarehouseIDs) > 0 {
|
||||
unionParts = append(unionParts, sapronakOutgoingTransfersSQL, sapronakOutgoingAdjustmentsSQL)
|
||||
@@ -855,6 +876,140 @@ func sapronakFlags(flags ...utils.FlagType) []string {
|
||||
return out
|
||||
}
|
||||
|
||||
func sapronakLegacyFlagByProductCategoryCase(categoryCodeExpr string) string {
|
||||
return fmt.Sprintf(
|
||||
`CASE
|
||||
WHEN UPPER(%s) = 'DOC' THEN '%s'
|
||||
WHEN UPPER(%s) = 'PLT' THEN '%s'
|
||||
WHEN UPPER(%s) IN ('RAW', 'PST', 'STR', 'FSR') THEN '%s'
|
||||
WHEN UPPER(%s) IN ('OBT', 'VTM', 'KMA') THEN '%s'
|
||||
ELSE NULL
|
||||
END`,
|
||||
categoryCodeExpr, utils.FlagDOC,
|
||||
categoryCodeExpr, utils.FlagPullet,
|
||||
categoryCodeExpr, utils.FlagPakan,
|
||||
categoryCodeExpr, utils.FlagOVK,
|
||||
)
|
||||
}
|
||||
|
||||
func sapronakIncomingPurchasesScopedSQL() string {
|
||||
return `
|
||||
WITH scoped_farm_allocations AS (
|
||||
SELECT
|
||||
sa.stockable_id AS purchase_item_id,
|
||||
COALESCE(SUM(sa.qty), 0) AS allocated_qty
|
||||
FROM stock_allocations sa
|
||||
LEFT JOIN recording_stocks rs ON rs.id = sa.usable_id AND sa.usable_type = ?
|
||||
LEFT JOIN recordings rec ON rec.id = rs.recording_id AND rec.deleted_at IS NULL
|
||||
LEFT JOIN project_chickins pc ON pc.id = sa.usable_id AND sa.usable_type = ?
|
||||
WHERE sa.stockable_type = ?
|
||||
AND sa.status = ?
|
||||
AND sa.allocation_purpose = ?
|
||||
AND COALESCE(rec.project_flock_kandangs_id, pc.project_flock_kandang_id) IN ?
|
||||
GROUP BY sa.stockable_id
|
||||
)
|
||||
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,
|
||||
'Pembelian' AS transaction_type,
|
||||
prod.name AS product_name,
|
||||
COALESCE((
|
||||
SELECT string_agg(
|
||||
f.name,
|
||||
' ' ORDER BY
|
||||
CASE
|
||||
WHEN UPPER(f.name) IN ('DOC', 'PAKAN', 'OVK', 'PULLET') THEN 0
|
||||
ELSE 1
|
||||
END,
|
||||
f.name
|
||||
)
|
||||
FROM flags f
|
||||
WHERE f.flagable_type = 'products' AND f.flagable_id = prod.id
|
||||
), '') AS product_category,
|
||||
COALESCE((
|
||||
SELECT string_agg(
|
||||
f.name,
|
||||
' ' ORDER BY
|
||||
CASE
|
||||
WHEN UPPER(f.name) IN ('DOC', 'PAKAN', 'OVK', 'PULLET') THEN 0
|
||||
ELSE 1
|
||||
END,
|
||||
f.name
|
||||
)
|
||||
FROM flags f
|
||||
WHERE f.flagable_type = 'products' AND f.flagable_id = prod.id
|
||||
), '') AS product_sub_category,
|
||||
'-' AS source_warehouse,
|
||||
w.name AS destination_warehouse,
|
||||
'' AS destination,
|
||||
pi.total_qty AS quantity,
|
||||
u.id AS unit_id,
|
||||
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 uoms u ON u.id = prod.uom_id
|
||||
JOIN warehouses w ON w.id = pi.warehouse_id
|
||||
WHERE w.kandang_id IS NOT NULL
|
||||
AND (
|
||||
pi.project_flock_kandang_id IN ?
|
||||
OR (pi.project_flock_kandang_id IS NULL AND pi.warehouse_id IN ?)
|
||||
)
|
||||
UNION ALL
|
||||
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,
|
||||
'Pembelian' AS transaction_type,
|
||||
prod.name AS product_name,
|
||||
COALESCE((
|
||||
SELECT string_agg(
|
||||
f.name,
|
||||
' ' ORDER BY
|
||||
CASE
|
||||
WHEN UPPER(f.name) IN ('DOC', 'PAKAN', 'OVK', 'PULLET') THEN 0
|
||||
ELSE 1
|
||||
END,
|
||||
f.name
|
||||
)
|
||||
FROM flags f
|
||||
WHERE f.flagable_type = 'products' AND f.flagable_id = prod.id
|
||||
), '') AS product_category,
|
||||
COALESCE((
|
||||
SELECT string_agg(
|
||||
f.name,
|
||||
' ' ORDER BY
|
||||
CASE
|
||||
WHEN UPPER(f.name) IN ('DOC', 'PAKAN', 'OVK', 'PULLET') THEN 0
|
||||
ELSE 1
|
||||
END,
|
||||
f.name
|
||||
)
|
||||
FROM flags f
|
||||
WHERE f.flagable_type = 'products' AND f.flagable_id = prod.id
|
||||
), '') AS product_sub_category,
|
||||
'-' AS source_warehouse,
|
||||
w.name AS destination_warehouse,
|
||||
'' AS destination,
|
||||
sfa.allocated_qty AS quantity,
|
||||
u.id AS unit_id,
|
||||
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 uoms u ON u.id = prod.uom_id
|
||||
JOIN warehouses w ON w.id = pi.warehouse_id
|
||||
JOIN scoped_farm_allocations sfa ON sfa.purchase_item_id = pi.id
|
||||
WHERE w.kandang_id IS NULL
|
||||
AND COALESCE(sfa.allocated_qty, 0) > 0
|
||||
`
|
||||
}
|
||||
|
||||
var (
|
||||
sapronakFlagsAll = sapronakFlags(utils.FlagDOC, utils.FlagPakan, utils.FlagOVK, utils.FlagPullet)
|
||||
sapronakFlagsUsage = sapronakFlags(utils.FlagPakan, utils.FlagOVK)
|
||||
@@ -862,18 +1017,44 @@ var (
|
||||
)
|
||||
|
||||
func (r *ClosingRepositoryImpl) joinSapronakProductFlag(db *gorm.DB, productAlias string) *gorm.DB {
|
||||
subquery := r.DB().
|
||||
actualFlags := r.DB().
|
||||
Table("flags").
|
||||
Select("DISTINCT ON (flagable_id) flagable_id, name").
|
||||
Select(`
|
||||
flagable_id,
|
||||
MIN(CASE
|
||||
WHEN UPPER(name) = 'DOC' THEN 1
|
||||
WHEN UPPER(name) = 'PULLET' THEN 2
|
||||
WHEN UPPER(name) = 'PAKAN' THEN 3
|
||||
WHEN UPPER(name) = 'OVK' THEN 4
|
||||
ELSE 5
|
||||
END) AS priority
|
||||
`).
|
||||
Where("flagable_type = ?", entity.FlagableTypeProduct).
|
||||
Where("name IN ?", sapronakFlagsAll).
|
||||
Order(fmt.Sprintf(
|
||||
"flagable_id, CASE WHEN name = '%s' THEN 1 WHEN name = '%s' THEN 2 WHEN name = '%s' THEN 3 WHEN name = '%s' THEN 4 ELSE 5 END",
|
||||
Where("UPPER(name) IN ?", sapronakFlagsAll).
|
||||
Group("flagable_id")
|
||||
|
||||
legacyFlagExpr := sapronakLegacyFlagByProductCategoryCase("pc.code")
|
||||
subquery := r.DB().
|
||||
Table("products AS sapronak_products").
|
||||
Select(fmt.Sprintf(`
|
||||
sapronak_products.id AS flagable_id,
|
||||
CASE
|
||||
WHEN actual_flags.priority = 1 THEN '%s'
|
||||
WHEN actual_flags.priority = 2 THEN '%s'
|
||||
WHEN actual_flags.priority = 3 THEN '%s'
|
||||
WHEN actual_flags.priority = 4 THEN '%s'
|
||||
ELSE %s
|
||||
END AS name
|
||||
`,
|
||||
utils.FlagDOC,
|
||||
utils.FlagPullet,
|
||||
utils.FlagPakan,
|
||||
utils.FlagOVK,
|
||||
))
|
||||
legacyFlagExpr,
|
||||
)).
|
||||
Joins("LEFT JOIN (?) AS actual_flags ON actual_flags.flagable_id = sapronak_products.id", actualFlags).
|
||||
Joins("LEFT JOIN product_categories pc ON pc.id = sapronak_products.product_category_id").
|
||||
Where("actual_flags.priority IS NOT NULL OR " + legacyFlagExpr + " IS NOT NULL")
|
||||
|
||||
return db.Joins("JOIN (?) f ON f.flagable_id = "+productAlias+".id", subquery)
|
||||
}
|
||||
@@ -1132,22 +1313,111 @@ func (r *ClosingRepositoryImpl) FetchSapronakUsageAllocatedDetails(ctx context.C
|
||||
return scanAndGroupDetails(query)
|
||||
}
|
||||
|
||||
func (r *ClosingRepositoryImpl) incomingPurchaseBase(ctx context.Context, kandangID uint, start, end *time.Time) *gorm.DB {
|
||||
func (r *ClosingRepositoryImpl) incomingPurchaseBase(ctx context.Context, projectFlockKandangID uint, kandangID uint, start, end *time.Time) *gorm.DB {
|
||||
db := r.withCtx(ctx).
|
||||
Table("purchase_items AS pi").
|
||||
Joins("JOIN purchases po ON po.id = pi.purchase_id AND po.deleted_at IS NULL").
|
||||
Joins("JOIN products p ON p.id = pi.product_id").
|
||||
Joins("JOIN warehouses w ON w.id = pi.warehouse_id").
|
||||
Where("w.kandang_id = ?", kandangID).
|
||||
Where("f.name IN ?", sapronakFlagsAll).
|
||||
Where("pi.received_date IS NOT NULL")
|
||||
if projectFlockKandangID > 0 {
|
||||
db = db.Where(
|
||||
"w.kandang_id = ? AND (pi.project_flock_kandang_id = ? OR pi.project_flock_kandang_id IS NULL)",
|
||||
kandangID,
|
||||
projectFlockKandangID,
|
||||
)
|
||||
} else {
|
||||
db = db.Where("w.kandang_id = ?", kandangID)
|
||||
}
|
||||
db = applyDateRange(db, "pi.received_date", start, end)
|
||||
return r.joinSapronakProductFlag(db, "p")
|
||||
}
|
||||
|
||||
func (r *ClosingRepositoryImpl) incomingFarmPurchaseAllocationBase(ctx context.Context, projectFlockKandangID uint, start, end *time.Time) *gorm.DB {
|
||||
db := r.withCtx(ctx).
|
||||
Table("stock_allocations AS sa").
|
||||
Joins("JOIN purchase_items pi ON pi.id = sa.stockable_id AND sa.stockable_type = ?", fifo.StockableKeyPurchaseItems.String()).
|
||||
Joins("JOIN purchases po ON po.id = pi.purchase_id AND po.deleted_at IS NULL").
|
||||
Joins("JOIN products p ON p.id = pi.product_id").
|
||||
Joins("JOIN warehouses w ON w.id = pi.warehouse_id").
|
||||
Joins("LEFT JOIN recording_stocks rs ON rs.id = sa.usable_id AND sa.usable_type = ?", fifo.UsableKeyRecordingStock.String()).
|
||||
Joins("LEFT JOIN recordings rec ON rec.id = rs.recording_id AND rec.deleted_at IS NULL").
|
||||
Joins("LEFT JOIN project_chickins pc ON pc.id = sa.usable_id AND sa.usable_type = ?", fifo.UsableKeyProjectChickin.String()).
|
||||
Where("sa.status = ?", entity.StockAllocationStatusActive).
|
||||
Where("sa.allocation_purpose = ?", entity.StockAllocationPurposeConsume).
|
||||
Where("w.kandang_id IS NULL").
|
||||
Where("COALESCE(rec.project_flock_kandangs_id, pc.project_flock_kandang_id) = ?", projectFlockKandangID).
|
||||
Where("f.name IN ?", sapronakFlagsAll).
|
||||
Where("pi.received_date IS NOT NULL")
|
||||
db = applyDateRange(db, "pi.received_date", start, end)
|
||||
return r.joinSapronakProductFlag(db, "p")
|
||||
}
|
||||
|
||||
func (r *ClosingRepositoryImpl) FetchSapronakIncoming(ctx context.Context, kandangID uint, start, end *time.Time) ([]SapronakIncomingRow, error) {
|
||||
func mergeSapronakIncomingRows(primary []SapronakIncomingRow, extra []SapronakIncomingRow) []SapronakIncomingRow {
|
||||
if len(extra) == 0 {
|
||||
return primary
|
||||
}
|
||||
|
||||
type key struct {
|
||||
productID uint
|
||||
flag string
|
||||
}
|
||||
|
||||
merged := make(map[key]*SapronakIncomingRow, len(primary)+len(extra))
|
||||
order := make([]key, 0, len(primary)+len(extra))
|
||||
|
||||
add := func(rows []SapronakIncomingRow) {
|
||||
for _, row := range rows {
|
||||
k := key{productID: row.ProductID, flag: row.Flag}
|
||||
if existing, ok := merged[k]; ok {
|
||||
existing.Qty += row.Qty
|
||||
existing.Value += row.Value
|
||||
if existing.ProductName == "" {
|
||||
existing.ProductName = row.ProductName
|
||||
}
|
||||
if existing.DefaultPrice == 0 {
|
||||
existing.DefaultPrice = row.DefaultPrice
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
copyRow := row
|
||||
merged[k] = ©Row
|
||||
order = append(order, k)
|
||||
}
|
||||
}
|
||||
|
||||
add(primary)
|
||||
add(extra)
|
||||
|
||||
result := make([]SapronakIncomingRow, 0, len(order))
|
||||
for _, k := range order {
|
||||
result = append(result, *merged[k])
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func mergeSapronakDetailMaps(primary map[uint][]SapronakDetailRow, extra map[uint][]SapronakDetailRow) map[uint][]SapronakDetailRow {
|
||||
if len(primary) == 0 && len(extra) == 0 {
|
||||
return map[uint][]SapronakDetailRow{}
|
||||
}
|
||||
if len(extra) == 0 {
|
||||
return primary
|
||||
}
|
||||
if len(primary) == 0 {
|
||||
return extra
|
||||
}
|
||||
|
||||
for productID, rows := range extra {
|
||||
primary[productID] = append(primary[productID], rows...)
|
||||
}
|
||||
return primary
|
||||
}
|
||||
|
||||
func (r *ClosingRepositoryImpl) FetchSapronakIncoming(ctx context.Context, projectFlockKandangID uint, kandangID uint, start, end *time.Time) ([]SapronakIncomingRow, error) {
|
||||
rows := make([]SapronakIncomingRow, 0)
|
||||
db := r.incomingPurchaseBase(ctx, kandangID, start, end).Select(`
|
||||
db := r.incomingPurchaseBase(ctx, projectFlockKandangID, kandangID, start, end).Select(`
|
||||
pi.product_id AS product_id,
|
||||
p.name AS product_name,
|
||||
f.name AS flag,
|
||||
@@ -1158,22 +1428,68 @@ func (r *ClosingRepositoryImpl) FetchSapronakIncoming(ctx context.Context, kanda
|
||||
if err := db.Group("pi.product_id, p.name, f.name, p.product_price").Scan(&rows).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rows, nil
|
||||
|
||||
if projectFlockKandangID == 0 {
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
farmRows := make([]SapronakIncomingRow, 0)
|
||||
farmDB := r.incomingFarmPurchaseAllocationBase(ctx, projectFlockKandangID, start, end).Select(`
|
||||
pi.product_id AS product_id,
|
||||
p.name AS product_name,
|
||||
f.name AS flag,
|
||||
COALESCE(SUM(sa.qty), 0) AS qty,
|
||||
COALESCE(SUM(sa.qty * pi.price), 0) AS value,
|
||||
COALESCE(p.product_price, 0) AS default_price
|
||||
`)
|
||||
if err := farmDB.Group("pi.product_id, p.name, f.name, p.product_price").Scan(&farmRows).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mergeSapronakIncomingRows(rows, farmRows), nil
|
||||
}
|
||||
|
||||
func (r *ClosingRepositoryImpl) FetchSapronakIncomingDetails(ctx context.Context, kandangID uint, start, end *time.Time) (map[uint][]SapronakDetailRow, error) {
|
||||
return scanAndGroupDetails(
|
||||
r.incomingPurchaseBase(ctx, kandangID, start, end).Select(`
|
||||
func (r *ClosingRepositoryImpl) FetchSapronakIncomingDetails(ctx context.Context, projectFlockKandangID uint, kandangID uint, start, end *time.Time) (map[uint][]SapronakDetailRow, error) {
|
||||
rows, err := scanAndGroupDetails(
|
||||
r.incomingPurchaseBase(ctx, projectFlockKandangID, kandangID, start, end).Select(`
|
||||
pi.product_id AS product_id,
|
||||
p.name AS product_name,
|
||||
f.name AS flag,
|
||||
pi.received_date AS date,
|
||||
COALESCE(po.po_number, '') AS reference,
|
||||
COALESCE(pi.total_qty,0) AS qty_in,
|
||||
0 AS qty_out,
|
||||
COALESCE(pi.price,0) AS price
|
||||
`),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if projectFlockKandangID == 0 {
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
farmRows, err := scanAndGroupDetails(
|
||||
r.incomingFarmPurchaseAllocationBase(ctx, projectFlockKandangID, start, end).Select(`
|
||||
pi.product_id AS product_id,
|
||||
p.name AS product_name,
|
||||
f.name AS flag,
|
||||
pi.received_date AS date,
|
||||
COALESCE(po.po_number, '') AS reference,
|
||||
COALESCE(SUM(sa.qty),0) AS qty_in,
|
||||
0 AS qty_out,
|
||||
COALESCE(pi.price,0) AS price
|
||||
`).Group(`
|
||||
pi.id, pi.product_id, p.name, f.name,
|
||||
pi.received_date, po.po_number, pi.price
|
||||
`),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mergeSapronakDetailMaps(rows, farmRows), nil
|
||||
}
|
||||
|
||||
type stockLogSapronakRow struct {
|
||||
|
||||
Reference in New Issue
Block a user