Merge remote-tracking branch 'origin/master'

This commit is contained in:
M_Kececi
2026-04-02 13:36:09 +03:00
parent f5c91abafa
commit 4549152594
15 changed files with 318 additions and 626 deletions

View File

@@ -2,8 +2,11 @@ package queries
import (
"database/sql"
"fmt"
"log"
"strconv"
"strings"
"time"
"bssapp-backend/models"
)
@@ -54,11 +57,11 @@ func InsertMissingProductionVariants(mssql *sql.DB, orderHeaderID string, userna
FROM dbo.trOrderLine l
LEFT JOIN dbo.prItemVariant pv
ON pv.ItemTypeCode = l.ItemTypeCode
AND pv.ItemCode = l.ItemCode
AND pv.ColorCode = l.ColorCode
AND ISNULL(pv.ItemDim1Code,'') = ISNULL(l.ItemDim1Code,'')
AND ISNULL(pv.ItemDim2Code,'') = ISNULL(l.ItemDim2Code,'')
AND ISNULL(pv.ItemDim3Code,'') = ISNULL(l.ItemDim3Code,'')
AND ISNULL(LTRIM(RTRIM(pv.ItemCode)),'') = ISNULL(LTRIM(RTRIM(l.ItemCode)),'')
AND ISNULL(LTRIM(RTRIM(pv.ColorCode)),'') = ISNULL(LTRIM(RTRIM(l.ColorCode)),'')
AND ISNULL(LTRIM(RTRIM(pv.ItemDim1Code)),'') = ISNULL(LTRIM(RTRIM(l.ItemDim1Code)),'')
AND ISNULL(LTRIM(RTRIM(pv.ItemDim2Code)),'') = ISNULL(LTRIM(RTRIM(l.ItemDim2Code)),'')
AND ISNULL(LTRIM(RTRIM(pv.ItemDim3Code)),'') = ISNULL(LTRIM(RTRIM(l.ItemDim3Code)),'')
WHERE l.OrderHeaderID = @p1
AND ISNULL(l.ItemCode,'') LIKE 'U%'
AND pv.ItemCode IS NULL
@@ -143,11 +146,11 @@ func VariantExists(mssql *sql.DB, itemTypeCode int16, itemCode string, colorCode
SELECT TOP 1 1
FROM dbo.prItemVariant
WHERE ItemTypeCode = @p1
AND ItemCode = @p2
AND ColorCode = @p3
AND ISNULL(ItemDim1Code,'') = ISNULL(@p4,'')
AND ISNULL(ItemDim2Code,'') = ISNULL(@p5,'')
AND ISNULL(ItemDim3Code,'') = ISNULL(@p6,'')
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)),'')
`, itemTypeCode, itemCode, colorCode, dim1, dim2, dim3).Scan(&exists)
if err == sql.ErrNoRows {
return false, nil
@@ -202,11 +205,11 @@ IF NOT EXISTS (
SELECT 1
FROM dbo.prItemVariant
WHERE ItemTypeCode = @p1
AND ItemCode = @p2
AND ColorCode = @p3
AND ISNULL(ItemDim1Code,'') = ISNULL(@p4,'')
AND ISNULL(ItemDim2Code,'') = ISNULL(@p5,'')
AND ISNULL(ItemDim3Code,'') = ISNULL(@p6,'')
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)),'')
)
INSERT INTO dbo.prItemVariant (
ItemTypeCode,
@@ -496,10 +499,11 @@ func GetOrderProductionLookupOptions(mssql *sql.DB) (models.OrderProductionCdIte
out := models.OrderProductionCdItemLookups{}
queryPairs := []struct {
Name string
Query string
Target *[]models.OrderProductionLookupOption
}{
{`SELECT
{"ItemDimTypeCodes", `SELECT
CAST(t.ItemDimTypeCode AS NVARCHAR(50)) AS Code,
ISNULL(d.ItemDimTypeDescription, CAST(t.ItemDimTypeCode AS NVARCHAR(50))) AS [Description]
FROM dbo.bsItemDimType t WITH(NOLOCK)
@@ -508,8 +512,8 @@ func GetOrderProductionLookupOptions(mssql *sql.DB) (models.OrderProductionCdIte
AND d.LangCode = 'TR'
WHERE ISNULL(t.IsBlocked, 0) = 0
ORDER BY t.ItemDimTypeCode`, &out.ItemDimTypeCodes},
{`SELECT DISTINCT CAST(ProductTypeCode AS NVARCHAR(50)) AS Code, CAST(ProductTypeCode AS NVARCHAR(50)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ProductTypeCode IS NOT NULL ORDER BY Code`, &out.ProductTypeCodes},
{`SELECT
{"ProductTypeCodes", `SELECT DISTINCT CAST(ProductTypeCode AS NVARCHAR(50)) AS Code, CAST(ProductTypeCode AS NVARCHAR(50)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ProductTypeCode IS NOT NULL ORDER BY Code`, &out.ProductTypeCodes},
{"ProductHierarchyIDs", `SELECT
CAST(h.ProductHierarchyID AS NVARCHAR(50)) AS Code,
LTRIM(RTRIM(
CONCAT(
@@ -525,26 +529,28 @@ func GetOrderProductionLookupOptions(mssql *sql.DB) (models.OrderProductionCdIte
ON d.ProductHierarchyLevelCode = h.ProductHierarchyLevelCode01
AND d.LangCode = 'TR'
ORDER BY h.ProductHierarchyID`, &out.ProductHierarchyIDs},
{`SELECT DISTINCT CAST(UnitOfMeasureCode1 AS NVARCHAR(50)) AS Code, CAST(UnitOfMeasureCode1 AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(UnitOfMeasureCode1,'') <> '' ORDER BY Code`, &out.UnitOfMeasureCode1List},
{`SELECT DISTINCT CAST(ItemAccountGrCode AS NVARCHAR(50)) AS Code, CAST(ItemAccountGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(ItemAccountGrCode,'') <> '' ORDER BY Code`, &out.ItemAccountGrCodes},
{`SELECT DISTINCT CAST(ItemTaxGrCode AS NVARCHAR(50)) AS Code, CAST(ItemTaxGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(ItemTaxGrCode,'') <> '' ORDER BY Code`, &out.ItemTaxGrCodes},
{`SELECT DISTINCT CAST(ItemPaymentPlanGrCode AS NVARCHAR(50)) AS Code, CAST(ItemPaymentPlanGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(ItemPaymentPlanGrCode,'') <> '' ORDER BY Code`, &out.ItemPaymentPlanGrCodes},
{`SELECT DISTINCT CAST(ItemDiscountGrCode AS NVARCHAR(50)) AS Code, CAST(ItemDiscountGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(ItemDiscountGrCode,'') <> '' ORDER BY Code`, &out.ItemDiscountGrCodes},
{`SELECT DISTINCT CAST(ItemVendorGrCode AS NVARCHAR(50)) AS Code, CAST(ItemVendorGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(ItemVendorGrCode,'') <> '' ORDER BY Code`, &out.ItemVendorGrCodes},
{`SELECT DISTINCT CAST(PromotionGroupCode AS NVARCHAR(50)) AS Code, CAST(PromotionGroupCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(PromotionGroupCode,'') <> '' ORDER BY Code`, &out.PromotionGroupCodes},
{`SELECT DISTINCT CAST(ProductCollectionGrCode AS NVARCHAR(50)) AS Code, CAST(ProductCollectionGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(ProductCollectionGrCode,'') <> '' ORDER BY Code`, &out.ProductCollectionGrCodes},
{`SELECT DISTINCT CAST(StorePriceLevelCode AS NVARCHAR(50)) AS Code, CAST(StorePriceLevelCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(StorePriceLevelCode,'') <> '' ORDER BY Code`, &out.StorePriceLevelCodes},
{`SELECT DISTINCT CAST(PerceptionOfFashionCode AS NVARCHAR(50)) AS Code, CAST(PerceptionOfFashionCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(PerceptionOfFashionCode,'') <> '' ORDER BY Code`, &out.PerceptionOfFashionCodes},
{`SELECT DISTINCT CAST(CommercialRoleCode AS NVARCHAR(50)) AS Code, CAST(CommercialRoleCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(CommercialRoleCode,'') <> '' ORDER BY Code`, &out.CommercialRoleCodes},
{`SELECT DISTINCT CAST(StoreCapacityLevelCode AS NVARCHAR(50)) AS Code, CAST(StoreCapacityLevelCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(StoreCapacityLevelCode,'') <> '' ORDER BY Code`, &out.StoreCapacityLevelCodes},
{`SELECT DISTINCT CAST(CustomsTariffNumberCode AS NVARCHAR(50)) AS Code, CAST(CustomsTariffNumberCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(CustomsTariffNumberCode,'') <> '' ORDER BY Code`, &out.CustomsTariffNumbers},
{`SELECT DISTINCT CAST(CompanyCode AS NVARCHAR(50)) AS Code, CAST(CompanyCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE ISNULL(CompanyCode,'') <> '' ORDER BY Code`, &out.CompanyCodes},
{"UnitOfMeasureCode1List", `SELECT DISTINCT CAST(UnitOfMeasureCode1 AS NVARCHAR(50)) AS Code, CAST(UnitOfMeasureCode1 AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(UnitOfMeasureCode1 AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.UnitOfMeasureCode1List},
{"ItemAccountGrCodes", `SELECT DISTINCT CAST(ItemAccountGrCode AS NVARCHAR(50)) AS Code, CAST(ItemAccountGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(ItemAccountGrCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.ItemAccountGrCodes},
{"ItemTaxGrCodes", `SELECT DISTINCT CAST(ItemTaxGrCode AS NVARCHAR(50)) AS Code, CAST(ItemTaxGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(ItemTaxGrCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.ItemTaxGrCodes},
{"ItemPaymentPlanGrCodes", `SELECT DISTINCT CAST(ItemPaymentPlanGrCode AS NVARCHAR(50)) AS Code, CAST(ItemPaymentPlanGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(ItemPaymentPlanGrCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.ItemPaymentPlanGrCodes},
{"ItemDiscountGrCodes", `SELECT DISTINCT CAST(ItemDiscountGrCode AS NVARCHAR(50)) AS Code, CAST(ItemDiscountGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(ItemDiscountGrCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.ItemDiscountGrCodes},
{"ItemVendorGrCodes", `SELECT DISTINCT CAST(ItemVendorGrCode AS NVARCHAR(50)) AS Code, CAST(ItemVendorGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(ItemVendorGrCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.ItemVendorGrCodes},
{"PromotionGroupCodes", `SELECT DISTINCT CAST(PromotionGroupCode AS NVARCHAR(50)) AS Code, CAST(PromotionGroupCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(PromotionGroupCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.PromotionGroupCodes},
{"ProductCollectionGrCodes", `SELECT DISTINCT CAST(ProductCollectionGrCode AS NVARCHAR(50)) AS Code, CAST(ProductCollectionGrCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(ProductCollectionGrCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.ProductCollectionGrCodes},
{"StorePriceLevelCodes", `SELECT DISTINCT CAST(StorePriceLevelCode AS NVARCHAR(50)) AS Code, CAST(StorePriceLevelCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(StorePriceLevelCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.StorePriceLevelCodes},
{"PerceptionOfFashionCodes", `SELECT DISTINCT CAST(PerceptionOfFashionCode AS NVARCHAR(50)) AS Code, CAST(PerceptionOfFashionCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(PerceptionOfFashionCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.PerceptionOfFashionCodes},
{"CommercialRoleCodes", `SELECT DISTINCT CAST(CommercialRoleCode AS NVARCHAR(50)) AS Code, CAST(CommercialRoleCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(CommercialRoleCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.CommercialRoleCodes},
{"StoreCapacityLevelCodes", `SELECT DISTINCT CAST(StoreCapacityLevelCode AS NVARCHAR(50)) AS Code, CAST(StoreCapacityLevelCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(StoreCapacityLevelCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.StoreCapacityLevelCodes},
{"CustomsTariffNumbers", `SELECT DISTINCT CAST(CustomsTariffNumberCode AS NVARCHAR(50)) AS Code, CAST(CustomsTariffNumberCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(CustomsTariffNumberCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.CustomsTariffNumbers},
{"CompanyCodes", `SELECT DISTINCT CAST(CompanyCode AS NVARCHAR(50)) AS Code, CAST(CompanyCode AS NVARCHAR(200)) AS [Description] FROM dbo.cdItem WITH(NOLOCK) WHERE NULLIF(LTRIM(RTRIM(CAST(CompanyCode AS NVARCHAR(200)))), '') IS NOT NULL ORDER BY Code`, &out.CompanyCodes},
}
for _, pair := range queryPairs {
start := time.Now()
log.Printf("[GetOrderProductionLookupOptions] executing [%s]", pair.Name)
rows, err := mssql.Query(pair.Query)
if err != nil {
return out, err
return out, fmt.Errorf("lookup query failed [%s]: %w", pair.Name, err)
}
list := make([]models.OrderProductionLookupOption, 0, 64)
@@ -552,7 +558,7 @@ func GetOrderProductionLookupOptions(mssql *sql.DB) (models.OrderProductionCdIte
var item models.OrderProductionLookupOption
if err := rows.Scan(&item.Code, &item.Description); err != nil {
rows.Close()
return out, err
return out, fmt.Errorf("lookup scan failed [%s]: %w", pair.Name, err)
}
item.Code = strings.TrimSpace(item.Code)
item.Description = strings.TrimSpace(item.Description)
@@ -560,9 +566,10 @@ func GetOrderProductionLookupOptions(mssql *sql.DB) (models.OrderProductionCdIte
}
if err := rows.Err(); err != nil {
rows.Close()
return out, err
return out, fmt.Errorf("lookup rows failed [%s]: %w", pair.Name, err)
}
rows.Close()
log.Printf("[GetOrderProductionLookupOptions] ok [%s] count=%d duration=%s", pair.Name, len(list), time.Since(start))
*pair.Target = list
}

View File

@@ -9,12 +9,12 @@ import (
func GetProductList() ([]models.Product, error) {
rows, err := db.MssqlDB.Query(`
SELECT
ProductCode
LTRIM(RTRIM(ProductCode)) AS ProductCode
FROM ProductFilterWithDescription('TR')
WHERE
ProductAtt42 IN ('SERI', 'AKSESUAR')
AND IsBlocked = 0
AND LEN(ProductCode) = 13 -- 🔹 yalnızca 13 karakterlik kodlar
AND LEN(LTRIM(RTRIM(ProductCode))) = 13
ORDER BY ProductCode;
`)
if err != nil {

View File

@@ -1,14 +1,19 @@
package queries
const GetProductAttributes = `
;WITH TypeDesc AS (
;WITH RequiredTypes AS (
SELECT
t.ItemTypeCode,
t.AttributeTypeCode,
ISNULL(t.AttributeTypeDescription, CAST(t.AttributeTypeCode AS NVARCHAR(30))) AS AttributeTypeDescription
FROM dbo.cdItemAttributeTypeDesc AS t WITH(NOLOCK)
ISNULL(NULLIF(td.AttributeTypeDescription, ''), CAST(t.AttributeTypeCode AS NVARCHAR(30))) AS AttributeTypeDescription
FROM dbo.cdItemAttributeType AS t WITH(NOLOCK)
LEFT JOIN dbo.cdItemAttributeTypeDesc AS td WITH(NOLOCK)
ON td.ItemTypeCode = t.ItemTypeCode
AND td.AttributeTypeCode = t.AttributeTypeCode
AND td.LangCode = 'TR'
WHERE t.ItemTypeCode = @p1
AND t.LangCode = 'TR'
AND ISNULL(t.IsBlocked, 0) = 0
AND ISNULL(t.IsRequired, 0) = 1
),
Attr AS (
SELECT
@@ -24,19 +29,21 @@ Attr AS (
AND d.LangCode = 'TR'
WHERE a.ItemTypeCode = @p1
AND ISNULL(a.IsBlocked, 0) = 0
),
AND ISNULL(a.AttributeCode, '') <> ''
)
SELECT
a.ItemTypeCode,
a.AttributeTypeCode,
ISNULL(NULLIF(td.AttributeTypeDescription, ''), CAST(a.AttributeTypeCode AS NVARCHAR(30))) AS AttributeTypeDescription,
rt.ItemTypeCode,
rt.AttributeTypeCode,
rt.AttributeTypeDescription,
a.AttributeCode,
a.AttributeDescription
FROM Attr a
LEFT JOIN TypeDesc td
ON td.ItemTypeCode = a.ItemTypeCode
AND td.AttributeTypeCode = a.AttributeTypeCode
FROM RequiredTypes AS rt
LEFT JOIN Attr AS a
ON a.ItemTypeCode = rt.ItemTypeCode
AND a.AttributeTypeCode = rt.AttributeTypeCode
WHERE ISNULL(a.AttributeCode, '') <> ''
ORDER BY
a.AttributeTypeCode,
CASE WHEN a.AttributeCode = '-' THEN 0 ELSE 1 END,
rt.AttributeTypeCode,
CASE WHEN a.AttributeCode IN ('-', '.') THEN 0 ELSE 1 END,
a.AttributeCode;
`

View File

@@ -3,27 +3,18 @@ package queries
const GetProductColors = `
DECLARE @ProductCode VARCHAR(30) = @p1;
WITH NormalizedColors AS (
SELECT
p.ProductCode,
CASE
WHEN ISNULL(v.ColorCode, '') = '000' THEN '001'
ELSE ISNULL(v.ColorCode, '')
END AS ColorCode
FROM ProductFilterWithDescription('TR') AS p
INNER JOIN prItemVariant AS v WITH(NOLOCK)
ON v.ItemCode = p.ProductCode
WHERE
p.ProductCode = @ProductCode
AND ISNULL(v.ColorCode, '') <> ''
)
SELECT DISTINCT
n.ProductCode,
n.ColorCode,
ISNULL(cd.ColorDescription, CASE WHEN n.ColorCode = '001' THEN 'SIYAH' ELSE '' END) AS ColorDescription
FROM NormalizedColors AS n
p.ProductCode,
v.ColorCode,
ISNULL(cd.ColorDescription, '') AS ColorDescription
FROM ProductFilterWithDescription('TR') AS p
INNER JOIN prItemVariant AS v WITH(NOLOCK)
ON v.ItemCode = p.ProductCode
LEFT JOIN cdColorDesc AS cd WITH(NOLOCK)
ON cd.ColorCode = n.ColorCode
ON cd.ColorCode = v.ColorCode
AND cd.LangCode = 'TR'
ORDER BY n.ColorCode;
WHERE
p.ProductCode = @ProductCode
AND ISNULL(v.ColorCode, '') <> ''
ORDER BY v.ColorCode;
`

View File

@@ -1,40 +1,24 @@
package queries
const GetProductSecondColors = `
WITH NormalizedVariants AS (
SELECT
Product.ProductCode,
CASE
WHEN ISNULL(prItemVariant.ColorCode, '') = '000' THEN '001'
ELSE ISNULL(prItemVariant.ColorCode, '')
END AS ColorCode,
CASE
WHEN ISNULL(prItemVariant.ItemDim2Code, '') = '000' THEN '001'
ELSE ISNULL(prItemVariant.ItemDim2Code, '')
END AS ItemDim2Code
FROM prItemVariant WITH(NOLOCK)
INNER JOIN ProductFilterWithDescription('TR') AS Product
ON prItemVariant.ItemCode = Product.ProductCode
WHERE Product.ProductCode = @ProductCode
)
SELECT
Variant.ProductCode,
Variant.ColorCode,
Variant.ItemDim2Code,
ISNULL(ColorDesc.ColorDescription, CASE WHEN Variant.ItemDim2Code = '001' THEN 'SIYAH' ELSE '' END) AS ColorDescription
FROM NormalizedVariants AS Variant
Product.ProductCode,
ISNULL(prItemVariant.ColorCode, '') AS ColorCode,
ISNULL(prItemVariant.ItemDim2Code, '') AS ItemDim2Code,
ISNULL(ColorDesc.ColorDescription, '') AS ColorDescription
FROM prItemVariant WITH(NOLOCK)
INNER JOIN ProductFilterWithDescription('TR') AS Product
ON prItemVariant.ItemCode = Product.ProductCode
LEFT JOIN cdColorDesc AS ColorDesc WITH(NOLOCK)
ON ColorDesc.ColorCode = Variant.ItemDim2Code
ON ColorDesc.ColorCode = prItemVariant.ItemDim2Code
AND ColorDesc.LangCode = 'TR'
WHERE Variant.ColorCode = CASE
WHEN ISNULL(@ColorCode, '') = '000' THEN '001'
ELSE ISNULL(@ColorCode, '')
END
AND Variant.ItemDim2Code <> ''
WHERE Product.ProductCode = @ProductCode
AND prItemVariant.ColorCode = @ColorCode
AND ISNULL(prItemVariant.ItemDim2Code, '') <> ''
GROUP BY
Variant.ProductCode,
Variant.ItemDim2Code,
Variant.ColorCode,
Product.ProductCode,
prItemVariant.ItemDim2Code,
prItemVariant.ColorCode,
ColorDesc.ColorDescription
ORDER BY Variant.ItemDim2Code
ORDER BY ItemDim2Code
`

View File

@@ -7,10 +7,12 @@ import (
"database/sql"
"encoding/json"
"errors"
"fmt"
"log"
"net/http"
"regexp"
"strings"
"time"
"github.com/gorilla/mux"
mssql "github.com/microsoft/go-mssqldb"
@@ -79,16 +81,26 @@ 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")
rid := fmt.Sprintf("opl-%d", time.Now().UnixNano())
w.Header().Set("X-Debug-Request-Id", rid)
log.Printf("[OrderProductionCdItemLookupsRoute] rid=%s started", rid)
lookups, err := queries.GetOrderProductionLookupOptions(mssql)
if err != nil {
log.Printf("[OrderProductionCdItemLookupsRoute] lookup error: %v", err)
http.Error(w, "Veritabani hatasi", http.StatusInternalServerError)
log.Printf("[OrderProductionCdItemLookupsRoute] rid=%s lookup error: %v", rid, err)
w.WriteHeader(http.StatusInternalServerError)
_ = json.NewEncoder(w).Encode(map[string]any{
"message": "Veritabani hatasi",
"step": "cditem-lookups",
"detail": err.Error(),
"requestId": rid,
})
return
}
log.Printf("[OrderProductionCdItemLookupsRoute] rid=%s success", rid)
if err := json.NewEncoder(w).Encode(lookups); err != nil {
log.Printf("[OrderProductionCdItemLookupsRoute] encode error: %v", err)
log.Printf("[OrderProductionCdItemLookupsRoute] rid=%s encode error: %v", rid, err)
}
})
}

View File

@@ -1,75 +0,0 @@
/* eslint-disable */
/**
* THIS FILE IS GENERATED AUTOMATICALLY.
* DO NOT EDIT.
*
* You are probably looking on adding startup/initialization code.
* Use "quasar new boot <name>" and add it there.
* One boot file per concern. Then reference the file(s) in quasar.config file > boot:
* boot: ['file', ...] // do not add ".js" extension to it.
*
* Boot files are your "main.js"
**/
import { Quasar } from 'quasar'
import { markRaw } from 'vue'
import RootComponent from 'app/src/App.vue'
import createStore from 'app/src/stores/index'
import createRouter from 'app/src/router/index'
export default async function (createAppFn, quasarUserOptions) {
// Create the app instance.
// Here we inject into it the Quasar UI, the router & possibly the store.
const app = createAppFn(RootComponent)
app.use(Quasar, quasarUserOptions)
const store = typeof createStore === 'function'
? await createStore({})
: createStore
app.use(store)
const router = markRaw(
typeof createRouter === 'function'
? await createRouter({store})
: createRouter
)
// make router instance available in store
store.use(({ store }) => { store.router = router })
// Expose the app, the router and the store.
// Note that we are not mounting the app here, since bootstrapping will be
// different depending on whether we are in a browser or on the server.
return {
app,
store,
router
}
}

View File

@@ -1,154 +0,0 @@
/* eslint-disable */
/**
* THIS FILE IS GENERATED AUTOMATICALLY.
* DO NOT EDIT.
*
* You are probably looking on adding startup/initialization code.
* Use "quasar new boot <name>" and add it there.
* One boot file per concern. Then reference the file(s) in quasar.config file > boot:
* boot: ['file', ...] // do not add ".js" extension to it.
*
* Boot files are your "main.js"
**/
import { createApp } from 'vue'
import '@quasar/extras/roboto-font/roboto-font.css'
import '@quasar/extras/material-icons/material-icons.css'
// We load Quasar stylesheet file
import 'quasar/dist/quasar.sass'
import 'src/css/app.css'
import createQuasarApp from './app.js'
import quasarUserOptions from './quasar-user-options.js'
const publicPath = `/`
async function start ({
app,
router
, store
}, bootFiles) {
let hasRedirected = false
const getRedirectUrl = url => {
try { return router.resolve(url).href }
catch (err) {}
return Object(url) === url
? null
: url
}
const redirect = url => {
hasRedirected = true
if (typeof url === 'string' && /^https?:\/\//.test(url)) {
window.location.href = url
return
}
const href = getRedirectUrl(url)
// continue if we didn't fail to resolve the url
if (href !== null) {
window.location.href = href
window.location.reload()
}
}
const urlPath = window.location.href.replace(window.location.origin, '')
for (let i = 0; hasRedirected === false && i < bootFiles.length; i++) {
try {
await bootFiles[i]({
app,
router,
store,
ssrContext: null,
redirect,
urlPath,
publicPath
})
}
catch (err) {
if (err && err.url) {
redirect(err.url)
return
}
console.error('[Quasar] boot error:', err)
return
}
}
if (hasRedirected === true) return
app.use(router)
app.mount('#q-app')
}
createQuasarApp(createApp, quasarUserOptions)
.then(app => {
// eventually remove this when Cordova/Capacitor/Electron support becomes old
const [ method, mapFn ] = Promise.allSettled !== void 0
? [
'allSettled',
bootFiles => bootFiles.map(result => {
if (result.status === 'rejected') {
console.error('[Quasar] boot error:', result.reason)
return
}
return result.value.default
})
]
: [
'all',
bootFiles => bootFiles.map(entry => entry.default)
]
return Promise[ method ]([
import(/* webpackMode: "eager" */ 'boot/dayjs')
]).then(bootFiles => {
const boot = mapFn(bootFiles).filter(entry => typeof entry === 'function')
start(app, boot)
})
})

View File

@@ -1,116 +0,0 @@
/* eslint-disable */
/**
* THIS FILE IS GENERATED AUTOMATICALLY.
* DO NOT EDIT.
*
* You are probably looking on adding startup/initialization code.
* Use "quasar new boot <name>" and add it there.
* One boot file per concern. Then reference the file(s) in quasar.config file > boot:
* boot: ['file', ...] // do not add ".js" extension to it.
*
* Boot files are your "main.js"
**/
import App from 'app/src/App.vue'
let appPrefetch = typeof App.preFetch === 'function'
? App.preFetch
: (
// Class components return the component options (and the preFetch hook) inside __c property
App.__c !== void 0 && typeof App.__c.preFetch === 'function'
? App.__c.preFetch
: false
)
function getMatchedComponents (to, router) {
const route = to
? (to.matched ? to : router.resolve(to).route)
: router.currentRoute.value
if (!route) { return [] }
const matched = route.matched.filter(m => m.components !== void 0)
if (matched.length === 0) { return [] }
return Array.prototype.concat.apply([], matched.map(m => {
return Object.keys(m.components).map(key => {
const comp = m.components[key]
return {
path: m.path,
c: comp
}
})
}))
}
export function addPreFetchHooks ({ router, store, publicPath }) {
// Add router hook for handling preFetch.
// Doing it after initial route is resolved so that we don't double-fetch
// the data that we already have. Using router.beforeResolve() so that all
// async components are resolved.
router.beforeResolve((to, from, next) => {
const
urlPath = window.location.href.replace(window.location.origin, ''),
matched = getMatchedComponents(to, router),
prevMatched = getMatchedComponents(from, router)
let diffed = false
const preFetchList = matched
.filter((m, i) => {
return diffed || (diffed = (
!prevMatched[i] ||
prevMatched[i].c !== m.c ||
m.path.indexOf('/:') > -1 // does it has params?
))
})
.filter(m => m.c !== void 0 && (
typeof m.c.preFetch === 'function'
// Class components return the component options (and the preFetch hook) inside __c property
|| (m.c.__c !== void 0 && typeof m.c.__c.preFetch === 'function')
))
.map(m => m.c.__c !== void 0 ? m.c.__c.preFetch : m.c.preFetch)
if (appPrefetch !== false) {
preFetchList.unshift(appPrefetch)
appPrefetch = false
}
if (preFetchList.length === 0) {
return next()
}
let hasRedirected = false
const redirect = url => {
hasRedirected = true
next(url)
}
const proceed = () => {
if (hasRedirected === false) { next() }
}
preFetchList.reduce(
(promise, preFetch) => promise.then(() => hasRedirected === false && preFetch({
store,
currentRoute: to,
previousRoute: from,
redirect,
urlPath,
publicPath
})),
Promise.resolve()
)
.then(proceed)
.catch(e => {
console.error(e)
proceed()
})
})
}

View File

@@ -1,23 +0,0 @@
/* eslint-disable */
/**
* THIS FILE IS GENERATED AUTOMATICALLY.
* DO NOT EDIT.
*
* You are probably looking on adding startup/initialization code.
* Use "quasar new boot <name>" and add it there.
* One boot file per concern. Then reference the file(s) in quasar.config file > boot:
* boot: ['file', ...] // do not add ".js" extension to it.
*
* Boot files are your "main.js"
**/
import lang from 'quasar/lang/tr.js'
import {Loading,Dialog,Notify} from 'quasar'
export default { config: {"notify":{"position":"top","timeout":2500}},lang,plugins: {Loading,Dialog,Notify} }

View File

@@ -1,4 +1,4 @@
<template>
<template>
<!-- ===========================================================
🧾 ORDER ENTRY PAGE (BSSApp)
v23 Sticky-stack + Drawer uyumlu yapı
@@ -2928,8 +2928,8 @@ async function onColorChange(colorCode) {
const data = res?.data || []
if (Array.isArray(data) && data.length > 0) {
renkOptions2.value = data.map(x => ({
label: `${x.item_dim2_code || x.ItemDim2Code || ''} - ${x.color_description || x.ColorDescription || ''}`.trim(),
value: x.item_dim2_code || x.ItemDim2Code || ''
label: x.item_dim2_code,
value: x.item_dim2_code
}))
console.log('🎨 2. renk listesi yüklendi:', renkOptions2.value.length)
} else {

View File

@@ -160,7 +160,7 @@
flat
size="sm"
color="warning"
label="cdItem Bilgisi"
label="Urun Boyutlandirma"
@click="openCdItemDialog(props.row.NewItemCode)"
/>
<q-btn
@@ -184,11 +184,16 @@
:options="getColorOptions(props.row)"
option-label="colorLabel"
option-value="color_code"
use-input
fill-input
hide-selected
input-debounce="0"
emit-value
map-options
dense
filled
label="Yeni Renk"
:disable="isColorSelectionLocked(props.row)"
@update:model-value="() => onNewColorChange(props.row)"
/>
</q-td>
@@ -201,11 +206,16 @@
:options="getSecondColorOptions(props.row)"
option-label="item_dim2_label"
option-value="item_dim2_code"
use-input
fill-input
hide-selected
input-debounce="0"
emit-value
map-options
dense
filled
label="Yeni 2. Renk"
:disable="isColorSelectionLocked(props.row)"
/>
</q-td>
</template>
@@ -232,7 +242,7 @@
<q-dialog v-model="cdItemDialogOpen" persistent>
<q-card style="min-width: 980px; max-width: 98vw;">
<q-card-section class="row items-center q-pb-none">
<div class="text-h6">Yeni Kod cdItem Bilgileri</div>
<div class="text-h6">Urun Boyutlandirma</div>
<q-space />
<q-badge color="warning" text-color="black">
{{ cdItemTargetCode || '-' }}
@@ -242,60 +252,10 @@
<q-card-section class="q-pt-md">
<div class="row q-col-gutter-sm">
<div class="col-12 col-md-4">
<q-select v-model="cdItemDraftForm.ItemDimTypeCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('itemDimTypeCodes')" label="ItemDimTypeCode" />
<q-select v-model="cdItemDraftForm.ItemDimTypeCode" dense filled use-input fill-input hide-selected input-debounce="0" emit-value map-options option-label="label" option-value="value" :options="lookupOptions('itemDimTypeCodes')" label="Boyut Secenekleri" />
</div>
<div class="col-12 col-md-4">
<q-select v-model="cdItemDraftForm.ProductTypeCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('productTypeCodes')" label="ProductTypeCode" />
</div>
<div class="col-12 col-md-4">
<q-select v-model="cdItemDraftForm.ProductHierarchyID" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('productHierarchyIDs')" label="ProductHierarchyID" />
</div>
<div class="col-12 col-md-4">
<q-select v-model="cdItemDraftForm.UnitOfMeasureCode1" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('unitOfMeasureCode1List')" label="UnitOfMeasureCode1" />
</div>
<div class="col-12 col-md-4">
<q-select v-model="cdItemDraftForm.ItemAccountGrCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('itemAccountGrCodes')" label="ItemAccountGrCode" />
</div>
<div class="col-12 col-md-4">
<q-select v-model="cdItemDraftForm.ItemTaxGrCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('itemTaxGrCodes')" label="ItemTaxGrCode" />
</div>
<div class="col-12 col-md-4">
<q-select v-model="cdItemDraftForm.ItemPaymentPlanGrCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('itemPaymentPlanGrCodes')" label="ItemPaymentPlanGrCode" />
</div>
<div class="col-12 col-md-4">
<q-select v-model="cdItemDraftForm.ItemDiscountGrCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('itemDiscountGrCodes')" label="ItemDiscountGrCode" />
</div>
<div class="col-12 col-md-4">
<q-select v-model="cdItemDraftForm.ItemVendorGrCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('itemVendorGrCodes')" label="ItemVendorGrCode" />
</div>
<div class="col-12 col-md-4">
<q-select v-model="cdItemDraftForm.PromotionGroupCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('promotionGroupCodes')" label="PromotionGroupCode" />
</div>
<div class="col-12 col-md-4">
<q-select v-model="cdItemDraftForm.ProductCollectionGrCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('productCollectionGrCodes')" label="ProductCollectionGrCode" />
</div>
<div class="col-12 col-md-4">
<q-select v-model="cdItemDraftForm.StorePriceLevelCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('storePriceLevelCodes')" label="StorePriceLevelCode" />
</div>
<div class="col-12 col-md-4">
<q-select v-model="cdItemDraftForm.PerceptionOfFashionCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('perceptionOfFashionCodes')" label="PerceptionOfFashionCode" />
</div>
<div class="col-12 col-md-4">
<q-select v-model="cdItemDraftForm.CommercialRoleCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('commercialRoleCodes')" label="CommercialRoleCode" />
</div>
<div class="col-12 col-md-4">
<q-select v-model="cdItemDraftForm.StoreCapacityLevelCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('storeCapacityLevelCodes')" label="StoreCapacityLevelCode" />
</div>
<div class="col-12 col-md-6">
<q-select v-model="cdItemDraftForm.CustomsTariffNumberCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('customsTariffNumbers')" label="CustomsTariffNumberCode" />
</div>
<div class="col-12 col-md-6">
<q-select v-model="cdItemDraftForm.CompanyCode" dense filled emit-value map-options option-label="label" option-value="value" :options="lookupOptions('companyCodes')" label="CompanyCode" />
<q-select v-model="cdItemDraftForm.ProductHierarchyID" dense filled use-input fill-input hide-selected input-debounce="0" emit-value map-options option-label="label" option-value="value" :options="lookupOptions('productHierarchyIDs')" label="Urun Hiyerarsi Grubu" />
</div>
</div>
</q-card-section>
@@ -332,6 +292,11 @@
v-model="row.AttributeCode"
dense
filled
use-input
fill-input
hide-selected
input-debounce="0"
@filter="(val, update) => onFilterAttributeOption(row, val, update)"
emit-value
map-options
option-label="label"
@@ -363,8 +328,8 @@ import { normalizeSearchText } from 'src/utils/searchText'
const route = useRoute()
const $q = useQuasar()
const store = useOrderProductionItemStore()
const BAGGI_CODE_PATTERN = /^[A-Z][0-9]{3}-[A-Z]{2,3}[0-9]{5}$/
const BAGGI_CODE_ERROR = 'Girdiginiz kod BAGGI kod sistemine uyumlu degil. Format: X999-XX99999'
const BAGGI_CODE_PATTERN = /^[A-Z][0-9]{3}-[A-Z]{3}[0-9]{5}$/
const BAGGI_CODE_ERROR = 'Girdiginiz kod BAGGI kod sistemine uyumlu degil. Format: X999-XXX99999'
const orderHeaderID = computed(() => String(route.params.orderHeaderID || '').trim())
const header = computed(() => store.header || {})
@@ -446,12 +411,11 @@ const newItemEntryModeOptions = [
{ label: 'Eski Kod Sec', value: 'selected' },
{ label: 'Yeni Kod Ekle', value: 'typed' }
]
const productCodeSelectOptions = computed(() =>
(productOptions.value || []).map(p => {
const code = String(p?.ProductCode || '').trim().toUpperCase()
return { label: code, value: code }
}).filter(x => !!x.value)
}).filter(x => !!x.value && x.value.length === 13)
)
function applyNewItemVisualState (row, source = 'typed') {
@@ -494,18 +458,49 @@ function onSelectProduct (row, code) {
}
function onNewItemEntryModeChange (row, mode) {
const next = String(mode || '').trim()
row.NewItemEntryMode = next
row.NewItemEntryMode = String(mode || '').trim()
row.NewItemCode = ''
row.NewItemMode = 'empty'
row.NewItemSource = ''
row.NewColor = ''
row.NewDim2 = ''
row.NewItemMode = 'empty'
row.NewItemSource = ''
}
function escapeRegExp (value) {
return String(value || '').replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
}
function buildNextCodeFromPrefix (prefix) {
const normalizedPrefix = String(prefix || '').trim().toUpperCase()
if (!/^[A-Z][0-9]{3}-[A-Z]{3}$/.test(normalizedPrefix)) return ''
const codeRegex = new RegExp(`^${escapeRegExp(normalizedPrefix)}(\\d{5})$`)
let maxSuffix = 0
for (const p of (productOptions.value || [])) {
const code = String(p?.ProductCode || '').trim().toUpperCase()
const m = code.match(codeRegex)
if (!m) continue
const n = Number(m[1] || 0)
if (Number.isFinite(n) && n > maxSuffix) maxSuffix = n
}
const next = maxSuffix > 0 ? maxSuffix + 1 : 1
return `${normalizedPrefix}${String(next).padStart(5, '0')}`
}
function onNewItemChange (row, val, source = 'typed') {
const prevCode = String(row?.NewItemCode || '').trim().toUpperCase()
const next = String(val || '').trim().toUpperCase()
let next = String(val || '').trim().toUpperCase()
if (source === 'typed' && row?.NewItemEntryMode === 'typed' && /^[A-Z][0-9]{3}-[A-Z]{3}$/.test(next)) {
const autoCode = buildNextCodeFromPrefix(next)
if (autoCode) {
next = autoCode
$q.notify({ type: 'info', message: `Yeni kod otomatik tamamlandi: ${autoCode}` })
}
}
if (next.length > 13) {
$q.notify({ type: 'negative', message: 'Model kodu en fazla 13 karakter olabilir.' })
row.NewItemCode = next.slice(0, 13)
@@ -526,7 +521,39 @@ function onNewItemChange (row, val, source = 'typed') {
store.fetchColors(row.NewItemCode)
}
if (row.NewItemMode === 'new' && isValidBaggiModelCode(row.NewItemCode) && row.NewItemCode !== prevCode) {
openCdItemDialog(row.NewItemCode)
openNewCodeSetupFlow(row.NewItemCode)
}
}
function isAttributeDraftComplete (rows) {
if (!Array.isArray(rows) || !rows.length) return false
return rows.every(r => String(r?.AttributeCode || '').trim())
}
function isNewCodeSetupComplete (itemCode) {
const code = String(itemCode || '').trim().toUpperCase()
if (!code) return false
const hasCdItem = !!store.getCdItemDraft(code)
const attrRows = store.getProductAttributeDraft(code)
return hasCdItem && isAttributeDraftComplete(attrRows)
}
function isColorSelectionLocked (row) {
const code = String(row?.NewItemCode || '').trim().toUpperCase()
if (!code) return true
if (row?.NewItemMode !== 'new') return false
return !isNewCodeSetupComplete(code)
}
function openNewCodeSetupFlow (itemCode) {
const code = String(itemCode || '').trim().toUpperCase()
if (!code) return
if (!store.getCdItemDraft(code)) {
openCdItemDialog(code)
return
}
if (!isAttributeDraftComplete(store.getProductAttributeDraft(code))) {
openAttributeDialog(code)
}
}
@@ -543,7 +570,7 @@ function getColorOptions (row) {
const list = store.colorOptionsByCode[code] || []
return list.map(c => ({
...c,
colorLabel: `${c.color_code || c.ColorCode || ''} - ${c.color_description || c.ColorDescription || ''}`.trim()
colorLabel: `${c.color_code} - ${c.color_description || ''}`.trim()
}))
}
@@ -554,8 +581,7 @@ function getSecondColorOptions (row) {
const list = store.secondColorOptionsByKey[key] || []
return list.map(c => ({
...c,
item_dim2_code: c.item_dim2_code || c.ItemDim2Code || '',
item_dim2_label: `${c.item_dim2_code || c.ItemDim2Code || ''} - ${c.color_description || c.ColorDescription || ''}`.trim()
item_dim2_label: `${c.item_dim2_code} - ${c.color_description || ''}`.trim()
}))
}
@@ -637,36 +663,64 @@ function createEmptyCdItemDraft (itemCode) {
return {
ItemTypeCode: '1',
ItemCode: String(itemCode || '').trim().toUpperCase(),
ItemDimTypeCode: '',
ProductTypeCode: '',
ItemDimTypeCode: '1',
ProductTypeCode: '1',
ProductHierarchyID: '',
UnitOfMeasureCode1: '',
UnitOfMeasureCode1: 'AD',
ItemAccountGrCode: '',
ItemTaxGrCode: '',
ItemTaxGrCode: '10%',
ItemPaymentPlanGrCode: '',
ItemDiscountGrCode: '',
ItemVendorGrCode: '',
PromotionGroupCode: '',
ProductCollectionGrCode: '',
StorePriceLevelCode: '',
PerceptionOfFashionCode: '',
CommercialRoleCode: '',
ProductCollectionGrCode: '0',
StorePriceLevelCode: '0',
PerceptionOfFashionCode: '0',
CommercialRoleCode: '0',
StoreCapacityLevelCode: '',
CustomsTariffNumberCode: '',
CompanyCode: ''
CompanyCode: '1'
}
}
function lookupOptions (key) {
if (key === 'itemDimTypeCodes') {
return [
{ value: '1', label: '1 - RENK' },
{ value: '2', label: '2 - RENK-BEDEN' },
{ value: '3', label: '3 - RENK-BEDEN-YAKA' }
]
}
const list = store.cdItemLookups?.[key] || []
return list.map(x => {
const code = String(x?.code || '').trim()
const desc = String(x?.description || '').trim()
return {
value: code,
label: desc ? `${code} - ${desc}` : code
}
})
return list
.map(x => {
const code = String(x?.code || '').trim()
const desc = String(x?.description || '').trim()
return {
value: code,
label: desc ? `${code} - ${desc}` : code,
_desc: desc
}
})
.filter(opt => !isDummyLookupOption(key, opt.value, opt._desc))
.map(({ value, label }) => ({ value, label }))
}
function isDummyLookupOption (key, codeRaw, descRaw) {
const code = String(codeRaw || '').trim().toUpperCase()
const desc = String(descRaw || '').trim().toUpperCase()
if (!code) return true
if (code === '0' || code === '00' || code === '000' || code === '0000') return true
if (desc.includes('DUMMY')) return true
// Is plani dokumanindaki sari/default alanlar
if (key === 'unitOfMeasureCode1List' && code === 'AD') return true
if (key === 'itemTaxGrCodes' && code === '10%') return true
if (key === 'companyCodes' && code === '1') return true
return false
}
async function openCdItemDialog (itemCode) {
@@ -700,27 +754,27 @@ function normalizeCdItemDraftForPayload (draftRaw) {
return {
ItemTypeCode: toIntOrNil(d.ItemTypeCode) || 1,
ItemCode: String(d.ItemCode || '').trim().toUpperCase(),
ItemDimTypeCode: toIntOrNil(d.ItemDimTypeCode),
ProductTypeCode: toIntOrNil(d.ProductTypeCode),
ItemDimTypeCode: toIntOrNil(d.ItemDimTypeCode) || 1,
ProductTypeCode: 1,
ProductHierarchyID: toIntOrNil(d.ProductHierarchyID),
UnitOfMeasureCode1: toStrOrNil(d.UnitOfMeasureCode1),
ItemAccountGrCode: toStrOrNil(d.ItemAccountGrCode),
ItemTaxGrCode: toStrOrNil(d.ItemTaxGrCode),
ItemPaymentPlanGrCode: toStrOrNil(d.ItemPaymentPlanGrCode),
ItemDiscountGrCode: toStrOrNil(d.ItemDiscountGrCode),
ItemVendorGrCode: toStrOrNil(d.ItemVendorGrCode),
PromotionGroupCode: toStrOrNil(d.PromotionGroupCode),
ProductCollectionGrCode: toStrOrNil(d.ProductCollectionGrCode),
StorePriceLevelCode: toStrOrNil(d.StorePriceLevelCode),
PerceptionOfFashionCode: toStrOrNil(d.PerceptionOfFashionCode),
CommercialRoleCode: toStrOrNil(d.CommercialRoleCode),
StoreCapacityLevelCode: toStrOrNil(d.StoreCapacityLevelCode),
CustomsTariffNumberCode: toStrOrNil(d.CustomsTariffNumberCode),
CompanyCode: toStrOrNil(d.CompanyCode)
UnitOfMeasureCode1: 'AD',
ItemAccountGrCode: null,
ItemTaxGrCode: '10%',
ItemPaymentPlanGrCode: null,
ItemDiscountGrCode: null,
ItemVendorGrCode: null,
PromotionGroupCode: null,
ProductCollectionGrCode: '0',
StorePriceLevelCode: '0',
PerceptionOfFashionCode: '0',
CommercialRoleCode: '0',
StoreCapacityLevelCode: null,
CustomsTariffNumberCode: null,
CompanyCode: '1'
}
}
function saveCdItemDraft () {
async function saveCdItemDraft () {
const payload = normalizeCdItemDraftForPayload(cdItemDraftForm.value)
if (!payload.ItemCode) {
$q.notify({ type: 'negative', message: 'ItemCode bos olamaz.' })
@@ -728,31 +782,7 @@ function saveCdItemDraft () {
}
store.setCdItemDraft(payload.ItemCode, payload)
cdItemDialogOpen.value = false
}
function createDummyAttributeRows () {
const sharedOptions = [
{ value: 'DAMATLIK', label: 'DAMATLIK - DAMATLIK' },
{ value: 'TAKIM', label: 'TAKIM - TAKIM ELBISE' },
{ value: 'CEKET', label: 'CEKET - CEKET' },
{ value: 'PANTOLON', label: 'PANTOLON - PANTOLON' }
]
const rows = [{
AttributeTypeCodeNumber: 1,
TypeLabel: '1-001 Urun Ana Grubu',
AttributeCode: '',
Options: sharedOptions
}]
for (let i = 2; i <= 50; i++) {
const code = String(i).padStart(3, '0')
rows.push({
AttributeTypeCodeNumber: i,
TypeLabel: `1-${code} Dummy Ozellik ${i}`,
AttributeCode: '',
Options: sharedOptions
})
}
return rows
await openAttributeDialog(payload.ItemCode)
}
function buildAttributeRowsFromLookup (list) {
@@ -780,13 +810,31 @@ function buildAttributeRowsFromLookup (list) {
.sort((a, b) => a.typeCode - b.typeCode)
.map(g => ({
AttributeTypeCodeNumber: g.typeCode,
TypeLabel: `${g.typeCode}-${g.typeDesc}`,
TypeLabel: `${g.typeCode} - ${g.typeDesc}`,
AttributeCode: '',
Options: g.options
AllOptions: [...g.options],
Options: [...g.options]
}))
return rows
}
function onFilterAttributeOption (row, val, update) {
const raw = String(val || '')
const needle = normalizeSearchText(raw)
const base = Array.isArray(row?.AllOptions) ? row.AllOptions : (Array.isArray(row?.Options) ? row.Options : [])
update(() => {
if (!needle) {
row.Options = [...base]
return
}
row.Options = base.filter(opt => {
const label = normalizeSearchText(opt?.label || '')
const value = normalizeSearchText(opt?.value || '')
return label.includes(needle) || value.includes(needle)
})
})
}
async function openAttributeDialog (itemCode) {
const code = String(itemCode || '').trim().toUpperCase()
if (!code) return
@@ -794,10 +842,22 @@ async function openAttributeDialog (itemCode) {
const existing = store.getProductAttributeDraft(code)
const fetched = await store.fetchProductAttributes(1)
const fromLookup = buildAttributeRowsFromLookup(fetched)
const baseRows = fromLookup.length ? fromLookup : createDummyAttributeRows()
if (!fromLookup.length) {
$q.notify({ type: 'negative', message: 'Urun ozellikleri listesi alinamadi. Lutfen daha sonra tekrar deneyin.' })
return
}
const baseRows = fromLookup
attributeRows.value = Array.isArray(existing) && existing.length
? JSON.parse(JSON.stringify(existing))
: baseRows
for (const row of (attributeRows.value || [])) {
if (!Array.isArray(row.AllOptions)) {
row.AllOptions = Array.isArray(row.Options) ? [...row.Options] : []
}
if (!Array.isArray(row.Options)) {
row.Options = [...row.AllOptions]
}
}
attributeDialogOpen.value = true
}
@@ -945,15 +1005,15 @@ function groupItems (items, prevRows = []) {
const prevMap = new Map()
for (const r of prevRows || []) {
if (!r?.RowKey) continue
prevMap.set(r.RowKey, {
NewDesc: String(r.NewDesc || '').trim(),
NewItemCode: String(r.NewItemCode || '').trim().toUpperCase(),
NewColor: String(r.NewColor || '').trim().toUpperCase(),
NewDim2: String(r.NewDim2 || '').trim().toUpperCase(),
NewItemMode: String(r.NewItemMode || '').trim(),
NewItemSource: String(r.NewItemSource || '').trim(),
NewItemEntryMode: String(r.NewItemEntryMode || '').trim()
})
prevMap.set(r.RowKey, {
NewDesc: String(r.NewDesc || '').trim(),
NewItemCode: String(r.NewItemCode || '').trim().toUpperCase(),
NewColor: String(r.NewColor || '').trim().toUpperCase(),
NewDim2: String(r.NewDim2 || '').trim().toUpperCase(),
NewItemMode: String(r.NewItemMode || '').trim(),
NewItemSource: String(r.NewItemSource || '').trim(),
NewItemEntryMode: String(r.NewItemEntryMode || '').trim()
})
}
const map = new Map()

View File

@@ -182,7 +182,15 @@ export const useOrderProductionItemStore = defineStore('orderproductionitems', {
this.cdItemLookups = res?.data || null
return this.cdItemLookups
} catch (err) {
this.error = err?.response?.data || err?.message || 'cdItem lookup listesi alinamadi'
const rid =
err?.response?.headers?.['x-debug-request-id'] ||
err?.response?.data?.requestId ||
''
logApiError('fetchCdItemLookups', err, { force, requestId: rid })
if (rid) {
console.error(`[OrderProductionItemStore] fetchCdItemLookups requestId=${rid}`)
}
this.error = extractApiErrorMessage(err, 'cdItem lookup listesi alinamadi')
return null
}
},

View File

@@ -1899,7 +1899,7 @@ export const useOrderEntryStore = defineStore('orderentry', {
const girilen = Number(form.fiyat || 0)
if (minFiyat > 0 && girilen < minFiyat && $q) {
if (minFiyat > 0 && girilen > 0 && girilen < minFiyat && $q) {
fiyatOK = await new Promise(resolve => {
$q.dialog({
title: 'Fiyat Uyarısı',
@@ -3644,16 +3644,7 @@ export const useOrderEntryStore = defineStore('orderentry', {
continue
}
// AKSBIR / bedensiz satırda kaynak adet bazen `row.adet`te tutuluyor.
// Bu fallback yoksa ItemDim1Code='' satırı Qty1=0 düşebiliyor.
const qty = toNum(
row.qty ??
row.Qty1 ??
row.miktar ??
row.adet ??
row.Adet ??
0
)
const qty = toNum(row.qty ?? row.Qty1 ?? row.miktar ?? 0)
// ✅ ComboKey stabil: bedenKey = '_'
const bedenKey = '_'