package repository import ( "context" "fmt" "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/repports/validations" "gitlab.com/mbugroup/lti-api.git/internal/utils" "gorm.io/gorm" ) type ExpenseRealizationRepository interface { repository.BaseRepository[entity.ExpenseRealization] IdExists(ctx context.Context, id uint64) (bool, error) GetByExpenseNonstockID(ctx context.Context, expenseNonstockID uint64) (*entity.ExpenseRealization, error) GetByProjectFlockID(ctx context.Context, projectFlockID uint) ([]entity.ExpenseRealization, error) GetClosingOverhead(ctx context.Context, projectFlockID uint, projectFlockKandangID *uint) ([]entity.ExpenseRealization, error) GetAllWithFilters(ctx context.Context, offset, limit int, filters *validation.ExpenseQuery) ([]entity.ExpenseRealization, int64, error) } type ExpenseRealizationRepositoryImpl struct { *repository.BaseRepositoryImpl[entity.ExpenseRealization] } func NewExpenseRealizationRepository(db *gorm.DB) ExpenseRealizationRepository { return &ExpenseRealizationRepositoryImpl{ BaseRepositoryImpl: repository.NewBaseRepository[entity.ExpenseRealization](db), } } func (r *ExpenseRealizationRepositoryImpl) IdExists(ctx context.Context, id uint64) (bool, error) { return repository.Exists[entity.ExpenseRealization](ctx, r.DB(), uint(id)) } func (r *ExpenseRealizationRepositoryImpl) GetByExpenseNonstockID(ctx context.Context, expenseNonstockID uint64) (*entity.ExpenseRealization, error) { var realization entity.ExpenseRealization err := r.DB().WithContext(ctx).Where("expense_nonstock_id = ?", expenseNonstockID).First(&realization).Error return &realization, err } func (r *ExpenseRealizationRepositoryImpl) GetByProjectFlockID(ctx context.Context, projectFlockID uint) ([]entity.ExpenseRealization, error) { var realizations []entity.ExpenseRealization err := r.DB().WithContext(ctx). Preload("ExpenseNonstock"). Preload("ExpenseNonstock.Nonstock"). Preload("ExpenseNonstock.Nonstock.Uom"). Preload("ExpenseNonstock.Nonstock.Flags"). Preload("ExpenseNonstock.Expense"). Joins("JOIN expense_nonstocks ON expense_nonstocks.id = expense_realizations.expense_nonstock_id"). Joins("JOIN expenses ON expenses.id = expense_nonstocks.expense_id"). Joins("LEFT JOIN project_flock_kandangs ON project_flock_kandangs.id = expense_nonstocks.project_flock_kandang_id"). Joins("LEFT JOIN kandangs ON kandangs.id = expense_nonstocks.kandang_id"). Where("project_flock_kandangs.project_flock_id = ? OR kandangs.id IN (SELECT kandang_id FROM project_flock_kandangs WHERE project_flock_id = ?)", projectFlockID, projectFlockID). Find(&realizations).Error return realizations, err } func (r *ExpenseRealizationRepositoryImpl) GetClosingOverhead(ctx context.Context, projectFlockID uint, projectFlockKandangID *uint) ([]entity.ExpenseRealization, error) { var realizations []entity.ExpenseRealization db := r.DB().WithContext(ctx). Preload("ExpenseNonstock"). Preload("ExpenseNonstock.Nonstock"). Preload("ExpenseNonstock.Nonstock.Uom"). Preload("ExpenseNonstock.Nonstock.Flags"). Preload("ExpenseNonstock.Expense"). Joins("JOIN expense_nonstocks ON expense_nonstocks.id = expense_realizations.expense_nonstock_id"). Joins("JOIN expenses ON expenses.id = expense_nonstocks.expense_id"). Joins("LEFT JOIN project_flock_kandangs ON project_flock_kandangs.id = expense_nonstocks.project_flock_kandang_id"). Where("expenses.realization_date IS NOT NULL"). Where("expenses.category = ?", "BOP") if projectFlockKandangID != nil { db = db.Where(`( expense_nonstocks.project_flock_kandang_id = ? OR (expenses.project_flock_id IS NOT NULL AND expenses.project_flock_id::jsonb @> ?::jsonb) )`, *projectFlockKandangID, fmt.Sprintf("[%d]", projectFlockID)) } else { db = db.Where(`( project_flock_kandangs.project_flock_id = ? OR (expenses.project_flock_id IS NOT NULL AND expenses.project_flock_id::jsonb @> ?::jsonb) )`, projectFlockID, fmt.Sprintf("[%d]", projectFlockID)) } err := db.Find(&realizations).Error return realizations, err } func (r *ExpenseRealizationRepositoryImpl) GetAllWithFilters(ctx context.Context, offset, limit int, filters *validation.ExpenseQuery) ([]entity.ExpenseRealization, int64, error) { var realizations []entity.ExpenseRealization var total int64 db := r.DB().WithContext(ctx). Model(&entity.ExpenseRealization{}). Preload("ExpenseNonstock", func(db *gorm.DB) *gorm.DB { return db. Preload("Expense"). Preload("Expense.Supplier"). Preload("Kandang"). Preload("Kandang.Location"). Preload("Nonstock"). Preload("Nonstock.Flags") }). Joins("JOIN expense_nonstocks ON expense_nonstocks.id = expense_realizations.expense_nonstock_id"). Joins("JOIN expenses ON expenses.id = expense_nonstocks.expense_id"). Joins("LEFT JOIN suppliers ON suppliers.id = expenses.supplier_id") if filters.Search != "" { db = db.Where("expenses.category ILIKE ? OR expenses.reference_number ILIKE ? OR expenses.po_number ILIKE ? OR expenses.notes ILIKE ? OR suppliers.name ILIKE ?", "%"+filters.Search+"%", "%"+filters.Search+"%", "%"+filters.Search+"%", "%"+filters.Search+"%", "%"+filters.Search+"%") } if filters.Category != "" { db = db.Where("expenses.category = ?", filters.Category) } if filters.SupplierId > 0 { db = db.Where("expenses.supplier_id = ?", filters.SupplierId) } if filters.KandangId > 0 { db = db.Where("expense_nonstocks.kandang_id = ?", filters.KandangId) } if filters.ProjectFlockKandangId > 0 { db = db.Where("expense_nonstocks.project_flock_kandang_id = ?", filters.ProjectFlockKandangId) } if filters.NonstockId > 0 { db = db.Where("expense_nonstocks.nonstock_id = ?", filters.NonstockId) } locationID := filters.LocationId areaID := filters.AreaId if filters.AllowedLocationIDs != nil || filters.AllowedAreaIDs != nil || locationID > 0 || areaID > 0 { db = db.Joins("JOIN kandangs ON kandangs.id = expense_nonstocks.kandang_id") } if filters.AllowedLocationIDs != nil { if len(filters.AllowedLocationIDs) == 0 { db = db.Where("1 = 0") } else { db = db.Where("kandangs.location_id IN ?", filters.AllowedLocationIDs) } } if filters.AllowedAreaIDs != nil { if len(filters.AllowedAreaIDs) == 0 { db = db.Where("1 = 0") } else { db = db.Joins("JOIN locations ON locations.id = kandangs.location_id"). Where("locations.area_id IN ?", filters.AllowedAreaIDs) } } if locationID > 0 || areaID > 0 { if locationID > 0 { db = db.Where("kandangs.location_id = ?", uint(locationID)) } if areaID > 0 { db = db.Joins("JOIN locations ON locations.id = kandangs.location_id"). Where("locations.area_id = ?", uint(areaID)) } } if filters.RealizationDate != "" { if realizationDate, err := utils.ParseDateString(filters.RealizationDate); err == nil { db = db.Where("DATE(expenses.realization_date) = ?", realizationDate) } } if err := db.Count(&total).Error; err != nil { return nil, 0, err } sortExpr := "expense_realizations.created_at" order := "DESC" if filters.SortOrder == "asc" { order = "ASC" } switch filters.SortBy { case "po_number": sortExpr = "expenses.po_number" case "reference_number": sortExpr = "expenses.reference_number" case "realization_date": sortExpr = "expenses.realization_date" case "transaction_date": sortExpr = "expenses.transaction_date" case "category": sortExpr = "expenses.category" case "product": sortExpr = "(SELECT name FROM nonstocks WHERE id = expense_nonstocks.nonstock_id)" case "supplier": sortExpr = "suppliers.name" case "location": sortExpr = "(SELECT l.name FROM kandangs k JOIN locations l ON l.id = k.location_id WHERE k.id = expense_nonstocks.kandang_id)" case "kandang": sortExpr = "(SELECT name FROM kandangs WHERE id = expense_nonstocks.kandang_id)" case "qty_pengajuan": sortExpr = "expense_nonstocks.qty" case "price_pengajuan": sortExpr = "expense_nonstocks.price" case "total_pengajuan": sortExpr = "expense_nonstocks.qty * expense_nonstocks.price" case "qty_realisasi": sortExpr = "expense_realizations.qty" case "price_realisasi": sortExpr = "expense_realizations.price" case "total_realisasi": sortExpr = "expense_realizations.qty * expense_realizations.price" } if err := db. Offset(offset). Limit(limit). Order(sortExpr + " " + order). Find(&realizations).Error; err != nil { return nil, 0, err } return realizations, total, nil }