package repositories import ( "context" "fmt" "strings" 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 PurchaseSupplierRepository interface { GetSuppliersWithPurchases(ctx context.Context, offset, limit int, filters *validation.PurchaseSupplierQuery) ([]entity.Supplier, int64, error) GetItemsBySuppliers(ctx context.Context, supplierIDs []uint, filters *validation.PurchaseSupplierQuery) ([]entity.PurchaseItem, error) } type purchaseSupplierRepositoryImpl struct { db *gorm.DB } func NewPurchaseSupplierRepository(db *gorm.DB) PurchaseSupplierRepository { return &purchaseSupplierRepositoryImpl{db: db} } func (r *purchaseSupplierRepositoryImpl) baseSupplierQuery(ctx context.Context, filters *validation.PurchaseSupplierQuery) *gorm.DB { dateColumn := "purchase_items.received_date" switch strings.ToLower(strings.TrimSpace(filters.FilterBy)) { case "po_date": dateColumn = "purchases.po_date" case "receive_date", "": dateColumn = "purchase_items.received_date" } 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") if filters.SupplierId > 0 { db = db.Where("suppliers.id = ?", filters.SupplierId) } if filters.ProductId > 0 { db = db.Where("purchase_items.product_id = ?", filters.ProductId) } if filters.ProductCategoryId > 0 { db = db. Joins("JOIN products ON products.id = purchase_items.product_id"). Where("products.product_category_id = ?", filters.ProductCategoryId) } if filters.AreaId > 0 { db = db. Joins("JOIN warehouses ON warehouses.id = purchase_items.warehouse_id"). Where("warehouses.area_id = ?", filters.AreaId) } if filters.StartDate != "" { if dateFrom, err := utils.ParseDateString(filters.StartDate); err == nil { db = db.Where(fmt.Sprintf("DATE(%s) >= ?", dateColumn), dateFrom) } } if filters.EndDate != "" { if dateTo, err := utils.ParseDateString(filters.EndDate); err == nil { db = db.Where(fmt.Sprintf("DATE(%s) <= ?", dateColumn), dateTo) } } return db } func (r *purchaseSupplierRepositoryImpl) GetSuppliersWithPurchases(ctx context.Context, offset, limit int, filters *validation.PurchaseSupplierQuery) ([]entity.Supplier, int64, error) { query := r.baseSupplierQuery(ctx, filters) var totalSuppliers int64 if err := query. Distinct("suppliers.id"). Count(&totalSuppliers).Error; err != nil { return nil, 0, err } if totalSuppliers == 0 { return []entity.Supplier{}, 0, nil } if offset < 0 { offset = 0 } var supplierIDs []uint if err := query. Select("suppliers.id"). Order("suppliers.id ASC"). Offset(offset). Limit(limit). Pluck("suppliers.id", &supplierIDs).Error; err != nil { return nil, 0, err } if len(supplierIDs) == 0 { return []entity.Supplier{}, totalSuppliers, nil } var suppliers []entity.Supplier if err := r.db.WithContext(ctx). Where("id IN ?", supplierIDs). Find(&suppliers).Error; err != nil { return nil, 0, err } return suppliers, totalSuppliers, nil } func (r *purchaseSupplierRepositoryImpl) GetItemsBySuppliers(ctx context.Context, supplierIDs []uint, filters *validation.PurchaseSupplierQuery) ([]entity.PurchaseItem, error) { if len(supplierIDs) == 0 { return []entity.PurchaseItem{}, nil } // Tentukan kolom tanggal yang akan dipakai untuk filter & sort dateColumn := "purchase_items.received_date" switch strings.ToLower(strings.TrimSpace(filters.FilterBy)) { case "po_date": dateColumn = "purchases.po_date" case "receive_date", "": dateColumn = "purchase_items.received_date" } orderDirection := "ASC" switch strings.ToUpper(strings.TrimSpace(filters.SortBy)) { case "DESC": orderDirection = "DESC" case "ASC", "": orderDirection = "ASC" } db := r.db.WithContext(ctx). Model(&entity.PurchaseItem{}). Preload("Purchase"). Preload("Purchase.Supplier"). Preload("Product"). Preload("Product.ProductCategory"). Preload("Warehouse"). Preload("Warehouse.Area"). Preload("Warehouse.Location"). Preload("Warehouse.Kandang"). Preload("ExpenseNonstock"). Preload("ExpenseNonstock.Expense"). Preload("ExpenseNonstock.Expense.Supplier"). Joins("JOIN purchases ON purchases.id = purchase_items.purchase_id"). Where("purchases.supplier_id IN ?", supplierIDs) if filters.ProductId > 0 { db = db.Where("purchase_items.product_id = ?", filters.ProductId) } if filters.ProductCategoryId > 0 { db = db. Joins("JOIN products ON products.id = purchase_items.product_id"). Where("products.product_category_id = ?", filters.ProductCategoryId) } if filters.AreaId > 0 { db = db. Joins("JOIN warehouses ON warehouses.id = purchase_items.warehouse_id"). Where("warehouses.area_id = ?", filters.AreaId) } if filters.StartDate != "" { if dateFrom, err := utils.ParseDateString(filters.StartDate); err == nil { db = db.Where(fmt.Sprintf("DATE(%s) >= ?", dateColumn), dateFrom) } } if filters.EndDate != "" { if dateTo, err := utils.ParseDateString(filters.EndDate); err == nil { db = db.Where(fmt.Sprintf("DATE(%s) <= ?", dateColumn), dateTo) } } // Urutkan berdasarkan kolom tanggal yang dipilih dan arah sort db = db.Order(fmt.Sprintf("%s %s", dateColumn, orderDirection)). Order("purchase_items.id ASC") var items []entity.PurchaseItem if err := db.Find(&items).Error; err != nil { return nil, err } return items, nil }