Improve pricing modal performance and charting
This commit is contained in:
@@ -25,29 +25,29 @@ type ComponentFilter struct {
|
||||
}
|
||||
|
||||
func (r *ComponentRepository) List(filter ComponentFilter, offset, limit int) ([]models.LotMetadata, int64, error) {
|
||||
var components []models.LotMetadata
|
||||
var total int64
|
||||
|
||||
query := r.db.Model(&models.LotMetadata{}).
|
||||
Preload("Lot").
|
||||
Preload("Category")
|
||||
baseQuery := r.db.Table("qt_lot_metadata AS m").
|
||||
Joins("LEFT JOIN lot AS l ON l.lot_name = m.lot_name").
|
||||
Joins("LEFT JOIN qt_categories AS c ON c.id = m.category_id")
|
||||
|
||||
if filter.Category != "" {
|
||||
query = query.Joins("JOIN qt_categories ON qt_lot_metadata.category_id = qt_categories.id").
|
||||
Where("qt_categories.code = ?", filter.Category)
|
||||
baseQuery = baseQuery.Where("c.code = ?", filter.Category)
|
||||
}
|
||||
if filter.Search != "" {
|
||||
search := "%" + filter.Search + "%"
|
||||
query = query.Where("lot_name LIKE ? OR model LIKE ?", search, search)
|
||||
baseQuery = baseQuery.Where("m.lot_name LIKE ? OR m.model LIKE ?", search, search)
|
||||
}
|
||||
if filter.HasPrice {
|
||||
query = query.Where("current_price IS NOT NULL AND current_price > 0")
|
||||
baseQuery = baseQuery.Where("m.current_price IS NOT NULL AND m.current_price > 0")
|
||||
}
|
||||
if filter.ExcludeHidden {
|
||||
query = query.Where("is_hidden = ? OR is_hidden IS NULL", false)
|
||||
baseQuery = baseQuery.Where("m.is_hidden = ? OR m.is_hidden IS NULL", false)
|
||||
}
|
||||
|
||||
query.Count(&total)
|
||||
if err := baseQuery.Count(&total).Error; err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
// Apply sorting
|
||||
sortDir := "ASC"
|
||||
@@ -55,30 +55,65 @@ func (r *ComponentRepository) List(filter ComponentFilter, offset, limit int) ([
|
||||
sortDir = "DESC"
|
||||
}
|
||||
|
||||
query := baseQuery.Session(&gorm.Session{})
|
||||
switch filter.SortField {
|
||||
case "popularity_score":
|
||||
query = query.Order("popularity_score " + sortDir)
|
||||
query = query.Order("m.popularity_score " + sortDir)
|
||||
case "current_price":
|
||||
query = query.Order("CASE WHEN current_price IS NULL OR current_price = 0 THEN 1 ELSE 0 END").
|
||||
Order("current_price " + sortDir)
|
||||
query = query.Order("CASE WHEN m.current_price IS NULL OR m.current_price = 0 THEN 1 ELSE 0 END").
|
||||
Order("m.current_price " + sortDir)
|
||||
case "lot_name":
|
||||
query = query.Order("lot_name " + sortDir)
|
||||
query = query.Order("m.lot_name " + sortDir)
|
||||
case "quote_count":
|
||||
// Sort by quote count from lot_log table
|
||||
query = query.
|
||||
Select("qt_lot_metadata.*, (SELECT COUNT(*) FROM lot_log WHERE lot_log.lot = qt_lot_metadata.lot_name) as quote_count_sort").
|
||||
Select("m.*, l.lot_description AS lot_description, c.id AS category_join_id, c.code AS category_code, (SELECT COUNT(*) FROM lot_log WHERE lot_log.lot = m.lot_name) as quote_count_sort").
|
||||
Order("quote_count_sort " + sortDir)
|
||||
default:
|
||||
// Default: sort by popularity, no price goes last
|
||||
query = query.
|
||||
Order("CASE WHEN current_price IS NULL OR current_price = 0 THEN 1 ELSE 0 END").
|
||||
Order("popularity_score DESC")
|
||||
Order("CASE WHEN m.current_price IS NULL OR m.current_price = 0 THEN 1 ELSE 0 END").
|
||||
Order("m.popularity_score DESC")
|
||||
}
|
||||
|
||||
err := query.
|
||||
type componentRow struct {
|
||||
models.LotMetadata
|
||||
LotDescription string `gorm:"column:lot_description"`
|
||||
CategoryJoinID *uint `gorm:"column:category_join_id"`
|
||||
CategoryCode *string `gorm:"column:category_code"`
|
||||
}
|
||||
var rows []componentRow
|
||||
selectQuery := query
|
||||
if filter.SortField != "quote_count" {
|
||||
selectQuery = selectQuery.Select("m.*, l.lot_description AS lot_description, c.id AS category_join_id, c.code AS category_code")
|
||||
}
|
||||
err := selectQuery.
|
||||
Offset(offset).
|
||||
Limit(limit).
|
||||
Find(&components).Error
|
||||
Scan(&rows).Error
|
||||
if err != nil {
|
||||
return nil, total, err
|
||||
}
|
||||
|
||||
components := make([]models.LotMetadata, len(rows))
|
||||
for i, row := range rows {
|
||||
comp := row.LotMetadata
|
||||
comp.Lot = &models.Lot{
|
||||
LotName: comp.LotName,
|
||||
LotDescription: row.LotDescription,
|
||||
}
|
||||
if row.CategoryCode != nil || row.CategoryJoinID != nil {
|
||||
comp.Category = &models.Category{
|
||||
ID: 0,
|
||||
Code: "",
|
||||
}
|
||||
if row.CategoryJoinID != nil {
|
||||
comp.Category.ID = *row.CategoryJoinID
|
||||
}
|
||||
if row.CategoryCode != nil {
|
||||
comp.Category.Code = *row.CategoryCode
|
||||
}
|
||||
}
|
||||
components[i] = comp
|
||||
}
|
||||
|
||||
return components, total, err
|
||||
}
|
||||
|
||||
@@ -86,13 +86,53 @@ func (r *PricelistRepository) CountActive() (int64, error) {
|
||||
}
|
||||
|
||||
func (r *PricelistRepository) toSummaries(pricelists []models.Pricelist) []models.PricelistSummary {
|
||||
// Get item counts for each pricelist
|
||||
if len(pricelists) == 0 {
|
||||
return []models.PricelistSummary{}
|
||||
}
|
||||
|
||||
ids := make([]uint, 0, len(pricelists))
|
||||
for _, pl := range pricelists {
|
||||
ids = append(ids, pl.ID)
|
||||
}
|
||||
|
||||
itemCounts := make(map[uint]int64, len(pricelists))
|
||||
type itemCountRow struct {
|
||||
PricelistID uint `gorm:"column:pricelist_id"`
|
||||
Count int64 `gorm:"column:cnt"`
|
||||
}
|
||||
var itemRows []itemCountRow
|
||||
_ = r.db.Model(&models.PricelistItem{}).
|
||||
Select("pricelist_id, COUNT(*) as cnt").
|
||||
Where("pricelist_id IN ?", ids).
|
||||
Group("pricelist_id").
|
||||
Scan(&itemRows).Error
|
||||
for _, row := range itemRows {
|
||||
itemCounts[row.PricelistID] = row.Count
|
||||
}
|
||||
|
||||
usageCounts := make(map[uint]int64, len(pricelists))
|
||||
type usageRow struct {
|
||||
PricelistID uint `gorm:"column:pricelist_id"`
|
||||
Count int64 `gorm:"column:cnt"`
|
||||
}
|
||||
var usageRows []usageRow
|
||||
usageQueries := []string{
|
||||
"SELECT pricelist_id, COUNT(*) as cnt FROM qt_configurations WHERE pricelist_id IN ? GROUP BY pricelist_id",
|
||||
"SELECT warehouse_pricelist_id as pricelist_id, COUNT(*) as cnt FROM qt_configurations WHERE warehouse_pricelist_id IN ? GROUP BY warehouse_pricelist_id",
|
||||
"SELECT competitor_pricelist_id as pricelist_id, COUNT(*) as cnt FROM qt_configurations WHERE competitor_pricelist_id IN ? GROUP BY competitor_pricelist_id",
|
||||
}
|
||||
for _, query := range usageQueries {
|
||||
usageRows = usageRows[:0]
|
||||
if err := r.db.Raw(query, ids).Scan(&usageRows).Error; err != nil {
|
||||
continue
|
||||
}
|
||||
for _, row := range usageRows {
|
||||
usageCounts[row.PricelistID] += row.Count
|
||||
}
|
||||
}
|
||||
|
||||
summaries := make([]models.PricelistSummary, len(pricelists))
|
||||
for i, pl := range pricelists {
|
||||
var itemCount int64
|
||||
r.db.Model(&models.PricelistItem{}).Where("pricelist_id = ?", pl.ID).Count(&itemCount)
|
||||
usageCount, _ := r.CountUsage(pl.ID)
|
||||
|
||||
summaries[i] = models.PricelistSummary{
|
||||
ID: pl.ID,
|
||||
Source: pl.Source,
|
||||
@@ -101,9 +141,9 @@ func (r *PricelistRepository) toSummaries(pricelists []models.Pricelist) []model
|
||||
CreatedAt: pl.CreatedAt,
|
||||
CreatedBy: pl.CreatedBy,
|
||||
IsActive: pl.IsActive,
|
||||
UsageCount: int(usageCount),
|
||||
UsageCount: int(usageCounts[pl.ID]),
|
||||
ExpiresAt: pl.ExpiresAt,
|
||||
ItemCount: itemCount,
|
||||
ItemCount: itemCounts[pl.ID],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user