Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -485,6 +485,54 @@ func normalizeDim1Token(s string) string {
|
|||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func variantCacheKey(item, color, dim2 string) string {
|
||||||
|
return item + "||" + color + "||" + dim2
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadVariantDim1SetTx(tx *sql.Tx, item, color, dim2 string) (map[string]struct{}, error) {
|
||||||
|
rows, err := tx.Query(`
|
||||||
|
SELECT ISNULL(LTRIM(RTRIM(V.ItemDim1Code)),'') AS ItemDim1Code
|
||||||
|
FROM BAGGI_V3.dbo.prItemVariant V WITH (NOLOCK)
|
||||||
|
WHERE ISNULL(LTRIM(RTRIM(V.ItemCode)),'') = @p1
|
||||||
|
AND (
|
||||||
|
(
|
||||||
|
ISNULL(LTRIM(RTRIM(V.ColorCode)),'') = @p2
|
||||||
|
AND (
|
||||||
|
ISNULL(LTRIM(RTRIM(@p3)),'') = ''
|
||||||
|
OR ISNULL(LTRIM(RTRIM(V.ItemDim2Code)),'') = @p3
|
||||||
|
)
|
||||||
|
)
|
||||||
|
OR (
|
||||||
|
ISNULL(LTRIM(RTRIM(@p3)),'') = ''
|
||||||
|
AND ISNULL(LTRIM(RTRIM(V.ItemDim2Code)),'') = @p2
|
||||||
|
)
|
||||||
|
)
|
||||||
|
`, item, color, dim2)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("variant set query hatası: %w", err)
|
||||||
|
}
|
||||||
|
defer rows.Close()
|
||||||
|
|
||||||
|
set := make(map[string]struct{})
|
||||||
|
for rows.Next() {
|
||||||
|
var raw string
|
||||||
|
if err := rows.Scan(&raw); err != nil {
|
||||||
|
return nil, fmt.Errorf("variant set scan hatası: %w", err)
|
||||||
|
}
|
||||||
|
norm := normalizeDim1Token(raw)
|
||||||
|
if norm != "" {
|
||||||
|
set[norm] = struct{}{}
|
||||||
|
}
|
||||||
|
if num := normalizeNumericToken(norm); num != "" {
|
||||||
|
set["#NUM:"+num] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err := rows.Err(); err != nil {
|
||||||
|
return nil, fmt.Errorf("variant set rows hatası: %w", err)
|
||||||
|
}
|
||||||
|
return set, nil
|
||||||
|
}
|
||||||
|
|
||||||
// =======================================================
|
// =======================================================
|
||||||
// AKSBIR DETECTION
|
// AKSBIR DETECTION
|
||||||
// =======================================================
|
// =======================================================
|
||||||
@@ -495,6 +543,10 @@ func normalizeDim1Token(s string) string {
|
|||||||
|
|
||||||
// Variant check: ItemCode + ColorCode + Dim1 + Dim2
|
// Variant check: ItemCode + ColorCode + Dim1 + Dim2
|
||||||
func ValidateItemVariant(tx *sql.Tx, ln models.OrderDetail) error {
|
func ValidateItemVariant(tx *sql.Tx, ln models.OrderDetail) error {
|
||||||
|
return ValidateItemVariantCached(tx, ln, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ValidateItemVariantCached(tx *sql.Tx, ln models.OrderDetail, cache map[string]map[string]struct{}) error {
|
||||||
fmt.Printf(
|
fmt.Printf(
|
||||||
"🧪 VARIANT GUARD INPUT | ClientKey=%s Item=%q Color=%q Dim1=%q Dim2=%q Dim3=%q Qty1=%v\n",
|
"🧪 VARIANT GUARD INPUT | ClientKey=%s Item=%q Color=%q Dim1=%q Dim2=%q Dim3=%q Qty1=%v\n",
|
||||||
safeNS(ln.ClientKey),
|
safeNS(ln.ClientKey),
|
||||||
@@ -527,56 +579,42 @@ func ValidateItemVariant(tx *sql.Tx, ln models.OrderDetail) error {
|
|||||||
dim1Norm := normalizeDim1Token(dim1)
|
dim1Norm := normalizeDim1Token(dim1)
|
||||||
dim1Numeric := normalizeNumericToken(dim1Norm)
|
dim1Numeric := normalizeNumericToken(dim1Norm)
|
||||||
|
|
||||||
|
fmt.Printf(
|
||||||
|
"🧪 VARIANT NORMALIZED | Item=%q Color=%q Dim1=%q Dim2=%q\n",
|
||||||
|
item, color, dim1Norm, dim2,
|
||||||
|
)
|
||||||
|
|
||||||
if item == "" {
|
if item == "" {
|
||||||
return fmt.Errorf(
|
return &models.ValidationError{
|
||||||
"ItemCode boş olamaz (ClientKey=%s)",
|
Code: "INVALID_ITEM_VARIANT",
|
||||||
safeNS(ln.ClientKey),
|
Message: "Tanımsız ürün kombinasyonu",
|
||||||
)
|
ClientKey: safeNS(ln.ClientKey),
|
||||||
fmt.Printf(
|
ItemCode: item,
|
||||||
"🧪 VARIANT NORMALIZED | Item=%q Color=%q Dim1=%q Dim2=%q\n",
|
ColorCode: color,
|
||||||
item, color, dim1, dim2,
|
Dim1: dim1,
|
||||||
)
|
Dim2: dim2,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var exists int
|
key := variantCacheKey(item, color, dim2)
|
||||||
err := tx.QueryRow(`
|
set := map[string]struct{}(nil)
|
||||||
SELECT CASE WHEN EXISTS (
|
if cache != nil {
|
||||||
SELECT 1
|
set = cache[key]
|
||||||
FROM BAGGI_V3.dbo.prItemVariant V WITH (NOLOCK)
|
}
|
||||||
CROSS APPLY (
|
if set == nil {
|
||||||
SELECT UPPER(REPLACE(REPLACE(REPLACE(ISNULL(LTRIM(RTRIM(V.ItemDim1Code)),'') ,' ', ''), 'YAS', ''), 'Y', '')) AS Dim1Norm
|
var err error
|
||||||
) X
|
set, err = loadVariantDim1SetTx(tx, item, color, dim2)
|
||||||
WHERE ISNULL(LTRIM(RTRIM(V.ItemCode)),'') = @p1
|
if err != nil {
|
||||||
AND (
|
return fmt.Errorf("ItemVariant kontrol query hatası: %w", err)
|
||||||
(
|
}
|
||||||
ISNULL(LTRIM(RTRIM(V.ColorCode)),'') = @p2
|
if cache != nil {
|
||||||
AND (
|
cache[key] = set
|
||||||
ISNULL(LTRIM(RTRIM(@p4)),'') = ''
|
}
|
||||||
OR ISNULL(LTRIM(RTRIM(V.ItemDim2Code)),'') = @p4
|
|
||||||
)
|
|
||||||
)
|
|
||||||
OR (
|
|
||||||
ISNULL(LTRIM(RTRIM(@p4)),'') = ''
|
|
||||||
AND ISNULL(LTRIM(RTRIM(V.ItemDim2Code)),'') = @p2
|
|
||||||
)
|
|
||||||
)
|
|
||||||
AND (
|
|
||||||
X.Dim1Norm = @p3
|
|
||||||
OR (
|
|
||||||
ISNULL(LTRIM(RTRIM(@p5)),'') <> ''
|
|
||||||
AND X.Dim1Norm NOT LIKE '%[^0-9]%'
|
|
||||||
AND SUBSTRING(X.Dim1Norm, PATINDEX('%[^0]%', X.Dim1Norm + '0'), LEN(X.Dim1Norm)) = @p5
|
|
||||||
)
|
|
||||||
)
|
|
||||||
) THEN 1 ELSE 0 END
|
|
||||||
`, item, color, dim1Norm, dim2, dim1Numeric).Scan(&exists)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("ItemVariant kontrol query hatası: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if exists != 1 {
|
_, okNorm := set[dim1Norm]
|
||||||
|
_, okNum := set["#NUM:"+dim1Numeric]
|
||||||
|
if !(okNorm || (dim1Numeric != "" && okNum)) {
|
||||||
return &models.ValidationError{
|
return &models.ValidationError{
|
||||||
Code: "INVALID_ITEM_VARIANT",
|
Code: "INVALID_ITEM_VARIANT",
|
||||||
Message: "Tanımsız ürün kombinasyonu",
|
Message: "Tanımsız ürün kombinasyonu",
|
||||||
@@ -998,6 +1036,7 @@ VALUES (
|
|||||||
defer insStmt.Close()
|
defer insStmt.Close()
|
||||||
|
|
||||||
lineResults := make([]OrderLineResult, 0, len(lines))
|
lineResults := make([]OrderLineResult, 0, len(lines))
|
||||||
|
variantCache := make(map[string]map[string]struct{})
|
||||||
|
|
||||||
// ✅ Duplicate Guard (payload içi)
|
// ✅ Duplicate Guard (payload içi)
|
||||||
seenCombo := make(map[string]bool)
|
seenCombo := make(map[string]bool)
|
||||||
@@ -1045,7 +1084,7 @@ VALUES (
|
|||||||
|
|
||||||
// ✅ INSERT ÖNCESİ ItemVariant GUARD
|
// ✅ INSERT ÖNCESİ ItemVariant GUARD
|
||||||
if qtyValue(ln.Qty1) > 0 {
|
if qtyValue(ln.Qty1) > 0 {
|
||||||
if err := ValidateItemVariant(tx, ln); err != nil {
|
if err := ValidateItemVariantCached(tx, ln, variantCache); err != nil {
|
||||||
fmt.Println("❌ VARIANT GUARD (INSERT):", err)
|
fmt.Println("❌ VARIANT GUARD (INSERT):", err)
|
||||||
return "", nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
@@ -1440,6 +1479,7 @@ WHERE OrderLineID=@p42 AND ISNULL(IsClosed,0)=0`)
|
|||||||
// LOOP
|
// LOOP
|
||||||
// ======================================================
|
// ======================================================
|
||||||
lineResults := make([]OrderLineResult, 0)
|
lineResults := make([]OrderLineResult, 0)
|
||||||
|
variantCache := make(map[string]map[string]struct{})
|
||||||
seenCombo := make(map[string]bool)
|
seenCombo := make(map[string]bool)
|
||||||
|
|
||||||
for _, ln := range lines {
|
for _, ln := range lines {
|
||||||
@@ -1555,7 +1595,7 @@ WHERE OrderLineID=@p42 AND ISNULL(IsClosed,0)=0`)
|
|||||||
|
|
||||||
// Variant guard
|
// Variant guard
|
||||||
if qtyValue(ln.Qty1) > 0 {
|
if qtyValue(ln.Qty1) > 0 {
|
||||||
if err := ValidateItemVariant(tx, ln); err != nil {
|
if err := ValidateItemVariantCached(tx, ln, variantCache); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user