mirror of
https://gitlab.com/mbugroup/lti-api.git
synced 2026-05-23 14:55:42 +00:00
Merge branch 'development' of https://gitlab.com/mbugroup/lti-api into feat/BE/sso-adjustment
This commit is contained in:
@@ -0,0 +1,195 @@
|
||||
package repositories
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type CustomerPaymentTransaction struct {
|
||||
TransactionType string `gorm:"column:transaction_type"`
|
||||
TransactionID int64 `gorm:"column:transaction_id"`
|
||||
CustomerID int64 `gorm:"column:customer_id"`
|
||||
TransDate time.Time `gorm:"column:trans_date"`
|
||||
DeliveryDate *time.Time `gorm:"column:delivery_date"`
|
||||
Reference string `gorm:"column:reference"`
|
||||
VehicleNumbers string `gorm:"column:vehicle_numbers"`
|
||||
Qty float64 `gorm:"column:qty"`
|
||||
Weight float64 `gorm:"column:weight"`
|
||||
AverageWeight float64 `gorm:"column:average_weight"`
|
||||
Price float64 `gorm:"column:price"`
|
||||
FinalPrice float64 `gorm:"column:final_price"`
|
||||
TotalPrice float64 `gorm:"column:total_price"`
|
||||
PaymentAmount float64 `gorm:"column:payment_amount"`
|
||||
PickupInfo string `gorm:"column:pickup_info"`
|
||||
SalesPerson string `gorm:"column:sales_person"`
|
||||
}
|
||||
|
||||
type CustomerPaymentRepository interface {
|
||||
GetCustomerPaymentTransactions(ctx context.Context, customerID *uint) ([]CustomerPaymentTransaction, error)
|
||||
GetInitialBalanceByCustomer(ctx context.Context, customerID uint) (float64, error)
|
||||
GetCustomerIDsWithTransactions(ctx context.Context, limit, offset int) ([]uint, int64, error)
|
||||
}
|
||||
|
||||
type customerPaymentRepositoryImpl struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
func NewCustomerPaymentRepository(db *gorm.DB) CustomerPaymentRepository {
|
||||
return &customerPaymentRepositoryImpl{db: db}
|
||||
}
|
||||
|
||||
func (r *customerPaymentRepositoryImpl) GetCustomerPaymentTransactions(ctx context.Context, customerID *uint) ([]CustomerPaymentTransaction, error) {
|
||||
salesQuery := r.db.WithContext(ctx).
|
||||
Table("marketing_delivery_products mdp").
|
||||
Select(`
|
||||
'SALES' AS transaction_type,
|
||||
mdp.id::BIGINT AS transaction_id,
|
||||
c.id::BIGINT AS customer_id,
|
||||
m.so_date::DATE AS trans_date,
|
||||
mdp.delivery_date::DATE AS delivery_date,
|
||||
m.so_number || '-' || TO_CHAR(mdp.delivery_date, 'YYYYMMDD') || '-' || CAST(pw.warehouse_id AS VARCHAR) AS reference,
|
||||
COALESCE(mdp.vehicle_number, '') AS vehicle_numbers,
|
||||
|
||||
COALESCE(mdp.usage_qty, 0)::NUMERIC(15,3) AS qty,
|
||||
COALESCE(mdp.total_weight, 0)::NUMERIC(15,3) AS weight,
|
||||
COALESCE(mdp.avg_weight, 0)::NUMERIC(15,3) AS average_weight,
|
||||
COALESCE(mdp.unit_price, 0)::NUMERIC(15,3) AS price,
|
||||
COALESCE(mdp.total_price, 0)::NUMERIC(15,3) AS final_price,
|
||||
COALESCE(mdp.total_price, 0)::NUMERIC(15,3) AS total_price,
|
||||
0::NUMERIC(15,3) AS payment_amount,
|
||||
w.name AS pickup_info,
|
||||
u.name AS sales_person
|
||||
`).
|
||||
Joins("INNER JOIN marketing_products mp ON mp.id = mdp.marketing_product_id").
|
||||
Joins("INNER JOIN marketings m ON m.id = mp.marketing_id").
|
||||
Joins("INNER JOIN customers c ON c.id = m.customer_id").
|
||||
Joins("INNER JOIN product_warehouses pw ON pw.id = mdp.product_warehouse_id").
|
||||
Joins("INNER JOIN warehouses w ON w.id = pw.warehouse_id").
|
||||
Joins("INNER JOIN users u ON u.id = m.sales_person_id").
|
||||
Where("mdp.delivery_date IS NOT NULL").
|
||||
Where("m.deleted_at IS NULL").
|
||||
Where("c.deleted_at IS NULL")
|
||||
|
||||
if customerID != nil {
|
||||
salesQuery = salesQuery.Where("c.id = ?", *customerID)
|
||||
}
|
||||
|
||||
paymentQuery := r.db.WithContext(ctx).
|
||||
Table("payments p").
|
||||
Select(`
|
||||
'PAYMENT' AS transaction_type,
|
||||
p.id::BIGINT AS transaction_id,
|
||||
c.id::BIGINT AS customer_id,
|
||||
p.payment_date::DATE AS trans_date,
|
||||
NULL AS delivery_date,
|
||||
COALESCE(p.reference_number, p.payment_code) AS reference,
|
||||
'-' AS vehicle_numbers,
|
||||
0::NUMERIC(15,3) AS qty,
|
||||
0::NUMERIC(15,3) AS weight,
|
||||
0::NUMERIC(15,3) AS average_weight,
|
||||
0::NUMERIC(15,3) AS price,
|
||||
0::NUMERIC(15,3) AS final_price,
|
||||
0::NUMERIC(15,3) AS total_price,
|
||||
p.nominal::NUMERIC(15,3) AS payment_amount,
|
||||
'-' AS pickup_info,
|
||||
'-' AS sales_person
|
||||
`).
|
||||
Joins("INNER JOIN customers c ON c.id = p.party_id").
|
||||
Where("p.party_type = ?", "CUSTOMER").
|
||||
Where("p.direction = ?", "IN").
|
||||
Where("p.transaction_type = ?", "PENJUALAN").
|
||||
Where("p.deleted_at IS NULL").
|
||||
Where("c.deleted_at IS NULL")
|
||||
|
||||
if customerID != nil {
|
||||
paymentQuery = paymentQuery.Where("c.id = ?", *customerID)
|
||||
}
|
||||
|
||||
var results []CustomerPaymentTransaction
|
||||
err := r.db.WithContext(ctx).
|
||||
Raw("? UNION ALL ? ORDER BY customer_id, trans_date, transaction_type DESC, transaction_id",
|
||||
salesQuery,
|
||||
paymentQuery,
|
||||
).
|
||||
Scan(&results).
|
||||
Error
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (r *customerPaymentRepositoryImpl) GetInitialBalanceByCustomer(ctx context.Context, customerID uint) (float64, error) {
|
||||
var result struct {
|
||||
Nominal float64
|
||||
}
|
||||
|
||||
err := r.db.WithContext(ctx).
|
||||
Table("payments").
|
||||
Select("COALESCE(SUM(nominal), 0) as nominal").
|
||||
Where("party_type = ?", "CUSTOMER").
|
||||
Where("party_id = ?", customerID).
|
||||
Where("transaction_type = ?", "SALDO_AWAL").
|
||||
Where("deleted_at IS NULL").
|
||||
Scan(&result).
|
||||
Error
|
||||
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return result.Nominal, nil
|
||||
}
|
||||
|
||||
func (r *customerPaymentRepositoryImpl) GetCustomerIDsWithTransactions(ctx context.Context, limit, offset int) ([]uint, int64, error) {
|
||||
subQuery := r.db.WithContext(ctx).
|
||||
Table("(" +
|
||||
"SELECT DISTINCT c.id as customer_id FROM marketing_delivery_products mdp " +
|
||||
"INNER JOIN marketing_products mp ON mp.id = mdp.marketing_product_id " +
|
||||
"INNER JOIN marketings m ON m.id = mp.marketing_id " +
|
||||
"INNER JOIN customers c ON c.id = m.customer_id " +
|
||||
"WHERE mdp.delivery_date IS NOT NULL AND m.deleted_at IS NULL AND c.deleted_at IS NULL " +
|
||||
"UNION " +
|
||||
"SELECT DISTINCT c.id as customer_id FROM payments p " +
|
||||
"INNER JOIN customers c ON c.id = p.party_id " +
|
||||
"WHERE p.party_type = 'CUSTOMER' AND p.direction = 'IN' " +
|
||||
"AND p.transaction_type = 'PENJUALAN' AND p.deleted_at IS NULL AND c.deleted_at IS NULL" +
|
||||
") as customer_ids")
|
||||
|
||||
var total int64
|
||||
if err := subQuery.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
var customerIDs []uint
|
||||
err := r.db.WithContext(ctx).
|
||||
Table("("+
|
||||
"SELECT DISTINCT c.id as customer_id FROM marketing_delivery_products mdp "+
|
||||
"INNER JOIN marketing_products mp ON mp.id = mdp.marketing_product_id "+
|
||||
"INNER JOIN marketings m ON m.id = mp.marketing_id "+
|
||||
"INNER JOIN customers c ON c.id = m.customer_id "+
|
||||
"WHERE mdp.delivery_date IS NOT NULL AND m.deleted_at IS NULL AND c.deleted_at IS NULL "+
|
||||
"UNION "+
|
||||
"SELECT DISTINCT c.id as customer_id FROM payments p "+
|
||||
"INNER JOIN customers c ON c.id = p.party_id "+
|
||||
"WHERE p.party_type = 'CUSTOMER' AND p.direction = 'IN' "+
|
||||
"AND p.transaction_type = 'PENJUALAN' AND p.deleted_at IS NULL AND c.deleted_at IS NULL"+
|
||||
") as customer_ids").
|
||||
Select("customer_id").
|
||||
Order("customer_id ASC").
|
||||
Limit(limit).
|
||||
Offset(offset).
|
||||
Pluck("customer_id", &customerIDs).
|
||||
Error
|
||||
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return customerIDs, total, nil
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||
validation "gitlab.com/mbugroup/lti-api.git/internal/modules/repports/validations"
|
||||
@@ -17,6 +18,8 @@ type DebtSupplierRepository interface {
|
||||
GetPurchasesBySuppliers(ctx context.Context, supplierIDs []uint, filters *validation.DebtSupplierQuery) ([]entity.Purchase, error)
|
||||
GetPaymentsBySuppliers(ctx context.Context, supplierIDs []uint, filters *validation.DebtSupplierQuery) ([]entity.Payment, error)
|
||||
GetPaymentTotalsByReferences(ctx context.Context, supplierIDs []uint, references []string) (map[string]float64, error)
|
||||
GetPaymentSummariesByReferences(ctx context.Context, supplierIDs []uint, references []string) (map[string]PaymentReferenceSummary, error)
|
||||
GetInitialBalanceTotals(ctx context.Context, supplierIDs []uint) (map[uint]float64, error)
|
||||
GetPurchaseTotalsBeforeDate(ctx context.Context, supplierIDs []uint, filters *validation.DebtSupplierQuery) (map[uint]float64, error)
|
||||
GetPaymentTotalsBeforeDate(ctx context.Context, supplierIDs []uint, filters *validation.DebtSupplierQuery) (map[uint]float64, error)
|
||||
}
|
||||
@@ -25,10 +28,30 @@ type debtSupplierRepositoryImpl struct {
|
||||
db *gorm.DB
|
||||
}
|
||||
|
||||
type PaymentReferenceSummary struct {
|
||||
Total float64
|
||||
LatestPaymentDate time.Time
|
||||
}
|
||||
|
||||
func NewDebtSupplierRepository(db *gorm.DB) DebtSupplierRepository {
|
||||
return &debtSupplierRepositoryImpl{db: db}
|
||||
}
|
||||
|
||||
func (r *debtSupplierRepositoryImpl) latestPurchaseApproval(ctx context.Context) *gorm.DB {
|
||||
return r.db.WithContext(ctx).
|
||||
Table("approvals AS a").
|
||||
Select("a.approvable_id, a.step_number, a.action").
|
||||
Joins(`
|
||||
JOIN (
|
||||
SELECT approvable_id, MAX(action_at) AS latest_action_at
|
||||
FROM approvals
|
||||
WHERE approvable_type = ?
|
||||
GROUP BY approvable_id
|
||||
) AS la ON la.approvable_id = a.approvable_id AND la.latest_action_at = a.action_at`,
|
||||
string(utils.ApprovalWorkflowPurchase),
|
||||
)
|
||||
}
|
||||
|
||||
func resolveDebtSupplierDateColumn(filterBy string) string {
|
||||
switch strings.ToLower(strings.TrimSpace(filterBy)) {
|
||||
case "po_date":
|
||||
@@ -46,7 +69,11 @@ func (r *debtSupplierRepositoryImpl) baseSupplierQuery(ctx context.Context, filt
|
||||
db := r.db.WithContext(ctx).
|
||||
Model(&entity.Supplier{}).
|
||||
Joins("JOIN purchases ON purchases.supplier_id = suppliers.id").
|
||||
Joins("JOIN purchase_items ON purchase_items.purchase_id = purchases.id")
|
||||
Joins("JOIN purchase_items ON purchase_items.purchase_id = purchases.id").
|
||||
Joins("JOIN (?) AS la ON la.approvable_id = purchases.id", r.latestPurchaseApproval(ctx)).
|
||||
Where("la.step_number >= ?", uint16(utils.PurchaseStepReceiving)).
|
||||
Where("(la.action IS NULL OR la.action != ?)", string(entity.ApprovalActionRejected)).
|
||||
Where("purchase_items.received_date IS NOT NULL")
|
||||
|
||||
if len(filters.SupplierIDs) > 0 {
|
||||
db = db.Where("suppliers.id IN ?", filters.SupplierIDs)
|
||||
@@ -167,7 +194,8 @@ func (r *debtSupplierRepositoryImpl) GetPaymentsBySuppliers(ctx context.Context,
|
||||
Model(&entity.Payment{}).
|
||||
Where("party_type = ?", string(utils.PaymentPartySupplier)).
|
||||
Where("direction = ?", "OUT").
|
||||
Where("party_id IN ?", supplierIDs)
|
||||
Where("party_id IN ?", supplierIDs).
|
||||
Where("transaction_type <> ?", string(utils.TransactionTypeSaldoAwal))
|
||||
|
||||
if strings.TrimSpace(filters.StartDate) != "" {
|
||||
if dateFrom, err := utils.ParseDateString(filters.StartDate); err == nil {
|
||||
@@ -198,7 +226,11 @@ func (r *debtSupplierRepositoryImpl) getPurchaseIDs(ctx context.Context, supplie
|
||||
Table("purchases").
|
||||
Select("DISTINCT purchases.id").
|
||||
Joins("JOIN purchase_items ON purchase_items.purchase_id = purchases.id").
|
||||
Where("purchases.supplier_id IN ?", supplierIDs)
|
||||
Joins("JOIN (?) AS la ON la.approvable_id = purchases.id", r.latestPurchaseApproval(ctx)).
|
||||
Where("purchases.supplier_id IN ?", supplierIDs).
|
||||
Where("la.step_number >= ?", uint16(utils.PurchaseStepReceiving)).
|
||||
Where("(la.action IS NULL OR la.action != ?)", string(entity.ApprovalActionRejected)).
|
||||
Where("purchase_items.received_date IS NOT NULL")
|
||||
|
||||
if filters.StartDate != "" {
|
||||
if dateFrom, err := utils.ParseDateString(filters.StartDate); err == nil {
|
||||
@@ -238,6 +270,7 @@ func (r *debtSupplierRepositoryImpl) GetPaymentTotalsByReferences(ctx context.Co
|
||||
Where("direction = ?", "OUT").
|
||||
Where("party_id IN ?", supplierIDs).
|
||||
Where("reference_number IN ?", references).
|
||||
Where("transaction_type <> ?", string(utils.TransactionTypeSaldoAwal)).
|
||||
Group("reference_number").
|
||||
Scan(&rows).Error; err != nil {
|
||||
return nil, err
|
||||
@@ -254,6 +287,75 @@ func (r *debtSupplierRepositoryImpl) GetPaymentTotalsByReferences(ctx context.Co
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *debtSupplierRepositoryImpl) GetPaymentSummariesByReferences(ctx context.Context, supplierIDs []uint, references []string) (map[string]PaymentReferenceSummary, error) {
|
||||
if len(supplierIDs) == 0 || len(references) == 0 {
|
||||
return map[string]PaymentReferenceSummary{}, nil
|
||||
}
|
||||
|
||||
type paymentRow struct {
|
||||
ReferenceNumber *string `gorm:"column:reference_number"`
|
||||
Total float64 `gorm:"column:total"`
|
||||
LatestPaymentDate time.Time `gorm:"column:latest_payment_date"`
|
||||
}
|
||||
|
||||
rows := make([]paymentRow, 0)
|
||||
if err := r.db.WithContext(ctx).
|
||||
Model(&entity.Payment{}).
|
||||
Select("reference_number, SUM(nominal) AS total, MAX(payment_date) AS latest_payment_date").
|
||||
Where("party_type = ?", string(utils.PaymentPartySupplier)).
|
||||
Where("direction = ?", "OUT").
|
||||
Where("party_id IN ?", supplierIDs).
|
||||
Where("reference_number IN ?", references).
|
||||
Where("transaction_type <> ?", string(utils.TransactionTypeSaldoAwal)).
|
||||
Group("reference_number").
|
||||
Scan(&rows).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make(map[string]PaymentReferenceSummary, len(rows))
|
||||
for _, row := range rows {
|
||||
if row.ReferenceNumber == nil || strings.TrimSpace(*row.ReferenceNumber) == "" {
|
||||
continue
|
||||
}
|
||||
result[*row.ReferenceNumber] = PaymentReferenceSummary{
|
||||
Total: row.Total,
|
||||
LatestPaymentDate: row.LatestPaymentDate,
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *debtSupplierRepositoryImpl) GetInitialBalanceTotals(ctx context.Context, supplierIDs []uint) (map[uint]float64, error) {
|
||||
if len(supplierIDs) == 0 {
|
||||
return map[uint]float64{}, nil
|
||||
}
|
||||
|
||||
type balanceRow struct {
|
||||
SupplierID uint `gorm:"column:supplier_id"`
|
||||
Total float64 `gorm:"column:total"`
|
||||
}
|
||||
|
||||
rows := make([]balanceRow, 0)
|
||||
if err := r.db.WithContext(ctx).
|
||||
Model(&entity.Payment{}).
|
||||
Select("party_id AS supplier_id, SUM(nominal) AS total").
|
||||
Where("party_type = ?", string(utils.PaymentPartySupplier)).
|
||||
Where("party_id IN ?", supplierIDs).
|
||||
Where("transaction_type = ?", string(utils.TransactionTypeSaldoAwal)).
|
||||
Group("party_id").
|
||||
Scan(&rows).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make(map[uint]float64, len(rows))
|
||||
for _, row := range rows {
|
||||
result[row.SupplierID] = row.Total
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (r *debtSupplierRepositoryImpl) GetPurchaseTotalsBeforeDate(ctx context.Context, supplierIDs []uint, filters *validation.DebtSupplierQuery) (map[uint]float64, error) {
|
||||
if len(supplierIDs) == 0 || strings.TrimSpace(filters.StartDate) == "" {
|
||||
return map[uint]float64{}, nil
|
||||
@@ -276,7 +378,11 @@ func (r *debtSupplierRepositoryImpl) GetPurchaseTotalsBeforeDate(ctx context.Con
|
||||
Table("purchases").
|
||||
Select("purchases.supplier_id AS supplier_id, SUM(purchase_items.total_price) AS total").
|
||||
Joins("JOIN purchase_items ON purchase_items.purchase_id = purchases.id").
|
||||
Joins("JOIN (?) AS la ON la.approvable_id = purchases.id", r.latestPurchaseApproval(ctx)).
|
||||
Where("purchases.supplier_id IN ?", supplierIDs).
|
||||
Where("la.step_number >= ?", uint16(utils.PurchaseStepReceiving)).
|
||||
Where("(la.action IS NULL OR la.action != ?)", string(entity.ApprovalActionRejected)).
|
||||
Where("purchase_items.received_date IS NOT NULL").
|
||||
Where(fmt.Sprintf("DATE(%s) < ?", dateColumn), dateFrom).
|
||||
Group("purchases.supplier_id").
|
||||
Scan(&rows).Error; err != nil {
|
||||
@@ -313,6 +419,7 @@ func (r *debtSupplierRepositoryImpl) GetPaymentTotalsBeforeDate(ctx context.Cont
|
||||
Where("party_type = ?", string(utils.PaymentPartySupplier)).
|
||||
Where("direction = ?", "OUT").
|
||||
Where("party_id IN ?", supplierIDs).
|
||||
Where("transaction_type <> ?", string(utils.TransactionTypeSaldoAwal)).
|
||||
Where("DATE(payment_date) < ?", dateFrom).
|
||||
Group("party_id").
|
||||
Scan(&rows).Error; err != nil {
|
||||
|
||||
@@ -6,45 +6,50 @@ import (
|
||||
|
||||
entity "gitlab.com/mbugroup/lti-api.git/internal/entities"
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/utils"
|
||||
"gitlab.com/mbugroup/lti-api.git/internal/utils/fifo"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type HppPerKandangRow struct {
|
||||
KandangID uint
|
||||
KandangName string
|
||||
KandangStatus string
|
||||
LocationID uint
|
||||
LocationName string
|
||||
PicID uint
|
||||
PicName string
|
||||
RemainingChickenBirds float64
|
||||
RemainingChickenWeight float64
|
||||
EggProductionWeightKg float64
|
||||
EggProductionPieces float64
|
||||
ProjectFlockKandangID uint
|
||||
ProjectFlockPeriod int
|
||||
KandangID uint
|
||||
KandangName string
|
||||
KandangStatus string
|
||||
LocationID uint
|
||||
LocationName string
|
||||
PicID uint
|
||||
PicName string
|
||||
RecordingCount int64
|
||||
// RemainingChickenBirds float64
|
||||
// RemainingChickenWeight float64
|
||||
EggProductionWeightKgRemaining float64
|
||||
// EggProductionPiecesRemaining float64
|
||||
// EggProductionTotalWeightKg float64
|
||||
// EggProductionTotalPieces float64
|
||||
}
|
||||
|
||||
type HppPerKandangCostRow struct {
|
||||
KandangID uint
|
||||
FeedCost float64
|
||||
OvkCost float64
|
||||
DocCost float64
|
||||
DocQty float64
|
||||
BudgetCost float64
|
||||
ExpenseCost float64
|
||||
ProjectFlockKandangID uint
|
||||
FeedCost float64
|
||||
OvkCost float64
|
||||
DocCost float64
|
||||
DocQty float64
|
||||
BudgetCost float64
|
||||
ExpenseCost float64
|
||||
}
|
||||
|
||||
type HppPerKandangSupplierRow struct {
|
||||
KandangID uint
|
||||
SupplierID uint
|
||||
SupplierName string
|
||||
SupplierAlias string
|
||||
Category string
|
||||
ProjectFlockKandangID uint
|
||||
SupplierID uint
|
||||
SupplierName string
|
||||
SupplierAlias string
|
||||
Category string
|
||||
}
|
||||
|
||||
type HppPerKandangRepository interface {
|
||||
GetRowsByPeriod(ctx context.Context, start, end time.Time, areaIDs, locationIDs, kandangIDs []int64) ([]HppPerKandangRow, error)
|
||||
GetFeedOvkDocCostByPeriod(ctx context.Context, start, end time.Time, areaIDs, locationIDs, kandangIDs []int64) ([]HppPerKandangCostRow, []HppPerKandangSupplierRow, error)
|
||||
GetFeedOvkDocCostByPeriod(ctx context.Context, start, end time.Time, projectFlockKandangIDs []uint) ([]HppPerKandangCostRow, []HppPerKandangSupplierRow, error)
|
||||
GetWeightRemainingByProjectFlockKandangIDs(ctx context.Context, start, end time.Time, projectFlockKandangIDs []uint) (map[uint]HppPerKandangRow, error)
|
||||
}
|
||||
|
||||
type hppPerKandangRepository struct {
|
||||
@@ -58,9 +63,32 @@ func NewHppPerKandangRepository(db *gorm.DB) HppPerKandangRepository {
|
||||
func (r *hppPerKandangRepository) GetRowsByPeriod(ctx context.Context, start, end time.Time, areaIDs, locationIDs, kandangIDs []int64) ([]HppPerKandangRow, error) {
|
||||
var rows []HppPerKandangRow
|
||||
|
||||
query := r.db.WithContext(ctx).
|
||||
latestApproval := r.db.WithContext(ctx).
|
||||
Table("approvals AS a").
|
||||
Select("a.approvable_id, a.action").
|
||||
Joins(`
|
||||
JOIN (
|
||||
SELECT approvable_id, MAX(action_at) AS latest_action_at
|
||||
FROM approvals
|
||||
WHERE approvable_type = ?
|
||||
GROUP BY approvable_id
|
||||
) AS la ON la.approvable_id = a.approvable_id AND la.latest_action_at = a.action_at`,
|
||||
string(utils.ApprovalWorkflowRecording),
|
||||
)
|
||||
|
||||
validRecordings := r.db.WithContext(ctx).
|
||||
Table("recordings AS r").
|
||||
Select("r.id, r.project_flock_kandangs_id, r.total_chick_qty").
|
||||
Joins("LEFT JOIN (?) AS la ON la.approvable_id = r.id", latestApproval).
|
||||
Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end).
|
||||
Where("r.deleted_at IS NULL").
|
||||
Where("(la.action IS NULL OR la.action != ?)", string(entity.ApprovalActionRejected))
|
||||
|
||||
query := r.db.WithContext(ctx).
|
||||
Table("project_flocks AS pf").
|
||||
Select(`
|
||||
pfk.id AS project_flock_kandang_id,
|
||||
pfk.period AS project_flock_period,
|
||||
k.id AS kandang_id,
|
||||
k.name AS kandang_name,
|
||||
k.status AS kandang_status,
|
||||
@@ -68,23 +96,31 @@ func (r *hppPerKandangRepository) GetRowsByPeriod(ctx context.Context, start, en
|
||||
loc.name AS location_name,
|
||||
pic.id AS pic_id,
|
||||
pic.name AS pic_name,
|
||||
COALESCE(MAX(r.total_chick_qty), 0) AS remaining_chicken_birds,
|
||||
COALESCE(SUM(rbw.total_weight), 0) AS remaining_chicken_weight,
|
||||
COALESCE(SUM(re.weight), 0) AS egg_production_weight_kg,
|
||||
COALESCE(SUM(re.qty), 0) AS egg_production_pieces`).
|
||||
Joins("JOIN project_flock_kandangs AS pfk ON pfk.id = r.project_flock_kandangs_id").
|
||||
COALESCE(COUNT(vr.id), 0) AS recording_count,
|
||||
COALESCE(MAX(vr.total_chick_qty), 0) AS remaining_chicken_birds,
|
||||
0 AS remaining_chicken_weight,
|
||||
0 AS egg_production_weight_kg,
|
||||
0 AS egg_production_pieces,
|
||||
0 AS egg_production_total_weight_kg,
|
||||
0 AS egg_production_total_pieces`).
|
||||
Joins("JOIN project_flock_kandangs AS pfk ON pfk.project_flock_id = pf.id").
|
||||
Joins(`
|
||||
LEFT JOIN (
|
||||
SELECT project_flock_kandang_id, MIN(chick_in_date) AS chick_in_date
|
||||
FROM project_chickins
|
||||
GROUP BY project_flock_kandang_id
|
||||
) AS pc ON pc.project_flock_kandang_id = pfk.id`).
|
||||
Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id").
|
||||
Joins("JOIN locations AS loc ON loc.id = k.location_id").
|
||||
Joins("JOIN users AS pic ON pic.id = k.pic_id").
|
||||
Joins("LEFT JOIN recording_bws AS rbw ON rbw.recording_id = r.id").
|
||||
Joins("LEFT JOIN recording_eggs AS re ON re.recording_id = r.id").
|
||||
Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end).
|
||||
Where("r.deleted_at IS NULL")
|
||||
Joins("LEFT JOIN (?) AS vr ON vr.project_flock_kandangs_id = pfk.id", validRecordings).
|
||||
Where("pf.category = ?", utils.ProjectFlockCategoryLaying).
|
||||
Where("(pfk.closed_at IS NULL OR ? BETWEEN pc.chick_in_date AND pfk.closed_at)", start)
|
||||
|
||||
query = applyLocationFilters(query, areaIDs, locationIDs, kandangIDs)
|
||||
|
||||
query = query.Group("k.id, k.name, k.status, loc.id, loc.name, pic.id, pic.name").
|
||||
Order("k.id ASC")
|
||||
query = query.Group("pfk.id, pfk.period, k.id, k.name, k.status, loc.id, loc.name, pic.id, pic.name").
|
||||
Order("pfk.id ASC")
|
||||
|
||||
if err := query.Scan(&rows).Error; err != nil {
|
||||
return nil, err
|
||||
@@ -93,74 +129,22 @@ func (r *hppPerKandangRepository) GetRowsByPeriod(ctx context.Context, start, en
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context, start, end time.Time, areaIDs, locationIDs, kandangIDs []int64) ([]HppPerKandangCostRow, []HppPerKandangSupplierRow, error) {
|
||||
func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context, start, end time.Time, projectFlockKandangIDs []uint) ([]HppPerKandangCostRow, []HppPerKandangSupplierRow, error) {
|
||||
var rows []HppPerKandangCostRow
|
||||
|
||||
recordingPfk := r.db.WithContext(ctx).
|
||||
Table("recordings AS r").
|
||||
Select("DISTINCT pfk.id").
|
||||
Joins("JOIN project_flock_kandangs AS pfk ON pfk.id = r.project_flock_kandangs_id").
|
||||
Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id").
|
||||
Joins("JOIN locations AS loc ON loc.id = k.location_id").
|
||||
Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end).
|
||||
Where("r.deleted_at IS NULL")
|
||||
recordingPfk = applyLocationFilters(recordingPfk, areaIDs, locationIDs, kandangIDs)
|
||||
|
||||
purchaseStockableKey := fifo.StockableKeyPurchaseItems.String()
|
||||
transferStockableKey := fifo.StockableKeyStockTransferIn.String()
|
||||
|
||||
query := r.db.WithContext(ctx).
|
||||
Table("recordings AS r").
|
||||
Select(`
|
||||
k.id AS kandang_id,
|
||||
COALESCE(SUM(CASE
|
||||
WHEN f.name = ? THEN COALESCE(sa.qty, 0) * COALESCE(pi.price, 0)
|
||||
WHEN sa.stockable_type = ? AND tf.name = ? THEN COALESCE(std.quantity, 0) * COALESCE(tpi.price, 0)
|
||||
ELSE 0
|
||||
END), 0) AS feed_cost,
|
||||
COALESCE(SUM(CASE
|
||||
WHEN f.name = ? THEN COALESCE(sa.qty, 0) * COALESCE(pi.price, 0)
|
||||
WHEN sa.stockable_type = ? AND tf.name = ? THEN COALESCE(std.quantity, 0) * COALESCE(tpi.price, 0)
|
||||
ELSE 0
|
||||
END), 0) AS ovk_cost`,
|
||||
utils.FlagPakan, transferStockableKey, utils.FlagPakan,
|
||||
utils.FlagOVK, transferStockableKey, utils.FlagOVK).
|
||||
Joins("JOIN project_flock_kandangs AS pfk ON pfk.id = r.project_flock_kandangs_id").
|
||||
Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id").
|
||||
Joins("JOIN locations AS loc ON loc.id = k.location_id").
|
||||
Joins("LEFT JOIN recording_stocks AS rs ON rs.recording_id = r.id").
|
||||
Joins("LEFT JOIN stock_allocations AS sa ON sa.usable_type = ? AND sa.usable_id = rs.id AND sa.status = ?", fifo.UsableKeyRecordingStock.String(), entity.StockAllocationStatusActive).
|
||||
Joins("LEFT JOIN purchase_items AS pi ON pi.id = sa.stockable_id AND sa.stockable_type = ?", purchaseStockableKey).
|
||||
Joins("LEFT JOIN stock_transfer_details AS std ON std.id = sa.stockable_id AND sa.stockable_type = ?", transferStockableKey).
|
||||
Joins("LEFT JOIN stock_transfers AS st ON st.id = std.stock_transfer_id").
|
||||
Joins("LEFT JOIN purchase_items AS tpi ON tpi.product_id = std.product_id AND tpi.warehouse_id = st.from_warehouse_id").
|
||||
Joins("LEFT JOIN flags AS f ON f.flagable_id = pi.product_id AND f.flagable_type = ?", entity.FlagableTypeProduct).
|
||||
Joins("LEFT JOIN flags AS tf ON tf.flagable_id = std.product_id AND tf.flagable_type = ?", entity.FlagableTypeProduct).
|
||||
Where("r.project_flock_kandangs_id IN (?)", recordingPfk.Session(&gorm.Session{NewDB: true})).
|
||||
Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end).
|
||||
Where("r.deleted_at IS NULL")
|
||||
|
||||
query = applyLocationFilters(query, areaIDs, locationIDs, kandangIDs)
|
||||
|
||||
query = query.Group("k.id").Order("k.id ASC")
|
||||
|
||||
if err := query.Scan(&rows).Error; err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
docRows := make([]struct {
|
||||
KandangID uint
|
||||
DocCost float64
|
||||
DocQty float64
|
||||
SupplierID *uint
|
||||
SupplierName *string
|
||||
SupplierAlias *string
|
||||
ProjectFlockKandangID uint
|
||||
DocCost float64
|
||||
DocQty float64
|
||||
SupplierID *uint
|
||||
SupplierName *string
|
||||
SupplierAlias *string
|
||||
}, 0)
|
||||
|
||||
docQuery := r.db.WithContext(ctx).
|
||||
Table("project_chickins AS pc").
|
||||
Select(`
|
||||
pfk.kandang_id AS kandang_id,
|
||||
pfk.id AS project_flock_kandang_id,
|
||||
COALESCE(SUM(pc.usage_qty * COALESCE(pi.price, 0)), 0) AS doc_cost,
|
||||
COALESCE(SUM(pc.usage_qty), 0) AS doc_qty,
|
||||
s.id AS supplier_id,
|
||||
@@ -172,9 +156,8 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context,
|
||||
Joins("LEFT JOIN purchase_items AS pi ON pi.product_warehouse_id = pc.product_warehouse_id").
|
||||
Joins("LEFT JOIN purchases AS pur ON pur.id = pi.purchase_id").
|
||||
Joins("LEFT JOIN suppliers AS s ON s.id = pur.supplier_id").
|
||||
Where("pc.project_flock_kandang_id IN (?)", recordingPfk.Session(&gorm.Session{NewDB: true})).
|
||||
Group("pfk.kandang_id, s.id, s.name, s.alias")
|
||||
docQuery = applyLocationFilters(docQuery, areaIDs, locationIDs, kandangIDs)
|
||||
Where("pc.project_flock_kandang_id IN ?", projectFlockKandangIDs).
|
||||
Group("pfk.id, s.id, s.name, s.alias")
|
||||
|
||||
if err := docQuery.Scan(&docRows).Error; err != nil {
|
||||
return nil, nil, err
|
||||
@@ -183,28 +166,28 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context,
|
||||
costMap := make(map[uint]*HppPerKandangCostRow, len(rows))
|
||||
for i := range rows {
|
||||
row := rows[i]
|
||||
costMap[row.KandangID] = &rows[i]
|
||||
costMap[row.ProjectFlockKandangID] = &rows[i]
|
||||
}
|
||||
|
||||
docSuppliers := make([]HppPerKandangSupplierRow, 0)
|
||||
docSeen := make(map[uint]map[uint]bool)
|
||||
for _, doc := range docRows {
|
||||
entry, ok := costMap[doc.KandangID]
|
||||
entry, ok := costMap[doc.ProjectFlockKandangID]
|
||||
if !ok {
|
||||
rows = append(rows, HppPerKandangCostRow{
|
||||
KandangID: doc.KandangID,
|
||||
ProjectFlockKandangID: doc.ProjectFlockKandangID,
|
||||
})
|
||||
entry = &rows[len(rows)-1]
|
||||
costMap[doc.KandangID] = entry
|
||||
costMap[doc.ProjectFlockKandangID] = entry
|
||||
}
|
||||
entry.DocCost += doc.DocCost
|
||||
entry.DocQty += doc.DocQty
|
||||
if doc.SupplierID != nil {
|
||||
if docSeen[doc.KandangID] == nil {
|
||||
docSeen[doc.KandangID] = make(map[uint]bool)
|
||||
if docSeen[doc.ProjectFlockKandangID] == nil {
|
||||
docSeen[doc.ProjectFlockKandangID] = make(map[uint]bool)
|
||||
}
|
||||
if !docSeen[doc.KandangID][*doc.SupplierID] {
|
||||
docSeen[doc.KandangID][*doc.SupplierID] = true
|
||||
if !docSeen[doc.ProjectFlockKandangID][*doc.SupplierID] {
|
||||
docSeen[doc.ProjectFlockKandangID][*doc.SupplierID] = true
|
||||
supplierName := ""
|
||||
if doc.SupplierName != nil {
|
||||
supplierName = *doc.SupplierName
|
||||
@@ -214,137 +197,75 @@ func (r *hppPerKandangRepository) GetFeedOvkDocCostByPeriod(ctx context.Context,
|
||||
supplierAlias = *doc.SupplierAlias
|
||||
}
|
||||
docSuppliers = append(docSuppliers, HppPerKandangSupplierRow{
|
||||
KandangID: doc.KandangID,
|
||||
SupplierID: *doc.SupplierID,
|
||||
SupplierName: supplierName,
|
||||
SupplierAlias: supplierAlias,
|
||||
Category: "DOC",
|
||||
ProjectFlockKandangID: doc.ProjectFlockKandangID,
|
||||
SupplierID: *doc.SupplierID,
|
||||
SupplierName: supplierName,
|
||||
SupplierAlias: supplierAlias,
|
||||
Category: "DOC",
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
budgetRows := make([]struct {
|
||||
KandangID uint
|
||||
BudgetCost float64
|
||||
}, 0)
|
||||
return rows, docSuppliers, nil
|
||||
}
|
||||
|
||||
pfkUsageSub := r.db.
|
||||
Table("project_chickins AS pc").
|
||||
Select(`
|
||||
pc.project_flock_kandang_id,
|
||||
SUM(pc.usage_qty) AS kandang_usage_qty`).
|
||||
Group("pc.project_flock_kandang_id")
|
||||
|
||||
projectUsageSub := r.db.
|
||||
Table("project_chickins AS pc").
|
||||
Select(`
|
||||
pfk.project_flock_id,
|
||||
SUM(pc.usage_qty) AS project_usage_qty`).
|
||||
Joins("JOIN project_flock_kandangs AS pfk ON pfk.id = pc.project_flock_kandang_id").
|
||||
Group("pfk.project_flock_id")
|
||||
|
||||
budgetQuery := r.db.WithContext(ctx).
|
||||
Table("project_flock_kandangs AS pfk").
|
||||
Select(`
|
||||
k.id AS kandang_id,
|
||||
COALESCE(SUM((pb.qty * pb.price) * COALESCE(k_usage.kandang_usage_qty, 0) / NULLIF(p_usage.project_usage_qty, 0)), 0) AS budget_cost`).
|
||||
Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id").
|
||||
Joins("JOIN locations AS loc ON loc.id = k.location_id").
|
||||
Joins("JOIN project_budgets AS pb ON pb.project_flock_id = pfk.project_flock_id").
|
||||
Joins("LEFT JOIN (?) AS k_usage ON k_usage.project_flock_kandang_id = pfk.id", pfkUsageSub).
|
||||
Joins("LEFT JOIN (?) AS p_usage ON p_usage.project_flock_id = pfk.project_flock_id", projectUsageSub).
|
||||
Where("pfk.id IN (?)", recordingPfk.Session(&gorm.Session{NewDB: true})).
|
||||
Group("k.id")
|
||||
budgetQuery = applyLocationFilters(budgetQuery, areaIDs, locationIDs, kandangIDs)
|
||||
|
||||
if err := budgetQuery.Scan(&budgetRows).Error; err != nil {
|
||||
return nil, nil, err
|
||||
func (r *hppPerKandangRepository) GetWeightRemainingByProjectFlockKandangIDs(ctx context.Context, start, end time.Time, projectFlockKandangIDs []uint) (map[uint]HppPerKandangRow, error) {
|
||||
if len(projectFlockKandangIDs) == 0 {
|
||||
return map[uint]HppPerKandangRow{}, nil
|
||||
}
|
||||
|
||||
for _, budget := range budgetRows {
|
||||
entry, ok := costMap[budget.KandangID]
|
||||
if !ok {
|
||||
rows = append(rows, HppPerKandangCostRow{
|
||||
KandangID: budget.KandangID,
|
||||
})
|
||||
entry = &rows[len(rows)-1]
|
||||
costMap[budget.KandangID] = entry
|
||||
}
|
||||
entry.BudgetCost += budget.BudgetCost
|
||||
latestApproval := r.db.WithContext(ctx).
|
||||
Table("approvals AS a").
|
||||
Select("a.approvable_id, a.action").
|
||||
Joins(`
|
||||
JOIN (
|
||||
SELECT approvable_id, MAX(action_at) AS latest_action_at
|
||||
FROM approvals
|
||||
WHERE approvable_type = ?
|
||||
GROUP BY approvable_id
|
||||
) AS la ON la.approvable_id = a.approvable_id AND la.latest_action_at = a.action_at`,
|
||||
string(utils.ApprovalWorkflowRecording),
|
||||
)
|
||||
|
||||
type eggRow struct {
|
||||
ProjectFlockKandangID uint
|
||||
EggProductionWeightKgRemaining float64
|
||||
// EggProductionPiecesRemaining float64
|
||||
// EggProductionTotalWeightKg float64
|
||||
// EggProductionTotalPieces float64
|
||||
}
|
||||
|
||||
expenseRows := make([]struct {
|
||||
KandangID uint
|
||||
ExpenseCost float64
|
||||
}, 0)
|
||||
|
||||
expenseQuery := r.db.WithContext(ctx).
|
||||
Table("project_flock_kandangs AS pfk").
|
||||
Select(`
|
||||
k.id AS kandang_id,
|
||||
COALESCE(SUM(er.qty * er.price), 0) AS expense_cost`).
|
||||
Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id").
|
||||
Joins("JOIN locations AS loc ON loc.id = k.location_id").
|
||||
Joins("JOIN expense_nonstocks AS en ON en.project_flock_kandang_id = pfk.id").
|
||||
Joins("JOIN expense_realizations AS er ON er.expense_nonstock_id = en.id").
|
||||
Where("pfk.id IN (?)", recordingPfk.Session(&gorm.Session{NewDB: true})).
|
||||
Group("k.id")
|
||||
expenseQuery = applyLocationFilters(expenseQuery, areaIDs, locationIDs, kandangIDs)
|
||||
|
||||
if err := expenseQuery.Scan(&expenseRows).Error; err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
for _, exp := range expenseRows {
|
||||
entry, ok := costMap[exp.KandangID]
|
||||
if !ok {
|
||||
rows = append(rows, HppPerKandangCostRow{
|
||||
KandangID: exp.KandangID,
|
||||
})
|
||||
entry = &rows[len(rows)-1]
|
||||
costMap[exp.KandangID] = entry
|
||||
}
|
||||
entry.ExpenseCost += exp.ExpenseCost
|
||||
}
|
||||
|
||||
feedSuppliers := make([]HppPerKandangSupplierRow, 0)
|
||||
|
||||
feedQuery := r.db.WithContext(ctx).
|
||||
eggRows := make([]eggRow, 0)
|
||||
query := r.db.WithContext(ctx).
|
||||
Table("recordings AS r").
|
||||
Select("DISTINCT k.id AS kandang_id, s.id AS supplier_id, s.name AS supplier_name, s.alias AS supplier_alias").
|
||||
Joins("JOIN project_flock_kandangs AS pfk ON pfk.id = r.project_flock_kandangs_id").
|
||||
Joins("JOIN kandangs AS k ON k.id = pfk.kandang_id").
|
||||
Joins("JOIN locations AS loc ON loc.id = k.location_id").
|
||||
Joins("LEFT JOIN recording_stocks AS rs ON rs.recording_id = r.id").
|
||||
Joins("LEFT JOIN stock_allocations AS sa ON sa.usable_type = ? AND sa.usable_id = rs.id AND sa.status = ?", fifo.UsableKeyRecordingStock.String(), entity.StockAllocationStatusActive).
|
||||
Joins("LEFT JOIN purchase_items AS pi ON pi.id = sa.stockable_id AND sa.stockable_type = ?", purchaseStockableKey).
|
||||
Joins("LEFT JOIN purchases AS pur ON pur.id = pi.purchase_id").
|
||||
Joins("LEFT JOIN suppliers AS s ON s.id = pur.supplier_id").
|
||||
Joins("LEFT JOIN flags AS f ON f.flagable_id = pi.product_id AND f.flagable_type = ?", entity.FlagableTypeProduct).
|
||||
Where("f.name IN ?", []utils.FlagType{utils.FlagPakan, utils.FlagOVK}).
|
||||
Where("r.project_flock_kandangs_id IN (?)", recordingPfk.Session(&gorm.Session{NewDB: true})).
|
||||
Where("r.record_datetime >= ? AND r.record_datetime < ?", start, end).
|
||||
Where("r.deleted_at IS NULL")
|
||||
feedQuery = applyLocationFilters(feedQuery, areaIDs, locationIDs, kandangIDs)
|
||||
Select(`
|
||||
r.project_flock_kandangs_id AS project_flock_kandang_id,
|
||||
COALESCE((SUM(re.weight) / NULLIF(SUM(re.total_qty), 0)) * SUM(re.total_qty - re.total_used), 0) AS egg_production_weight_kg_remaining`).
|
||||
Joins("LEFT JOIN (?) AS la ON la.approvable_id = r.id", latestApproval).
|
||||
Joins("LEFT JOIN recording_eggs AS re ON re.recording_id = r.id").
|
||||
Where("r.project_flock_kandangs_id IN ?", projectFlockKandangIDs).
|
||||
Where("r.record_datetime < ?", end).
|
||||
Where("r.deleted_at IS NULL").
|
||||
Where("(la.action IS NULL OR la.action != ?)", string(entity.ApprovalActionRejected)).
|
||||
Group("r.project_flock_kandangs_id")
|
||||
|
||||
if err := feedQuery.Scan(&feedSuppliers).Error; err != nil {
|
||||
return nil, nil, err
|
||||
if err := query.Scan(&eggRows).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for i := range feedSuppliers {
|
||||
if _, exists := costMap[feedSuppliers[i].KandangID]; !exists {
|
||||
rows = append(rows, HppPerKandangCostRow{
|
||||
KandangID: feedSuppliers[i].KandangID,
|
||||
})
|
||||
costMap[feedSuppliers[i].KandangID] = &rows[len(rows)-1]
|
||||
result := make(map[uint]HppPerKandangRow, len(eggRows))
|
||||
for _, row := range eggRows {
|
||||
result[row.ProjectFlockKandangID] = HppPerKandangRow{
|
||||
ProjectFlockKandangID: row.ProjectFlockKandangID,
|
||||
EggProductionWeightKgRemaining: row.EggProductionWeightKgRemaining,
|
||||
// EggProductionPiecesRemaining: row.EggProductionPiecesRemaining,
|
||||
// EggProductionTotalWeightKg: row.EggProductionTotalWeightKg,
|
||||
// EggProductionTotalPieces: row.EggProductionTotalPieces,
|
||||
}
|
||||
feedSuppliers[i].Category = "FEED"
|
||||
}
|
||||
|
||||
supplierRows := append(docSuppliers, feedSuppliers...)
|
||||
|
||||
return rows, supplierRows, nil
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func applyLocationFilters(query *gorm.DB, areaIDs, locationIDs, kandangIDs []int64) *gorm.DB {
|
||||
@@ -355,7 +276,7 @@ func applyLocationFilters(query *gorm.DB, areaIDs, locationIDs, kandangIDs []int
|
||||
query = query.Where("k.location_id IN ?", locationIDs)
|
||||
}
|
||||
if len(kandangIDs) > 0 {
|
||||
query = query.Where("k.id IN ?", kandangIDs)
|
||||
query = query.Where("pfk.id IN ?", kandangIDs)
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@ import (
|
||||
|
||||
type ProductionResultRepository interface {
|
||||
GetRecordingsByProjectFlockKandang(ctx context.Context, projectFlockKandangID uint, offset, limit int) ([]entity.Recording, int64, error)
|
||||
GetProductionStandardIDByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) (uint, error)
|
||||
}
|
||||
|
||||
type productionResultRepositoryImpl struct {
|
||||
@@ -76,3 +77,25 @@ func (r *productionResultRepositoryImpl) GetRecordingsByProjectFlockKandang(
|
||||
|
||||
return recordings, total, nil
|
||||
}
|
||||
|
||||
func (r *productionResultRepositoryImpl) GetProductionStandardIDByProjectFlockKandangID(ctx context.Context, projectFlockKandangID uint) (uint, error) {
|
||||
if projectFlockKandangID == 0 {
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
var row struct {
|
||||
ProductionStandardID uint `gorm:"column:production_standard_id"`
|
||||
}
|
||||
|
||||
err := r.db.WithContext(ctx).
|
||||
Table("project_flock_kandangs pfk").
|
||||
Select("pf.production_standard_id").
|
||||
Joins("JOIN project_flocks pf ON pf.id = pfk.project_flock_id").
|
||||
Where("pfk.id = ?", projectFlockKandangID).
|
||||
Take(&row).Error
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return row.ProductionStandardID, nil
|
||||
}
|
||||
|
||||
@@ -25,6 +25,21 @@ func NewPurchaseSupplierRepository(db *gorm.DB) PurchaseSupplierRepository {
|
||||
return &purchaseSupplierRepositoryImpl{db: db}
|
||||
}
|
||||
|
||||
func (r *purchaseSupplierRepositoryImpl) latestPurchaseApproval(ctx context.Context) *gorm.DB {
|
||||
return r.db.WithContext(ctx).
|
||||
Table("approvals AS a").
|
||||
Select("a.approvable_id, a.step_number, a.action").
|
||||
Joins(`
|
||||
JOIN (
|
||||
SELECT approvable_id, MAX(action_at) AS latest_action_at
|
||||
FROM approvals
|
||||
WHERE approvable_type = ?
|
||||
GROUP BY approvable_id
|
||||
) AS la ON la.approvable_id = a.approvable_id AND la.latest_action_at = a.action_at`,
|
||||
string(utils.ApprovalWorkflowPurchase),
|
||||
)
|
||||
}
|
||||
|
||||
func (r *purchaseSupplierRepositoryImpl) baseSupplierQuery(ctx context.Context, filters *validation.PurchaseSupplierQuery) *gorm.DB {
|
||||
dateColumn := "purchase_items.received_date"
|
||||
switch strings.ToLower(strings.TrimSpace(filters.FilterBy)) {
|
||||
@@ -34,10 +49,16 @@ func (r *purchaseSupplierRepositoryImpl) baseSupplierQuery(ctx context.Context,
|
||||
dateColumn = "purchase_items.received_date"
|
||||
}
|
||||
|
||||
latestApproval := r.latestPurchaseApproval(ctx)
|
||||
|
||||
db := r.db.WithContext(ctx).
|
||||
Model(&entity.Supplier{}).
|
||||
Joins("JOIN purchases ON purchases.supplier_id = suppliers.id").
|
||||
Joins("JOIN purchase_items ON purchase_items.purchase_id = purchases.id")
|
||||
Joins("JOIN purchase_items ON purchase_items.purchase_id = purchases.id").
|
||||
Joins("JOIN (?) AS la ON la.approvable_id = purchases.id", latestApproval).
|
||||
Where("la.step_number >= ?", uint16(utils.PurchaseStepReceiving)).
|
||||
Where("(la.action IS NULL OR la.action != ?)", string(entity.ApprovalActionRejected)).
|
||||
Where("purchase_items.received_date IS NOT NULL")
|
||||
|
||||
if filters.SupplierId > 0 {
|
||||
db = db.Where("suppliers.id = ?", filters.SupplierId)
|
||||
@@ -160,7 +181,11 @@ func (r *purchaseSupplierRepositoryImpl) GetItemsBySuppliers(ctx context.Context
|
||||
Preload("ExpenseNonstock.Expense").
|
||||
Preload("ExpenseNonstock.Expense.Supplier").
|
||||
Joins("JOIN purchases ON purchases.id = purchase_items.purchase_id").
|
||||
Where("purchases.supplier_id IN ?", supplierIDs)
|
||||
Joins("JOIN (?) AS la ON la.approvable_id = purchases.id", r.latestPurchaseApproval(ctx)).
|
||||
Where("purchases.supplier_id IN ?", supplierIDs).
|
||||
Where("la.step_number >= ?", uint16(utils.PurchaseStepReceiving)).
|
||||
Where("(la.action IS NULL OR la.action != ?)", string(entity.ApprovalActionRejected)).
|
||||
Where("purchase_items.received_date IS NOT NULL")
|
||||
|
||||
if filters.ProductId > 0 {
|
||||
db = db.Where("purchase_items.product_id = ?", filters.ProductId)
|
||||
|
||||
Reference in New Issue
Block a user