Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -14,6 +14,7 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -77,6 +78,90 @@ type productSeriesAutoStats struct {
|
|||||||
Skipped int
|
Skipped int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var productSeriesFallbackMu sync.Mutex
|
||||||
|
var productSeriesFallbackCachedCode string
|
||||||
|
var productSeriesFallbackCachedID int64
|
||||||
|
var productSeriesFallbackCachedAt time.Time
|
||||||
|
|
||||||
|
func productSeriesFallbackEnabled() bool {
|
||||||
|
// Default on: user explicitly requested "stok var ama seri yoksa 1- ata".
|
||||||
|
raw := strings.TrimSpace(strings.ToLower(os.Getenv("PRODUCT_SERIES_FALLBACK_ON_EMPTY")))
|
||||||
|
if raw == "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return raw == "1" || raw == "true" || raw == "on" || raw == "yes"
|
||||||
|
}
|
||||||
|
|
||||||
|
func productSeriesFallbackCode() string {
|
||||||
|
code := strings.TrimSpace(os.Getenv("PRODUCT_SERIES_FALLBACK_SERIES_CODE"))
|
||||||
|
if code == "" {
|
||||||
|
code = "1-"
|
||||||
|
}
|
||||||
|
return code
|
||||||
|
}
|
||||||
|
|
||||||
|
func productSeriesResolveFallbackSeries(ctx context.Context, pg *sql.DB) (int64, string, error) {
|
||||||
|
if !productSeriesFallbackEnabled() {
|
||||||
|
return 0, "", nil
|
||||||
|
}
|
||||||
|
code := productSeriesFallbackCode()
|
||||||
|
if code == "" {
|
||||||
|
return 0, "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
productSeriesFallbackMu.Lock()
|
||||||
|
// Cache for a bit to avoid repeated lookups under high throughput.
|
||||||
|
if productSeriesFallbackCachedCode == code && productSeriesFallbackCachedAt.After(time.Now().Add(-10*time.Minute)) {
|
||||||
|
id := productSeriesFallbackCachedID
|
||||||
|
productSeriesFallbackMu.Unlock()
|
||||||
|
return id, code, nil
|
||||||
|
}
|
||||||
|
productSeriesFallbackMu.Unlock()
|
||||||
|
|
||||||
|
var id int64
|
||||||
|
var gotCode string
|
||||||
|
err := pg.QueryRowContext(ctx, `
|
||||||
|
SELECT id, COALESCE(code,'')
|
||||||
|
FROM dfgrp
|
||||||
|
WHERE master='zbggseri'
|
||||||
|
AND COALESCE(is_active, TRUE)=TRUE
|
||||||
|
AND (
|
||||||
|
code = $1
|
||||||
|
OR title = $1
|
||||||
|
OR title LIKE $1 || '%'
|
||||||
|
)
|
||||||
|
ORDER BY
|
||||||
|
CASE
|
||||||
|
WHEN code = $1 THEN 0
|
||||||
|
WHEN title = $1 THEN 1
|
||||||
|
ELSE 2
|
||||||
|
END,
|
||||||
|
id
|
||||||
|
LIMIT 1
|
||||||
|
`, code).Scan(&id, &gotCode)
|
||||||
|
if err != nil {
|
||||||
|
if err == sql.ErrNoRows {
|
||||||
|
// cache negative for a short period too
|
||||||
|
productSeriesFallbackMu.Lock()
|
||||||
|
productSeriesFallbackCachedCode = code
|
||||||
|
productSeriesFallbackCachedID = 0
|
||||||
|
productSeriesFallbackCachedAt = time.Now()
|
||||||
|
productSeriesFallbackMu.Unlock()
|
||||||
|
return 0, code, nil
|
||||||
|
}
|
||||||
|
return 0, code, err
|
||||||
|
}
|
||||||
|
if gotCode != "" {
|
||||||
|
code = gotCode
|
||||||
|
}
|
||||||
|
productSeriesFallbackMu.Lock()
|
||||||
|
productSeriesFallbackCachedCode = code
|
||||||
|
productSeriesFallbackCachedID = id
|
||||||
|
productSeriesFallbackCachedAt = time.Now()
|
||||||
|
productSeriesFallbackMu.Unlock()
|
||||||
|
return id, code, nil
|
||||||
|
}
|
||||||
|
|
||||||
var productSeriesSizeGroups = map[string][]string{
|
var productSeriesSizeGroups = map[string][]string{
|
||||||
"tak": {"44", "46", "48", "50", "52", "54", "56", "58", "60", "62", "64", "66", "68", "70", "72", "74"},
|
"tak": {"44", "46", "48", "50", "52", "54", "56", "58", "60", "62", "64", "66", "68", "70", "72", "74"},
|
||||||
"ayk": {"39", "40", "41", "42", "43", "44", "45", "46"},
|
"ayk": {"39", "40", "41", "42", "43", "44", "45", "46"},
|
||||||
@@ -345,6 +430,35 @@ func productSeriesApplyVariant(ctx context.Context, pg *sql.DB, v productSeriesA
|
|||||||
return 0, 1, nil
|
return 0, 1, nil
|
||||||
}
|
}
|
||||||
selected := productSeriesSelectRules(v, rules)
|
selected := productSeriesSelectRules(v, rules)
|
||||||
|
if len(selected) == 0 {
|
||||||
|
fallbackID, _, err := productSeriesResolveFallbackSeries(ctx, pg)
|
||||||
|
if err != nil {
|
||||||
|
return 0, 1, err
|
||||||
|
}
|
||||||
|
if fallbackID > 0 {
|
||||||
|
// Only apply fallback when the variant has no assignments yet.
|
||||||
|
var exists int
|
||||||
|
checkErr := pg.QueryRowContext(ctx, `
|
||||||
|
SELECT 1
|
||||||
|
FROM zbggseri
|
||||||
|
WHERE mmitem_id=$1
|
||||||
|
AND dim1=$2
|
||||||
|
AND (($3::bigint IS NULL AND dim3 IS NULL) OR dim3=$3::bigint)
|
||||||
|
LIMIT 1
|
||||||
|
`, mmitemID, dim1ID, nullableInt64ForAuto(dim3ID)).Scan(&exists)
|
||||||
|
if checkErr == nil {
|
||||||
|
// keep existing manual/previous assignment; nothing to do
|
||||||
|
return 0, 0, nil
|
||||||
|
}
|
||||||
|
if checkErr != nil && checkErr != sql.ErrNoRows {
|
||||||
|
return 0, 1, checkErr
|
||||||
|
}
|
||||||
|
// Use the fallback series as the single selected rule.
|
||||||
|
selected = []productSeriesAutoRule{{SeriesID: fallbackID}}
|
||||||
|
} else {
|
||||||
|
return 0, 1, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
if !apply {
|
if !apply {
|
||||||
return len(selected), 0, nil
|
return len(selected), 0, nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user