Merge remote-tracking branch 'origin/master'

This commit is contained in:
M_Kececi
2026-04-02 16:30:19 +03:00
parent 7a98652a8e
commit 028c11e042
10 changed files with 783 additions and 175 deletions

View File

@@ -576,6 +576,11 @@ func InitRoutes(pgDB *sql.DB, mssql *sql.DB, ml *mailer.GraphMailer) *mux.Router
"order", "view",
wrapV3(http.HandlerFunc(routes.GetProductColorsHandler)),
)
bindV3(r, pgDB,
"/api/product-newcolors", "GET",
"order", "view",
wrapV3(http.HandlerFunc(routes.GetProductNewColorsHandler)),
)
bindV3(r, pgDB,
"/api/product-colorsize", "GET",
@@ -588,6 +593,11 @@ func InitRoutes(pgDB *sql.DB, mssql *sql.DB, ml *mailer.GraphMailer) *mux.Router
"order", "view",
wrapV3(http.HandlerFunc(routes.GetProductSecondColorsHandler)),
)
bindV3(r, pgDB,
"/api/product-newsecondcolor", "GET",
"order", "view",
wrapV3(http.HandlerFunc(routes.GetProductNewSecondColorsHandler)),
)
bindV3(r, pgDB,
"/api/product-attributes", "GET",
"order", "view",

View File

@@ -65,10 +65,6 @@ func InsertMissingProductionVariants(mssql *sql.DB, orderHeaderID string, userna
WHERE l.OrderHeaderID = @p1
AND ISNULL(l.ItemCode,'') LIKE 'U%'
AND pv.ItemCode IS NULL
),
MaxPlu AS (
SELECT ISNULL(MAX(PLU),0) AS BasePlu
FROM dbo.prItemVariant WITH (UPDLOCK, HOLDLOCK)
)
INSERT INTO dbo.prItemVariant (
ItemTypeCode,
@@ -77,7 +73,6 @@ INSERT INTO dbo.prItemVariant (
ItemDim1Code,
ItemDim2Code,
ItemDim3Code,
PLU,
IsSalesOrderClosed,
IsPurchaseOrderClosed,
IsLocked,
@@ -97,7 +92,6 @@ SELECT
m.ItemDim1Code,
m.ItemDim2Code,
m.ItemDim3Code,
mp.BasePlu + ROW_NUMBER() OVER (ORDER BY m.ItemCode, m.ColorCode, m.ItemDim1Code, m.ItemDim2Code, m.ItemDim3Code),
0,
0,
0,
@@ -109,8 +103,7 @@ SELECT
NEWID(),
0,
0
FROM Missing m
CROSS JOIN MaxPlu mp;
FROM Missing m;
`
res, err := mssql.Exec(query, orderHeaderID, username)
@@ -140,17 +133,67 @@ WHERE OrderHeaderID = @p1 AND OrderLineID = @p2
return itemTypeCode, dim1, dim2, dim3, err
}
type OrderLineDims struct {
ItemTypeCode int16
ItemDim1Code string
ItemDim2Code string
ItemDim3Code string
}
func GetOrderLineDimsMap(mssql *sql.DB, orderHeaderID string) (map[string]OrderLineDims, error) {
rows, err := mssql.Query(`
SELECT
CAST(OrderLineID AS NVARCHAR(50)) AS OrderLineID,
ItemTypeCode,
ISNULL(ItemDim1Code,'') AS ItemDim1Code,
ISNULL(ItemDim2Code,'') AS ItemDim2Code,
ISNULL(ItemDim3Code,'') AS ItemDim3Code
FROM dbo.trOrderLine WITH(NOLOCK)
WHERE OrderHeaderID = @p1
`, orderHeaderID)
if err != nil {
return nil, err
}
defer rows.Close()
out := make(map[string]OrderLineDims, 128)
for rows.Next() {
var lineID string
var d OrderLineDims
if err := rows.Scan(&lineID, &d.ItemTypeCode, &d.ItemDim1Code, &d.ItemDim2Code, &d.ItemDim3Code); err != nil {
return nil, err
}
out[strings.TrimSpace(lineID)] = d
}
if err := rows.Err(); err != nil {
return nil, err
}
return out, nil
}
func VariantExists(mssql *sql.DB, itemTypeCode int16, itemCode string, colorCode string, dim1 string, dim2 string, dim3 string) (bool, error) {
var exists int
err := mssql.QueryRow(`
SELECT TOP 1 1
FROM dbo.prItemVariant
WHERE ItemTypeCode = @p1
AND ISNULL(LTRIM(RTRIM(ItemCode)),'') = ISNULL(LTRIM(RTRIM(@p2)),'')
AND ISNULL(LTRIM(RTRIM(ColorCode)),'') = ISNULL(LTRIM(RTRIM(@p3)),'')
AND ISNULL(LTRIM(RTRIM(ItemDim1Code)),'') = ISNULL(LTRIM(RTRIM(@p4)),'')
AND ISNULL(LTRIM(RTRIM(ItemDim2Code)),'') = ISNULL(LTRIM(RTRIM(@p5)),'')
AND ISNULL(LTRIM(RTRIM(ItemDim3Code)),'') = ISNULL(LTRIM(RTRIM(@p6)),'')
AND ItemCode = @p2
AND (
ColorCode = @p3
OR (@p3 = '' AND (ColorCode IS NULL OR ColorCode = ''))
)
AND (
ItemDim1Code = @p4
OR (@p4 = '' AND (ItemDim1Code IS NULL OR ItemDim1Code = ''))
)
AND (
ItemDim2Code = @p5
OR (@p5 = '' AND (ItemDim2Code IS NULL OR ItemDim2Code = ''))
)
AND (
ItemDim3Code = @p6
OR (@p6 = '' AND (ItemDim3Code IS NULL OR ItemDim3Code = ''))
)
`, itemTypeCode, itemCode, colorCode, dim1, dim2, dim3).Scan(&exists)
if err == sql.ErrNoRows {
return false, nil
@@ -171,17 +214,24 @@ func InsertMissingVariantsTx(
return 0, nil
}
var basePlu int64
if err := tx.QueryRow(`
SELECT ISNULL(MAX(PLU),0) AS BasePlu
FROM dbo.prItemVariant WITH (UPDLOCK, HOLDLOCK)
`).Scan(&basePlu); err != nil {
return 0, err
}
var inserted int64
ensuredItems := make(map[string]struct{}, len(missing))
for i, v := range missing {
uniqueVariants := make([]models.OrderProductionMissingVariant, 0, len(missing))
seenVariants := make(map[string]struct{}, len(missing))
for _, v := range missing {
variantKey := strconv.FormatInt(int64(v.ItemTypeCode), 10) + "|" +
strings.ToUpper(strings.TrimSpace(v.ItemCode)) + "|" +
strings.ToUpper(strings.TrimSpace(v.ColorCode)) + "|" +
strings.ToUpper(strings.TrimSpace(v.ItemDim1Code)) + "|" +
strings.ToUpper(strings.TrimSpace(v.ItemDim2Code)) + "|" +
strings.ToUpper(strings.TrimSpace(v.ItemDim3Code))
if _, ok := seenVariants[variantKey]; ok {
continue
}
seenVariants[variantKey] = struct{}{}
uniqueVariants = append(uniqueVariants, v)
itemKey := strconv.FormatInt(int64(v.ItemTypeCode), 10) + "|" + v.ItemCode
if _, ok := ensuredItems[itemKey]; !ok {
draft, hasDraft := cdItemByCode[itemKey]
@@ -198,55 +248,89 @@ FROM dbo.prItemVariant WITH (UPDLOCK, HOLDLOCK)
}
ensuredItems[itemKey] = struct{}{}
}
}
plu := basePlu + int64(i) + 1
res, err := tx.Exec(`
IF NOT EXISTS (
SELECT 1
FROM dbo.prItemVariant
WHERE ItemTypeCode = @p1
AND ISNULL(LTRIM(RTRIM(ItemCode)),'') = ISNULL(LTRIM(RTRIM(@p2)),'')
AND ISNULL(LTRIM(RTRIM(ColorCode)),'') = ISNULL(LTRIM(RTRIM(@p3)),'')
AND ISNULL(LTRIM(RTRIM(ItemDim1Code)),'') = ISNULL(LTRIM(RTRIM(@p4)),'')
AND ISNULL(LTRIM(RTRIM(ItemDim2Code)),'') = ISNULL(LTRIM(RTRIM(@p5)),'')
AND ISNULL(LTRIM(RTRIM(ItemDim3Code)),'') = ISNULL(LTRIM(RTRIM(@p6)),'')
if len(uniqueVariants) == 0 {
return 0, nil
}
args := make([]any, 0, len(uniqueVariants)*6+1)
valueRows := make([]string, 0, len(uniqueVariants))
paramPos := 1
for _, v := range uniqueVariants {
valueRows = append(valueRows, fmt.Sprintf("(@p%d,@p%d,@p%d,@p%d,@p%d,@p%d)", paramPos, paramPos+1, paramPos+2, paramPos+3, paramPos+4, paramPos+5))
args = append(args, v.ItemTypeCode, v.ItemCode, v.ColorCode, v.ItemDim1Code, v.ItemDim2Code, v.ItemDim3Code)
paramPos += 6
}
usernameParam := paramPos
args = append(args, username)
query := fmt.Sprintf(`
SET NOCOUNT ON;
WITH Missing(ItemTypeCode, ItemCode, ColorCode, ItemDim1Code, ItemDim2Code, ItemDim3Code) AS (
SELECT *
FROM (VALUES %s) AS v(ItemTypeCode, ItemCode, ColorCode, ItemDim1Code, ItemDim2Code, ItemDim3Code)
)
INSERT INTO dbo.prItemVariant (
ItemTypeCode,
ItemCode,
ColorCode,
ItemDim1Code,
ItemDim2Code,
ItemDim3Code,
PLU,
IsSalesOrderClosed,
IsPurchaseOrderClosed,
IsLocked,
IsBlocked,
CreatedUserName,
CreatedDate,
LastUpdatedUserName,
LastUpdatedDate,
RowGuid,
UseInternet,
IsStoreOrderClosed
ItemTypeCode,
ItemCode,
ColorCode,
ItemDim1Code,
ItemDim2Code,
ItemDim3Code,
IsSalesOrderClosed,
IsPurchaseOrderClosed,
IsLocked,
IsBlocked,
CreatedUserName,
CreatedDate,
LastUpdatedUserName,
LastUpdatedDate,
RowGuid,
UseInternet,
IsStoreOrderClosed
)
VALUES (
@p1, @p2, @p3, @p4, @p5, @p6,
@p7,
0, 0, 0, 0,
@p8, GETDATE(), @p8, GETDATE(),
NEWID(),
0,
0
);
`, v.ItemTypeCode, v.ItemCode, v.ColorCode, v.ItemDim1Code, v.ItemDim2Code, v.ItemDim3Code, plu, username)
if err != nil {
return inserted, err
}
if rows, err := res.RowsAffected(); err == nil {
inserted += rows
}
SELECT
m.ItemTypeCode,
m.ItemCode,
m.ColorCode,
m.ItemDim1Code,
m.ItemDim2Code,
m.ItemDim3Code,
0, 0, 0, 0,
@p%d, GETDATE(), @p%d, GETDATE(),
NEWID(),
0,
0
FROM Missing m
LEFT JOIN dbo.prItemVariant pv
ON pv.ItemTypeCode = m.ItemTypeCode
AND pv.ItemCode = m.ItemCode
AND (
pv.ColorCode = m.ColorCode
OR (m.ColorCode = '' AND (pv.ColorCode IS NULL OR pv.ColorCode = ''))
)
AND (
pv.ItemDim1Code = m.ItemDim1Code
OR (m.ItemDim1Code = '' AND (pv.ItemDim1Code IS NULL OR pv.ItemDim1Code = ''))
)
AND (
pv.ItemDim2Code = m.ItemDim2Code
OR (m.ItemDim2Code = '' AND (pv.ItemDim2Code IS NULL OR pv.ItemDim2Code = ''))
)
AND (
pv.ItemDim3Code = m.ItemDim3Code
OR (m.ItemDim3Code = '' AND (pv.ItemDim3Code IS NULL OR pv.ItemDim3Code = ''))
)
WHERE pv.ItemCode IS NULL;
`, strings.Join(valueRows, ","), usernameParam, usernameParam)
res, err := tx.Exec(query, args...)
if err != nil {
return inserted, err
}
if rows, rowsErr := res.RowsAffected(); rowsErr == nil {
inserted += rows
}
return inserted, nil
}
@@ -341,7 +425,7 @@ BEGIN
'AD', '', 0, 0,
1, 1, 1, 0, 1, 0,
0, 0, 0, 0, 0, 0,
'', '10%', '', '', '',
'', '%10', '', '', '',
'', '', '0', '0', '0',
'0', '', '', 0, '', '1',
0, 0, '1900-01-01', 0, 0,
@@ -369,7 +453,15 @@ SET
ProductHierarchyID = COALESCE(@p5, ProductHierarchyID),
UnitOfMeasureCode1 = COALESCE(NULLIF(@p6,''), UnitOfMeasureCode1),
ItemAccountGrCode = COALESCE(NULLIF(@p7,''), ItemAccountGrCode),
ItemTaxGrCode = COALESCE(NULLIF(@p8,''), ItemTaxGrCode),
ItemTaxGrCode = CASE
WHEN NULLIF(@p8,'') IS NULL THEN ItemTaxGrCode
WHEN EXISTS (
SELECT 1
FROM dbo.cdItemTaxGr g WITH(NOLOCK)
WHERE LTRIM(RTRIM(g.ItemTaxGrCode)) = LTRIM(RTRIM(@p8))
) THEN @p8
ELSE ItemTaxGrCode
END,
ItemPaymentPlanGrCode = COALESCE(NULLIF(@p9,''), ItemPaymentPlanGrCode),
ItemDiscountGrCode = COALESCE(NULLIF(@p10,''), ItemDiscountGrCode),
ItemVendorGrCode = COALESCE(NULLIF(@p11,''), ItemVendorGrCode),
@@ -411,23 +503,67 @@ WHERE ItemTypeCode = @p1
}
func UpdateOrderLinesTx(tx *sql.Tx, orderHeaderID string, lines []models.OrderProductionUpdateLine, username string) (int64, error) {
if len(lines) == 0 {
return 0, nil
}
const chunkSize = 300
var updated int64
for _, line := range lines {
res, err := tx.Exec(`
UPDATE dbo.trOrderLine
SET
ItemCode = @p1,
ColorCode = @p2,
ItemDim2Code = @p3,
LineDescription = COALESCE(NULLIF(@p4,''), LineDescription),
LastUpdatedUserName = @p5,
LastUpdatedDate = GETDATE()
WHERE OrderHeaderID = @p6 AND OrderLineID = @p7
`, line.NewItemCode, line.NewColor, line.NewDim2, line.NewDesc, username, orderHeaderID, line.OrderLineID)
if err != nil {
return updated, err
for i := 0; i < len(lines); i += chunkSize {
end := i + chunkSize
if end > len(lines) {
end = len(lines)
}
if rows, err := res.RowsAffected(); err == nil {
chunk := lines[i:end]
values := make([]string, 0, len(chunk))
args := make([]any, 0, len(chunk)*5+2)
paramPos := 1
for _, line := range chunk {
values = append(values, fmt.Sprintf("(@p%d,@p%d,@p%d,@p%d,@p%d)", paramPos, paramPos+1, paramPos+2, paramPos+3, paramPos+4))
args = append(args,
strings.TrimSpace(line.OrderLineID),
line.NewItemCode,
line.NewColor,
line.NewDim2,
line.NewDesc,
)
paramPos += 5
}
orderHeaderParam := paramPos
usernameParam := paramPos + 1
args = append(args, orderHeaderID, username)
query := fmt.Sprintf(`
SET NOCOUNT ON;
WITH src (OrderLineID, NewItemCode, NewColor, NewDim2, NewDesc) AS (
SELECT *
FROM (VALUES %s) AS v (OrderLineID, NewItemCode, NewColor, NewDim2, NewDesc)
)
UPDATE l
SET
l.ItemCode = s.NewItemCode,
l.ColorCode = s.NewColor,
l.ItemDim2Code = s.NewDim2,
l.LineDescription = COALESCE(NULLIF(s.NewDesc,''), l.LineDescription),
l.LastUpdatedUserName = @p%d,
l.LastUpdatedDate = GETDATE()
FROM dbo.trOrderLine l
JOIN src s
ON CAST(l.OrderLineID AS NVARCHAR(50)) = s.OrderLineID
WHERE l.OrderHeaderID = @p%d;
`, strings.Join(values, ","), usernameParam, orderHeaderParam)
chunkStart := time.Now()
res, execErr := tx.Exec(query, args...)
if execErr != nil {
return updated, fmt.Errorf("update lines chunk failed chunkStart=%d chunkEnd=%d duration_ms=%d: %w", i, end, time.Since(chunkStart).Milliseconds(), execErr)
}
log.Printf("[UpdateOrderLinesTx] orderHeaderID=%s chunk=%d-%d duration_ms=%d", orderHeaderID, i, end, time.Since(chunkStart).Milliseconds())
if rows, rowsErr := res.RowsAffected(); rowsErr == nil {
updated += rows
}
}
@@ -439,58 +575,89 @@ func UpsertItemAttributesTx(tx *sql.Tx, attrs []models.OrderProductionItemAttrib
return 0, nil
}
// SQL Server parameter limiti (2100) nedeniyle batch'li set-based upsert kullanilir.
const chunkSize = 400 // 400 * 4 param + 1 username = 1601
var affected int64
for _, a := range attrs {
res, err := tx.Exec(`
IF EXISTS (
SELECT 1
FROM dbo.prItemAttribute
WHERE ItemTypeCode = @p1
AND ItemCode = @p2
AND AttributeTypeCode = @p3
for i := 0; i < len(attrs); i += chunkSize {
end := i + chunkSize
if end > len(attrs) {
end = len(attrs)
}
chunk := attrs[i:end]
values := make([]string, 0, len(chunk))
args := make([]any, 0, len(chunk)*4+1)
paramPos := 1
for _, a := range chunk {
values = append(values, fmt.Sprintf("(@p%d,@p%d,@p%d,@p%d)", paramPos, paramPos+1, paramPos+2, paramPos+3))
args = append(args, a.ItemTypeCode, a.ItemCode, a.AttributeTypeCode, a.AttributeCode)
paramPos += 4
}
usernameParam := paramPos
args = append(args, username)
query := fmt.Sprintf(`
SET NOCOUNT ON;
DECLARE @updated INT = 0;
DECLARE @inserted INT = 0;
WITH src (ItemTypeCode, ItemCode, AttributeTypeCode, AttributeCode) AS (
SELECT *
FROM (VALUES %s) AS v (ItemTypeCode, ItemCode, AttributeTypeCode, AttributeCode)
)
BEGIN
UPDATE dbo.prItemAttribute
SET
AttributeCode = @p4,
LastUpdatedUserName = @p5,
LastUpdatedDate = GETDATE()
WHERE ItemTypeCode = @p1
AND ItemCode = @p2
AND AttributeTypeCode = @p3
END
ELSE
BEGIN
INSERT INTO dbo.prItemAttribute (
ItemTypeCode,
ItemCode,
AttributeTypeCode,
AttributeCode,
CreatedUserName,
CreatedDate,
LastUpdatedUserName,
LastUpdatedDate,
RowGuid
)
VALUES (
@p1,
@p2,
@p3,
@p4,
@p5,
GETDATE(),
@p5,
GETDATE(),
NEWID()
)
END
`, a.ItemTypeCode, a.ItemCode, a.AttributeTypeCode, a.AttributeCode, username)
if err != nil {
UPDATE tgt
SET
tgt.AttributeCode = src.AttributeCode,
tgt.LastUpdatedUserName = @p%d,
tgt.LastUpdatedDate = GETDATE()
FROM dbo.prItemAttribute tgt
JOIN src
ON src.ItemTypeCode = tgt.ItemTypeCode
AND src.ItemCode = tgt.ItemCode
AND src.AttributeTypeCode = tgt.AttributeTypeCode;
SET @updated = @@ROWCOUNT;
WITH src (ItemTypeCode, ItemCode, AttributeTypeCode, AttributeCode) AS (
SELECT *
FROM (VALUES %s) AS v (ItemTypeCode, ItemCode, AttributeTypeCode, AttributeCode)
)
INSERT INTO dbo.prItemAttribute (
ItemTypeCode,
ItemCode,
AttributeTypeCode,
AttributeCode,
CreatedUserName,
CreatedDate,
LastUpdatedUserName,
LastUpdatedDate,
RowGuid
)
SELECT
src.ItemTypeCode,
src.ItemCode,
src.AttributeTypeCode,
src.AttributeCode,
@p%d,
GETDATE(),
@p%d,
GETDATE(),
NEWID()
FROM src
LEFT JOIN dbo.prItemAttribute tgt
ON src.ItemTypeCode = tgt.ItemTypeCode
AND src.ItemCode = tgt.ItemCode
AND src.AttributeTypeCode = tgt.AttributeTypeCode
WHERE tgt.ItemCode IS NULL;
SET @inserted = @@ROWCOUNT;
SELECT (@updated + @inserted) AS Affected;
`, strings.Join(values, ","), usernameParam, strings.Join(values, ","), usernameParam, usernameParam)
var chunkAffected int64
if err := tx.QueryRow(query, args...).Scan(&chunkAffected); err != nil {
return affected, err
}
if rows, err := res.RowsAffected(); err == nil {
affected += rows
}
affected += chunkAffected
}
return affected, nil
}

View File

@@ -0,0 +1,16 @@
package queries
const GetProductNewColors = `
SELECT
CAST(@p1 AS NVARCHAR(30)) AS ProductCode,
LTRIM(RTRIM(c.ColorCode)) AS ColorCode,
ISNULL(NULLIF(LTRIM(RTRIM(cd.ColorDescription)), ''), ISNULL(NULLIF(LTRIM(RTRIM(c.ColorHex)), ''), LTRIM(RTRIM(c.ColorCode)))) AS ColorDescription
FROM dbo.cdColor AS c WITH(NOLOCK)
LEFT JOIN dbo.cdColorDesc AS cd WITH(NOLOCK)
ON cd.ColorCode = c.ColorCode
AND cd.LangCode = 'TR'
WHERE ISNULL(c.IsBlocked, 0) = 0
AND LEN(LTRIM(RTRIM(ISNULL(c.ColorCode, '')))) = 3
AND LTRIM(RTRIM(ISNULL(c.ColorCatalogCode1, ''))) = N'ÜRÜN'
ORDER BY LTRIM(RTRIM(c.ColorCode));
`

View File

@@ -0,0 +1,16 @@
package queries
const GetProductNewSecondColors = `
SELECT
LTRIM(RTRIM(@ProductCode)) AS ProductCode,
LTRIM(RTRIM(ISNULL(@ColorCode, ''))) AS ColorCode,
LTRIM(RTRIM(d2.ItemDim2Code)) AS ItemDim2Code,
ISNULL(NULLIF(LTRIM(RTRIM(cd.ColorDescription)), ''), LTRIM(RTRIM(d2.ItemDim2Code))) AS ColorDescription
FROM dbo.cdItemDim2 AS d2 WITH(NOLOCK)
LEFT JOIN dbo.cdColorDesc AS cd WITH(NOLOCK)
ON cd.ColorCode = d2.ItemDim2Code
AND cd.LangCode = 'TR'
WHERE ISNULL(d2.IsBlocked, 0) = 0
AND LEN(LTRIM(RTRIM(ISNULL(d2.ItemDim2Code, '')))) = 3
ORDER BY LTRIM(RTRIM(d2.ItemDim2Code));
`

View File

@@ -150,6 +150,9 @@ func OrderProductionInsertMissingRoute(mssql *sql.DB) http.Handler {
func OrderProductionValidateRoute(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")
rid := fmt.Sprintf("opv-%d", time.Now().UnixNano())
w.Header().Set("X-Debug-Request-Id", rid)
start := time.Now()
id := mux.Vars(r)["id"]
if id == "" {
@@ -167,11 +170,16 @@ func OrderProductionValidateRoute(mssql *sql.DB) http.Handler {
return
}
stepStart := time.Now()
missing, err := buildMissingVariants(mssql, id, payload.Lines)
if err != nil {
log.Printf("[OrderProductionValidateRoute] rid=%s orderHeaderID=%s step=build_missing failed duration_ms=%d err=%v",
rid, id, time.Since(stepStart).Milliseconds(), err)
writeDBError(w, http.StatusInternalServerError, "validate_missing_variants", id, "", len(payload.Lines), err)
return
}
log.Printf("[OrderProductionValidateRoute] rid=%s orderHeaderID=%s lineCount=%d missingCount=%d build_missing_ms=%d total_ms=%d",
rid, id, len(payload.Lines), len(missing), time.Since(stepStart).Milliseconds(), time.Since(start).Milliseconds())
resp := map[string]any{
"missingCount": len(missing),
@@ -189,6 +197,9 @@ func OrderProductionValidateRoute(mssql *sql.DB) http.Handler {
func OrderProductionApplyRoute(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")
rid := fmt.Sprintf("opa-%d", time.Now().UnixNano())
w.Header().Set("X-Debug-Request-Id", rid)
start := time.Now()
id := mux.Vars(r)["id"]
if id == "" {
@@ -206,13 +217,20 @@ func OrderProductionApplyRoute(mssql *sql.DB) http.Handler {
return
}
stepMissingStart := time.Now()
missing, err := buildMissingVariants(mssql, id, payload.Lines)
if err != nil {
log.Printf("[OrderProductionApplyRoute] rid=%s orderHeaderID=%s step=build_missing failed duration_ms=%d err=%v",
rid, id, time.Since(stepMissingStart).Milliseconds(), err)
writeDBError(w, http.StatusInternalServerError, "apply_validate_missing_variants", id, "", len(payload.Lines), err)
return
}
log.Printf("[OrderProductionApplyRoute] rid=%s orderHeaderID=%s lineCount=%d missingCount=%d build_missing_ms=%d",
rid, id, len(payload.Lines), len(missing), time.Since(stepMissingStart).Milliseconds())
if len(missing) > 0 && !payload.InsertMissing {
log.Printf("[OrderProductionApplyRoute] rid=%s orderHeaderID=%s early_exit=missing_variants total_ms=%d",
rid, id, time.Since(start).Milliseconds())
w.WriteHeader(http.StatusConflict)
_ = json.NewEncoder(w).Encode(map[string]any{
"missingCount": len(missing),
@@ -231,43 +249,68 @@ func OrderProductionApplyRoute(mssql *sql.DB) http.Handler {
username = "system"
}
stepBeginStart := time.Now()
tx, err := mssql.Begin()
if err != nil {
writeDBError(w, http.StatusInternalServerError, "begin_tx", id, username, len(payload.Lines), err)
return
}
defer tx.Rollback()
log.Printf("[OrderProductionApplyRoute] rid=%s orderHeaderID=%s step=begin_tx duration_ms=%d", rid, id, time.Since(stepBeginStart).Milliseconds())
stepTxSettingsStart := time.Now()
if _, err := tx.Exec(`SET XACT_ABORT ON; SET LOCK_TIMEOUT 15000;`); err != nil {
writeDBError(w, http.StatusInternalServerError, "tx_settings", id, username, len(payload.Lines), err)
return
}
log.Printf("[OrderProductionApplyRoute] rid=%s orderHeaderID=%s step=tx_settings duration_ms=%d", rid, id, time.Since(stepTxSettingsStart).Milliseconds())
var inserted int64
if payload.InsertMissing {
cdItemByCode := buildCdItemDraftMap(payload.CdItems)
stepInsertMissingStart := time.Now()
inserted, err = queries.InsertMissingVariantsTx(tx, missing, username, cdItemByCode)
if err != nil {
writeDBError(w, http.StatusInternalServerError, "insert_missing_variants", id, username, len(missing), err)
return
}
log.Printf("[OrderProductionApplyRoute] rid=%s orderHeaderID=%s step=insert_missing inserted=%d duration_ms=%d",
rid, id, inserted, time.Since(stepInsertMissingStart).Milliseconds())
}
stepValidateAttrStart := time.Now()
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
}
log.Printf("[OrderProductionApplyRoute] rid=%s orderHeaderID=%s step=validate_attributes count=%d duration_ms=%d",
rid, id, len(payload.ProductAttributes), time.Since(stepValidateAttrStart).Milliseconds())
stepUpdateLinesStart := time.Now()
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)
return
}
log.Printf("[OrderProductionApplyRoute] rid=%s orderHeaderID=%s step=update_lines updated=%d duration_ms=%d",
rid, id, updated, time.Since(stepUpdateLinesStart).Milliseconds())
stepUpsertAttrStart := time.Now()
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
}
log.Printf("[OrderProductionApplyRoute] rid=%s orderHeaderID=%s step=upsert_attributes affected=%d duration_ms=%d",
rid, id, attributeAffected, time.Since(stepUpsertAttrStart).Milliseconds())
stepCommitStart := time.Now()
if err := tx.Commit(); err != nil {
writeDBError(w, http.StatusInternalServerError, "commit_tx", id, username, len(payload.Lines), err)
return
}
log.Printf("[OrderProductionApplyRoute] rid=%s orderHeaderID=%s step=commit duration_ms=%d total_ms=%d",
rid, id, time.Since(stepCommitStart).Milliseconds(), time.Since(start).Milliseconds())
resp := map[string]any{
"updated": updated,
@@ -319,7 +362,13 @@ func buildCdItemDraftMap(list []models.OrderProductionCdItemDraft) map[string]mo
}
func buildMissingVariants(mssql *sql.DB, orderHeaderID string, lines []models.OrderProductionUpdateLine) ([]models.OrderProductionMissingVariant, error) {
start := time.Now()
missing := make([]models.OrderProductionMissingVariant, 0)
lineDimsMap, err := queries.GetOrderLineDimsMap(mssql, orderHeaderID)
if err != nil {
return nil, err
}
existsCache := make(map[string]bool, len(lines))
for _, line := range lines {
lineID := strings.TrimSpace(line.OrderLineID)
@@ -331,28 +380,43 @@ func buildMissingVariants(mssql *sql.DB, orderHeaderID string, lines []models.Or
continue
}
itemTypeCode, dim1, _, dim3, err := queries.GetOrderLineDims(mssql, orderHeaderID, lineID)
if err != nil {
return nil, err
dims, ok := lineDimsMap[lineID]
if !ok {
continue
}
exists, err := queries.VariantExists(mssql, itemTypeCode, newItem, newColor, dim1, newDim2, dim3)
if err != nil {
return nil, err
cacheKey := fmt.Sprintf("%d|%s|%s|%s|%s|%s",
dims.ItemTypeCode,
strings.ToUpper(strings.TrimSpace(newItem)),
strings.ToUpper(strings.TrimSpace(newColor)),
strings.ToUpper(strings.TrimSpace(dims.ItemDim1Code)),
strings.ToUpper(strings.TrimSpace(newDim2)),
strings.ToUpper(strings.TrimSpace(dims.ItemDim3Code)),
)
exists, cached := existsCache[cacheKey]
if !cached {
var checkErr error
exists, checkErr = queries.VariantExists(mssql, dims.ItemTypeCode, newItem, newColor, dims.ItemDim1Code, newDim2, dims.ItemDim3Code)
if checkErr != nil {
return nil, checkErr
}
existsCache[cacheKey] = exists
}
if !exists {
missing = append(missing, models.OrderProductionMissingVariant{
OrderLineID: lineID,
ItemTypeCode: itemTypeCode,
ItemTypeCode: dims.ItemTypeCode,
ItemCode: newItem,
ColorCode: newColor,
ItemDim1Code: dim1,
ItemDim1Code: dims.ItemDim1Code,
ItemDim2Code: newDim2,
ItemDim3Code: dim3,
ItemDim3Code: dims.ItemDim3Code,
})
}
}
log.Printf("[buildMissingVariants] orderHeaderID=%s lineCount=%d dimMapCount=%d missingCount=%d total_ms=%d",
orderHeaderID, len(lines), len(lineDimsMap), len(missing), time.Since(start).Milliseconds())
return missing, nil
}

View File

@@ -0,0 +1,45 @@
package routes
import (
"bssapp-backend/auth"
"bssapp-backend/db"
"bssapp-backend/models"
"bssapp-backend/queries"
"encoding/json"
"log"
"net/http"
)
func GetProductNewColorsHandler(w http.ResponseWriter, r *http.Request) {
claims, ok := auth.GetClaimsFromContext(r.Context())
if !ok || claims == nil {
http.Error(w, "unauthorized", http.StatusUnauthorized)
return
}
code := r.URL.Query().Get("code")
if code == "" {
http.Error(w, "Eksik parametre: code gerekli", http.StatusBadRequest)
return
}
rows, err := db.MssqlDB.Query(queries.GetProductNewColors, code)
if err != nil {
http.Error(w, "Yeni urun renk listesi alinamadi: "+err.Error(), http.StatusInternalServerError)
return
}
defer rows.Close()
var list []models.ProductColor
for rows.Next() {
var c models.ProductColor
if err := rows.Scan(&c.ProductCode, &c.ColorCode, &c.ColorDescription); err != nil {
log.Println("Satir okunamadi:", err)
continue
}
list = append(list, c)
}
w.Header().Set("Content-Type", "application/json; charset=utf-8")
_ = json.NewEncoder(w).Encode(list)
}

View File

@@ -0,0 +1,51 @@
package routes
import (
"bssapp-backend/auth"
"bssapp-backend/db"
"bssapp-backend/models"
"bssapp-backend/queries"
"database/sql"
"encoding/json"
"log"
"net/http"
)
func GetProductNewSecondColorsHandler(w http.ResponseWriter, r *http.Request) {
claims, ok := auth.GetClaimsFromContext(r.Context())
if !ok || claims == nil {
http.Error(w, "unauthorized", http.StatusUnauthorized)
return
}
code := r.URL.Query().Get("code")
color := r.URL.Query().Get("color")
if code == "" || color == "" {
http.Error(w, "Eksik parametre: code ve color gerekli", http.StatusBadRequest)
return
}
rows, err := db.MssqlDB.Query(
queries.GetProductNewSecondColors,
sql.Named("ProductCode", code),
sql.Named("ColorCode", color),
)
if err != nil {
http.Error(w, "Yeni urun 2. renk listesi alinamadi: "+err.Error(), http.StatusInternalServerError)
return
}
defer rows.Close()
var list []models.ProductSecondColor
for rows.Next() {
var c models.ProductSecondColor
if err := rows.Scan(&c.ProductCode, &c.ColorCode, &c.ItemDim2Code, &c.ColorDescription); err != nil {
log.Println("Satir okunamadi:", err)
continue
}
list = append(list, c)
}
w.Header().Set("Content-Type", "application/json; charset=utf-8")
_ = json.NewEncoder(w).Encode(list)
}