mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-25 15:55:44 +00:00
629 lines
20 KiB
Go
629 lines
20 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)
|
|
ListProjectFlockKandangsForSapronak(ctx context.Context, params *validation.CountSapronakQuery) ([]entity.ProjectFlockKandang, error)
|
|
MapSapronakStartDates(ctx context.Context, pfkIDs []uint) (map[uint]time.Time, 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)
|
|
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)
|
|
FetchSapronakAdjustments(ctx context.Context, kandangID uint, start, end *time.Time) (map[uint][]SapronakDetailRow, map[uint][]SapronakDetailRow, error)
|
|
FetchSapronakTransfers(ctx context.Context, kandangID uint, start, end *time.Time) (map[uint][]SapronakDetailRow, map[uint][]SapronakDetailRow, 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
|
|
}
|
|
|
|
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 ?
|
|
`
|
|
)
|
|
|
|
type SapronakIncomingRow struct {
|
|
ProductID uint
|
|
ProductName string
|
|
Flag string
|
|
Qty float64
|
|
Value float64
|
|
DefaultPrice float64
|
|
}
|
|
|
|
type SapronakUsageRow struct {
|
|
ProductID uint
|
|
ProductName string
|
|
Flag string
|
|
Qty float64
|
|
DefaultPrice float64
|
|
}
|
|
|
|
type SapronakDetailRow struct {
|
|
ProductID uint
|
|
ProductName string
|
|
Flag string
|
|
Date *time.Time
|
|
Reference string
|
|
QtyIn float64
|
|
QtyOut float64
|
|
Price float64
|
|
}
|
|
|
|
func (r *ClosingRepositoryImpl) ListProjectFlockKandangsForSapronak(ctx context.Context, params *validation.CountSapronakQuery) ([]entity.ProjectFlockKandang, error) {
|
|
db := r.DB().
|
|
WithContext(ctx).
|
|
Preload("ProjectFlock").
|
|
Preload("Kandang")
|
|
|
|
if params != nil {
|
|
if params.ProjectFlockID > 0 {
|
|
db = db.Where("project_flock_kandangs.project_flock_id = ?", params.ProjectFlockID)
|
|
}
|
|
if params.KandangID > 0 {
|
|
db = db.Where("project_flock_kandangs.kandang_id = ?", params.KandangID)
|
|
}
|
|
if params.ProjectFlockKandangID > 0 {
|
|
db = db.Where("project_flock_kandangs.id = ?", params.ProjectFlockKandangID)
|
|
}
|
|
}
|
|
|
|
var pfks []entity.ProjectFlockKandang
|
|
if err := db.Find(&pfks).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
return pfks, nil
|
|
}
|
|
|
|
func (r *ClosingRepositoryImpl) MapSapronakStartDates(ctx context.Context, pfkIDs []uint) (map[uint]time.Time, error) {
|
|
result := make(map[uint]time.Time, len(pfkIDs))
|
|
if len(pfkIDs) == 0 {
|
|
return result, nil
|
|
}
|
|
|
|
var rows []struct {
|
|
ProjectFlockKandangID uint `gorm:"column:project_flock_kandang_id"`
|
|
StartDate *time.Time `gorm:"column:start_date"`
|
|
}
|
|
|
|
if err := r.DB().
|
|
WithContext(ctx).
|
|
Table("project_chickins").
|
|
Select("project_flock_kandang_id, MIN(chick_in_date) AS start_date").
|
|
Where("project_flock_kandang_id IN ?", pfkIDs).
|
|
Group("project_flock_kandang_id").
|
|
Scan(&rows).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
for _, row := range rows {
|
|
if row.StartDate != nil {
|
|
result[row.ProjectFlockKandangID] = row.StartDate.UTC()
|
|
}
|
|
}
|
|
|
|
return result, nil
|
|
}
|
|
|
|
func (r *ClosingRepositoryImpl) FetchSapronakIncoming(ctx context.Context, kandangID uint, start, end *time.Time) ([]SapronakIncomingRow, error) {
|
|
rows := make([]SapronakIncomingRow, 0)
|
|
|
|
db := r.DB().
|
|
WithContext(ctx).
|
|
Table("purchase_items AS pi").
|
|
Select(`
|
|
pi.product_id AS product_id,
|
|
p.name AS product_name,
|
|
f.name AS flag,
|
|
COALESCE(SUM(pi.total_qty), 0) AS qty,
|
|
COALESCE(SUM(pi.total_qty * pi.price), 0) AS value,
|
|
COALESCE(p.product_price, 0) AS default_price
|
|
`).
|
|
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 flags f ON f.flagable_id = p.id AND f.flagable_type = ?", entity.FlagableTypeProduct).
|
|
Joins("JOIN warehouses w ON w.id = pi.warehouse_id").
|
|
Where("w.kandang_id = ?", kandangID).
|
|
Where("f.name IN ?", []string{string(utils.FlagDOC), string(utils.FlagPakan), string(utils.FlagOVK)}).
|
|
Where("pi.received_date IS NOT NULL")
|
|
|
|
if start != nil {
|
|
db = db.Where("pi.received_date >= ?", *start)
|
|
}
|
|
if end != nil {
|
|
db = db.Where("pi.received_date < ?", *end)
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
func (r *ClosingRepositoryImpl) FetchSapronakUsage(ctx context.Context, pfkID uint, start, end *time.Time) ([]SapronakUsageRow, error) {
|
|
rows := make([]SapronakUsageRow, 0)
|
|
if pfkID == 0 {
|
|
return rows, nil
|
|
}
|
|
|
|
db := r.DB().
|
|
WithContext(ctx).
|
|
Table("recording_stocks AS rs").
|
|
Select(`
|
|
pw.product_id AS product_id,
|
|
p.name AS product_name,
|
|
f.name AS flag,
|
|
COALESCE(SUM(rs.usage_qty), 0) AS qty,
|
|
COALESCE(p.product_price, 0) AS default_price
|
|
`).
|
|
Joins("JOIN recordings r ON r.id = rs.recording_id AND r.deleted_at IS NULL").
|
|
Joins("JOIN product_warehouses pw ON pw.id = rs.product_warehouse_id").
|
|
Joins("JOIN products p ON p.id = pw.product_id").
|
|
Joins("JOIN flags f ON f.flagable_id = p.id AND f.flagable_type = ?", entity.FlagableTypeProduct).
|
|
Where("r.project_flock_kandangs_id = ?", pfkID).
|
|
Where("f.name IN ?", []string{string(utils.FlagDOC), string(utils.FlagPakan), string(utils.FlagOVK)})
|
|
|
|
if start != nil {
|
|
db = db.Where("r.record_datetime >= ?", *start)
|
|
}
|
|
if end != nil {
|
|
db = db.Where("r.record_datetime < ?", *end)
|
|
}
|
|
|
|
if err := db.Group("pw.product_id, p.name, f.name, p.product_price").Scan(&rows).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return rows, nil
|
|
}
|
|
|
|
func (r *ClosingRepositoryImpl) FetchSapronakIncomingDetails(ctx context.Context, kandangID uint, start, end *time.Time) (map[uint][]SapronakDetailRow, error) {
|
|
rows := make([]SapronakDetailRow, 0)
|
|
|
|
db := r.DB().
|
|
WithContext(ctx).
|
|
Table("purchase_items AS pi").
|
|
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
|
|
`).
|
|
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 flags f ON f.flagable_id = p.id AND f.flagable_type = ?", entity.FlagableTypeProduct).
|
|
Joins("JOIN warehouses w ON w.id = pi.warehouse_id").
|
|
Where("w.kandang_id = ?", kandangID).
|
|
Where("f.name IN ?", []string{string(utils.FlagDOC), string(utils.FlagPakan), string(utils.FlagOVK)}).
|
|
Where("pi.received_date IS NOT NULL")
|
|
|
|
if start != nil {
|
|
db = db.Where("pi.received_date >= ?", *start)
|
|
}
|
|
if end != nil {
|
|
db = db.Where("pi.received_date < ?", *end)
|
|
}
|
|
|
|
if err := db.Scan(&rows).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result := make(map[uint][]SapronakDetailRow)
|
|
for _, row := range rows {
|
|
result[row.ProductID] = append(result[row.ProductID], row)
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func (r *ClosingRepositoryImpl) FetchSapronakUsageDetails(ctx context.Context, pfkID uint, start, end *time.Time) (map[uint][]SapronakDetailRow, error) {
|
|
rows := make([]SapronakDetailRow, 0)
|
|
|
|
db := r.DB().
|
|
WithContext(ctx).
|
|
Table("recording_stocks AS rs").
|
|
Select(`
|
|
pw.product_id AS product_id,
|
|
p.name AS product_name,
|
|
f.name AS flag,
|
|
r.record_datetime AS date,
|
|
CAST(r.id AS TEXT) AS reference,
|
|
0 AS qty_in,
|
|
COALESCE(rs.usage_qty,0) AS qty_out,
|
|
COALESCE(p.product_price,0) AS price
|
|
`).
|
|
Joins("JOIN recordings r ON r.id = rs.recording_id AND r.deleted_at IS NULL").
|
|
Joins("JOIN product_warehouses pw ON pw.id = rs.product_warehouse_id").
|
|
Joins("JOIN products p ON p.id = pw.product_id").
|
|
Joins("JOIN flags f ON f.flagable_id = p.id AND f.flagable_type = ?", entity.FlagableTypeProduct).
|
|
Where("r.project_flock_kandangs_id = ?", pfkID).
|
|
Where("f.name IN ?", []string{string(utils.FlagDOC), string(utils.FlagPakan), string(utils.FlagOVK)})
|
|
|
|
if start != nil {
|
|
db = db.Where("r.record_datetime >= ?", *start)
|
|
}
|
|
if end != nil {
|
|
db = db.Where("r.record_datetime < ?", *end)
|
|
}
|
|
|
|
if err := db.Scan(&rows).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
result := make(map[uint][]SapronakDetailRow)
|
|
for _, row := range rows {
|
|
result[row.ProductID] = append(result[row.ProductID], row)
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
func (r *ClosingRepositoryImpl) FetchSapronakAdjustments(ctx context.Context, kandangID uint, start, end *time.Time) (map[uint][]SapronakDetailRow, map[uint][]SapronakDetailRow, error) {
|
|
incoming := make(map[uint][]SapronakDetailRow)
|
|
outgoing := make(map[uint][]SapronakDetailRow)
|
|
|
|
rows := make([]struct {
|
|
ID uint
|
|
ProductID uint
|
|
ProductName string
|
|
Flag string
|
|
CreatedAt *time.Time
|
|
Increase float64
|
|
Decrease float64
|
|
Price float64
|
|
}, 0)
|
|
|
|
db := r.DB().
|
|
WithContext(ctx).
|
|
Table("stock_logs sl").
|
|
Select(`
|
|
sl.id AS id,
|
|
pw.product_id AS product_id,
|
|
p.name AS product_name,
|
|
f.name AS flag,
|
|
sl.created_at AS created_at,
|
|
COALESCE(sl.increase,0) AS increase,
|
|
COALESCE(sl.decrease,0) AS decrease,
|
|
COALESCE(p.product_price,0) AS price
|
|
`).
|
|
Joins("JOIN product_warehouses pw ON pw.id = sl.product_warehouse_id").
|
|
Joins("JOIN products p ON p.id = pw.product_id").
|
|
Joins("JOIN flags f ON f.flagable_id = p.id AND f.flagable_type = ?", entity.FlagableTypeProduct).
|
|
Joins("JOIN warehouses w ON w.id = pw.warehouse_id").
|
|
Where("sl.loggable_type = ?", entity.LogTypeAdjustment).
|
|
Where("w.kandang_id = ?", kandangID).
|
|
Where("f.name IN ?", []string{string(utils.FlagDOC), string(utils.FlagPakan), string(utils.FlagOVK)})
|
|
|
|
if start != nil {
|
|
db = db.Where("sl.created_at >= ?", *start)
|
|
}
|
|
if end != nil {
|
|
db = db.Where("sl.created_at < ?", *end)
|
|
}
|
|
|
|
if err := db.Scan(&rows).Error; err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
for _, row := range rows {
|
|
ref := fmt.Sprintf("ADJ-%d", row.ID)
|
|
if row.Increase > 0 {
|
|
incoming[row.ProductID] = append(incoming[row.ProductID], SapronakDetailRow{
|
|
ProductID: row.ProductID,
|
|
ProductName: row.ProductName,
|
|
Flag: row.Flag,
|
|
Date: row.CreatedAt,
|
|
Reference: ref,
|
|
QtyIn: row.Increase,
|
|
QtyOut: 0,
|
|
Price: row.Price,
|
|
})
|
|
}
|
|
if row.Decrease > 0 {
|
|
outgoing[row.ProductID] = append(outgoing[row.ProductID], SapronakDetailRow{
|
|
ProductID: row.ProductID,
|
|
ProductName: row.ProductName,
|
|
Flag: row.Flag,
|
|
Date: row.CreatedAt,
|
|
Reference: ref,
|
|
QtyIn: 0,
|
|
QtyOut: row.Decrease,
|
|
Price: row.Price,
|
|
})
|
|
}
|
|
}
|
|
|
|
return incoming, outgoing, nil
|
|
}
|
|
|
|
func (r *ClosingRepositoryImpl) FetchSapronakTransfers(ctx context.Context, kandangID uint, start, end *time.Time) (map[uint][]SapronakDetailRow, map[uint][]SapronakDetailRow, error) {
|
|
incoming := make(map[uint][]SapronakDetailRow)
|
|
outgoing := make(map[uint][]SapronakDetailRow)
|
|
|
|
rows := make([]struct {
|
|
ID uint
|
|
ProductID uint
|
|
ProductName string
|
|
Flag string
|
|
CreatedAt *time.Time
|
|
Increase float64
|
|
Decrease float64
|
|
Price float64
|
|
}, 0)
|
|
|
|
db := r.DB().
|
|
WithContext(ctx).
|
|
Table("stock_logs sl").
|
|
Select(`
|
|
sl.id AS id,
|
|
pw.product_id AS product_id,
|
|
p.name AS product_name,
|
|
f.name AS flag,
|
|
sl.created_at AS created_at,
|
|
COALESCE(sl.increase,0) AS increase,
|
|
COALESCE(sl.decrease,0) AS decrease,
|
|
COALESCE(p.product_price,0) AS price
|
|
`).
|
|
Joins("JOIN product_warehouses pw ON pw.id = sl.product_warehouse_id").
|
|
Joins("JOIN products p ON p.id = pw.product_id").
|
|
Joins("JOIN flags f ON f.flagable_id = p.id AND f.flagable_type = ?", entity.FlagableTypeProduct).
|
|
Joins("JOIN warehouses w ON w.id = pw.warehouse_id").
|
|
Where("sl.loggable_type = ?", entity.LogTypeTransfer).
|
|
Where("w.kandang_id = ?", kandangID).
|
|
Where("f.name IN ?", []string{string(utils.FlagDOC), string(utils.FlagPakan), string(utils.FlagOVK)})
|
|
|
|
if start != nil {
|
|
db = db.Where("sl.created_at >= ?", *start)
|
|
}
|
|
if end != nil {
|
|
db = db.Where("sl.created_at < ?", *end)
|
|
}
|
|
|
|
if err := db.Scan(&rows).Error; err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
for _, row := range rows {
|
|
ref := fmt.Sprintf("TRF-%d", row.ID)
|
|
if row.Increase > 0 {
|
|
incoming[row.ProductID] = append(incoming[row.ProductID], SapronakDetailRow{
|
|
ProductID: row.ProductID,
|
|
ProductName: row.ProductName,
|
|
Flag: row.Flag,
|
|
Date: row.CreatedAt,
|
|
Reference: ref,
|
|
QtyIn: row.Increase,
|
|
QtyOut: 0,
|
|
Price: row.Price,
|
|
})
|
|
}
|
|
if row.Decrease > 0 {
|
|
outgoing[row.ProductID] = append(outgoing[row.ProductID], SapronakDetailRow{
|
|
ProductID: row.ProductID,
|
|
ProductName: row.ProductName,
|
|
Flag: row.Flag,
|
|
Date: row.CreatedAt,
|
|
Reference: ref,
|
|
QtyIn: 0,
|
|
QtyOut: row.Decrease,
|
|
Price: row.Price,
|
|
})
|
|
}
|
|
}
|
|
|
|
return incoming, outgoing, nil
|
|
}
|