Merge remote-tracking branch 'origin/master'

This commit is contained in:
M_Kececi
2026-06-02 16:14:54 +03:00
parent 5f3e975b6d
commit b4e87cfd47
25 changed files with 4918 additions and 287 deletions

View File

@@ -0,0 +1,123 @@
package queries
import (
"bssapp-backend/db"
"context"
"database/sql"
"fmt"
"strings"
)
// GetProductPricingFilterOptions returns distinct option values for ProductPricing filters.
// This is used to render filter dropdowns without loading the full dataset.
func GetProductPricingFilterOptions(ctx context.Context, field string, q string, limit int, scopeUrunIlkGrubu []string) ([]string, error) {
mssql := db.MssqlDB
if mssql == nil {
return nil, fmt.Errorf("mssql db is nil")
}
field = strings.TrimSpace(field)
q = strings.TrimSpace(q)
if limit <= 0 || limit > 200 {
limit = 120
}
if len(scopeUrunIlkGrubu) > 3 {
scopeUrunIlkGrubu = scopeUrunIlkGrubu[:3]
}
// Map UI filter fields -> MSSQL expression in ProductFilterWithDescription('TR')
var expr string
switch field {
case "productCode":
expr = "LTRIM(RTRIM(ProductCode))"
case "brandGroupSelection":
expr = `CASE ABS(CHECKSUM(LTRIM(RTRIM(ProductCode)))) % 3
WHEN 0 THEN 'MARKA GRUBU A'
WHEN 1 THEN 'MARKA GRUBU B'
ELSE 'MARKA GRUBU C'
END`
case "marka":
expr = "COALESCE(LTRIM(RTRIM(ProductAtt10Desc)), '')"
case "askiliYan":
expr = "COALESCE(LTRIM(RTRIM(ProductAtt45Desc)), '')"
case "kategori":
expr = "COALESCE(LTRIM(RTRIM(ProductAtt44Desc)), '')"
case "urunIlkGrubu":
expr = "COALESCE(LTRIM(RTRIM(ProductAtt42Desc)), '')"
case "urunAnaGrubu":
expr = "COALESCE(LTRIM(RTRIM(ProductAtt01Desc)), '')"
case "urunAltGrubu":
expr = "COALESCE(LTRIM(RTRIM(ProductAtt02Desc)), '')"
case "icerik":
expr = "COALESCE(LTRIM(RTRIM(ProductAtt41Desc)), '')"
case "karisim":
expr = "COALESCE(LTRIM(RTRIM(ProductAtt29Desc)), '')"
default:
return nil, fmt.Errorf("invalid field")
}
// NOTE: We keep the same base constraints as the listing query.
// q: prefix match to keep it sargable-ish.
args := make([]any, 0, 8)
where := []string{
"ProductAtt42 IN ('SERI', 'AKSESUAR')",
"IsBlocked = 0",
"LEN(LTRIM(RTRIM(ProductCode))) = 13",
}
if len(scopeUrunIlkGrubu) > 0 && field != "urunIlkGrubu" {
// Cascade scope: allow limiting options by the already selected "Urun Ilk Grubu" (desc).
// We filter by desc value because UI uses desc fields.
placeholders := make([]string, 0, len(scopeUrunIlkGrubu))
for _, v := range scopeUrunIlkGrubu {
v = strings.TrimSpace(v)
if v == "" {
continue
}
placeholders = append(placeholders, fmt.Sprintf("@p%d", len(args)+1))
args = append(args, v)
}
if len(placeholders) > 0 {
where = append(where, fmt.Sprintf("COALESCE(LTRIM(RTRIM(ProductAtt42Desc)), '') IN (%s)", strings.Join(placeholders, ", ")))
}
}
if q != "" {
// For productCode, allow contains if user types middle; for others use prefix.
if field == "productCode" {
where = append(where, expr+fmt.Sprintf(" LIKE @p%d", len(args)+1))
args = append(args, "%"+q+"%")
} else {
where = append(where, expr+fmt.Sprintf(" LIKE @p%d", len(args)+1))
args = append(args, q+"%")
}
}
whereSQL := strings.Join(where, " AND ")
sqlText := fmt.Sprintf(`
SELECT TOP (%d)
X.val
FROM (
SELECT DISTINCT NULLIF(%s, '') AS val
FROM ProductFilterWithDescription('TR')
WHERE %s
) X
WHERE X.val IS NOT NULL
ORDER BY X.val ASC;
`, limit, expr, whereSQL)
rows, err := mssql.QueryContext(ctx, sqlText, args...)
if err != nil {
return nil, err
}
defer rows.Close()
out := make([]string, 0, limit)
for rows.Next() {
var v sql.NullString
if err := rows.Scan(&v); err != nil {
return nil, err
}
if s := strings.TrimSpace(v.String); s != "" {
out = append(out, s)
}
}
return out, rows.Err()
}