Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -1597,6 +1597,17 @@ func renderOrderGrid(pdf *gofpdf.Fpdf, header *OrderHeader, rows []PdfRow, hasVa
|
||||
layout := newPdfLayout(pdf)
|
||||
catSizes := buildCategorySizeMap(rows)
|
||||
|
||||
normalizeYetiskinGarsonTokenGo := func(v string) string {
|
||||
s := strings.ToUpper(strings.TrimSpace(v))
|
||||
if strings.Contains(s, "GARSON") {
|
||||
return "GARSON"
|
||||
}
|
||||
if strings.Contains(s, "YETISKIN") || strings.Contains(s, "YETİSKİN") {
|
||||
return "YETISKIN"
|
||||
}
|
||||
return "GENEL"
|
||||
}
|
||||
|
||||
// Grup: ÜRÜN ANA GRUBU
|
||||
type group struct {
|
||||
Name string
|
||||
@@ -1609,15 +1620,19 @@ func renderOrderGrid(pdf *gofpdf.Fpdf, header *OrderHeader, rows []PdfRow, hasVa
|
||||
var order []string
|
||||
|
||||
for _, r := range rows {
|
||||
name := strings.TrimSpace(r.GroupMain)
|
||||
if name == "" {
|
||||
name = "GENEL"
|
||||
ana := strings.TrimSpace(r.GroupMain)
|
||||
if ana == "" {
|
||||
ana = "GENEL"
|
||||
}
|
||||
g, ok := groups[name]
|
||||
yg := normalizeYetiskinGarsonTokenGo(r.YetiskinGarson)
|
||||
name := strings.TrimSpace(fmt.Sprintf("%s %s", yg, ana))
|
||||
groupKey := fmt.Sprintf("%s::%s", yg, ana)
|
||||
|
||||
g, ok := groups[groupKey]
|
||||
if !ok {
|
||||
g = &group{Name: name}
|
||||
groups[name] = g
|
||||
order = append(order, name)
|
||||
groups[groupKey] = g
|
||||
order = append(order, groupKey)
|
||||
}
|
||||
g.Rows = append(g.Rows, r)
|
||||
g.Adet += r.TotalQty
|
||||
@@ -1673,8 +1688,8 @@ func renderOrderGrid(pdf *gofpdf.Fpdf, header *OrderHeader, rows []PdfRow, hasVa
|
||||
newPage(firstPage, true)
|
||||
firstPage = false
|
||||
|
||||
for _, name := range order {
|
||||
g := groups[name]
|
||||
for _, key := range order {
|
||||
g := groups[key]
|
||||
|
||||
for _, row := range g.Rows {
|
||||
rh := calcRowHeight(pdf, layout, row)
|
||||
|
||||
@@ -9,12 +9,15 @@ import (
|
||||
"errors"
|
||||
"log"
|
||||
"net/http"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
mssql "github.com/microsoft/go-mssqldb"
|
||||
)
|
||||
|
||||
var baggiModelCodeRegex = regexp.MustCompile(`^[A-Z][0-9]{3}-[A-Z]{3}[0-9]{5}$`)
|
||||
|
||||
// ======================================================
|
||||
// 📌 OrderProductionItemsRoute — U ürün satırları
|
||||
// ======================================================
|
||||
@@ -73,6 +76,23 @@ func OrderProductionItemsRoute(mssql *sql.DB) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
func OrderProductionCdItemLookupsRoute(mssql *sql.DB) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
|
||||
lookups, err := queries.GetOrderProductionLookupOptions(mssql)
|
||||
if err != nil {
|
||||
log.Printf("[OrderProductionCdItemLookupsRoute] lookup error: %v", err)
|
||||
http.Error(w, "Veritabani hatasi", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
if err := json.NewEncoder(w).Encode(lookups); err != nil {
|
||||
log.Printf("[OrderProductionCdItemLookupsRoute] encode error: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// ======================================================
|
||||
// 📌 OrderProductionInsertMissingRoute — eksik varyantları ekler
|
||||
// ======================================================
|
||||
@@ -208,13 +228,24 @@ func OrderProductionApplyRoute(mssql *sql.DB) http.Handler {
|
||||
|
||||
var inserted int64
|
||||
if payload.InsertMissing {
|
||||
inserted, err = queries.InsertMissingVariantsTx(tx, missing, username)
|
||||
cdItemByCode := buildCdItemDraftMap(payload.CdItems)
|
||||
inserted, err = queries.InsertMissingVariantsTx(tx, missing, username, cdItemByCode)
|
||||
if err != nil {
|
||||
writeDBError(w, http.StatusInternalServerError, "insert_missing_variants", id, username, len(missing), err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if err := validateProductAttributes(payload.ProductAttributes); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
attributeAffected, err := queries.UpsertItemAttributesTx(tx, payload.ProductAttributes, username)
|
||||
if err != nil {
|
||||
writeDBError(w, http.StatusInternalServerError, "upsert_item_attributes", id, username, len(payload.ProductAttributes), err)
|
||||
return
|
||||
}
|
||||
|
||||
updated, err := queries.UpdateOrderLinesTx(tx, id, payload.Lines, username)
|
||||
if err != nil {
|
||||
writeDBError(w, http.StatusInternalServerError, "update_order_lines", id, username, len(payload.Lines), err)
|
||||
@@ -227,8 +258,9 @@ func OrderProductionApplyRoute(mssql *sql.DB) http.Handler {
|
||||
}
|
||||
|
||||
resp := map[string]any{
|
||||
"updated": updated,
|
||||
"inserted": inserted,
|
||||
"updated": updated,
|
||||
"inserted": inserted,
|
||||
"attributeUpserted": attributeAffected,
|
||||
}
|
||||
if err := json.NewEncoder(w).Encode(resp); err != nil {
|
||||
log.Printf("❌ encode error: %v", err)
|
||||
@@ -236,6 +268,44 @@ func OrderProductionApplyRoute(mssql *sql.DB) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
func validateProductAttributes(attrs []models.OrderProductionItemAttributeRow) error {
|
||||
for _, a := range attrs {
|
||||
if strings.TrimSpace(a.ItemCode) == "" {
|
||||
return errors.New("Urun ozellikleri icin ItemCode zorunlu")
|
||||
}
|
||||
if !baggiModelCodeRegex.MatchString(strings.ToUpper(strings.TrimSpace(a.ItemCode))) {
|
||||
return errors.New("Girdiginiz kod BAGGI kod sistemine uyumlu degil. Format: X999-XXX99999")
|
||||
}
|
||||
if a.ItemTypeCode <= 0 {
|
||||
return errors.New("Urun ozellikleri icin ItemTypeCode zorunlu")
|
||||
}
|
||||
if a.AttributeTypeCode <= 0 {
|
||||
return errors.New("Urun ozellikleri icin AttributeTypeCode zorunlu")
|
||||
}
|
||||
if strings.TrimSpace(a.AttributeCode) == "" {
|
||||
return errors.New("Urun ozellikleri icin AttributeCode zorunlu")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func buildCdItemDraftMap(list []models.OrderProductionCdItemDraft) map[string]models.OrderProductionCdItemDraft {
|
||||
out := make(map[string]models.OrderProductionCdItemDraft, len(list))
|
||||
for _, item := range list {
|
||||
code := strings.ToUpper(strings.TrimSpace(item.ItemCode))
|
||||
if code == "" {
|
||||
continue
|
||||
}
|
||||
item.ItemCode = code
|
||||
if item.ItemTypeCode == 0 {
|
||||
item.ItemTypeCode = 1
|
||||
}
|
||||
key := queries.NormalizeCdItemMapKey(item.ItemTypeCode, item.ItemCode)
|
||||
out[key] = item
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func buildMissingVariants(mssql *sql.DB, orderHeaderID string, lines []models.OrderProductionUpdateLine) ([]models.OrderProductionMissingVariant, error) {
|
||||
missing := make([]models.OrderProductionMissingVariant, 0)
|
||||
|
||||
@@ -279,9 +349,13 @@ func validateUpdateLines(lines []models.OrderProductionUpdateLine) error {
|
||||
if strings.TrimSpace(line.OrderLineID) == "" {
|
||||
return errors.New("OrderLineID zorunlu")
|
||||
}
|
||||
if strings.TrimSpace(line.NewItemCode) == "" {
|
||||
code := strings.ToUpper(strings.TrimSpace(line.NewItemCode))
|
||||
if code == "" {
|
||||
return errors.New("Yeni urun kodu zorunlu")
|
||||
}
|
||||
if !baggiModelCodeRegex.MatchString(code) {
|
||||
return errors.New("Girdiginiz kod BAGGI kod sistemine uyumlu degil. Format: X999-XXX99999")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
54
svc/routes/productattributes.go
Normal file
54
svc/routes/productattributes.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"bssapp-backend/auth"
|
||||
"bssapp-backend/db"
|
||||
"bssapp-backend/models"
|
||||
"bssapp-backend/queries"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func GetProductAttributesHandler(w http.ResponseWriter, r *http.Request) {
|
||||
claims, ok := auth.GetClaimsFromContext(r.Context())
|
||||
if !ok || claims == nil {
|
||||
http.Error(w, "unauthorized", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
itemTypeCode := int16(1)
|
||||
if raw := r.URL.Query().Get("itemTypeCode"); raw != "" {
|
||||
v, err := strconv.Atoi(raw)
|
||||
if err != nil || v <= 0 {
|
||||
http.Error(w, "itemTypeCode gecersiz", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
itemTypeCode = int16(v)
|
||||
}
|
||||
|
||||
rows, err := db.MssqlDB.Query(queries.GetProductAttributes, itemTypeCode)
|
||||
if err != nil {
|
||||
http.Error(w, "Product attributes alinamadi: "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
list := make([]models.ProductAttributeOption, 0, 256)
|
||||
for rows.Next() {
|
||||
var x models.ProductAttributeOption
|
||||
if err := rows.Scan(
|
||||
&x.ItemTypeCode,
|
||||
&x.AttributeTypeCode,
|
||||
&x.AttributeTypeDescription,
|
||||
&x.AttributeCode,
|
||||
&x.AttributeDescription,
|
||||
); err != nil {
|
||||
continue
|
||||
}
|
||||
list = append(list, x)
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
_ = json.NewEncoder(w).Encode(list)
|
||||
}
|
||||
@@ -45,7 +45,7 @@ func GetProductSecondColorsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var list []models.ProductSecondColor
|
||||
for rows.Next() {
|
||||
var c models.ProductSecondColor
|
||||
if err := rows.Scan(&c.ProductCode, &c.ColorCode, &c.ItemDim2Code); err != nil {
|
||||
if err := rows.Scan(&c.ProductCode, &c.ColorCode, &c.ItemDim2Code, &c.ColorDescription); err != nil {
|
||||
log.Println("⚠️ Satır okunamadı:", err)
|
||||
continue
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user