Merge remote-tracking branch 'origin/master'

This commit is contained in:
M_Kececi
2026-03-29 22:41:02 +03:00
parent 96ede55936
commit 05c6103a3a
10 changed files with 629 additions and 92 deletions

View File

@@ -87,6 +87,7 @@ type OrderLineRaw struct {
LineDescription sql.NullString
UrunAnaGrubu sql.NullString
UrunAltGrubu sql.NullString
YetiskinGarson sql.NullString
IsClosed sql.NullBool
WithHoldingTaxType sql.NullString
DOVCode sql.NullString
@@ -101,20 +102,21 @@ type OrderLineRaw struct {
=========================================================== */
type PdfRow struct {
Model string
Color string
GroupMain string
GroupSub string
Description string
Category string
SizeQty map[string]int
TotalQty int
Price float64
Currency string
Amount float64
Termin string
IsClosed bool
OrderLineIDs map[string]string
Model string
Color string
GroupMain string
GroupSub string
YetiskinGarson string
Description string
Category string
SizeQty map[string]int
TotalQty int
Price float64
Currency string
Amount float64
Termin string
IsClosed bool
OrderLineIDs map[string]string
ClosedSizes map[string]bool // 🆕 her beden için IsClosed bilgisi
}
@@ -332,7 +334,140 @@ func parseNumericSize(v string) (int, bool) {
return n, true
}
func detectBedenGroupGo(bedenList []string, ana, alt string) string {
func deriveKategoriTokenGo(urunKategori, yetiskinGarson string) string {
kat := normalizeTextForMatchGo(urunKategori)
if strings.Contains(kat, "GARSON") {
return "GARSON"
}
if strings.Contains(kat, "YETISKIN") {
return "YETISKIN"
}
return ""
}
func normalizeRuleAltGroupGo(urunAltGrubu string) string {
return normalizeTextForMatchGo(urunAltGrubu)
}
func pickBestGroupFromCandidatesGo(groupKeys, bedenList []string, schemas map[string][]string) string {
if len(groupKeys) == 0 {
return ""
}
if len(groupKeys) == 1 {
return strings.TrimSpace(groupKeys[0])
}
normalizedBeden := make([]string, 0, len(bedenList))
for _, b := range bedenList {
n := normalizeBedenLabelGo(b)
if strings.TrimSpace(n) == "" {
n = " "
}
normalizedBeden = append(normalizedBeden, n)
}
if len(normalizedBeden) == 0 {
return strings.TrimSpace(groupKeys[0])
}
bestKey := strings.TrimSpace(groupKeys[0])
bestScore := -1
for _, key := range groupKeys {
k := strings.TrimSpace(key)
if k == "" {
continue
}
normalizedSchema := map[string]bool{}
for _, sv := range schemas[k] {
ns := normalizeBedenLabelGo(sv)
if strings.TrimSpace(ns) == "" {
ns = " "
}
normalizedSchema[ns] = true
}
score := 0
for _, b := range normalizedBeden {
if normalizedSchema[b] {
score++
}
}
if score > bestScore {
bestScore = score
bestKey = k
}
}
return bestKey
}
func resolveGroupFromProductSizeMatchRulesGo(
matchData *ProductSizeMatchResponse,
bedenList []string,
urunAnaGrubu, urunKategori, yetiskinGarson, urunAltGrubu string,
) string {
if matchData == nil || len(matchData.Rules) == 0 {
return ""
}
kategoriToken := deriveKategoriTokenGo(urunKategori, yetiskinGarson)
ana := normalizeTextForMatchGo(urunAnaGrubu)
alt := normalizeRuleAltGroupGo(urunAltGrubu)
if kategoriToken == "" || ana == "" {
return ""
}
candidateGroupKeys := make([]string, 0, 2)
seen := map[string]bool{}
for i := range matchData.Rules {
rule := &matchData.Rules[i]
if normalizeTextForMatchGo(rule.UrunAnaGrubu) != ana {
continue
}
ruleKategori := normalizeTextForMatchGo(rule.Kategori)
if ruleKategori != kategoriToken {
continue
}
ruleAlt := normalizeTextForMatchGo(rule.UrunAltGrubu)
if ruleAlt != alt {
continue
}
for _, g := range rule.GroupKeys {
key := strings.TrimSpace(g)
if key == "" || seen[key] {
continue
}
seen[key] = true
candidateGroupKeys = append(candidateGroupKeys, key)
}
}
if len(candidateGroupKeys) == 0 {
return ""
}
return pickBestGroupFromCandidatesGo(candidateGroupKeys, bedenList, matchData.Schemas)
}
func detectBedenGroupGo(
matchData *ProductSizeMatchResponse,
bedenList []string,
ana, alt, urunKategori, yetiskinGarson string,
) string {
ruleBased := resolveGroupFromProductSizeMatchRulesGo(
matchData,
bedenList,
ana,
urunKategori,
yetiskinGarson,
alt,
)
if ruleBased != "" {
return ruleBased
}
if matchData != nil && len(matchData.Rules) > 0 {
return ""
}
ana = normalizeTextForMatchGo(ana)
alt = normalizeTextForMatchGo(alt)
@@ -368,6 +503,15 @@ func detectBedenGroupGo(bedenList []string, ana, alt string) string {
strings.Contains(ana, "YETİŞKIN/GARSON") || strings.Contains(alt, "YETİŞKIN/GARSON") ||
strings.Contains(ana, "YETİŞKİN/GARSON") || strings.Contains(alt, "YETİŞKİN/GARSON")
// Ayakkabi kurali garsondan once uygulanmali:
// GARSON + AYAKKABI => ayk_garson, digerleri => ayk
if strings.Contains(ana, "AYAKKABI") || strings.Contains(alt, "AYAKKABI") {
if hasGarson {
return catAykGar
}
return catAyk
}
// ✅ Garson → yaş (ürün tipi fark etmeksizin)
if hasGarson {
return catYas
@@ -618,6 +762,7 @@ func getOrderLinesFromDB(db *sql.DB, orderID string) ([]OrderLineRaw, error) {
L.LineDescription,
P.ProductAtt01Desc,
P.ProductAtt02Desc,
P.ProductAtt44Desc,
L.IsClosed,
L.WithHoldingTaxTypeCode,
L.DOVCode,
@@ -656,6 +801,7 @@ func getOrderLinesFromDB(db *sql.DB, orderID string) ([]OrderLineRaw, error) {
&l.LineDescription,
&l.UrunAnaGrubu,
&l.UrunAltGrubu,
&l.YetiskinGarson,
&l.IsClosed,
&l.WithHoldingTaxType,
&l.DOVCode,
@@ -675,7 +821,7 @@ func getOrderLinesFromDB(db *sql.DB, orderID string) ([]OrderLineRaw, error) {
4) NORMALIZE + CATEGORY MAP
=========================================================== */
func normalizeOrderLinesForPdf(lines []OrderLineRaw) []PdfRow {
func normalizeOrderLinesForPdf(lines []OrderLineRaw, matchData *ProductSizeMatchResponse) []PdfRow {
type comboKey struct {
Model, Color, Color2 string
}
@@ -701,16 +847,17 @@ func normalizeOrderLinesForPdf(lines []OrderLineRaw) []PdfRow {
if _, ok := merged[key]; !ok {
merged[key] = &PdfRow{
Model: model,
Color: displayColor,
GroupMain: s64(raw.UrunAnaGrubu),
GroupSub: s64(raw.UrunAltGrubu),
Description: s64(raw.LineDescription),
SizeQty: make(map[string]int),
Currency: s64(raw.DocCurrencyCode),
Price: f64(raw.Price),
OrderLineIDs: make(map[string]string),
ClosedSizes: make(map[string]bool), // 🆕
Model: model,
Color: displayColor,
GroupMain: s64(raw.UrunAnaGrubu),
GroupSub: s64(raw.UrunAltGrubu),
YetiskinGarson: s64(raw.YetiskinGarson),
Description: s64(raw.LineDescription),
SizeQty: make(map[string]int),
Currency: s64(raw.DocCurrencyCode),
Price: f64(raw.Price),
OrderLineIDs: make(map[string]string),
ClosedSizes: make(map[string]bool), // 🆕
}
}
row := merged[key]
@@ -751,7 +898,7 @@ func normalizeOrderLinesForPdf(lines []OrderLineRaw) []PdfRow {
for s := range r.SizeQty {
sizes = append(sizes, s)
}
r.Category = detectBedenGroupGo(sizes, r.GroupMain, r.GroupSub)
r.Category = detectBedenGroupGo(matchData, sizes, r.GroupMain, r.GroupSub, r.YetiskinGarson, r.YetiskinGarson)
r.Amount = float64(r.TotalQty) * r.Price
out = append(out, *r)
}
@@ -1555,7 +1702,7 @@ func renderOrderGrid(pdf *gofpdf.Fpdf, header *OrderHeader, rows []PdfRow, hasVa
HTTP HANDLER → /api/order/pdf/{id}
=========================================================== */
func OrderPDFHandler(db *sql.DB) http.Handler {
func OrderPDFHandler(db *sql.DB, pgDB *sql.DB) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
orderID := mux.Vars(r)["id"]
@@ -1612,7 +1759,30 @@ func OrderPDFHandler(db *sql.DB) http.Handler {
}
// Normalize
rows := normalizeOrderLinesForPdf(lines)
var sizeMatchData *ProductSizeMatchResponse
if pgDB == nil {
http.Error(w, "product-size-match db not initialized", http.StatusInternalServerError)
return
}
if m, err := loadProductSizeMatchData(pgDB); err != nil {
log.Printf("❌ OrderPDF product-size-match load failed orderID=%s: %v", orderID, err)
http.Error(w, "product-size-match load failed: "+err.Error(), http.StatusInternalServerError)
return
} else {
sizeMatchData = m
}
rows := normalizeOrderLinesForPdf(lines, sizeMatchData)
unmapped := make([]string, 0)
for _, rr := range rows {
if strings.TrimSpace(rr.Category) == "" {
unmapped = append(unmapped, fmt.Sprintf("%s/%s/%s", rr.Model, rr.GroupMain, rr.GroupSub))
}
}
if len(unmapped) > 0 {
log.Printf("❌ OrderPDF product-size-match unmapped orderID=%s rows=%v", orderID, unmapped)
http.Error(w, "product-size-match unmapped rows", http.StatusInternalServerError)
return
}
log.Printf("📄 OrderPDF normalized rows orderID=%s rowCount=%d", orderID, len(rows))
for i, rr := range rows {
if i >= 30 {