Merge remote-tracking branch 'origin/master'

This commit is contained in:
M_Kececi
2026-03-04 13:20:58 +03:00
parent 4dc0415546
commit 96d782e474
17 changed files with 1946 additions and 565 deletions

View File

@@ -561,6 +561,18 @@ func InitRoutes(pgDB *sql.DB, mssql *sql.DB, ml *mailer.GraphMailer) *mux.Router
wrapV3(http.HandlerFunc(routes.GetProductStockQueryHandler)),
)
bindV3(r, pgDB,
"/api/product-stock-attribute-options", "GET",
"order", "view",
wrapV3(http.HandlerFunc(routes.GetProductStockAttributeOptionsHandler)),
)
bindV3(r, pgDB,
"/api/product-stock-query-by-attributes", "GET",
"order", "view",
wrapV3(http.HandlerFunc(routes.GetProductStockQueryByAttributesHandler)),
)
bindV3(r, pgDB,
"/api/product-images", "GET",
"order", "view",

View File

@@ -2,6 +2,7 @@ package queries
import (
"database/sql"
"strconv"
"bssapp-backend/models"
)
@@ -156,7 +157,16 @@ FROM dbo.prItemVariant WITH (UPDLOCK, HOLDLOCK)
}
var inserted int64
ensuredItems := make(map[string]struct{}, len(missing))
for i, v := range missing {
itemKey := strconv.FormatInt(int64(v.ItemTypeCode), 10) + "|" + v.ItemCode
if _, ok := ensuredItems[itemKey]; !ok {
if err := ensureCdItemTx(tx, v.ItemTypeCode, v.ItemCode, username); err != nil {
return inserted, err
}
ensuredItems[itemKey] = struct{}{}
}
plu := basePlu + int64(i) + 1
res, err := tx.Exec(`
IF NOT EXISTS (
@@ -197,6 +207,93 @@ VALUES (
return inserted, nil
}
func ensureCdItemTx(tx *sql.Tx, itemTypeCode int16, itemCode string, username string) error {
_, err := tx.Exec(`
IF NOT EXISTS (
SELECT 1
FROM dbo.cdItem
WHERE ItemTypeCode = @p1
AND ItemCode = @p2
)
BEGIN
;WITH Template AS (
SELECT TOP 1
ItemDimTypeCode, ProductTypeCode, ProductHierarchyID,
UnitOfMeasureCode1, UnitOfMeasureCode2, UnitConvertRate, UnitConvertRateNotFixed,
UseInternet, UsePOS, UseStore, EnablePartnerCompanies, UseManufacturing, UseSerialNumber,
GenerateOpticalDataMatrixCode, ByWeight, SupplyPeriod, GuaranteePeriod, ShelfLife, OrderLeadTime,
ItemAccountGrCode, ItemTaxGrCode, ItemPaymentPlanGrCode, ItemDiscountGrCode, ItemVendorGrCode,
PromotionGroupCode, PromotionGroupCode2, ProductCollectionGrCode, StorePriceLevelCode, PerceptionOfFashionCode,
CommercialRoleCode, StoreCapacityLevelCode, CustomsTariffNumberCode, IsFixedExpense, BOMEntityCode, CompanyCode,
IsBlocked, IsLocked, LockedDate, IsSalesOrderClosed, IsPurchaseOrderClosed, UseRoll, UseBatch,
MaxCreditCardInstallmentCount, GenerateSerialNumber, IsSubsequentDeliveryForR, IsSubsequentDeliveryForRI,
IGACommissionGroup, UniFreeCommissionGroup, CustomsProductGroupCode, IsUTSDeclaratedItem, IsStoreOrderClosed
FROM dbo.cdItem WITH (UPDLOCK, HOLDLOCK)
WHERE ItemTypeCode = @p1
AND ItemCode LIKE 'U%'
ORDER BY CreatedDate DESC
)
INSERT INTO dbo.cdItem (
ItemTypeCode, ItemCode,
ItemDimTypeCode, ProductTypeCode, ProductHierarchyID,
UnitOfMeasureCode1, UnitOfMeasureCode2, UnitConvertRate, UnitConvertRateNotFixed,
UseInternet, UsePOS, UseStore, EnablePartnerCompanies, UseManufacturing, UseSerialNumber,
GenerateOpticalDataMatrixCode, ByWeight, SupplyPeriod, GuaranteePeriod, ShelfLife, OrderLeadTime,
ItemAccountGrCode, ItemTaxGrCode, ItemPaymentPlanGrCode, ItemDiscountGrCode, ItemVendorGrCode,
PromotionGroupCode, PromotionGroupCode2, ProductCollectionGrCode, StorePriceLevelCode, PerceptionOfFashionCode,
CommercialRoleCode, StoreCapacityLevelCode, CustomsTariffNumberCode, IsFixedExpense, BOMEntityCode, CompanyCode,
IsBlocked, IsLocked, LockedDate, IsSalesOrderClosed, IsPurchaseOrderClosed,
CreatedUserName, CreatedDate, LastUpdatedUserName, LastUpdatedDate, RowGuid,
UseRoll, UseBatch, MaxCreditCardInstallmentCount, GenerateSerialNumber,
IsSubsequentDeliveryForR, IsSubsequentDeliveryForRI,
IGACommissionGroup, UniFreeCommissionGroup, CustomsProductGroupCode, IsUTSDeclaratedItem, IsStoreOrderClosed
)
SELECT
@p1, @p2,
t.ItemDimTypeCode, t.ProductTypeCode, t.ProductHierarchyID,
t.UnitOfMeasureCode1, t.UnitOfMeasureCode2, t.UnitConvertRate, t.UnitConvertRateNotFixed,
t.UseInternet, t.UsePOS, t.UseStore, t.EnablePartnerCompanies, t.UseManufacturing, t.UseSerialNumber,
t.GenerateOpticalDataMatrixCode, t.ByWeight, t.SupplyPeriod, t.GuaranteePeriod, t.ShelfLife, t.OrderLeadTime,
t.ItemAccountGrCode, t.ItemTaxGrCode, t.ItemPaymentPlanGrCode, t.ItemDiscountGrCode, t.ItemVendorGrCode,
t.PromotionGroupCode, t.PromotionGroupCode2, t.ProductCollectionGrCode, t.StorePriceLevelCode, t.PerceptionOfFashionCode,
t.CommercialRoleCode, t.StoreCapacityLevelCode, t.CustomsTariffNumberCode, t.IsFixedExpense, t.BOMEntityCode, t.CompanyCode,
t.IsBlocked, t.IsLocked, t.LockedDate, t.IsSalesOrderClosed, t.IsPurchaseOrderClosed,
@p3, GETDATE(), @p3, GETDATE(), NEWID(),
t.UseRoll, t.UseBatch, t.MaxCreditCardInstallmentCount, t.GenerateSerialNumber,
t.IsSubsequentDeliveryForR, t.IsSubsequentDeliveryForRI,
t.IGACommissionGroup, t.UniFreeCommissionGroup, t.CustomsProductGroupCode, t.IsUTSDeclaratedItem, t.IsStoreOrderClosed
FROM Template t;
IF @@ROWCOUNT = 0
BEGIN
INSERT INTO dbo.cdItem (
ItemTypeCode, ItemCode,
ItemDimTypeCode, ProductTypeCode, ProductHierarchyID,
UnitOfMeasureCode1, UnitConvertRate, UnitConvertRateNotFixed,
UseInternet, UsePOS, UseStore, EnablePartnerCompanies, UseManufacturing, UseSerialNumber,
GenerateOpticalDataMatrixCode, ByWeight, SupplyPeriod, GuaranteePeriod, ShelfLife, OrderLeadTime,
IsFixedExpense, IsBlocked, IsLocked, LockedDate, IsSalesOrderClosed, IsPurchaseOrderClosed,
CreatedUserName, CreatedDate, LastUpdatedUserName, LastUpdatedDate, RowGuid,
UseRoll, UseBatch, MaxCreditCardInstallmentCount, GenerateSerialNumber,
IsSubsequentDeliveryForR, IsSubsequentDeliveryForRI, IsUTSDeclaratedItem, IsStoreOrderClosed
)
VALUES (
@p1, @p2,
2, 1, 2,
'AD', 0, 0,
0, 1, 1, 0, 1, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, '1900-01-01', 0, 0,
@p3, GETDATE(), @p3, GETDATE(), NEWID(),
0, 0, 12, 0,
0, 0, 0, 0
);
END
END
`, itemTypeCode, itemCode, username)
return err
}
func UpdateOrderLinesTx(tx *sql.Tx, orderHeaderID string, lines []models.OrderProductionUpdateLine, username string) (int64, error) {
var updated int64
for _, line := range lines {

View File

@@ -1,11 +1,11 @@
package queries
// GetProductStockQuery:
// Ürün kodu bazlı, optimize stok + attribute sorgusu.
// Urun kodu bazli, STOCK/PICK/RESERVE/DISP ayrik CTE ile optimize sorgu.
const GetProductStockQuery = `
DECLARE @ProductCode NVARCHAR(50) = @p1;
;WITH INV AS
;WITH STOCK AS
(
SELECT
CompanyCode,
@@ -19,180 +19,216 @@ DECLARE @ProductCode NVARCHAR(50) = @p1;
ItemDim1Code,
ItemDim2Code,
ItemDim3Code,
SUM(PickingQty1) AS PickingQty1,
SUM(ReserveQty1) AS ReserveQty1,
SUM(DispOrderQty1) AS DispOrderQty1,
SUM(InventoryQty1) AS InventoryQty1
FROM
(
SELECT
CompanyCode, OfficeCode, StoreTypeCode, StoreCode, WarehouseCode,
ItemTypeCode, ItemCode, ColorCode, ItemDim1Code, ItemDim2Code, ItemDim3Code,
Qty1 AS PickingQty1, 0 AS ReserveQty1, 0 AS DispOrderQty1, 0 AS InventoryQty1
FROM PickingStates
WHERE ItemTypeCode = 1
AND ItemCode = @ProductCode
AND LEN(ItemCode) = 13
AND LEN(@ProductCode) = 13
UNION ALL
SELECT
CompanyCode, OfficeCode, StoreTypeCode, StoreCode, WarehouseCode,
ItemTypeCode, ItemCode, ColorCode, ItemDim1Code, ItemDim2Code, ItemDim3Code,
0, Qty1, 0, 0
FROM ReserveStates
WHERE ItemTypeCode = 1
AND ItemCode = @ProductCode
AND LEN(ItemCode) = 13
AND LEN(@ProductCode) = 13
UNION ALL
SELECT
CompanyCode, OfficeCode, StoreTypeCode, StoreCode, WarehouseCode,
ItemTypeCode, ItemCode, ColorCode, ItemDim1Code, ItemDim2Code, ItemDim3Code,
0, 0, Qty1, 0
FROM DispOrderStates
WHERE ItemTypeCode = 1
AND ItemCode = @ProductCode
AND LEN(ItemCode) = 13
AND LEN(@ProductCode) = 13
UNION ALL
SELECT
CompanyCode, OfficeCode, StoreTypeCode, StoreCode, WarehouseCode,
ItemTypeCode, ItemCode, ColorCode, ItemDim1Code, ItemDim2Code, ItemDim3Code,
0, 0, 0, SUM(In_Qty1 - Out_Qty1)
FROM trStock WITH (NOLOCK)
WHERE ItemTypeCode = 1
AND ItemCode = @ProductCode
AND LEN(ItemCode) = 13
AND LEN(@ProductCode) = 13
GROUP BY
CompanyCode, OfficeCode, StoreTypeCode, StoreCode, WarehouseCode,
ItemTypeCode, ItemCode, ColorCode, ItemDim1Code, ItemDim2Code, ItemDim3Code
) X
GROUP BY
CompanyCode, OfficeCode, StoreTypeCode, StoreCode, WarehouseCode,
ItemTypeCode, ItemCode, ColorCode, ItemDim1Code, ItemDim2Code, ItemDim3Code
),
Attr AS
(
SELECT TOP 1
ProductCode,
ProductDescription,
ProductAtt01Desc,
ProductAtt02Desc,
ProductAtt10Desc,
ProductAtt11Desc,
ProductAtt21Desc,
ProductAtt22Desc,
ProductAtt23Desc,
ProductAtt24Desc,
ProductAtt25Desc,
ProductAtt26Desc,
ProductAtt27Desc,
ProductAtt28Desc,
ProductAtt29Desc,
ProductAtt30Desc,
ProductAtt31Desc,
ProductAtt32Desc,
ProductAtt33Desc,
ProductAtt34Desc,
ProductAtt35Desc,
ProductAtt36Desc,
ProductAtt37Desc,
ProductAtt38Desc,
ProductAtt39Desc,
ProductAtt40Desc,
ProductAtt41Desc,
ProductAtt42Desc,
ProductAtt43Desc,
ProductAtt44Desc,
ProductAtt45Desc,
ProductAtt46Desc
FROM ProductFilterWithDescription('TR')
WHERE ProductCode = @ProductCode
AND LEN(ProductCode) = 13
AND LEN(@ProductCode) = 13
),
Price AS
(
SELECT TOP 1
Price
FROM prItemBasePrice WITH (NOLOCK)
SUM(In_Qty1 - Out_Qty1) AS InventoryQty1
FROM trStock WITH(NOLOCK)
WHERE ItemTypeCode = 1
AND ItemCode = @ProductCode
AND LEN(ItemCode) = 13
AND LEN(@ProductCode) = 13
ORDER BY PriceDate DESC
GROUP BY
CompanyCode, OfficeCode, StoreTypeCode, StoreCode, WarehouseCode,
ItemTypeCode, ItemCode, ColorCode,
ItemDim1Code, ItemDim2Code, ItemDim3Code
),
PICK AS
(
SELECT
CompanyCode, OfficeCode, StoreTypeCode, StoreCode, WarehouseCode,
ItemTypeCode, ItemCode, ColorCode,
ItemDim1Code, ItemDim2Code, ItemDim3Code,
SUM(Qty1) AS PickingQty1
FROM PickingStates
WHERE ItemTypeCode = 1
AND ItemCode = @ProductCode
AND LEN(ItemCode) = 13
AND LEN(@ProductCode) = 13
GROUP BY
CompanyCode, OfficeCode, StoreTypeCode, StoreCode, WarehouseCode,
ItemTypeCode, ItemCode, ColorCode,
ItemDim1Code, ItemDim2Code, ItemDim3Code
),
RESERVE AS
(
SELECT
CompanyCode, OfficeCode, StoreTypeCode, StoreCode, WarehouseCode,
ItemTypeCode, ItemCode, ColorCode,
ItemDim1Code, ItemDim2Code, ItemDim3Code,
SUM(Qty1) AS ReserveQty1
FROM ReserveStates
WHERE ItemTypeCode = 1
AND ItemCode = @ProductCode
AND LEN(ItemCode) = 13
AND LEN(@ProductCode) = 13
GROUP BY
CompanyCode, OfficeCode, StoreTypeCode, StoreCode, WarehouseCode,
ItemTypeCode, ItemCode, ColorCode,
ItemDim1Code, ItemDim2Code, ItemDim3Code
),
DISP AS
(
SELECT
CompanyCode, OfficeCode, StoreTypeCode, StoreCode, WarehouseCode,
ItemTypeCode, ItemCode, ColorCode,
ItemDim1Code, ItemDim2Code, ItemDim3Code,
SUM(Qty1) AS DispOrderQty1
FROM DispOrderStates
WHERE ItemTypeCode = 1
AND ItemCode = @ProductCode
AND LEN(ItemCode) = 13
AND LEN(@ProductCode) = 13
GROUP BY
CompanyCode, OfficeCode, StoreTypeCode, StoreCode, WarehouseCode,
ItemTypeCode, ItemCode, ColorCode,
ItemDim1Code, ItemDim2Code, ItemDim3Code
)
SELECT
I.WarehouseCode AS Depo_Kodu,
S.WarehouseCode AS Depo_Kodu,
W.WarehouseDescription AS Depo_Adi,
IT.ItemTypeDescription AS InventoryType,
I.ItemCode AS Urun_Kodu,
A.ProductDescription AS Madde_Aciklamasi,
I.ColorCode AS Renk_Kodu,
bsItemTypeDesc.ItemTypeDescription AS InventoryType,
S.ItemCode AS Urun_Kodu,
P.ProductDescription AS Madde_Aciklamasi,
S.ColorCode AS Renk_Kodu,
C.ColorDescription AS Renk_Aciklamasi,
I.ItemDim1Code AS Beden,
I.ItemDim2Code AS Yaka,
ROUND(I.InventoryQty1 - I.PickingQty1 - I.ReserveQty1 - I.DispOrderQty1, U.RoundDigit) AS Kullanilabilir_Envanter,
A.ProductAtt01Desc AS URUN_ANA_GRUBU,
A.ProductAtt02Desc AS URUN_ALT_GRUBU,
A.ProductAtt10Desc AS MARKA,
A.ProductAtt11Desc AS DR,
A.ProductAtt21Desc AS KALIP,
A.ProductAtt22Desc AS IKINCI_PARCA_KALIP,
A.ProductAtt23Desc AS PACA_GENISLIGI,
A.ProductAtt24Desc AS UCUNCU_PARCA_KALIP,
A.ProductAtt25Desc AS UCUNCU_PARCA_MODEL,
A.ProductAtt26Desc AS BIRINCI_PARCA_KUMAS,
A.ProductAtt27Desc AS IKINCI_PARCA_KUMAS,
A.ProductAtt28Desc AS UCUNCU_PARCA_KUMAS,
A.ProductAtt29Desc AS BIRINCI_PARCA_KARISIM,
A.ProductAtt30Desc AS IKINCI_PARCA_KARISIM,
A.ProductAtt31Desc AS UCUNCU_PARCA_KARISIM,
A.ProductAtt32Desc AS YAKA_TIPI,
A.ProductAtt33Desc AS DUGME,
A.ProductAtt34Desc AS YIRTMAC,
A.ProductAtt35Desc AS SEZON_YILI,
A.ProductAtt36Desc AS MEVSIM,
A.ProductAtt37Desc AS TABAN,
A.ProductAtt38Desc AS BIRINCI_PARCA_FIT,
A.ProductAtt39Desc AS IKINCI_PARCA_FIT,
A.ProductAtt40Desc AS BOS2,
A.ProductAtt41Desc AS KISA_KAR,
A.ProductAtt42Desc AS SERI_FASON,
A.ProductAtt43Desc AS STOK_GIRIS_YONTEMI,
A.ProductAtt44Desc AS YETISKIN_GARSON,
A.ProductAtt45Desc AS ASKILI_YAN,
A.ProductAtt46Desc AS BOS3,
P.Price AS Fiyat
FROM INV I
JOIN cdItem CI WITH (NOLOCK)
ON CI.ItemTypeCode = I.ItemTypeCode
AND CI.ItemCode = I.ItemCode
LEFT JOIN cdUnitOfMeasure U WITH (NOLOCK)
ON U.UnitOfMeasureCode = CI.UnitOfMeasureCode1
LEFT JOIN cdWarehouseDesc W WITH (NOLOCK)
ON W.WarehouseCode = I.WarehouseCode
AND W.LangCode = 'TR'
LEFT JOIN bsItemTypeDesc IT WITH (NOLOCK)
ON IT.ItemTypeCode = I.ItemTypeCode
AND IT.LangCode = 'TR'
LEFT JOIN cdColorDesc C WITH (NOLOCK)
ON C.ColorCode = I.ColorCode
AND C.LangCode = 'TR'
CROSS JOIN Attr A
OUTER APPLY (SELECT TOP 1 Price FROM Price) P
S.ItemDim1Code AS Beden,
S.ItemDim2Code AS Yaka,
ROUND(
S.InventoryQty1
- ISNULL(PK.PickingQty1,0)
- ISNULL(RS.ReserveQty1,0)
- ISNULL(DP.DispOrderQty1,0),
cdUnitOfMeasure.RoundDigit
) AS Kullanilabilir_Envanter,
P.ProductAtt01Desc AS URUN_ANA_GRUBU,
P.ProductAtt02Desc AS URUN_ALT_GRUBU,
P.ProductAtt10Desc AS MARKA,
P.ProductAtt11Desc AS DR,
P.ProductAtt21Desc AS KALIP,
P.ProductAtt22Desc AS IKINCI_PARCA_KALIP,
P.ProductAtt23Desc AS PACA_GENISLIGI,
P.ProductAtt24Desc AS UCUNCU_PARCA_KALIP,
P.ProductAtt25Desc AS UCUNCU_PARCA_MODEL,
P.ProductAtt26Desc AS BIRINCI_PARCA_KUMAS,
P.ProductAtt27Desc AS IKINCI_PARCA_KUMAS,
P.ProductAtt28Desc AS UCUNCU_PARCA_KUMAS,
P.ProductAtt29Desc AS BIRINCI_PARCA_KARISIM,
P.ProductAtt30Desc AS IKINCI_PARCA_KARISIM,
P.ProductAtt31Desc AS UCUNCU_PARCA_KARISIM,
P.ProductAtt32Desc AS YAKA_TIPI,
P.ProductAtt33Desc AS DUGME,
P.ProductAtt34Desc AS YIRTMAC,
P.ProductAtt35Desc AS SEZON_YILI,
P.ProductAtt36Desc AS MEVSIM,
P.ProductAtt37Desc AS TABAN,
P.ProductAtt38Desc AS BIRINCI_PARCA_FIT,
P.ProductAtt39Desc AS IKINCI_PARCA_FIT,
P.ProductAtt40Desc AS BOS2,
P.ProductAtt41Desc AS KISA_KAR,
P.ProductAtt42Desc AS SERI_FASON,
P.ProductAtt43Desc AS STOK_GIRIS_YONTEMI,
P.ProductAtt44Desc AS YETISKIN_GARSON,
P.ProductAtt45Desc AS ASKILI_YAN,
P.ProductAtt46Desc AS BOS3,
prFilteredBasePrice.Price AS Fiyat
FROM STOCK S
LEFT JOIN PICK PK
ON PK.CompanyCode=S.CompanyCode
AND PK.OfficeCode=S.OfficeCode
AND PK.StoreTypeCode=S.StoreTypeCode
AND PK.StoreCode=S.StoreCode
AND PK.WarehouseCode=S.WarehouseCode
AND PK.ItemTypeCode=S.ItemTypeCode
AND PK.ItemCode=S.ItemCode
AND PK.ColorCode=S.ColorCode
AND PK.ItemDim1Code=S.ItemDim1Code
AND PK.ItemDim2Code=S.ItemDim2Code
AND PK.ItemDim3Code=S.ItemDim3Code
LEFT JOIN RESERVE RS
ON RS.CompanyCode=S.CompanyCode
AND RS.OfficeCode=S.OfficeCode
AND RS.StoreTypeCode=S.StoreTypeCode
AND RS.StoreCode=S.StoreCode
AND RS.WarehouseCode=S.WarehouseCode
AND RS.ItemTypeCode=S.ItemTypeCode
AND RS.ItemCode=S.ItemCode
AND RS.ColorCode=S.ColorCode
AND RS.ItemDim1Code=S.ItemDim1Code
AND RS.ItemDim2Code=S.ItemDim2Code
AND RS.ItemDim3Code=S.ItemDim3Code
LEFT JOIN DISP DP
ON DP.CompanyCode=S.CompanyCode
AND DP.OfficeCode=S.OfficeCode
AND DP.StoreTypeCode=S.StoreTypeCode
AND DP.StoreCode=S.StoreCode
AND DP.WarehouseCode=S.WarehouseCode
AND DP.ItemTypeCode=S.ItemTypeCode
AND DP.ItemCode=S.ItemCode
AND DP.ColorCode=S.ColorCode
AND DP.ItemDim1Code=S.ItemDim1Code
AND DP.ItemDim2Code=S.ItemDim2Code
AND DP.ItemDim3Code=S.ItemDim3Code
JOIN cdItem WITH(NOLOCK)
ON S.ItemCode = cdItem.ItemCode
AND S.ItemTypeCode = cdItem.ItemTypeCode
LEFT JOIN cdUnitOfMeasure WITH(NOLOCK)
ON cdItem.UnitOfMeasureCode1 = cdUnitOfMeasure.UnitOfMeasureCode
LEFT JOIN ProductFilterWithDescription('TR') P
ON P.ProductCode = S.ItemCode
LEFT JOIN bsItemTypeDesc WITH(NOLOCK)
ON bsItemTypeDesc.ItemTypeCode = S.ItemTypeCode
AND bsItemTypeDesc.LangCode='TR'
LEFT JOIN cdWarehouseDesc W WITH(NOLOCK)
ON W.WarehouseCode = S.WarehouseCode
AND W.LangCode='TR'
LEFT JOIN cdColorDesc C WITH(NOLOCK)
ON C.ColorCode = S.ColorCode
AND C.LangCode='TR'
LEFT JOIN (
SELECT
ItemCode,
ItemTypeCode,
Price,
ROW_NUMBER() OVER (PARTITION BY ItemCode, ItemTypeCode ORDER BY PriceDate DESC) AS RowNum
FROM prItemBasePrice WITH(NOLOCK)
) prFilteredBasePrice
ON prFilteredBasePrice.ItemCode = S.ItemCode
AND prFilteredBasePrice.ItemTypeCode = S.ItemTypeCode
AND prFilteredBasePrice.RowNum = 1
WHERE
I.ItemTypeCode = 1
AND I.ItemCode = @ProductCode
AND LEN(I.ItemCode) = 13
S.ItemTypeCode IN (1)
AND S.ItemCode = @ProductCode
AND LEN(S.ItemCode) = 13
AND LEN(@ProductCode) = 13
AND (I.InventoryQty1 - I.PickingQty1 - I.ReserveQty1 - I.DispOrderQty1) > 0
AND CI.IsBlocked = 0
AND I.WarehouseCode IN
AND (
S.InventoryQty1
- ISNULL(PK.PickingQty1,0)
- ISNULL(RS.ReserveQty1,0)
- ISNULL(DP.DispOrderQty1,0)
) > 0
AND cdItem.IsBlocked = 0
AND S.WarehouseCode IN
(
'1-0-14','1-0-10','1-0-8','1-2-5','1-2-4','1-0-12','100','1-0-28',
'1-0-24','1-2-6','1-1-14','1-0-2','1-0-52','1-1-2','1-0-21','1-1-3',

View File

@@ -0,0 +1,239 @@
package queries
// GetProductStockAttributeOptionsQuery:
// Urun ozellik filtre secenekleri (distinct aciklamalar).
const GetProductStockAttributeOptionsQuery = `
WITH PF AS
(
SELECT
LTRIM(RTRIM(ProductAtt01Desc)) AS ProductAtt01Desc,
LTRIM(RTRIM(ProductAtt02Desc)) AS ProductAtt02Desc,
LTRIM(RTRIM(ProductAtt10Desc)) AS ProductAtt10Desc,
LTRIM(RTRIM(ProductAtt11Desc)) AS ProductAtt11Desc,
LTRIM(RTRIM(ProductAtt21Desc)) AS ProductAtt21Desc,
LTRIM(RTRIM(ProductAtt35Desc)) AS ProductAtt35Desc,
LTRIM(RTRIM(ProductAtt36Desc)) AS ProductAtt36Desc,
LTRIM(RTRIM(ProductAtt44Desc)) AS ProductAtt44Desc
FROM ProductFilterWithDescription('TR')
WHERE LEN(ProductCode) = 13
)
SELECT 'att01' AS FieldName, ProductAtt01Desc AS FieldValue FROM PF WHERE ProductAtt01Desc <> '' GROUP BY ProductAtt01Desc
UNION ALL
SELECT 'att02', ProductAtt02Desc FROM PF WHERE ProductAtt02Desc <> '' GROUP BY ProductAtt02Desc
UNION ALL
SELECT 'att10', ProductAtt10Desc FROM PF WHERE ProductAtt10Desc <> '' GROUP BY ProductAtt10Desc
UNION ALL
SELECT 'att11', ProductAtt11Desc FROM PF WHERE ProductAtt11Desc <> '' GROUP BY ProductAtt11Desc
UNION ALL
SELECT 'att21', ProductAtt21Desc FROM PF WHERE ProductAtt21Desc <> '' GROUP BY ProductAtt21Desc
UNION ALL
SELECT 'att35', ProductAtt35Desc FROM PF WHERE ProductAtt35Desc <> '' GROUP BY ProductAtt35Desc
UNION ALL
SELECT 'att36', ProductAtt36Desc FROM PF WHERE ProductAtt36Desc <> '' GROUP BY ProductAtt36Desc
UNION ALL
SELECT 'att44', ProductAtt44Desc FROM PF WHERE ProductAtt44Desc <> '' GROUP BY ProductAtt44Desc;
`
// GetProductStockQueryByAttributes:
// Urun ozelliklerine gore stok detay sorgusu.
const GetProductStockQueryByAttributes = `
DECLARE @Att01 NVARCHAR(100) = NULLIF(LTRIM(RTRIM(@p1)), '');
DECLARE @Att02 NVARCHAR(100) = NULLIF(LTRIM(RTRIM(@p2)), '');
DECLARE @Att10 NVARCHAR(100) = NULLIF(LTRIM(RTRIM(@p3)), '');
DECLARE @Att11 NVARCHAR(100) = NULLIF(LTRIM(RTRIM(@p4)), '');
DECLARE @Att21 NVARCHAR(100) = NULLIF(LTRIM(RTRIM(@p5)), '');
DECLARE @Att35 NVARCHAR(100) = NULLIF(LTRIM(RTRIM(@p6)), '');
DECLARE @Att36 NVARCHAR(100) = NULLIF(LTRIM(RTRIM(@p7)), '');
DECLARE @Att44 NVARCHAR(100) = NULLIF(LTRIM(RTRIM(@p8)), '');
;WITH AttrFiltered AS
(
SELECT
ProductCode,
ProductDescription,
ProductAtt01Desc,
ProductAtt02Desc,
ProductAtt10Desc,
ProductAtt11Desc,
ProductAtt21Desc,
ProductAtt22Desc,
ProductAtt23Desc,
ProductAtt24Desc,
ProductAtt25Desc,
ProductAtt26Desc,
ProductAtt27Desc,
ProductAtt28Desc,
ProductAtt29Desc,
ProductAtt30Desc,
ProductAtt31Desc,
ProductAtt32Desc,
ProductAtt33Desc,
ProductAtt34Desc,
ProductAtt35Desc,
ProductAtt36Desc,
ProductAtt37Desc,
ProductAtt38Desc,
ProductAtt39Desc,
ProductAtt40Desc,
ProductAtt41Desc,
ProductAtt42Desc,
ProductAtt43Desc,
ProductAtt44Desc,
ProductAtt45Desc,
ProductAtt46Desc
FROM ProductFilterWithDescription('TR')
WHERE LEN(ProductCode) = 13
AND (@Att01 IS NULL OR ProductAtt01Desc = @Att01)
AND (@Att02 IS NULL OR ProductAtt02Desc = @Att02)
AND (@Att10 IS NULL OR ProductAtt10Desc = @Att10)
AND (@Att11 IS NULL OR ProductAtt11Desc = @Att11)
AND (@Att21 IS NULL OR ProductAtt21Desc = @Att21)
AND (@Att35 IS NULL OR ProductAtt35Desc = @Att35)
AND (@Att36 IS NULL OR ProductAtt36Desc = @Att36)
AND (@Att44 IS NULL OR ProductAtt44Desc = @Att44)
),
INV AS
(
SELECT
X.CompanyCode,
X.OfficeCode,
X.StoreTypeCode,
X.StoreCode,
X.WarehouseCode,
X.ItemTypeCode,
X.ItemCode,
X.ColorCode,
X.ItemDim1Code,
X.ItemDim2Code,
X.ItemDim3Code,
SUM(X.PickingQty1) AS PickingQty1,
SUM(X.ReserveQty1) AS ReserveQty1,
SUM(X.DispOrderQty1) AS DispOrderQty1,
SUM(X.InventoryQty1) AS InventoryQty1
FROM
(
SELECT
P.CompanyCode, P.OfficeCode, P.StoreTypeCode, P.StoreCode, P.WarehouseCode,
P.ItemTypeCode, P.ItemCode, P.ColorCode, P.ItemDim1Code, P.ItemDim2Code, P.ItemDim3Code,
P.Qty1 AS PickingQty1, 0 AS ReserveQty1, 0 AS DispOrderQty1, 0 AS InventoryQty1
FROM PickingStates P
INNER JOIN AttrFiltered AF ON AF.ProductCode = P.ItemCode
WHERE P.ItemTypeCode = 1
AND LEN(P.ItemCode) = 13
UNION ALL
SELECT
R.CompanyCode, R.OfficeCode, R.StoreTypeCode, R.StoreCode, R.WarehouseCode,
R.ItemTypeCode, R.ItemCode, R.ColorCode, R.ItemDim1Code, R.ItemDim2Code, R.ItemDim3Code,
0, R.Qty1, 0, 0
FROM ReserveStates R
INNER JOIN AttrFiltered AF ON AF.ProductCode = R.ItemCode
WHERE R.ItemTypeCode = 1
AND LEN(R.ItemCode) = 13
UNION ALL
SELECT
D.CompanyCode, D.OfficeCode, D.StoreTypeCode, D.StoreCode, D.WarehouseCode,
D.ItemTypeCode, D.ItemCode, D.ColorCode, D.ItemDim1Code, D.ItemDim2Code, D.ItemDim3Code,
0, 0, D.Qty1, 0
FROM DispOrderStates D
INNER JOIN AttrFiltered AF ON AF.ProductCode = D.ItemCode
WHERE D.ItemTypeCode = 1
AND LEN(D.ItemCode) = 13
UNION ALL
SELECT
T.CompanyCode, T.OfficeCode, T.StoreTypeCode, T.StoreCode, T.WarehouseCode,
T.ItemTypeCode, T.ItemCode, T.ColorCode, T.ItemDim1Code, T.ItemDim2Code, T.ItemDim3Code,
0, 0, 0, SUM(T.In_Qty1 - T.Out_Qty1)
FROM trStock T WITH (NOLOCK)
INNER JOIN AttrFiltered AF ON AF.ProductCode = T.ItemCode
WHERE T.ItemTypeCode = 1
AND LEN(T.ItemCode) = 13
GROUP BY
T.CompanyCode, T.OfficeCode, T.StoreTypeCode, T.StoreCode, T.WarehouseCode,
T.ItemTypeCode, T.ItemCode, T.ColorCode, T.ItemDim1Code, T.ItemDim2Code, T.ItemDim3Code
) X
GROUP BY
X.CompanyCode, X.OfficeCode, X.StoreTypeCode, X.StoreCode, X.WarehouseCode,
X.ItemTypeCode, X.ItemCode, X.ColorCode, X.ItemDim1Code, X.ItemDim2Code, X.ItemDim3Code
)
SELECT
I.WarehouseCode AS Depo_Kodu,
W.WarehouseDescription AS Depo_Adi,
IT.ItemTypeDescription AS InventoryType,
I.ItemCode AS Urun_Kodu,
AF.ProductDescription AS Madde_Aciklamasi,
I.ColorCode AS Renk_Kodu,
C.ColorDescription AS Renk_Aciklamasi,
I.ItemDim1Code AS Beden,
I.ItemDim2Code AS Yaka,
ROUND(I.InventoryQty1 - I.PickingQty1 - I.ReserveQty1 - I.DispOrderQty1, U.RoundDigit) AS Kullanilabilir_Envanter,
AF.ProductAtt01Desc AS URUN_ANA_GRUBU,
AF.ProductAtt02Desc AS URUN_ALT_GRUBU,
AF.ProductAtt10Desc AS MARKA,
AF.ProductAtt11Desc AS DR,
AF.ProductAtt21Desc AS KALIP,
AF.ProductAtt22Desc AS IKINCI_PARCA_KALIP,
AF.ProductAtt23Desc AS PACA_GENISLIGI,
AF.ProductAtt24Desc AS UCUNCU_PARCA_KALIP,
AF.ProductAtt25Desc AS UCUNCU_PARCA_MODEL,
AF.ProductAtt26Desc AS BIRINCI_PARCA_KUMAS,
AF.ProductAtt27Desc AS IKINCI_PARCA_KUMAS,
AF.ProductAtt28Desc AS UCUNCU_PARCA_KUMAS,
AF.ProductAtt29Desc AS BIRINCI_PARCA_KARISIM,
AF.ProductAtt30Desc AS IKINCI_PARCA_KARISIM,
AF.ProductAtt31Desc AS UCUNCU_PARCA_KARISIM,
AF.ProductAtt32Desc AS YAKA_TIPI,
AF.ProductAtt33Desc AS DUGME,
AF.ProductAtt34Desc AS YIRTMAC,
AF.ProductAtt35Desc AS SEZON_YILI,
AF.ProductAtt36Desc AS MEVSIM,
AF.ProductAtt37Desc AS TABAN,
AF.ProductAtt38Desc AS BIRINCI_PARCA_FIT,
AF.ProductAtt39Desc AS IKINCI_PARCA_FIT,
AF.ProductAtt40Desc AS BOS2,
AF.ProductAtt41Desc AS KISA_KAR,
AF.ProductAtt42Desc AS SERI_FASON,
AF.ProductAtt43Desc AS STOK_GIRIS_YONTEMI,
AF.ProductAtt44Desc AS YETISKIN_GARSON,
AF.ProductAtt45Desc AS ASKILI_YAN,
AF.ProductAtt46Desc AS BOS3,
P.Price AS Fiyat
FROM INV I
INNER JOIN AttrFiltered AF
ON AF.ProductCode = I.ItemCode
JOIN cdItem CI WITH (NOLOCK)
ON CI.ItemTypeCode = I.ItemTypeCode
AND CI.ItemCode = I.ItemCode
LEFT JOIN cdUnitOfMeasure U WITH (NOLOCK)
ON U.UnitOfMeasureCode = CI.UnitOfMeasureCode1
LEFT JOIN cdWarehouseDesc W WITH (NOLOCK)
ON W.WarehouseCode = I.WarehouseCode
AND W.LangCode = 'TR'
LEFT JOIN bsItemTypeDesc IT WITH (NOLOCK)
ON IT.ItemTypeCode = I.ItemTypeCode
AND IT.LangCode = 'TR'
LEFT JOIN cdColorDesc C WITH (NOLOCK)
ON C.ColorCode = I.ColorCode
AND C.LangCode = 'TR'
OUTER APPLY (
SELECT TOP 1 Price
FROM prItemBasePrice PB WITH (NOLOCK)
WHERE PB.ItemTypeCode = 1
AND PB.ItemCode = I.ItemCode
AND LEN(PB.ItemCode) = 13
ORDER BY PB.PriceDate DESC
) P
WHERE
I.ItemTypeCode = 1
AND LEN(I.ItemCode) = 13
AND (I.InventoryQty1 - I.PickingQty1 - I.ReserveQty1 - I.DispOrderQty1) > 0
AND CI.IsBlocked = 0
AND I.WarehouseCode IN
(
'1-0-14','1-0-10','1-0-8','1-2-5','1-2-4','1-0-12','100','1-0-28',
'1-0-24','1-2-6','1-1-14','1-0-2','1-0-52','1-1-2','1-0-21','1-1-3',
'1-0-33','101','1-014','1-0-49','1-0-36'
);
`

View File

@@ -12,6 +12,7 @@ import (
"strings"
"github.com/gorilla/mux"
mssql "github.com/microsoft/go-mssqldb"
)
// ======================================================
@@ -136,8 +137,7 @@ func OrderProductionValidateRoute(mssql *sql.DB) http.Handler {
missing, err := buildMissingVariants(mssql, id, payload.Lines)
if err != nil {
log.Printf("validate error: %v", err)
http.Error(w, "Veritabani hatasi", http.StatusInternalServerError)
writeDBError(w, http.StatusInternalServerError, "validate_missing_variants", id, "", len(payload.Lines), err)
return
}
@@ -176,8 +176,7 @@ func OrderProductionApplyRoute(mssql *sql.DB) http.Handler {
missing, err := buildMissingVariants(mssql, id, payload.Lines)
if err != nil {
log.Printf("apply validate error: %v", err)
http.Error(w, "Veritabani hatasi", http.StatusInternalServerError)
writeDBError(w, http.StatusInternalServerError, "apply_validate_missing_variants", id, "", len(payload.Lines), err)
return
}
@@ -202,7 +201,7 @@ func OrderProductionApplyRoute(mssql *sql.DB) http.Handler {
tx, err := mssql.Begin()
if err != nil {
http.Error(w, "Veritabani hatasi", http.StatusInternalServerError)
writeDBError(w, http.StatusInternalServerError, "begin_tx", id, username, len(payload.Lines), err)
return
}
defer tx.Rollback()
@@ -211,22 +210,19 @@ func OrderProductionApplyRoute(mssql *sql.DB) http.Handler {
if payload.InsertMissing {
inserted, err = queries.InsertMissingVariantsTx(tx, missing, username)
if err != nil {
log.Printf("insert missing error: %v", err)
http.Error(w, "Veritabani hatasi", http.StatusInternalServerError)
writeDBError(w, http.StatusInternalServerError, "insert_missing_variants", id, username, len(missing), err)
return
}
}
updated, err := queries.UpdateOrderLinesTx(tx, id, payload.Lines, username)
if err != nil {
log.Printf("update order lines error: %v", err)
http.Error(w, "Veritabani hatasi", http.StatusInternalServerError)
writeDBError(w, http.StatusInternalServerError, "update_order_lines", id, username, len(payload.Lines), err)
return
}
if err := tx.Commit(); err != nil {
log.Printf("commit error: %v", err)
http.Error(w, "Veritabani hatasi", http.StatusInternalServerError)
writeDBError(w, http.StatusInternalServerError, "commit_tx", id, username, len(payload.Lines), err)
return
}
@@ -289,3 +285,26 @@ func validateUpdateLines(lines []models.OrderProductionUpdateLine) error {
}
return nil
}
func writeDBError(w http.ResponseWriter, status int, step string, orderHeaderID string, username string, lineCount int, err error) {
var sqlErr mssql.Error
if errors.As(err, &sqlErr) {
log.Printf(
"❌ SQL error step=%s orderHeaderID=%s user=%s lineCount=%d number=%d state=%d class=%d server=%s proc=%s line=%d message=%s",
step, orderHeaderID, username, lineCount,
sqlErr.Number, sqlErr.State, sqlErr.Class, sqlErr.ServerName, sqlErr.ProcName, sqlErr.LineNo, sqlErr.Message,
)
} else {
log.Printf(
"❌ DB error step=%s orderHeaderID=%s user=%s lineCount=%d err=%v",
step, orderHeaderID, username, lineCount, err,
)
}
w.WriteHeader(status)
_ = json.NewEncoder(w).Encode(map[string]any{
"message": "Veritabani hatasi",
"step": step,
"detail": err.Error(),
})
}

View File

@@ -0,0 +1,128 @@
package routes
import (
"bssapp-backend/db"
"bssapp-backend/queries"
"context"
"encoding/json"
"log"
"net/http"
"strings"
"time"
)
// GetProductStockAttributeOptionsHandler
// GET /api/product-stock-attribute-options
func GetProductStockAttributeOptionsHandler(w http.ResponseWriter, _ *http.Request) {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
rows, err := db.MssqlDB.QueryContext(ctx, queries.GetProductStockAttributeOptionsQuery)
if err != nil {
log.Printf("[PRODUCT-STOCK-ATTR-OPTIONS] SQL hatasi: %v", err)
http.Error(w, "SQL hatasi: "+err.Error(), http.StatusInternalServerError)
return
}
defer rows.Close()
result := map[string][]string{
"att01": {},
"att02": {},
"att10": {},
"att11": {},
"att21": {},
"att35": {},
"att36": {},
"att44": {},
}
for rows.Next() {
var fieldName, fieldValue string
if err := rows.Scan(&fieldName, &fieldValue); err != nil {
continue
}
fieldName = strings.TrimSpace(fieldName)
fieldValue = strings.TrimSpace(fieldValue)
if fieldName == "" || fieldValue == "" {
continue
}
result[fieldName] = append(result[fieldName], fieldValue)
}
if err := rows.Err(); err != nil {
http.Error(w, "Satir okuma hatasi: "+err.Error(), http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json; charset=utf-8")
_ = json.NewEncoder(w).Encode(result)
}
// GetProductStockQueryByAttributesHandler
// GET /api/product-stock-query-by-attributes?att01=...&att02=...
func GetProductStockQueryByAttributesHandler(w http.ResponseWriter, r *http.Request) {
att01 := strings.TrimSpace(r.URL.Query().Get("att01"))
att02 := strings.TrimSpace(r.URL.Query().Get("att02"))
att10 := strings.TrimSpace(r.URL.Query().Get("att10"))
att11 := strings.TrimSpace(r.URL.Query().Get("att11"))
att21 := strings.TrimSpace(r.URL.Query().Get("att21"))
att35 := strings.TrimSpace(r.URL.Query().Get("att35"))
att36 := strings.TrimSpace(r.URL.Query().Get("att36"))
att44 := strings.TrimSpace(r.URL.Query().Get("att44"))
hasAny := att01 != "" || att02 != "" || att10 != "" || att11 != "" || att21 != "" || att35 != "" || att36 != "" || att44 != ""
if !hasAny {
http.Error(w, "En az bir urun ozelligi secilmelidir", http.StatusBadRequest)
return
}
start := time.Now()
ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second)
defer cancel()
log.Printf(
"[PRODUCT-STOCK-BY-ATTRS] request att01=%q att02=%q att10=%q att11=%q att21=%q att35=%q att36=%q att44=%q",
att01, att02, att10, att11, att21, att35, att36, att44,
)
rows, err := db.MssqlDB.QueryContext(ctx, queries.GetProductStockQueryByAttributes, att01, att02, att10, att11, att21, att35, att36, att44)
if err != nil {
log.Printf("[PRODUCT-STOCK-BY-ATTRS] SQL hatasi: %v", err)
http.Error(w, "SQL hatasi: "+err.Error(), http.StatusInternalServerError)
return
}
defer rows.Close()
columns, err := rows.Columns()
if err != nil {
http.Error(w, "Kolon bilgisi alinamadi", http.StatusInternalServerError)
return
}
result := make([]map[string]interface{}, 0, 256)
for rows.Next() {
raw := make([]interface{}, len(columns))
dest := make([]interface{}, len(columns))
for i := range raw {
dest[i] = &raw[i]
}
if err := rows.Scan(dest...); err != nil {
continue
}
rowMap := make(map[string]interface{}, len(columns))
for i, c := range columns {
rowMap[c] = normalizeSQLValue(raw[i])
}
result = append(result, rowMap)
}
if err := rows.Err(); err != nil {
log.Printf("[PRODUCT-STOCK-BY-ATTRS] rows err elapsed=%s err=%v", time.Since(start), err)
http.Error(w, "Satir okuma hatasi: "+err.Error(), http.StatusInternalServerError)
return
}
log.Printf("[PRODUCT-STOCK-BY-ATTRS] success rows=%d elapsed=%s", len(result), time.Since(start))
w.Header().Set("Content-Type", "application/json; charset=utf-8")
_ = json.NewEncoder(w).Encode(result)
}