Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -12,40 +12,230 @@ func GetOrderListExcel(
|
||||
orderDate string,
|
||||
) (*sql.Rows, error) {
|
||||
|
||||
q := OrderListBaseQuery + " AND 1=1 "
|
||||
args := []interface{}{}
|
||||
q := `
|
||||
SELECT
|
||||
CAST(h.OrderHeaderID AS NVARCHAR(50)) AS OrderHeaderID,
|
||||
ISNULL(h.OrderNumber,'') AS OrderNumber,
|
||||
CONVERT(varchar,h.OrderDate,23) AS OrderDate,
|
||||
|
||||
// SEARCH
|
||||
ISNULL(h.CurrAccCode,'') AS CurrAccCode,
|
||||
ISNULL(ca.CurrAccDescription,'') AS CurrAccDescription,
|
||||
|
||||
ISNULL(mt.AttributeDescription,'') AS MusteriTemsilcisi,
|
||||
ISNULL(py.AttributeDescription,'') AS Piyasa,
|
||||
|
||||
ISNULL(h.DocCurrencyCode,'TRY') AS DocCurrencyCode,
|
||||
|
||||
-------------------------------------------------
|
||||
-- BELGE PB TOPLAM
|
||||
-------------------------------------------------
|
||||
ISNULL(t.TotalAmount,0) AS TotalAmount,
|
||||
|
||||
-------------------------------------------------
|
||||
-- USD TOPLAM
|
||||
-------------------------------------------------
|
||||
CASE
|
||||
WHEN h.DocCurrencyCode = 'USD'
|
||||
THEN ISNULL(t.TotalAmount,0)
|
||||
|
||||
WHEN h.DocCurrencyCode = 'TRY'
|
||||
AND usd.Rate > 0
|
||||
THEN ISNULL(t.TotalTRY,0) / usd.Rate
|
||||
|
||||
WHEN h.DocCurrencyCode IN ('EUR','GBP')
|
||||
AND cur.Rate > 0
|
||||
AND usd.Rate > 0
|
||||
THEN (ISNULL(t.TotalAmount,0) * cur.Rate) / usd.Rate
|
||||
|
||||
ELSE 0
|
||||
END AS TotalAmountUSD,
|
||||
|
||||
ISNULL(t.PackedAmount,0) AS PackedAmount,
|
||||
|
||||
CASE
|
||||
WHEN h.DocCurrencyCode = 'USD'
|
||||
THEN ISNULL(t.PackedAmount,0)
|
||||
|
||||
WHEN h.DocCurrencyCode = 'TRY'
|
||||
AND usd.Rate > 0
|
||||
THEN ISNULL(t.PackedTRY,0) / usd.Rate
|
||||
|
||||
WHEN cur.Rate > 0
|
||||
AND usd.Rate > 0
|
||||
THEN (ISNULL(t.PackedAmount,0) * cur.Rate) / usd.Rate
|
||||
|
||||
ELSE 0
|
||||
END AS PackedUSD,
|
||||
|
||||
CASE
|
||||
WHEN ISNULL(t.TotalAmount,0) > 0
|
||||
THEN (ISNULL(t.PackedAmount,0) * 100.0) / NULLIF(t.TotalAmount,0)
|
||||
ELSE 0
|
||||
END AS PackedRatePct,
|
||||
|
||||
ISNULL(h.Description,'') AS Description,
|
||||
|
||||
usd.Rate AS ExchangeRateUSD
|
||||
|
||||
FROM dbo.trOrderHeader h
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
-- ✅ LINE CURRENCY TOPLAM
|
||||
-------------------------------------------------
|
||||
LEFT JOIN (
|
||||
|
||||
SELECT
|
||||
l.OrderHeaderID,
|
||||
|
||||
-- Belge para birimi toplam
|
||||
SUM(
|
||||
CASE
|
||||
WHEN c.CurrencyCode = h.DocCurrencyCode
|
||||
THEN c.NetAmount
|
||||
ELSE 0
|
||||
END
|
||||
) AS TotalAmount,
|
||||
|
||||
-- TRY toplam
|
||||
SUM(
|
||||
CASE
|
||||
WHEN c.CurrencyCode = 'TRY'
|
||||
THEN c.NetAmount
|
||||
ELSE 0
|
||||
END
|
||||
) AS TotalTRY,
|
||||
|
||||
-- Paketlenen (OrderLine IsClosed=1) belge PB toplam
|
||||
SUM(
|
||||
CASE
|
||||
WHEN ISNULL(l.IsClosed,0) = 1
|
||||
AND c.CurrencyCode = h.DocCurrencyCode
|
||||
THEN c.NetAmount
|
||||
ELSE 0
|
||||
END
|
||||
) AS PackedAmount,
|
||||
|
||||
-- Paketlenen TRY toplam
|
||||
SUM(
|
||||
CASE
|
||||
WHEN ISNULL(l.IsClosed,0) = 1
|
||||
AND c.CurrencyCode = 'TRY'
|
||||
THEN c.NetAmount
|
||||
ELSE 0
|
||||
END
|
||||
) AS PackedTRY
|
||||
|
||||
FROM dbo.trOrderLineCurrency c
|
||||
|
||||
JOIN dbo.trOrderLine l
|
||||
ON l.OrderLineID = c.OrderLineID
|
||||
|
||||
JOIN dbo.trOrderHeader h
|
||||
ON h.OrderHeaderID = l.OrderHeaderID
|
||||
|
||||
GROUP BY l.OrderHeaderID
|
||||
|
||||
) t ON t.OrderHeaderID = h.OrderHeaderID
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
-- CARİ
|
||||
-------------------------------------------------
|
||||
LEFT JOIN dbo.cdCurrAccDesc ca
|
||||
ON ca.CurrAccCode = h.CurrAccCode
|
||||
AND ca.LangCode='TR'
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
-- TEMSİLCİ / PİYASA
|
||||
-------------------------------------------------
|
||||
LEFT JOIN dbo.CustomerAttributesFilter f
|
||||
ON f.CurrAccCode = h.CurrAccCode
|
||||
|
||||
LEFT JOIN dbo.cdCurrAccAttributeDesc mt
|
||||
ON mt.CurrAccTypeCode=3
|
||||
AND mt.AttributeTypeCode=2
|
||||
AND mt.AttributeCode=f.CustomerAtt02
|
||||
AND mt.LangCode='TR'
|
||||
|
||||
LEFT JOIN dbo.cdCurrAccAttributeDesc py
|
||||
ON py.CurrAccTypeCode=3
|
||||
AND py.AttributeTypeCode=1
|
||||
AND py.AttributeCode=f.CustomerAtt01
|
||||
AND py.LangCode='TR'
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
-- USD → TRY
|
||||
-------------------------------------------------
|
||||
OUTER APPLY (
|
||||
SELECT TOP 1 Rate
|
||||
FROM dbo.AllExchangeRates
|
||||
WHERE CurrencyCode='USD'
|
||||
AND RelationCurrencyCode='TRY'
|
||||
AND ExchangeTypeCode=6
|
||||
AND Rate>0
|
||||
AND Date<=CAST(GETDATE() AS date)
|
||||
ORDER BY Date DESC
|
||||
) usd
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
-- DOC → TRY
|
||||
-------------------------------------------------
|
||||
OUTER APPLY (
|
||||
SELECT TOP 1 Rate
|
||||
FROM dbo.AllExchangeRates
|
||||
WHERE CurrencyCode=h.DocCurrencyCode
|
||||
AND RelationCurrencyCode='TRY'
|
||||
AND ExchangeTypeCode=6
|
||||
AND Rate>0
|
||||
AND Date<=CAST(GETDATE() AS date)
|
||||
ORDER BY Date DESC
|
||||
) cur
|
||||
|
||||
|
||||
WHERE
|
||||
ISNULL(h.IsCancelOrder,0)=0
|
||||
AND h.OrderTypeCode=1
|
||||
AND h.ProcessCode='WS'
|
||||
AND h.IsClosed=0
|
||||
`
|
||||
|
||||
args := []any{}
|
||||
|
||||
// ================= SEARCH =================
|
||||
if search != "" {
|
||||
q += `
|
||||
AND (
|
||||
LOWER(h.OrderNumber) LIKE LOWER(@p1) OR
|
||||
LOWER(h.CurrAccCode) LIKE LOWER(@p1) OR
|
||||
LOWER(ca.CurrAccDescription) LIKE LOWER(@p1) OR
|
||||
LOWER(h.Description) LIKE LOWER(@p1) OR
|
||||
LOWER(mt.AttributeDescription) LIKE LOWER(@p1) OR
|
||||
LOWER(py.AttributeDescription) LIKE LOWER(@p1)
|
||||
LOWER(h.OrderNumber) LIKE LOWER(@p1)
|
||||
OR LOWER(h.CurrAccCode) LIKE LOWER(@p1)
|
||||
OR LOWER(ca.CurrAccDescription) LIKE LOWER(@p1)
|
||||
OR LOWER(h.Description) LIKE LOWER(@p1)
|
||||
OR LOWER(mt.AttributeDescription) LIKE LOWER(@p1)
|
||||
OR LOWER(py.AttributeDescription) LIKE LOWER(@p1)
|
||||
)
|
||||
`
|
||||
args = append(args, "%"+search+"%")
|
||||
}
|
||||
|
||||
// CURRACC
|
||||
// ================= CURRACC =================
|
||||
if currAcc != "" {
|
||||
q += fmt.Sprintf(" AND h.CurrAccCode = @p%d ", len(args)+1)
|
||||
args = append(args, currAcc)
|
||||
}
|
||||
|
||||
// DATE
|
||||
// ================= DATE =================
|
||||
if orderDate != "" {
|
||||
q += fmt.Sprintf(
|
||||
" AND CONVERT(varchar, h.OrderDate, 23) = @p%d ",
|
||||
" AND CONVERT(varchar,h.OrderDate,23) = @p%d ",
|
||||
len(args)+1,
|
||||
)
|
||||
args = append(args, orderDate)
|
||||
}
|
||||
|
||||
// ORDER BY SONDA
|
||||
// ================= ORDER =================
|
||||
q += " ORDER BY h.CreatedDate DESC "
|
||||
|
||||
return db.Query(q, args...)
|
||||
|
||||
@@ -8,15 +8,12 @@ import (
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// GetOrderByID — Sipariş başlığı (header) ve satırlarını (lines) getirir.
|
||||
// GetOrderByID returns order header and lines.
|
||||
func GetOrderByID(orderID string) (*models.OrderHeader, []models.OrderDetail, error) {
|
||||
conn := db.GetDB()
|
||||
|
||||
logger.Printf("🧾 [GetOrderByID] begin • id=%s", orderID)
|
||||
logger.Printf("[GetOrderByID] begin id=%s", orderID)
|
||||
|
||||
// =====================================================
|
||||
// HEADER (Cari adı join'li)
|
||||
// =====================================================
|
||||
var header models.OrderHeader
|
||||
qHeader := `
|
||||
SELECT
|
||||
@@ -176,61 +173,76 @@ func GetOrderByID(orderID string) (*models.OrderHeader, []models.OrderDetail, er
|
||||
&header.LastUpdatedDate,
|
||||
&header.IsProposalBased,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
logger.Printf("⚠️ [GetOrderByID] sipariş bulunamadı: %s", orderID)
|
||||
logger.Printf("[GetOrderByID] not found: %s", orderID)
|
||||
return nil, nil, sql.ErrNoRows
|
||||
}
|
||||
logger.Printf("❌ [GetOrderByID] header sorgu hatası: %v", err)
|
||||
logger.Printf("[GetOrderByID] header error: %v", err)
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
logger.Printf("✅ [GetOrderByID] header loaded • orderNo=%v currAcc=%v",
|
||||
header.OrderNumber, header.CurrAccCode.String)
|
||||
|
||||
// =====================================================
|
||||
// LINES
|
||||
// =====================================================
|
||||
qLines := `
|
||||
SELECT
|
||||
CAST(L.OrderLineID AS varchar(36)) AS OrderLineID,
|
||||
L.SortOrder,
|
||||
L.ItemTypeCode,
|
||||
L.ItemCode,
|
||||
L.ColorCode,
|
||||
L.ItemDim1Code,
|
||||
L.ItemDim2Code,
|
||||
L.ItemDim3Code,
|
||||
L.Qty1,
|
||||
L.Qty2,
|
||||
L.Price,
|
||||
L.VatRate,
|
||||
L.PCTRate,
|
||||
L.DocCurrencyCode,
|
||||
L.DeliveryDate,
|
||||
L.PlannedDateOfLading,
|
||||
L.LineDescription,
|
||||
L.IsClosed,
|
||||
L.CreatedUserName,
|
||||
L.CreatedDate,
|
||||
L.LastUpdatedUserName,
|
||||
L.LastUpdatedDate,
|
||||
P.ProductAtt42Desc AS UrunIlkGrubu,
|
||||
P.ProductAtt01Desc AS UrunAnaGrubu,
|
||||
P.ProductAtt02Desc AS UrunAltGrubu,
|
||||
P.ProductAtt38Desc AS Fit1,
|
||||
P.ProductAtt39Desc AS Fit2
|
||||
FROM BAGGI_V3.dbo.trOrderLine AS L
|
||||
LEFT JOIN ProductFilterWithDescription('TR') AS P
|
||||
ON LTRIM(RTRIM(P.ProductCode)) = LTRIM(RTRIM(L.ItemCode))
|
||||
WHERE L.OrderHeaderID = @p1
|
||||
ORDER BY L.SortOrder ASC;
|
||||
`
|
||||
SELECT
|
||||
CAST(L.OrderLineID AS varchar(36)) AS OrderLineID,
|
||||
L.SortOrder,
|
||||
L.ItemTypeCode,
|
||||
L.ItemCode,
|
||||
L.ColorCode,
|
||||
L.ItemDim1Code,
|
||||
L.ItemDim2Code,
|
||||
L.ItemDim3Code,
|
||||
L.Qty1,
|
||||
L.Qty2,
|
||||
|
||||
ISNULL(CD.Price, 0) AS Price,
|
||||
ISNULL(CD.CurrencyCode, ISNULL(L.DocCurrencyCode, 'TRY')) AS DocCurrencyCode,
|
||||
ISNULL(CD.RelationCurrencyCode, ISNULL(L.DocCurrencyCode, 'TRY')) AS RelationCurrencyCode,
|
||||
ISNULL(CD.ExchangeRate, ISNULL(L.PriceExchangeRate, 1)) AS PriceExchangeRate,
|
||||
ISNULL(CD.PriceVI, ISNULL(L.Price, 0)) AS DocPrice,
|
||||
ISNULL(CD.AmountVI, ISNULL(L.Price, 0) * ISNULL(L.Qty1, 0)) AS DocAmount,
|
||||
ISNULL(CD.LDiscount1, 0) AS LineDiscount,
|
||||
ISNULL(CD.TDiscount1, 0) AS TotalDiscount,
|
||||
ISNULL(CD.TaxBase, 0) AS TaxBase,
|
||||
ISNULL(CD.Pct, 0) AS Pct,
|
||||
ISNULL(CD.Vat, 0) AS VatAmount,
|
||||
ISNULL(CD.VatDeducation, 0) AS VatDeducation,
|
||||
ISNULL(CD.NetAmount, 0) AS NetAmount,
|
||||
ISNULL(CL.Price, ISNULL(CD.Price, 0)) AS LocalPrice,
|
||||
ISNULL(CL.Amount, ISNULL(CD.Amount, 0)) AS LocalAmount,
|
||||
|
||||
L.VatRate,
|
||||
L.PCTRate,
|
||||
L.DeliveryDate,
|
||||
L.PlannedDateOfLading,
|
||||
L.LineDescription,
|
||||
L.IsClosed,
|
||||
L.CreatedUserName,
|
||||
L.CreatedDate,
|
||||
L.LastUpdatedUserName,
|
||||
L.LastUpdatedDate,
|
||||
|
||||
P.ProductAtt42Desc AS UrunIlkGrubu,
|
||||
P.ProductAtt01Desc AS UrunAnaGrubu,
|
||||
P.ProductAtt02Desc AS UrunAltGrubu,
|
||||
P.ProductAtt38Desc AS Fit1,
|
||||
P.ProductAtt39Desc AS Fit2
|
||||
FROM BAGGI_V3.dbo.trOrderLine AS L
|
||||
LEFT JOIN BAGGI_V3.dbo.trOrderLineCurrency AS CD WITH (NOLOCK)
|
||||
ON CD.OrderLineID = L.OrderLineID
|
||||
AND CD.CurrencyCode = ISNULL(NULLIF(LTRIM(RTRIM(L.DocCurrencyCode)), ''), 'TRY')
|
||||
LEFT JOIN BAGGI_V3.dbo.trOrderLineCurrency AS CL WITH (NOLOCK)
|
||||
ON CL.OrderLineID = L.OrderLineID
|
||||
AND CL.CurrencyCode = 'TRY'
|
||||
LEFT JOIN ProductFilterWithDescription('TR') AS P
|
||||
ON LTRIM(RTRIM(P.ProductCode)) = LTRIM(RTRIM(L.ItemCode))
|
||||
WHERE L.OrderHeaderID = @p1
|
||||
ORDER BY L.SortOrder ASC;
|
||||
`
|
||||
|
||||
rows, err := conn.Query(qLines, orderID)
|
||||
if err != nil {
|
||||
logger.Printf("❌ [GetOrderByID] line sorgu hatası: %v", err)
|
||||
logger.Printf("[GetOrderByID] lines error: %v", err)
|
||||
return &header, nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
@@ -250,9 +262,22 @@ func GetOrderByID(orderID string) (*models.OrderHeader, []models.OrderDetail, er
|
||||
&ln.Qty1,
|
||||
&ln.Qty2,
|
||||
&ln.Price,
|
||||
&ln.DocCurrencyCode,
|
||||
&ln.RelationCurrencyCode,
|
||||
&ln.PriceExchangeRate,
|
||||
&ln.DocPrice,
|
||||
&ln.DocAmount,
|
||||
&ln.LineDiscount,
|
||||
&ln.TotalDiscount,
|
||||
&ln.TaxBase,
|
||||
&ln.Pct,
|
||||
&ln.VatAmount,
|
||||
&ln.VatDeducation,
|
||||
&ln.NetAmount,
|
||||
&ln.LocalPrice,
|
||||
&ln.LocalAmount,
|
||||
&ln.VatRate,
|
||||
&ln.PCTRate,
|
||||
&ln.DocCurrencyCode,
|
||||
&ln.DeliveryDate,
|
||||
&ln.PlannedDateOfLading,
|
||||
&ln.LineDescription,
|
||||
@@ -267,14 +292,14 @@ func GetOrderByID(orderID string) (*models.OrderHeader, []models.OrderDetail, er
|
||||
&ln.Fit1,
|
||||
&ln.Fit2,
|
||||
); err != nil {
|
||||
return &header, nil, fmt.Errorf("line scan hatası: %w", err)
|
||||
return &header, nil, fmt.Errorf("line scan error: %w", err)
|
||||
}
|
||||
lines = append(lines, ln)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return &header, nil, fmt.Errorf("line rows hatası: %w", err)
|
||||
return &header, nil, fmt.Errorf("line rows error: %w", err)
|
||||
}
|
||||
|
||||
logger.Printf("📦 [GetOrderByID] lines loaded • count=%d", len(lines))
|
||||
logger.Printf("[GetOrderByID] lines loaded count=%d", len(lines))
|
||||
return &header, lines, nil
|
||||
}
|
||||
|
||||
@@ -13,9 +13,10 @@ import (
|
||||
"bssapp-backend/models"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/google/uuid"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
func nf0(v models.NullFloat64) float64 {
|
||||
@@ -25,6 +26,311 @@ func nf0(v models.NullFloat64) float64 {
|
||||
return v.Float64
|
||||
}
|
||||
|
||||
// =======================================================
|
||||
// ✅ trOrderLineCurrency UPSERT (Doc Price / Amount yaz)
|
||||
// =======================================================
|
||||
func upsertLineCurrency(
|
||||
tx *sql.Tx,
|
||||
lineID string,
|
||||
|
||||
docCurrency string,
|
||||
exRate float64,
|
||||
|
||||
docPrice float64,
|
||||
qty float64,
|
||||
|
||||
lDis float64, // Line Discount %
|
||||
tDis float64, // Total Discount %
|
||||
|
||||
vatRate float64,
|
||||
ln models.OrderDetail,
|
||||
|
||||
user string,
|
||||
) error {
|
||||
|
||||
// ================= NORMALIZE =================
|
||||
|
||||
if docCurrency == "" {
|
||||
docCurrency = "TRY"
|
||||
}
|
||||
|
||||
if exRate <= 0 {
|
||||
exRate = 1
|
||||
}
|
||||
|
||||
relationCurrency := safeNS(ln.RelationCurrencyCode)
|
||||
if relationCurrency == "" {
|
||||
relationCurrency = docCurrency
|
||||
}
|
||||
|
||||
if ln.LineDiscount.Valid {
|
||||
lDis = ln.LineDiscount.Float64
|
||||
}
|
||||
if ln.TotalDiscount.Valid {
|
||||
tDis = ln.TotalDiscount.Float64
|
||||
}
|
||||
|
||||
basePrice := docPrice // Price (KDV hariç)
|
||||
if docCurrency == "TRY" && ln.LocalPrice.Valid && ln.LocalPrice.Float64 > 0 {
|
||||
basePrice = ln.LocalPrice.Float64
|
||||
}
|
||||
|
||||
amountBase := basePrice * qty // Amount (KDV hariç)
|
||||
if docCurrency == "TRY" && ln.LocalAmount.Valid && ln.LocalAmount.Float64 > 0 {
|
||||
amountBase = ln.LocalAmount.Float64
|
||||
}
|
||||
|
||||
priceVI := basePrice // PriceVI (KDV dahil)
|
||||
if ln.DocPrice.Valid && ln.DocPrice.Float64 > 0 {
|
||||
priceVI = ln.DocPrice.Float64
|
||||
}
|
||||
|
||||
amountVI := priceVI * qty // AmountVI (KDV dahil)
|
||||
if ln.DocAmount.Valid && ln.DocAmount.Float64 > 0 {
|
||||
amountVI = ln.DocAmount.Float64
|
||||
if qty > 0 {
|
||||
priceVI = amountVI / qty
|
||||
}
|
||||
}
|
||||
|
||||
// ================= DISCOUNT =================
|
||||
|
||||
afterLineDis := amountBase * (1 - lDis/100)
|
||||
afterTotalDis := afterLineDis * (1 - tDis/100)
|
||||
|
||||
// ================= TAX =================
|
||||
|
||||
taxBase := afterTotalDis
|
||||
if ln.TaxBase.Valid {
|
||||
taxBase = ln.TaxBase.Float64
|
||||
}
|
||||
|
||||
vat := taxBase * vatRate / 100
|
||||
if ln.VatAmount.Valid {
|
||||
vat = ln.VatAmount.Float64
|
||||
}
|
||||
|
||||
vatDeducation := 0.0
|
||||
if ln.VatDeducation.Valid {
|
||||
vatDeducation = ln.VatDeducation.Float64
|
||||
}
|
||||
|
||||
net := taxBase + vat - vatDeducation
|
||||
if ln.NetAmount.Valid {
|
||||
net = ln.NetAmount.Float64
|
||||
}
|
||||
|
||||
pct := 0.0
|
||||
if ln.Pct.Valid {
|
||||
pct = ln.Pct.Float64
|
||||
}
|
||||
|
||||
// payload yoksa doc tutarı net ile hizala
|
||||
if !ln.DocAmount.Valid {
|
||||
amountVI = net
|
||||
if qty > 0 {
|
||||
priceVI = amountVI / qty
|
||||
}
|
||||
}
|
||||
|
||||
// ================= LOCAL =================
|
||||
|
||||
localPrice := basePrice * exRate
|
||||
localAmount := amountBase * exRate
|
||||
|
||||
localPriceVI := priceVI * exRate
|
||||
localAmountVI := amountVI * exRate
|
||||
|
||||
localTaxBase := taxBase * exRate
|
||||
localVat := vat * exRate
|
||||
localVatDeducation := vatDeducation * exRate
|
||||
localNet := net * exRate
|
||||
|
||||
// ================= DOC =================
|
||||
|
||||
_, err := tx.Exec(`
|
||||
MERGE BAGGI_V3.dbo.trOrderLineCurrency AS T
|
||||
USING (SELECT @p1 AS OrderLineID, @p2 AS CurrencyCode) AS S
|
||||
ON T.OrderLineID=S.OrderLineID AND T.CurrencyCode=S.CurrencyCode
|
||||
|
||||
WHEN MATCHED THEN UPDATE SET
|
||||
RelationCurrencyCode=@p3,
|
||||
|
||||
ExchangeRate=@p4,
|
||||
|
||||
PriceVI=@p5,
|
||||
AmountVI=@p6,
|
||||
|
||||
Price=@p7,
|
||||
Amount=@p8,
|
||||
|
||||
LDiscount1=@p9,
|
||||
TDiscount1=@p10,
|
||||
|
||||
TaxBase=@p11,
|
||||
Pct=@p12,
|
||||
Vat=@p13,
|
||||
VatDeducation=@p14,
|
||||
NetAmount=@p15,
|
||||
|
||||
LastUpdatedUserName=@p16,
|
||||
LastUpdatedDate=GETDATE()
|
||||
|
||||
WHEN NOT MATCHED THEN INSERT (
|
||||
OrderLineID,
|
||||
CurrencyCode,
|
||||
RelationCurrencyCode,
|
||||
|
||||
ExchangeRate,
|
||||
|
||||
PriceVI,
|
||||
AmountVI,
|
||||
|
||||
Price,
|
||||
Amount,
|
||||
|
||||
LDiscount1,
|
||||
TDiscount1,
|
||||
|
||||
TaxBase,
|
||||
Pct,
|
||||
Vat,
|
||||
VatDeducation,
|
||||
NetAmount,
|
||||
|
||||
CreatedUserName,
|
||||
CreatedDate
|
||||
)
|
||||
VALUES (
|
||||
@p1,@p2,@p3,
|
||||
@p4,
|
||||
@p5,@p6,
|
||||
@p7,@p8,
|
||||
@p9,@p10,
|
||||
@p11,@p12,@p13,@p14,@p15,
|
||||
@p16,GETDATE()
|
||||
);`,
|
||||
lineID,
|
||||
docCurrency,
|
||||
relationCurrency,
|
||||
|
||||
exRate,
|
||||
|
||||
priceVI,
|
||||
amountVI,
|
||||
|
||||
basePrice,
|
||||
amountBase,
|
||||
|
||||
lDis,
|
||||
tDis,
|
||||
|
||||
taxBase,
|
||||
pct,
|
||||
vat,
|
||||
vatDeducation,
|
||||
net,
|
||||
|
||||
user,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if docCurrency != "TRY" {
|
||||
_, err = tx.Exec(`
|
||||
MERGE BAGGI_V3.dbo.trOrderLineCurrency AS T
|
||||
USING (SELECT @p1 AS OrderLineID,'TRY' AS CurrencyCode) AS S
|
||||
ON T.OrderLineID=S.OrderLineID AND T.CurrencyCode=S.CurrencyCode
|
||||
|
||||
WHEN MATCHED THEN UPDATE SET
|
||||
RelationCurrencyCode=@p2,
|
||||
|
||||
ExchangeRate=@p3,
|
||||
|
||||
PriceVI=@p4,
|
||||
AmountVI=@p5,
|
||||
|
||||
Price=@p6,
|
||||
Amount=@p7,
|
||||
|
||||
LDiscount1=@p8,
|
||||
TDiscount1=@p9,
|
||||
|
||||
TaxBase=@p10,
|
||||
Pct=@p11,
|
||||
Vat=@p12,
|
||||
VatDeducation=@p13,
|
||||
NetAmount=@p14,
|
||||
|
||||
LastUpdatedUserName=@p15,
|
||||
LastUpdatedDate=GETDATE()
|
||||
|
||||
WHEN NOT MATCHED THEN INSERT (
|
||||
OrderLineID,
|
||||
CurrencyCode,
|
||||
RelationCurrencyCode,
|
||||
|
||||
ExchangeRate,
|
||||
|
||||
PriceVI,
|
||||
AmountVI,
|
||||
|
||||
Price,
|
||||
Amount,
|
||||
|
||||
LDiscount1,
|
||||
TDiscount1,
|
||||
|
||||
TaxBase,
|
||||
Pct,
|
||||
Vat,
|
||||
VatDeducation,
|
||||
NetAmount,
|
||||
|
||||
CreatedUserName,
|
||||
CreatedDate
|
||||
)
|
||||
VALUES (
|
||||
@p1,'TRY',@p2,
|
||||
@p3,
|
||||
@p4,@p5,
|
||||
@p6,@p7,
|
||||
@p8,@p9,
|
||||
@p10,@p11,@p12,@p13,@p14,
|
||||
@p15,GETDATE()
|
||||
);`,
|
||||
lineID,
|
||||
docCurrency,
|
||||
exRate,
|
||||
|
||||
localPriceVI,
|
||||
localAmountVI,
|
||||
|
||||
localPrice,
|
||||
localAmount,
|
||||
|
||||
lDis,
|
||||
tDis,
|
||||
|
||||
localTaxBase,
|
||||
pct,
|
||||
localVat,
|
||||
localVatDeducation,
|
||||
localNet,
|
||||
|
||||
user,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// =======================================================
|
||||
// COMBO KEY & STRING HELPERS
|
||||
// =======================================================
|
||||
@@ -52,6 +358,32 @@ func qtyValue(q models.NullFloat64) float64 {
|
||||
return q.Float64
|
||||
}
|
||||
|
||||
func buildV3AuditUser(user *models.User) string {
|
||||
if user == nil {
|
||||
return "V3-0"
|
||||
}
|
||||
|
||||
v3Name := strings.ToUpper(strings.TrimSpace(user.V3Username))
|
||||
v3Group := user.V3UserGroup
|
||||
if v3Group >= 100 && v3Group%100 == 0 {
|
||||
v3Group = v3Group / 100
|
||||
}
|
||||
|
||||
if v3Name != "" && v3Group > 0 {
|
||||
return fmt.Sprintf("V3-%s%d", v3Name, v3Group)
|
||||
}
|
||||
if v3Name != "" {
|
||||
return "V3-" + v3Name
|
||||
}
|
||||
if username := strings.TrimSpace(user.Username); username != "" {
|
||||
return username
|
||||
}
|
||||
if v3Group > 0 {
|
||||
return fmt.Sprintf("V3-%d", v3Group)
|
||||
}
|
||||
return "V3-0"
|
||||
}
|
||||
|
||||
// VatCode: NullString → string
|
||||
// - NULL → ""
|
||||
// - "0" → "" (FK patlamasın, sadece anlamlı kodlar gönderiyoruz)
|
||||
@@ -173,9 +505,6 @@ func ValidateItemVariant(tx *sql.Tx, ln models.OrderDetail) error {
|
||||
|
||||
}
|
||||
|
||||
// İstersen debug:
|
||||
// fmt.Printf("🧪 VARIANT CHECK item=%q color=%q dim1=%q dim2=%q clientKey=%s\n", item, color, dim1, dim2, safeNS(ln.ClientKey))
|
||||
|
||||
var exists int
|
||||
err := tx.QueryRow(`
|
||||
SELECT CASE WHEN EXISTS (
|
||||
@@ -297,12 +626,6 @@ type OrderLineResult struct {
|
||||
|
||||
// =======================================================
|
||||
// PART 1 — InsertOrder (header + lines insert) — FINAL v5.1
|
||||
// ✔ OrderHeaderID backend üretir
|
||||
// ✔ LOCAL-... numara gelirse gerçek WS numarası üretir
|
||||
// ✔ Full debug
|
||||
// ✔ Tüm satırlar INSERT edilir
|
||||
// ✔ INSERT öncesi ItemVariant Guard
|
||||
// ✔ Payload içi Duplicate Guard (comboKey)
|
||||
// =======================================================
|
||||
|
||||
func InsertOrder(header models.OrderHeader, lines []models.OrderDetail, user *models.User) (string, []OrderLineResult, error) {
|
||||
@@ -317,7 +640,7 @@ func InsertOrder(header models.OrderHeader, lines []models.OrderDetail, user *mo
|
||||
defer tx.Rollback()
|
||||
|
||||
now := time.Now()
|
||||
v3User := fmt.Sprintf("V3U%d-%s", user.V3UserGroup, user.V3Username)
|
||||
v3User := buildV3AuditUser(user)
|
||||
|
||||
// =======================================================
|
||||
// 1) BACKEND — OrderHeaderID üretimi (HER ZAMAN)
|
||||
@@ -368,7 +691,6 @@ func InsertOrder(header models.OrderHeader, lines []models.OrderDetail, user *mo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// =======================================================
|
||||
// 4) HEADER INSERT
|
||||
// =======================================================
|
||||
@@ -423,6 +745,7 @@ VALUES (
|
||||
|
||||
fmt.Println("🟪 HEADER INSERT ÇALIŞIYOR...")
|
||||
|
||||
// ✅ exRate burada gerçekten kullanılıyor (ExchangeRate parametresi)
|
||||
headerParams := []any{
|
||||
header.OrderHeaderID,
|
||||
nullableInt16(header.OrderTypeCode, 1),
|
||||
@@ -474,7 +797,7 @@ VALUES (
|
||||
nullableString(header.GLTypeCode, ""),
|
||||
nullableString(header.DocCurrencyCode, "TRY"),
|
||||
nullableString(header.LocalCurrencyCode, "TRY"),
|
||||
nullableFloat64(header.ExchangeRate, exRate),
|
||||
nullableFloat64(header.ExchangeRate, exRate), // ✅ exRate kullanıldı
|
||||
|
||||
nullableFloat64(header.TDisRate1, 0),
|
||||
nullableFloat64(header.TDisRate2, 0),
|
||||
@@ -520,6 +843,7 @@ VALUES (
|
||||
nullableBool(header.IsProposalBased, false),
|
||||
}
|
||||
|
||||
// ✅ queryHeader artık gerçekten kullanılıyor → "Unused variable 'queryHeader'" biter
|
||||
if _, err := tx.Exec(queryHeader, headerParams...); err != nil {
|
||||
fmt.Println("❌ HEADER INSERT ERROR:", err)
|
||||
return "", nil, fmt.Errorf("header insert hatasi: %w", err)
|
||||
@@ -527,6 +851,7 @@ VALUES (
|
||||
|
||||
fmt.Println("🟩 HEADER INSERT OK — ID:", newID)
|
||||
|
||||
// headerParams ... (senin mevcut hali aynen)
|
||||
// =======================================================
|
||||
// 5) LINE INSERT
|
||||
// =======================================================
|
||||
@@ -590,7 +915,6 @@ VALUES (
|
||||
seenCombo := make(map[string]bool)
|
||||
|
||||
for i, ln := range lines {
|
||||
// ===================== PART 2 (Satır 301-600) =====================
|
||||
fmt.Println("────────────────────────────────────")
|
||||
fmt.Printf("🟨 [INSERT] LINE %d — gelen OrderLineID=%s\n", i+1, ln.OrderLineID)
|
||||
|
||||
@@ -630,6 +954,7 @@ VALUES (
|
||||
}
|
||||
|
||||
planned := nullableDateString(ln.PlannedDateOfLading)
|
||||
|
||||
// ✅ INSERT ÖNCESİ ItemVariant GUARD
|
||||
if qtyValue(ln.Qty1) > 0 {
|
||||
if err := ValidateItemVariant(tx, ln); err != nil {
|
||||
@@ -637,6 +962,7 @@ VALUES (
|
||||
return "", nil, err
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Printf(
|
||||
"🚨 INSERT LINE[%d] | LineID=%s ClientKey=%s Item=%q Color=%q Dim1=%q Dim2=%q Dim3=%q Qty1=%v\n",
|
||||
i+1,
|
||||
@@ -708,6 +1034,28 @@ VALUES (
|
||||
return "", nil, fmt.Errorf("line insert hatasi: %w", err)
|
||||
}
|
||||
|
||||
// ✅ NEW: trOrderLineCurrency yaz
|
||||
if err := upsertLineCurrency(
|
||||
tx,
|
||||
ln.OrderLineID,
|
||||
|
||||
safeNS(ln.DocCurrencyCode),
|
||||
nf0(ln.PriceExchangeRate),
|
||||
|
||||
nf0(ln.Price),
|
||||
nf0(ln.Qty1),
|
||||
|
||||
nf0(ln.LDisRate1), // ✅ Line discount
|
||||
0, // ✅ Total discount (istersen header’dan alırsın)
|
||||
|
||||
nf0(ln.VatRate), // ✅ Vat rate
|
||||
ln,
|
||||
|
||||
v3User,
|
||||
); err != nil {
|
||||
return "", nil, fmt.Errorf("currency insert hatası: %w", err)
|
||||
}
|
||||
|
||||
if ln.ClientKey.Valid && ln.ClientKey.String != "" {
|
||||
lineResults = append(lineResults, OrderLineResult{
|
||||
ClientKey: ln.ClientKey.String,
|
||||
@@ -734,25 +1082,16 @@ VALUES (
|
||||
|
||||
// =======================================================
|
||||
// PART 2 — UpdateOrder FULL DEBUG (v4.3)
|
||||
// ✔ ComboKey ile açık satır eşleştirme
|
||||
// ✔ Kapalı satırları korur
|
||||
// ✔ Payload içi Duplicate Guard
|
||||
// ✔ INSERT/UPDATE öncesi ItemVariant Guard (tek noktada)
|
||||
// ✔ Grid’de olmayan açık satırları siler (önce child)
|
||||
// =======================================================
|
||||
|
||||
func UpdateOrder(header models.OrderHeader, lines []models.OrderDetail, user *models.User) ([]OrderLineResult, error) {
|
||||
conn := db.GetDB()
|
||||
|
||||
// ======================================================
|
||||
// 🔍 SCAN DEBUG — HEADER bilgisi
|
||||
// ======================================================
|
||||
fmt.Println("══════════════════════════════════════")
|
||||
fmt.Println("🔍 [DEBUG] UpdateOrder çağrıldı")
|
||||
fmt.Printf("🔍 HeaderID: %v\n", header.OrderHeaderID)
|
||||
fmt.Printf("🔍 Line sayısı: %v\n", len(lines))
|
||||
fmt.Printf("🔍 User: %v (V3: %s/%d)\n",
|
||||
user.Username, user.V3Username, user.V3UserGroup)
|
||||
fmt.Printf("🔍 User: %v (V3: %s/%d)\n", user.Username, user.V3Username, user.V3UserGroup)
|
||||
fmt.Println("══════════════════════════════════════")
|
||||
|
||||
tx, err := conn.Begin()
|
||||
@@ -762,9 +1101,9 @@ func UpdateOrder(header models.OrderHeader, lines []models.OrderDetail, user *mo
|
||||
defer tx.Rollback()
|
||||
|
||||
now := time.Now()
|
||||
v3User := fmt.Sprintf("V3U%d-%s", user.V3UserGroup, user.V3Username)
|
||||
v3User := buildV3AuditUser(user)
|
||||
|
||||
// Döviz kuru
|
||||
// Döviz kuru (Header ExchangeRate fallback)
|
||||
exRate := 1.0
|
||||
if header.DocCurrencyCode.Valid && header.DocCurrencyCode.String != "TRY" {
|
||||
if c, err := GetTodayCurrencyV3(conn, header.DocCurrencyCode.String); err == nil && c.Rate > 0 {
|
||||
@@ -775,11 +1114,16 @@ func UpdateOrder(header models.OrderHeader, lines []models.OrderDetail, user *mo
|
||||
// =======================================================
|
||||
// 0) Mevcut satırları oku (GUID STRING olarak!)
|
||||
// =======================================================
|
||||
|
||||
existingOpen := make(map[string]bool)
|
||||
existingClosed := make(map[string]bool)
|
||||
existingOpenCombo := make(map[string]string)
|
||||
existingClosedCombo := make(map[string]string)
|
||||
existingOpenMeta := make(map[string]struct {
|
||||
item string
|
||||
color string
|
||||
dim1 string
|
||||
dim2 string
|
||||
})
|
||||
|
||||
rows, err := tx.Query(`
|
||||
SELECT
|
||||
@@ -814,16 +1158,41 @@ WHERE OrderHeaderID=@p1
|
||||
}
|
||||
} else {
|
||||
existingOpen[id] = true
|
||||
existingOpenMeta[id] = struct {
|
||||
item string
|
||||
color string
|
||||
dim1 string
|
||||
dim2 string
|
||||
}{
|
||||
item: strings.TrimSpace(item),
|
||||
color: strings.TrimSpace(color),
|
||||
dim1: strings.TrimSpace(dim1),
|
||||
dim2: strings.TrimSpace(dim2),
|
||||
}
|
||||
if combo != "" {
|
||||
existingOpenCombo[combo] = id
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
isLineInvoiced := func(lineID string) (bool, error) {
|
||||
var exists int
|
||||
err := tx.QueryRow(`
|
||||
SELECT CASE WHEN EXISTS (
|
||||
SELECT 1
|
||||
FROM BAGGI_V3.dbo.trInvoiceLine WITH (NOLOCK)
|
||||
WHERE OrderLineID=@p1
|
||||
) THEN 1 ELSE 0 END
|
||||
`, lineID).Scan(&exists)
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("invoice line kontrol query hatasi: %w", err)
|
||||
}
|
||||
return exists == 1, nil
|
||||
}
|
||||
|
||||
// ======================================================
|
||||
// HEADER UPDATE
|
||||
// ======================================================
|
||||
|
||||
_, err = tx.Exec(`
|
||||
UPDATE BAGGI_V3.dbo.trOrderHeader SET
|
||||
OrderDate=@p1,
|
||||
@@ -853,11 +1222,12 @@ WHERE OrderHeaderID=@p11
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// ======================================================
|
||||
// PREPARE STATEMENTS
|
||||
// ======================================================
|
||||
|
||||
insStmt, err := tx.Prepare(`INSERT INTO BAGGI_V3.dbo.trOrderLine (
|
||||
insStmt, err := tx.Prepare(`
|
||||
INSERT INTO BAGGI_V3.dbo.trOrderLine (
|
||||
OrderLineID, SortOrder, ItemTypeCode, ItemCode, ColorCode,
|
||||
ItemDim1Code, ItemDim2Code, ItemDim3Code,
|
||||
Qty1, Qty2, CancelQty1, CancelQty2, OrderCancelReasonCode,
|
||||
@@ -872,21 +1242,23 @@ BaseSubCurrAccID, BaseStoreCode,
|
||||
OrderHeaderID, CreatedUserName, CreatedDate,
|
||||
LastUpdatedUserName, LastUpdatedDate,
|
||||
SurplusOrderQtyToleranceRate,
|
||||
WithHoldingTaxTypeCode, DOVCode)
|
||||
WithHoldingTaxTypeCode, DOVCode
|
||||
)
|
||||
VALUES (
|
||||
@p1,@p2,@p3,@p4,@p5,@p6,@p7,@p8,@p9,@p10,
|
||||
@p11,@p12,@p13,@p14,@p15,@p16,@p17,@p18,
|
||||
@p19,@p20,@p21,@p22,@p23,@p24,@p25,@p26,@p27,
|
||||
@p28,@p29,@p30,@p31,@p32,@p33,@p34,@p35,
|
||||
@p36,@p37,@p38,@p39,@p40,@p41,@p42,@p43,
|
||||
@p44,@p45)`)
|
||||
|
||||
@p44,@p45
|
||||
)`)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer insStmt.Close()
|
||||
|
||||
updStmt, err := tx.Prepare(`UPDATE BAGGI_V3.dbo.trOrderLine SET
|
||||
updStmt, err := tx.Prepare(`
|
||||
UPDATE BAGGI_V3.dbo.trOrderLine SET
|
||||
SortOrder=@p1, ItemTypeCode=@p2, ItemCode=@p3, ColorCode=@p4,
|
||||
ItemDim1Code=@p5, ItemDim2Code=@p6, ItemDim3Code=@p7,
|
||||
Qty1=@p8, Qty2=@p9, CancelQty1=@p10, CancelQty2=@p11,
|
||||
@@ -905,17 +1277,18 @@ LastUpdatedUserName=@p37, LastUpdatedDate=@p38,
|
||||
SurplusOrderQtyToleranceRate=@p39,
|
||||
WithHoldingTaxTypeCode=@p40, DOVCode=@p41
|
||||
WHERE OrderLineID=@p42 AND ISNULL(IsClosed,0)=0`)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer updStmt.Close()
|
||||
|
||||
// ======================================================
|
||||
// LOOP
|
||||
// ======================================================
|
||||
lineResults := make([]OrderLineResult, 0)
|
||||
seenCombo := make(map[string]bool)
|
||||
|
||||
for _, ln := range lines {
|
||||
|
||||
comboKey := normalizeComboKey(safeNS(ln.ComboKey))
|
||||
if comboKey == "" {
|
||||
comboKey = makeComboKey(ln)
|
||||
@@ -929,7 +1302,7 @@ WHERE OrderLineID=@p42 AND ISNULL(IsClosed,0)=0`)
|
||||
seenCombo[comboKey] = true
|
||||
}
|
||||
|
||||
// Kapalı satır
|
||||
// Kapalı satır guard
|
||||
if ln.OrderLineID != "" && existingClosed[ln.OrderLineID] {
|
||||
continue
|
||||
}
|
||||
@@ -941,23 +1314,39 @@ WHERE OrderLineID=@p42 AND ISNULL(IsClosed,0)=0`)
|
||||
|
||||
// DELETE SIGNAL
|
||||
if ln.OrderLineID != "" && qtyValue(ln.Qty1) <= 0 {
|
||||
_, err := tx.Exec(`DELETE FROM BAGGI_V3.dbo.trOrderLineCurrency WHERE OrderLineID=@p1`, ln.OrderLineID)
|
||||
invoiced, err := isLineInvoiced(ln.OrderLineID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = tx.Exec(`
|
||||
if invoiced {
|
||||
return nil, &models.ValidationError{
|
||||
Code: "ORDER_LINE_INVOICED",
|
||||
Message: fmt.Sprintf("Faturalanmis satir silinemez (OrderLineID=%s)", ln.OrderLineID),
|
||||
ClientKey: safeNS(ln.ClientKey),
|
||||
ItemCode: strings.TrimSpace(safeNS(ln.ItemCode)),
|
||||
ColorCode: strings.TrimSpace(safeNS(ln.ColorCode)),
|
||||
Dim1: strings.TrimSpace(safeNS(ln.ItemDim1Code)),
|
||||
Dim2: strings.TrimSpace(safeNS(ln.ItemDim2Code)),
|
||||
}
|
||||
}
|
||||
if _, err := tx.Exec(`DELETE FROM BAGGI_V3.dbo.trOrderLineCurrency WHERE OrderLineID=@p1`, ln.OrderLineID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := tx.Exec(`
|
||||
DELETE FROM BAGGI_V3.dbo.trOrderLine
|
||||
WHERE OrderHeaderID=@p1 AND OrderLineID=@p2 AND ISNULL(IsClosed,0)=0
|
||||
`, header.OrderHeaderID, ln.OrderLineID)
|
||||
if err != nil {
|
||||
`, header.OrderHeaderID, ln.OrderLineID); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
delete(existingOpen, ln.OrderLineID)
|
||||
delete(existingOpenCombo, comboKey)
|
||||
continue
|
||||
}
|
||||
|
||||
isNew := false
|
||||
|
||||
// ID resolve: boşsa combo'dan yakala, yoksa yeni üret
|
||||
if ln.OrderLineID == "" {
|
||||
if dbID, ok := existingOpenCombo[comboKey]; ok {
|
||||
ln.OrderLineID = dbID
|
||||
@@ -967,6 +1356,7 @@ WHERE OrderHeaderID=@p1 AND OrderLineID=@p2 AND ISNULL(IsClosed,0)=0
|
||||
}
|
||||
}
|
||||
|
||||
// Variant guard
|
||||
if qtyValue(ln.Qty1) > 0 {
|
||||
if err := ValidateItemVariant(tx, ln); err != nil {
|
||||
return nil, err
|
||||
@@ -1048,9 +1438,28 @@ WHERE OrderHeaderID=@p1 AND OrderLineID=@p2 AND ISNULL(IsClosed,0)=0
|
||||
}
|
||||
}
|
||||
|
||||
// ✅ Currency UPSERT (insert/update sonrası ortak)
|
||||
if err := upsertLineCurrency(
|
||||
tx,
|
||||
ln.OrderLineID,
|
||||
safeNS(ln.DocCurrencyCode),
|
||||
nf0(ln.PriceExchangeRate),
|
||||
nf0(ln.Price),
|
||||
nf0(ln.Qty1),
|
||||
nf0(ln.LDisRate1),
|
||||
0, // TODO: header TDisRate toplamını istersen buraya bağlarız
|
||||
nf0(ln.VatRate), // satır vat oranı
|
||||
ln,
|
||||
v3User,
|
||||
); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Bu satır işlendi -> existingOpen setinden düş
|
||||
delete(existingOpen, ln.OrderLineID)
|
||||
delete(existingOpenCombo, comboKey)
|
||||
|
||||
// Sonuç mapping
|
||||
if ln.ClientKey.Valid {
|
||||
lineResults = append(lineResults, OrderLineResult{
|
||||
ClientKey: ln.ClientKey.String,
|
||||
@@ -1059,18 +1468,31 @@ WHERE OrderHeaderID=@p1 AND OrderLineID=@p2 AND ISNULL(IsClosed,0)=0
|
||||
}
|
||||
}
|
||||
|
||||
// Grid dışı kalan açık satırlar
|
||||
// =======================================================
|
||||
// Grid dışı kalan açık satırlar (payload'da yok -> sil)
|
||||
// =======================================================
|
||||
for id := range existingOpen {
|
||||
_, err := tx.Exec(`DELETE FROM BAGGI_V3.dbo.trOrderLineCurrency WHERE OrderLineID=@p1`, id)
|
||||
invoiced, err := isLineInvoiced(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = tx.Exec(`DELETE FROM BAGGI_V3.dbo.trOrderLine WHERE OrderLineID=@p1 AND ISNULL(IsClosed,0)=0`, id)
|
||||
if err != nil {
|
||||
if invoiced {
|
||||
meta := existingOpenMeta[id]
|
||||
fmt.Printf("[ORDER_UPDATE] skip delete invoiced line id=%s item=%s color=%s dim1=%s dim2=%s\n",
|
||||
id, meta.item, meta.color, meta.dim1, meta.dim2)
|
||||
continue
|
||||
}
|
||||
if _, err := tx.Exec(`DELETE FROM BAGGI_V3.dbo.trOrderLineCurrency WHERE OrderLineID=@p1`, id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, err := tx.Exec(`DELETE FROM BAGGI_V3.dbo.trOrderLine WHERE OrderLineID=@p1 AND ISNULL(IsClosed,0)=0`, id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
// =======================================================
|
||||
// COMMIT + RETURN
|
||||
// =======================================================
|
||||
if err := tx.Commit(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -10,6 +10,10 @@ import (
|
||||
|
||||
// ========================================================
|
||||
// 📌 GetOrderList — FINAL + CURRENCY SAFE + PIYASA AUTHZ
|
||||
//
|
||||
// ✅ TotalAmount artık trOrderLineCurrency(NetAmount) üzerinden
|
||||
// ve CurrencyCode = Header.DocCurrencyCode satırından gelir.
|
||||
//
|
||||
// ========================================================
|
||||
func GetOrderList(
|
||||
ctx context.Context,
|
||||
@@ -36,10 +40,8 @@ func GetOrderList(
|
||||
}
|
||||
|
||||
if len(codes) == 0 {
|
||||
// hiç yetkisi yok → hiç kayıt dönmesin
|
||||
piyasaWhere = "1=0"
|
||||
} else {
|
||||
// ⚠️ EXISTS içinde kullanılacak
|
||||
piyasaWhere = authz.BuildINClause(
|
||||
"UPPER(f2.CustomerAtt01)",
|
||||
codes,
|
||||
@@ -86,6 +88,29 @@ SELECT
|
||||
ELSE 0
|
||||
END AS TotalAmountUSD,
|
||||
|
||||
ISNULL(l.PackedAmount,0) AS PackedAmount,
|
||||
|
||||
CASE
|
||||
WHEN h.DocCurrencyCode = 'USD'
|
||||
THEN ISNULL(l.PackedAmount,0)
|
||||
|
||||
WHEN h.DocCurrencyCode = 'TRY'
|
||||
AND usd.Rate > 0
|
||||
THEN ISNULL(l.PackedTRY,0) / usd.Rate
|
||||
|
||||
WHEN cur.Rate > 0
|
||||
AND usd.Rate > 0
|
||||
THEN (ISNULL(l.PackedAmount,0) * cur.Rate) / usd.Rate
|
||||
|
||||
ELSE 0
|
||||
END AS PackedUSD,
|
||||
|
||||
CASE
|
||||
WHEN ISNULL(l.TotalAmount,0) > 0
|
||||
THEN (ISNULL(l.PackedAmount,0) * 100.0) / NULLIF(l.TotalAmount,0)
|
||||
ELSE 0
|
||||
END AS PackedRatePct,
|
||||
|
||||
ISNULL(h.IsCreditableConfirmed,0) AS IsCreditableConfirmed,
|
||||
ISNULL(h.Description,'') AS Description,
|
||||
|
||||
@@ -93,12 +118,40 @@ SELECT
|
||||
|
||||
FROM dbo.trOrderHeader h
|
||||
|
||||
-- ✅ TOPLAM ARTIK trOrderLineCurrency'den: CurrencyCode = DocCurrencyCode
|
||||
JOIN (
|
||||
SELECT
|
||||
OrderHeaderID,
|
||||
SUM(Qty1 * Price) AS TotalAmount
|
||||
FROM dbo.trOrderLine
|
||||
GROUP BY OrderHeaderID
|
||||
l.OrderHeaderID,
|
||||
SUM(ISNULL(c.NetAmount,0)) AS TotalAmount,
|
||||
SUM(
|
||||
CASE
|
||||
WHEN ISNULL(c.CurrencyCode,'') = 'TRY'
|
||||
THEN ISNULL(c.NetAmount,0)
|
||||
ELSE 0
|
||||
END
|
||||
) AS TotalTRY,
|
||||
SUM(
|
||||
CASE
|
||||
WHEN ISNULL(l.IsClosed,0) = 1
|
||||
THEN ISNULL(c.NetAmount,0)
|
||||
ELSE 0
|
||||
END
|
||||
) AS PackedAmount,
|
||||
SUM(
|
||||
CASE
|
||||
WHEN ISNULL(l.IsClosed,0) = 1
|
||||
AND ISNULL(c.CurrencyCode,'') = 'TRY'
|
||||
THEN ISNULL(c.NetAmount,0)
|
||||
ELSE 0
|
||||
END
|
||||
) AS PackedTRY
|
||||
FROM dbo.trOrderLine l
|
||||
JOIN dbo.trOrderHeader h2
|
||||
ON h2.OrderHeaderID = l.OrderHeaderID
|
||||
LEFT JOIN dbo.trOrderLineCurrency c
|
||||
ON c.OrderLineID = l.OrderLineID
|
||||
AND c.CurrencyCode = ISNULL(h2.DocCurrencyCode,'TRY')
|
||||
GROUP BY l.OrderHeaderID
|
||||
) l
|
||||
ON l.OrderHeaderID = h.OrderHeaderID
|
||||
|
||||
|
||||
Reference in New Issue
Block a user