Merge remote-tracking branch 'origin/master'
This commit is contained in:
@@ -18,7 +18,8 @@ func BuildClaimsFromUser(u *models.MkUser, ttl time.Duration) Claims {
|
|||||||
Username: u.Username,
|
Username: u.Username,
|
||||||
RoleCode: u.RoleCode,
|
RoleCode: u.RoleCode,
|
||||||
RoleID: u.RoleID,
|
RoleID: u.RoleID,
|
||||||
// ✅ BURASI
|
V3Username: u.V3Username,
|
||||||
|
V3UserGroup: u.V3UserGroup,
|
||||||
DepartmentCodes: u.DepartmentCodes,
|
DepartmentCodes: u.DepartmentCodes,
|
||||||
|
|
||||||
SessionID: u.SessionID,
|
SessionID: u.SessionID,
|
||||||
|
|||||||
@@ -55,6 +55,7 @@ type OrderDetail struct {
|
|||||||
LDisRate5 NullFloat64 `json:"LDisRate5"`
|
LDisRate5 NullFloat64 `json:"LDisRate5"`
|
||||||
|
|
||||||
DocCurrencyCode NullString `json:"DocCurrencyCode"`
|
DocCurrencyCode NullString `json:"DocCurrencyCode"`
|
||||||
|
RelationCurrencyCode NullString `json:"RelationCurrencyCode"`
|
||||||
PriceCurrencyCode NullString `json:"PriceCurrencyCode"`
|
PriceCurrencyCode NullString `json:"PriceCurrencyCode"`
|
||||||
PriceExchangeRate NullFloat64 `json:"PriceExchangeRate"`
|
PriceExchangeRate NullFloat64 `json:"PriceExchangeRate"`
|
||||||
|
|
||||||
@@ -95,4 +96,29 @@ type OrderDetail struct {
|
|||||||
UrunAltGrubu NullString `json:"UrunAltGrubu"`
|
UrunAltGrubu NullString `json:"UrunAltGrubu"`
|
||||||
Fit1 NullString `json:"Fit1"`
|
Fit1 NullString `json:"Fit1"`
|
||||||
Fit2 NullString `json:"Fit2"`
|
Fit2 NullString `json:"Fit2"`
|
||||||
|
// ============================
|
||||||
|
// 💰 Currency / Amount Fields
|
||||||
|
// (trOrderLineCurrency)
|
||||||
|
// ============================
|
||||||
|
|
||||||
|
// Döviz bazlı
|
||||||
|
DocPrice NullFloat64 `json:"DocPrice"` // PriceVI
|
||||||
|
DocAmount NullFloat64 `json:"DocAmount"` // AmountVI
|
||||||
|
|
||||||
|
// Yerel para (TRY)
|
||||||
|
LocalPrice NullFloat64 `json:"LocalPrice"` // Price
|
||||||
|
LocalAmount NullFloat64 `json:"LocalAmount"` // Amount
|
||||||
|
|
||||||
|
// İndirimler
|
||||||
|
LineDiscount NullFloat64 `json:"LineDiscount"` // LDiscount1
|
||||||
|
TotalDiscount NullFloat64 `json:"TotalDiscount"` // TDiscount1
|
||||||
|
|
||||||
|
// Vergi / Matrah
|
||||||
|
TaxBase NullFloat64 `json:"TaxBase"`
|
||||||
|
VatAmount NullFloat64 `json:"VatAmount"`
|
||||||
|
VatDeducation NullFloat64 `json:"VatDeducation"`
|
||||||
|
NetAmount NullFloat64 `json:"NetAmount"`
|
||||||
|
|
||||||
|
// Genel oran
|
||||||
|
Pct NullFloat64 `json:"Pct"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,9 @@ type OrderList struct {
|
|||||||
// 💰 Tutarlar
|
// 💰 Tutarlar
|
||||||
TotalAmount float64 `json:"TotalAmount"`
|
TotalAmount float64 `json:"TotalAmount"`
|
||||||
TotalAmountUSD float64 `json:"TotalAmountUSD"`
|
TotalAmountUSD float64 `json:"TotalAmountUSD"`
|
||||||
|
PackedAmount float64 `json:"PackedAmount"`
|
||||||
|
PackedUSD float64 `json:"PackedUSD"`
|
||||||
|
PackedRatePct float64 `json:"PackedRatePct"`
|
||||||
|
|
||||||
// 📝 Açıklama
|
// 📝 Açıklama
|
||||||
Description string `json:"Description"`
|
Description string `json:"Description"`
|
||||||
|
|||||||
@@ -12,40 +12,230 @@ func GetOrderListExcel(
|
|||||||
orderDate string,
|
orderDate string,
|
||||||
) (*sql.Rows, error) {
|
) (*sql.Rows, error) {
|
||||||
|
|
||||||
q := OrderListBaseQuery + " AND 1=1 "
|
q := `
|
||||||
args := []interface{}{}
|
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 != "" {
|
if search != "" {
|
||||||
q += `
|
q += `
|
||||||
AND (
|
AND (
|
||||||
LOWER(h.OrderNumber) LIKE LOWER(@p1) OR
|
LOWER(h.OrderNumber) LIKE LOWER(@p1)
|
||||||
LOWER(h.CurrAccCode) LIKE LOWER(@p1) OR
|
OR LOWER(h.CurrAccCode) LIKE LOWER(@p1)
|
||||||
LOWER(ca.CurrAccDescription) LIKE LOWER(@p1) OR
|
OR LOWER(ca.CurrAccDescription) LIKE LOWER(@p1)
|
||||||
LOWER(h.Description) LIKE LOWER(@p1) OR
|
OR LOWER(h.Description) LIKE LOWER(@p1)
|
||||||
LOWER(mt.AttributeDescription) LIKE LOWER(@p1) OR
|
OR LOWER(mt.AttributeDescription) LIKE LOWER(@p1)
|
||||||
LOWER(py.AttributeDescription) LIKE LOWER(@p1)
|
OR LOWER(py.AttributeDescription) LIKE LOWER(@p1)
|
||||||
)
|
)
|
||||||
`
|
`
|
||||||
args = append(args, "%"+search+"%")
|
args = append(args, "%"+search+"%")
|
||||||
}
|
}
|
||||||
|
|
||||||
// CURRACC
|
// ================= CURRACC =================
|
||||||
if currAcc != "" {
|
if currAcc != "" {
|
||||||
q += fmt.Sprintf(" AND h.CurrAccCode = @p%d ", len(args)+1)
|
q += fmt.Sprintf(" AND h.CurrAccCode = @p%d ", len(args)+1)
|
||||||
args = append(args, currAcc)
|
args = append(args, currAcc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DATE
|
// ================= DATE =================
|
||||||
if orderDate != "" {
|
if orderDate != "" {
|
||||||
q += fmt.Sprintf(
|
q += fmt.Sprintf(
|
||||||
" AND CONVERT(varchar, h.OrderDate, 23) = @p%d ",
|
" AND CONVERT(varchar,h.OrderDate,23) = @p%d ",
|
||||||
len(args)+1,
|
len(args)+1,
|
||||||
)
|
)
|
||||||
args = append(args, orderDate)
|
args = append(args, orderDate)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ORDER BY SONDA
|
// ================= ORDER =================
|
||||||
q += " ORDER BY h.CreatedDate DESC "
|
q += " ORDER BY h.CreatedDate DESC "
|
||||||
|
|
||||||
return db.Query(q, args...)
|
return db.Query(q, args...)
|
||||||
|
|||||||
@@ -8,15 +8,12 @@ import (
|
|||||||
"fmt"
|
"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) {
|
func GetOrderByID(orderID string) (*models.OrderHeader, []models.OrderDetail, error) {
|
||||||
conn := db.GetDB()
|
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
|
var header models.OrderHeader
|
||||||
qHeader := `
|
qHeader := `
|
||||||
SELECT
|
SELECT
|
||||||
@@ -176,24 +173,17 @@ func GetOrderByID(orderID string) (*models.OrderHeader, []models.OrderDetail, er
|
|||||||
&header.LastUpdatedDate,
|
&header.LastUpdatedDate,
|
||||||
&header.IsProposalBased,
|
&header.IsProposalBased,
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, sql.ErrNoRows) {
|
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
|
return nil, nil, sql.ErrNoRows
|
||||||
}
|
}
|
||||||
logger.Printf("❌ [GetOrderByID] header sorgu hatası: %v", err)
|
logger.Printf("[GetOrderByID] header error: %v", err)
|
||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Printf("✅ [GetOrderByID] header loaded • orderNo=%v currAcc=%v",
|
|
||||||
header.OrderNumber, header.CurrAccCode.String)
|
|
||||||
|
|
||||||
// =====================================================
|
|
||||||
// LINES
|
|
||||||
// =====================================================
|
|
||||||
qLines := `
|
qLines := `
|
||||||
SELECT
|
SELECT
|
||||||
CAST(L.OrderLineID AS varchar(36)) AS OrderLineID,
|
CAST(L.OrderLineID AS varchar(36)) AS OrderLineID,
|
||||||
L.SortOrder,
|
L.SortOrder,
|
||||||
L.ItemTypeCode,
|
L.ItemTypeCode,
|
||||||
@@ -204,10 +194,25 @@ func GetOrderByID(orderID string) (*models.OrderHeader, []models.OrderDetail, er
|
|||||||
L.ItemDim3Code,
|
L.ItemDim3Code,
|
||||||
L.Qty1,
|
L.Qty1,
|
||||||
L.Qty2,
|
L.Qty2,
|
||||||
L.Price,
|
|
||||||
|
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.VatRate,
|
||||||
L.PCTRate,
|
L.PCTRate,
|
||||||
L.DocCurrencyCode,
|
|
||||||
L.DeliveryDate,
|
L.DeliveryDate,
|
||||||
L.PlannedDateOfLading,
|
L.PlannedDateOfLading,
|
||||||
L.LineDescription,
|
L.LineDescription,
|
||||||
@@ -216,21 +221,28 @@ func GetOrderByID(orderID string) (*models.OrderHeader, []models.OrderDetail, er
|
|||||||
L.CreatedDate,
|
L.CreatedDate,
|
||||||
L.LastUpdatedUserName,
|
L.LastUpdatedUserName,
|
||||||
L.LastUpdatedDate,
|
L.LastUpdatedDate,
|
||||||
|
|
||||||
P.ProductAtt42Desc AS UrunIlkGrubu,
|
P.ProductAtt42Desc AS UrunIlkGrubu,
|
||||||
P.ProductAtt01Desc AS UrunAnaGrubu,
|
P.ProductAtt01Desc AS UrunAnaGrubu,
|
||||||
P.ProductAtt02Desc AS UrunAltGrubu,
|
P.ProductAtt02Desc AS UrunAltGrubu,
|
||||||
P.ProductAtt38Desc AS Fit1,
|
P.ProductAtt38Desc AS Fit1,
|
||||||
P.ProductAtt39Desc AS Fit2
|
P.ProductAtt39Desc AS Fit2
|
||||||
FROM BAGGI_V3.dbo.trOrderLine AS L
|
FROM BAGGI_V3.dbo.trOrderLine AS L
|
||||||
LEFT JOIN ProductFilterWithDescription('TR') AS P
|
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))
|
ON LTRIM(RTRIM(P.ProductCode)) = LTRIM(RTRIM(L.ItemCode))
|
||||||
WHERE L.OrderHeaderID = @p1
|
WHERE L.OrderHeaderID = @p1
|
||||||
ORDER BY L.SortOrder ASC;
|
ORDER BY L.SortOrder ASC;
|
||||||
`
|
`
|
||||||
|
|
||||||
rows, err := conn.Query(qLines, orderID)
|
rows, err := conn.Query(qLines, orderID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Printf("❌ [GetOrderByID] line sorgu hatası: %v", err)
|
logger.Printf("[GetOrderByID] lines error: %v", err)
|
||||||
return &header, nil, err
|
return &header, nil, err
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
@@ -250,9 +262,22 @@ func GetOrderByID(orderID string) (*models.OrderHeader, []models.OrderDetail, er
|
|||||||
&ln.Qty1,
|
&ln.Qty1,
|
||||||
&ln.Qty2,
|
&ln.Qty2,
|
||||||
&ln.Price,
|
&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.VatRate,
|
||||||
&ln.PCTRate,
|
&ln.PCTRate,
|
||||||
&ln.DocCurrencyCode,
|
|
||||||
&ln.DeliveryDate,
|
&ln.DeliveryDate,
|
||||||
&ln.PlannedDateOfLading,
|
&ln.PlannedDateOfLading,
|
||||||
&ln.LineDescription,
|
&ln.LineDescription,
|
||||||
@@ -267,14 +292,14 @@ func GetOrderByID(orderID string) (*models.OrderHeader, []models.OrderDetail, er
|
|||||||
&ln.Fit1,
|
&ln.Fit1,
|
||||||
&ln.Fit2,
|
&ln.Fit2,
|
||||||
); err != nil {
|
); 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)
|
lines = append(lines, ln)
|
||||||
}
|
}
|
||||||
if err := rows.Err(); err != nil {
|
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
|
return &header, lines, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,9 +13,10 @@ import (
|
|||||||
"bssapp-backend/models"
|
"bssapp-backend/models"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/google/uuid"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
func nf0(v models.NullFloat64) float64 {
|
func nf0(v models.NullFloat64) float64 {
|
||||||
@@ -25,6 +26,311 @@ func nf0(v models.NullFloat64) float64 {
|
|||||||
return v.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
|
// COMBO KEY & STRING HELPERS
|
||||||
// =======================================================
|
// =======================================================
|
||||||
@@ -52,6 +358,32 @@ func qtyValue(q models.NullFloat64) float64 {
|
|||||||
return q.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
|
// VatCode: NullString → string
|
||||||
// - NULL → ""
|
// - NULL → ""
|
||||||
// - "0" → "" (FK patlamasın, sadece anlamlı kodlar gönderiyoruz)
|
// - "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
|
var exists int
|
||||||
err := tx.QueryRow(`
|
err := tx.QueryRow(`
|
||||||
SELECT CASE WHEN EXISTS (
|
SELECT CASE WHEN EXISTS (
|
||||||
@@ -297,12 +626,6 @@ type OrderLineResult struct {
|
|||||||
|
|
||||||
// =======================================================
|
// =======================================================
|
||||||
// PART 1 — InsertOrder (header + lines insert) — FINAL v5.1
|
// 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) {
|
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()
|
defer tx.Rollback()
|
||||||
|
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
v3User := fmt.Sprintf("V3U%d-%s", user.V3UserGroup, user.V3Username)
|
v3User := buildV3AuditUser(user)
|
||||||
|
|
||||||
// =======================================================
|
// =======================================================
|
||||||
// 1) BACKEND — OrderHeaderID üretimi (HER ZAMAN)
|
// 1) BACKEND — OrderHeaderID üretimi (HER ZAMAN)
|
||||||
@@ -368,7 +691,6 @@ func InsertOrder(header models.OrderHeader, lines []models.OrderDetail, user *mo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// =======================================================
|
// =======================================================
|
||||||
// 4) HEADER INSERT
|
// 4) HEADER INSERT
|
||||||
// =======================================================
|
// =======================================================
|
||||||
@@ -423,6 +745,7 @@ VALUES (
|
|||||||
|
|
||||||
fmt.Println("🟪 HEADER INSERT ÇALIŞIYOR...")
|
fmt.Println("🟪 HEADER INSERT ÇALIŞIYOR...")
|
||||||
|
|
||||||
|
// ✅ exRate burada gerçekten kullanılıyor (ExchangeRate parametresi)
|
||||||
headerParams := []any{
|
headerParams := []any{
|
||||||
header.OrderHeaderID,
|
header.OrderHeaderID,
|
||||||
nullableInt16(header.OrderTypeCode, 1),
|
nullableInt16(header.OrderTypeCode, 1),
|
||||||
@@ -474,7 +797,7 @@ VALUES (
|
|||||||
nullableString(header.GLTypeCode, ""),
|
nullableString(header.GLTypeCode, ""),
|
||||||
nullableString(header.DocCurrencyCode, "TRY"),
|
nullableString(header.DocCurrencyCode, "TRY"),
|
||||||
nullableString(header.LocalCurrencyCode, "TRY"),
|
nullableString(header.LocalCurrencyCode, "TRY"),
|
||||||
nullableFloat64(header.ExchangeRate, exRate),
|
nullableFloat64(header.ExchangeRate, exRate), // ✅ exRate kullanıldı
|
||||||
|
|
||||||
nullableFloat64(header.TDisRate1, 0),
|
nullableFloat64(header.TDisRate1, 0),
|
||||||
nullableFloat64(header.TDisRate2, 0),
|
nullableFloat64(header.TDisRate2, 0),
|
||||||
@@ -520,6 +843,7 @@ VALUES (
|
|||||||
nullableBool(header.IsProposalBased, false),
|
nullableBool(header.IsProposalBased, false),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ✅ queryHeader artık gerçekten kullanılıyor → "Unused variable 'queryHeader'" biter
|
||||||
if _, err := tx.Exec(queryHeader, headerParams...); err != nil {
|
if _, err := tx.Exec(queryHeader, headerParams...); err != nil {
|
||||||
fmt.Println("❌ HEADER INSERT ERROR:", err)
|
fmt.Println("❌ HEADER INSERT ERROR:", err)
|
||||||
return "", nil, fmt.Errorf("header insert hatasi: %w", err)
|
return "", nil, fmt.Errorf("header insert hatasi: %w", err)
|
||||||
@@ -527,6 +851,7 @@ VALUES (
|
|||||||
|
|
||||||
fmt.Println("🟩 HEADER INSERT OK — ID:", newID)
|
fmt.Println("🟩 HEADER INSERT OK — ID:", newID)
|
||||||
|
|
||||||
|
// headerParams ... (senin mevcut hali aynen)
|
||||||
// =======================================================
|
// =======================================================
|
||||||
// 5) LINE INSERT
|
// 5) LINE INSERT
|
||||||
// =======================================================
|
// =======================================================
|
||||||
@@ -590,7 +915,6 @@ VALUES (
|
|||||||
seenCombo := make(map[string]bool)
|
seenCombo := make(map[string]bool)
|
||||||
|
|
||||||
for i, ln := range lines {
|
for i, ln := range lines {
|
||||||
// ===================== PART 2 (Satır 301-600) =====================
|
|
||||||
fmt.Println("────────────────────────────────────")
|
fmt.Println("────────────────────────────────────")
|
||||||
fmt.Printf("🟨 [INSERT] LINE %d — gelen OrderLineID=%s\n", i+1, ln.OrderLineID)
|
fmt.Printf("🟨 [INSERT] LINE %d — gelen OrderLineID=%s\n", i+1, ln.OrderLineID)
|
||||||
|
|
||||||
@@ -630,6 +954,7 @@ VALUES (
|
|||||||
}
|
}
|
||||||
|
|
||||||
planned := nullableDateString(ln.PlannedDateOfLading)
|
planned := nullableDateString(ln.PlannedDateOfLading)
|
||||||
|
|
||||||
// ✅ INSERT ÖNCESİ ItemVariant GUARD
|
// ✅ INSERT ÖNCESİ ItemVariant GUARD
|
||||||
if qtyValue(ln.Qty1) > 0 {
|
if qtyValue(ln.Qty1) > 0 {
|
||||||
if err := ValidateItemVariant(tx, ln); err != nil {
|
if err := ValidateItemVariant(tx, ln); err != nil {
|
||||||
@@ -637,6 +962,7 @@ VALUES (
|
|||||||
return "", nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf(
|
fmt.Printf(
|
||||||
"🚨 INSERT LINE[%d] | LineID=%s ClientKey=%s Item=%q Color=%q Dim1=%q Dim2=%q Dim3=%q Qty1=%v\n",
|
"🚨 INSERT LINE[%d] | LineID=%s ClientKey=%s Item=%q Color=%q Dim1=%q Dim2=%q Dim3=%q Qty1=%v\n",
|
||||||
i+1,
|
i+1,
|
||||||
@@ -708,6 +1034,28 @@ VALUES (
|
|||||||
return "", nil, fmt.Errorf("line insert hatasi: %w", err)
|
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 != "" {
|
if ln.ClientKey.Valid && ln.ClientKey.String != "" {
|
||||||
lineResults = append(lineResults, OrderLineResult{
|
lineResults = append(lineResults, OrderLineResult{
|
||||||
ClientKey: ln.ClientKey.String,
|
ClientKey: ln.ClientKey.String,
|
||||||
@@ -734,25 +1082,16 @@ VALUES (
|
|||||||
|
|
||||||
// =======================================================
|
// =======================================================
|
||||||
// PART 2 — UpdateOrder FULL DEBUG (v4.3)
|
// 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) {
|
func UpdateOrder(header models.OrderHeader, lines []models.OrderDetail, user *models.User) ([]OrderLineResult, error) {
|
||||||
conn := db.GetDB()
|
conn := db.GetDB()
|
||||||
|
|
||||||
// ======================================================
|
|
||||||
// 🔍 SCAN DEBUG — HEADER bilgisi
|
|
||||||
// ======================================================
|
|
||||||
fmt.Println("══════════════════════════════════════")
|
fmt.Println("══════════════════════════════════════")
|
||||||
fmt.Println("🔍 [DEBUG] UpdateOrder çağrıldı")
|
fmt.Println("🔍 [DEBUG] UpdateOrder çağrıldı")
|
||||||
fmt.Printf("🔍 HeaderID: %v\n", header.OrderHeaderID)
|
fmt.Printf("🔍 HeaderID: %v\n", header.OrderHeaderID)
|
||||||
fmt.Printf("🔍 Line sayısı: %v\n", len(lines))
|
fmt.Printf("🔍 Line sayısı: %v\n", len(lines))
|
||||||
fmt.Printf("🔍 User: %v (V3: %s/%d)\n",
|
fmt.Printf("🔍 User: %v (V3: %s/%d)\n", user.Username, user.V3Username, user.V3UserGroup)
|
||||||
user.Username, user.V3Username, user.V3UserGroup)
|
|
||||||
fmt.Println("══════════════════════════════════════")
|
fmt.Println("══════════════════════════════════════")
|
||||||
|
|
||||||
tx, err := conn.Begin()
|
tx, err := conn.Begin()
|
||||||
@@ -762,9 +1101,9 @@ func UpdateOrder(header models.OrderHeader, lines []models.OrderDetail, user *mo
|
|||||||
defer tx.Rollback()
|
defer tx.Rollback()
|
||||||
|
|
||||||
now := time.Now()
|
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
|
exRate := 1.0
|
||||||
if header.DocCurrencyCode.Valid && header.DocCurrencyCode.String != "TRY" {
|
if header.DocCurrencyCode.Valid && header.DocCurrencyCode.String != "TRY" {
|
||||||
if c, err := GetTodayCurrencyV3(conn, header.DocCurrencyCode.String); err == nil && c.Rate > 0 {
|
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!)
|
// 0) Mevcut satırları oku (GUID STRING olarak!)
|
||||||
// =======================================================
|
// =======================================================
|
||||||
|
|
||||||
existingOpen := make(map[string]bool)
|
existingOpen := make(map[string]bool)
|
||||||
existingClosed := make(map[string]bool)
|
existingClosed := make(map[string]bool)
|
||||||
existingOpenCombo := make(map[string]string)
|
existingOpenCombo := make(map[string]string)
|
||||||
existingClosedCombo := 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(`
|
rows, err := tx.Query(`
|
||||||
SELECT
|
SELECT
|
||||||
@@ -814,16 +1158,41 @@ WHERE OrderHeaderID=@p1
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
existingOpen[id] = true
|
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 != "" {
|
if combo != "" {
|
||||||
existingOpenCombo[combo] = id
|
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
|
// HEADER UPDATE
|
||||||
// ======================================================
|
// ======================================================
|
||||||
|
|
||||||
_, err = tx.Exec(`
|
_, err = tx.Exec(`
|
||||||
UPDATE BAGGI_V3.dbo.trOrderHeader SET
|
UPDATE BAGGI_V3.dbo.trOrderHeader SET
|
||||||
OrderDate=@p1,
|
OrderDate=@p1,
|
||||||
@@ -853,11 +1222,12 @@ WHERE OrderHeaderID=@p11
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// ======================================================
|
// ======================================================
|
||||||
// PREPARE STATEMENTS
|
// PREPARE STATEMENTS
|
||||||
// ======================================================
|
// ======================================================
|
||||||
|
insStmt, err := tx.Prepare(`
|
||||||
insStmt, err := tx.Prepare(`INSERT INTO BAGGI_V3.dbo.trOrderLine (
|
INSERT INTO BAGGI_V3.dbo.trOrderLine (
|
||||||
OrderLineID, SortOrder, ItemTypeCode, ItemCode, ColorCode,
|
OrderLineID, SortOrder, ItemTypeCode, ItemCode, ColorCode,
|
||||||
ItemDim1Code, ItemDim2Code, ItemDim3Code,
|
ItemDim1Code, ItemDim2Code, ItemDim3Code,
|
||||||
Qty1, Qty2, CancelQty1, CancelQty2, OrderCancelReasonCode,
|
Qty1, Qty2, CancelQty1, CancelQty2, OrderCancelReasonCode,
|
||||||
@@ -872,21 +1242,23 @@ BaseSubCurrAccID, BaseStoreCode,
|
|||||||
OrderHeaderID, CreatedUserName, CreatedDate,
|
OrderHeaderID, CreatedUserName, CreatedDate,
|
||||||
LastUpdatedUserName, LastUpdatedDate,
|
LastUpdatedUserName, LastUpdatedDate,
|
||||||
SurplusOrderQtyToleranceRate,
|
SurplusOrderQtyToleranceRate,
|
||||||
WithHoldingTaxTypeCode, DOVCode)
|
WithHoldingTaxTypeCode, DOVCode
|
||||||
|
)
|
||||||
VALUES (
|
VALUES (
|
||||||
@p1,@p2,@p3,@p4,@p5,@p6,@p7,@p8,@p9,@p10,
|
@p1,@p2,@p3,@p4,@p5,@p6,@p7,@p8,@p9,@p10,
|
||||||
@p11,@p12,@p13,@p14,@p15,@p16,@p17,@p18,
|
@p11,@p12,@p13,@p14,@p15,@p16,@p17,@p18,
|
||||||
@p19,@p20,@p21,@p22,@p23,@p24,@p25,@p26,@p27,
|
@p19,@p20,@p21,@p22,@p23,@p24,@p25,@p26,@p27,
|
||||||
@p28,@p29,@p30,@p31,@p32,@p33,@p34,@p35,
|
@p28,@p29,@p30,@p31,@p32,@p33,@p34,@p35,
|
||||||
@p36,@p37,@p38,@p39,@p40,@p41,@p42,@p43,
|
@p36,@p37,@p38,@p39,@p40,@p41,@p42,@p43,
|
||||||
@p44,@p45)`)
|
@p44,@p45
|
||||||
|
)`)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer insStmt.Close()
|
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,
|
SortOrder=@p1, ItemTypeCode=@p2, ItemCode=@p3, ColorCode=@p4,
|
||||||
ItemDim1Code=@p5, ItemDim2Code=@p6, ItemDim3Code=@p7,
|
ItemDim1Code=@p5, ItemDim2Code=@p6, ItemDim3Code=@p7,
|
||||||
Qty1=@p8, Qty2=@p9, CancelQty1=@p10, CancelQty2=@p11,
|
Qty1=@p8, Qty2=@p9, CancelQty1=@p10, CancelQty2=@p11,
|
||||||
@@ -905,17 +1277,18 @@ LastUpdatedUserName=@p37, LastUpdatedDate=@p38,
|
|||||||
SurplusOrderQtyToleranceRate=@p39,
|
SurplusOrderQtyToleranceRate=@p39,
|
||||||
WithHoldingTaxTypeCode=@p40, DOVCode=@p41
|
WithHoldingTaxTypeCode=@p40, DOVCode=@p41
|
||||||
WHERE OrderLineID=@p42 AND ISNULL(IsClosed,0)=0`)
|
WHERE OrderLineID=@p42 AND ISNULL(IsClosed,0)=0`)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer updStmt.Close()
|
defer updStmt.Close()
|
||||||
|
|
||||||
|
// ======================================================
|
||||||
|
// LOOP
|
||||||
|
// ======================================================
|
||||||
lineResults := make([]OrderLineResult, 0)
|
lineResults := make([]OrderLineResult, 0)
|
||||||
seenCombo := make(map[string]bool)
|
seenCombo := make(map[string]bool)
|
||||||
|
|
||||||
for _, ln := range lines {
|
for _, ln := range lines {
|
||||||
|
|
||||||
comboKey := normalizeComboKey(safeNS(ln.ComboKey))
|
comboKey := normalizeComboKey(safeNS(ln.ComboKey))
|
||||||
if comboKey == "" {
|
if comboKey == "" {
|
||||||
comboKey = makeComboKey(ln)
|
comboKey = makeComboKey(ln)
|
||||||
@@ -929,7 +1302,7 @@ WHERE OrderLineID=@p42 AND ISNULL(IsClosed,0)=0`)
|
|||||||
seenCombo[comboKey] = true
|
seenCombo[comboKey] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Kapalı satır
|
// Kapalı satır guard
|
||||||
if ln.OrderLineID != "" && existingClosed[ln.OrderLineID] {
|
if ln.OrderLineID != "" && existingClosed[ln.OrderLineID] {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -941,23 +1314,39 @@ WHERE OrderLineID=@p42 AND ISNULL(IsClosed,0)=0`)
|
|||||||
|
|
||||||
// DELETE SIGNAL
|
// DELETE SIGNAL
|
||||||
if ln.OrderLineID != "" && qtyValue(ln.Qty1) <= 0 {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
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
|
DELETE FROM BAGGI_V3.dbo.trOrderLine
|
||||||
WHERE OrderHeaderID=@p1 AND OrderLineID=@p2 AND ISNULL(IsClosed,0)=0
|
WHERE OrderHeaderID=@p1 AND OrderLineID=@p2 AND ISNULL(IsClosed,0)=0
|
||||||
`, header.OrderHeaderID, ln.OrderLineID)
|
`, header.OrderHeaderID, ln.OrderLineID); err != nil {
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
delete(existingOpen, ln.OrderLineID)
|
delete(existingOpen, ln.OrderLineID)
|
||||||
delete(existingOpenCombo, comboKey)
|
delete(existingOpenCombo, comboKey)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
isNew := false
|
isNew := false
|
||||||
|
|
||||||
|
// ID resolve: boşsa combo'dan yakala, yoksa yeni üret
|
||||||
if ln.OrderLineID == "" {
|
if ln.OrderLineID == "" {
|
||||||
if dbID, ok := existingOpenCombo[comboKey]; ok {
|
if dbID, ok := existingOpenCombo[comboKey]; ok {
|
||||||
ln.OrderLineID = dbID
|
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 qtyValue(ln.Qty1) > 0 {
|
||||||
if err := ValidateItemVariant(tx, ln); err != nil {
|
if err := ValidateItemVariant(tx, ln); err != nil {
|
||||||
return nil, err
|
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(existingOpen, ln.OrderLineID)
|
||||||
delete(existingOpenCombo, comboKey)
|
delete(existingOpenCombo, comboKey)
|
||||||
|
|
||||||
|
// Sonuç mapping
|
||||||
if ln.ClientKey.Valid {
|
if ln.ClientKey.Valid {
|
||||||
lineResults = append(lineResults, OrderLineResult{
|
lineResults = append(lineResults, OrderLineResult{
|
||||||
ClientKey: ln.ClientKey.String,
|
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 {
|
for id := range existingOpen {
|
||||||
_, err := tx.Exec(`DELETE FROM BAGGI_V3.dbo.trOrderLineCurrency WHERE OrderLineID=@p1`, id)
|
invoiced, err := isLineInvoiced(id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
_, err = tx.Exec(`DELETE FROM BAGGI_V3.dbo.trOrderLine WHERE OrderLineID=@p1 AND ISNULL(IsClosed,0)=0`, id)
|
if invoiced {
|
||||||
if err != nil {
|
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
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// =======================================================
|
||||||
|
// COMMIT + RETURN
|
||||||
|
// =======================================================
|
||||||
if err := tx.Commit(); err != nil {
|
if err := tx.Commit(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,10 @@ import (
|
|||||||
|
|
||||||
// ========================================================
|
// ========================================================
|
||||||
// 📌 GetOrderList — FINAL + CURRENCY SAFE + PIYASA AUTHZ
|
// 📌 GetOrderList — FINAL + CURRENCY SAFE + PIYASA AUTHZ
|
||||||
|
//
|
||||||
|
// ✅ TotalAmount artık trOrderLineCurrency(NetAmount) üzerinden
|
||||||
|
// ve CurrencyCode = Header.DocCurrencyCode satırından gelir.
|
||||||
|
//
|
||||||
// ========================================================
|
// ========================================================
|
||||||
func GetOrderList(
|
func GetOrderList(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
@@ -36,10 +40,8 @@ func GetOrderList(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if len(codes) == 0 {
|
if len(codes) == 0 {
|
||||||
// hiç yetkisi yok → hiç kayıt dönmesin
|
|
||||||
piyasaWhere = "1=0"
|
piyasaWhere = "1=0"
|
||||||
} else {
|
} else {
|
||||||
// ⚠️ EXISTS içinde kullanılacak
|
|
||||||
piyasaWhere = authz.BuildINClause(
|
piyasaWhere = authz.BuildINClause(
|
||||||
"UPPER(f2.CustomerAtt01)",
|
"UPPER(f2.CustomerAtt01)",
|
||||||
codes,
|
codes,
|
||||||
@@ -86,6 +88,29 @@ SELECT
|
|||||||
ELSE 0
|
ELSE 0
|
||||||
END AS TotalAmountUSD,
|
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.IsCreditableConfirmed,0) AS IsCreditableConfirmed,
|
||||||
ISNULL(h.Description,'') AS Description,
|
ISNULL(h.Description,'') AS Description,
|
||||||
|
|
||||||
@@ -93,12 +118,40 @@ SELECT
|
|||||||
|
|
||||||
FROM dbo.trOrderHeader h
|
FROM dbo.trOrderHeader h
|
||||||
|
|
||||||
|
-- ✅ TOPLAM ARTIK trOrderLineCurrency'den: CurrencyCode = DocCurrencyCode
|
||||||
JOIN (
|
JOIN (
|
||||||
SELECT
|
SELECT
|
||||||
OrderHeaderID,
|
l.OrderHeaderID,
|
||||||
SUM(Qty1 * Price) AS TotalAmount
|
SUM(ISNULL(c.NetAmount,0)) AS TotalAmount,
|
||||||
FROM dbo.trOrderLine
|
SUM(
|
||||||
GROUP BY OrderHeaderID
|
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
|
) l
|
||||||
ON l.OrderHeaderID = h.OrderHeaderID
|
ON l.OrderHeaderID = h.OrderHeaderID
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,8 @@ func (r *MkUserRepository) GetByUsername(username string) (*models.MkUser, error
|
|||||||
FILTER (WHERE d.code IS NOT NULL),
|
FILTER (WHERE d.code IS NOT NULL),
|
||||||
'{}'
|
'{}'
|
||||||
) AS department_codes,
|
) AS department_codes,
|
||||||
|
COALESCE(MAX(n.username), '') AS v3_username,
|
||||||
|
COALESCE(MAX(n.user_group_code::text), '') AS v3_usergroup,
|
||||||
|
|
||||||
u.password_updated_at,
|
u.password_updated_at,
|
||||||
u.created_at,
|
u.created_at,
|
||||||
@@ -67,6 +69,13 @@ LEFT JOIN dfusr_dprt ud
|
|||||||
LEFT JOIN mk_dprt d
|
LEFT JOIN mk_dprt d
|
||||||
ON d.id = ud.dprt_id
|
ON d.id = ud.dprt_id
|
||||||
|
|
||||||
|
LEFT JOIN dfusr_nebim_user un
|
||||||
|
ON un.dfusr_id = u.id
|
||||||
|
|
||||||
|
LEFT JOIN mk_nebim_user n
|
||||||
|
ON n.id = un.mk_nebim_user_id
|
||||||
|
AND n.is_active = true
|
||||||
|
|
||||||
WHERE LOWER(u.username) = LOWER($1)
|
WHERE LOWER(u.username) = LOWER($1)
|
||||||
|
|
||||||
GROUP BY
|
GROUP BY
|
||||||
@@ -85,6 +94,8 @@ LIMIT 1
|
|||||||
&u.RoleCode,
|
&u.RoleCode,
|
||||||
|
|
||||||
pq.Array(&u.DepartmentCodes), // ✅
|
pq.Array(&u.DepartmentCodes), // ✅
|
||||||
|
&u.V3Username,
|
||||||
|
&u.V3UserGroup,
|
||||||
|
|
||||||
&u.PasswordUpdatedAt,
|
&u.PasswordUpdatedAt,
|
||||||
|
|
||||||
@@ -127,6 +138,8 @@ func (r *MkUserRepository) GetByID(id int64) (*models.MkUser, error) {
|
|||||||
FILTER (WHERE d.code IS NOT NULL),
|
FILTER (WHERE d.code IS NOT NULL),
|
||||||
'{}'
|
'{}'
|
||||||
) AS department_codes,
|
) AS department_codes,
|
||||||
|
COALESCE(MAX(n.username), '') AS v3_username,
|
||||||
|
COALESCE(MAX(n.user_group_code::text), '') AS v3_usergroup,
|
||||||
|
|
||||||
u.password_updated_at,
|
u.password_updated_at,
|
||||||
u.created_at,
|
u.created_at,
|
||||||
@@ -149,7 +162,14 @@ LEFT JOIN dfusr_dprt ud
|
|||||||
LEFT JOIN mk_dprt d
|
LEFT JOIN mk_dprt d
|
||||||
ON d.id = ud.dprt_id
|
ON d.id = ud.dprt_id
|
||||||
|
|
||||||
WHERE LOWER(u.username) = LOWER($1)
|
LEFT JOIN dfusr_nebim_user un
|
||||||
|
ON un.dfusr_id = u.id
|
||||||
|
|
||||||
|
LEFT JOIN mk_nebim_user n
|
||||||
|
ON n.id = un.mk_nebim_user_id
|
||||||
|
AND n.is_active = true
|
||||||
|
|
||||||
|
WHERE u.id = $1
|
||||||
|
|
||||||
GROUP BY
|
GROUP BY
|
||||||
u.id, r.id
|
u.id, r.id
|
||||||
@@ -166,6 +186,8 @@ LIMIT 1
|
|||||||
&u.RoleID,
|
&u.RoleID,
|
||||||
&u.RoleCode,
|
&u.RoleCode,
|
||||||
pq.Array(&u.DepartmentCodes), // ✅
|
pq.Array(&u.DepartmentCodes), // ✅
|
||||||
|
&u.V3Username,
|
||||||
|
&u.V3UserGroup,
|
||||||
&u.PasswordUpdatedAt,
|
&u.PasswordUpdatedAt,
|
||||||
&u.CreatedAt,
|
&u.CreatedAt,
|
||||||
&u.UpdatedAt,
|
&u.UpdatedAt,
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package routes
|
package routes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bssapp-backend/models"
|
|
||||||
"bssapp-backend/queries"
|
"bssapp-backend/queries"
|
||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -14,25 +13,50 @@ import (
|
|||||||
func OrderListExcelRoute(db *sql.DB) http.Handler {
|
func OrderListExcelRoute(db *sql.DB) http.Handler {
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
|
w.Header().Set("Cache-Control", "no-store")
|
||||||
|
|
||||||
|
// ======================
|
||||||
|
// PARAMS
|
||||||
|
// ======================
|
||||||
search := r.URL.Query().Get("search")
|
search := r.URL.Query().Get("search")
|
||||||
currAcc := r.URL.Query().Get("CurrAccCode")
|
currAcc := r.URL.Query().Get("CurrAccCode")
|
||||||
orderDate := r.URL.Query().Get("OrderDate")
|
orderDate := r.URL.Query().Get("OrderDate")
|
||||||
|
|
||||||
|
// ======================
|
||||||
|
// QUERY
|
||||||
|
// ======================
|
||||||
rows, err := queries.GetOrderListExcel(db, search, currAcc, orderDate)
|
rows, err := queries.GetOrderListExcel(db, search, currAcc, orderDate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
http.Error(w, "Veritabanı hatası", 500)
|
http.Error(w, err.Error(), 500)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer rows.Close()
|
defer rows.Close()
|
||||||
|
|
||||||
|
// ======================
|
||||||
|
// EXCEL INIT
|
||||||
|
// ======================
|
||||||
f := excelize.NewFile()
|
f := excelize.NewFile()
|
||||||
sheet := "Orders"
|
sheet := "Orders"
|
||||||
f.SetSheetName("Sheet1", sheet)
|
f.SetSheetName("Sheet1", sheet)
|
||||||
|
|
||||||
|
// ======================
|
||||||
|
// HEADERS
|
||||||
|
// ======================
|
||||||
headers := []string{
|
headers := []string{
|
||||||
"Sipariş No", "Tarih", "Cari Kod", "Cari Adı",
|
"Sipariş No",
|
||||||
"Temsilci", "Piyasa", "Onay Tarihi", "PB",
|
"Tarih",
|
||||||
"Tutar", "Tutar (USD)", "Açıklama",
|
"Cari Kod",
|
||||||
|
"Cari Adı",
|
||||||
|
"Temsilci",
|
||||||
|
"Piyasa",
|
||||||
|
"PB",
|
||||||
|
"Tutar",
|
||||||
|
"Tutar (USD)",
|
||||||
|
"Paketlenen Tutar",
|
||||||
|
"Paketlenen (USD)",
|
||||||
|
"Paketlenme (%)",
|
||||||
|
"USD Kur",
|
||||||
|
"Açıklama",
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, h := range headers {
|
for i, h := range headers {
|
||||||
@@ -40,52 +64,108 @@ func OrderListExcelRoute(db *sql.DB) http.Handler {
|
|||||||
f.SetCellValue(sheet, cell, h)
|
f.SetCellValue(sheet, cell, h)
|
||||||
}
|
}
|
||||||
|
|
||||||
rowIdx := 2
|
// ======================
|
||||||
|
// ROWS
|
||||||
|
// ======================
|
||||||
|
row := 2
|
||||||
|
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
var o models.OrderList
|
|
||||||
_ = rows.Scan(
|
// 🔴 15 KOLON = 15 DEĞİŞKEN
|
||||||
&o.OrderHeaderID,
|
var (
|
||||||
&o.OrderNumber,
|
id, no, date, code, name string
|
||||||
&o.OrderDate,
|
rep, piyasa, cur string
|
||||||
&o.CurrAccCode,
|
|
||||||
&o.CurrAccDescription,
|
total float64
|
||||||
&o.MusteriTemsilcisi,
|
totalUSD float64
|
||||||
&o.Piyasa,
|
packedAmount float64
|
||||||
&o.CreditableConfirmedDate,
|
packedUSD float64
|
||||||
&o.DocCurrencyCode,
|
packedRatePct float64
|
||||||
&o.TotalAmount,
|
usdRate float64
|
||||||
&o.TotalAmountUSD,
|
|
||||||
&o.IsCreditableConfirmed,
|
desc string
|
||||||
&o.Description,
|
|
||||||
&o.ExchangeRateUSD,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
f.SetSheetRow(sheet, fmt.Sprintf("A%d", rowIdx), &[]interface{}{
|
// 🔴 SELECT SIRASIYLA BİREBİR
|
||||||
o.OrderNumber,
|
err := rows.Scan(
|
||||||
o.OrderDate,
|
&id, // 1
|
||||||
o.CurrAccCode,
|
&no, // 2
|
||||||
o.CurrAccDescription,
|
&date, // 3
|
||||||
o.MusteriTemsilcisi,
|
&code, // 4
|
||||||
o.Piyasa,
|
&name, // 5
|
||||||
o.CreditableConfirmedDate,
|
&rep, // 6
|
||||||
o.DocCurrencyCode,
|
&piyasa, // 7
|
||||||
o.TotalAmount,
|
&cur, // 8
|
||||||
o.TotalAmountUSD,
|
&total, // 9
|
||||||
o.Description,
|
&totalUSD, // 10
|
||||||
|
&packedAmount, // 11
|
||||||
|
&packedUSD, // 12
|
||||||
|
&packedRatePct, // 13
|
||||||
|
&desc, // 14
|
||||||
|
&usdRate, // 15
|
||||||
|
)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Scan error: "+err.Error(), 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// ======================
|
||||||
|
// WRITE ROW
|
||||||
|
// ======================
|
||||||
|
f.SetSheetRow(sheet, fmt.Sprintf("A%d", row), &[]any{
|
||||||
|
no,
|
||||||
|
date,
|
||||||
|
code,
|
||||||
|
name,
|
||||||
|
rep,
|
||||||
|
piyasa,
|
||||||
|
cur,
|
||||||
|
total,
|
||||||
|
totalUSD,
|
||||||
|
packedAmount,
|
||||||
|
packedUSD,
|
||||||
|
packedRatePct,
|
||||||
|
usdRate,
|
||||||
|
desc,
|
||||||
})
|
})
|
||||||
rowIdx++
|
|
||||||
|
row++
|
||||||
|
}
|
||||||
|
|
||||||
|
// ======================
|
||||||
|
// BUFFER WRITE
|
||||||
|
// ======================
|
||||||
|
buf, err := f.WriteToBuffer()
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), 500)
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
filename := fmt.Sprintf(
|
filename := fmt.Sprintf(
|
||||||
"order_list_%s.xlsx",
|
"siparis_listesi_%s.xlsx",
|
||||||
time.Now().Format("2006-01-02_15-04"),
|
time.Now().Format("20060102_150405"),
|
||||||
)
|
)
|
||||||
|
|
||||||
w.Header().Set("Content-Type",
|
// ======================
|
||||||
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
|
// RESPONSE
|
||||||
w.Header().Set("Content-Disposition",
|
// ======================
|
||||||
"attachment; filename="+filename)
|
w.Header().Set(
|
||||||
|
"Content-Type",
|
||||||
|
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
||||||
|
)
|
||||||
|
|
||||||
_ = f.Write(w)
|
w.Header().Set(
|
||||||
|
"Content-Disposition",
|
||||||
|
"attachment; filename=\""+filename+"\"",
|
||||||
|
)
|
||||||
|
|
||||||
|
w.Header().Set(
|
||||||
|
"Content-Length",
|
||||||
|
fmt.Sprint(len(buf.Bytes())),
|
||||||
|
)
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
_, _ = w.Write(buf.Bytes())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ func OrderListRoute(mssql *sql.DB) http.Handler {
|
|||||||
count := 0
|
count := 0
|
||||||
|
|
||||||
// ==================================================
|
// ==================================================
|
||||||
// 🧠 SCAN — SQL SELECT ile BİRE BİR (14 kolon)
|
// 🧠 SCAN — SQL SELECT ile BİRE BİR (17 kolon)
|
||||||
// ==================================================
|
// ==================================================
|
||||||
for rows.Next() {
|
for rows.Next() {
|
||||||
|
|
||||||
@@ -80,11 +80,14 @@ func OrderListRoute(mssql *sql.DB) http.Handler {
|
|||||||
|
|
||||||
&o.TotalAmount, // 10
|
&o.TotalAmount, // 10
|
||||||
&o.TotalAmountUSD, // 11
|
&o.TotalAmountUSD, // 11
|
||||||
|
&o.PackedAmount, // 12
|
||||||
|
&o.PackedUSD, // 13
|
||||||
|
&o.PackedRatePct, // 14
|
||||||
|
|
||||||
&o.IsCreditableConfirmed, // 12
|
&o.IsCreditableConfirmed, // 15
|
||||||
&o.Description, // 13
|
&o.Description, // 16
|
||||||
|
|
||||||
&o.ExchangeRateUSD, // 14
|
&o.ExchangeRateUSD, // 17
|
||||||
)
|
)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package utils
|
|||||||
import (
|
import (
|
||||||
"bssapp-backend/auth"
|
"bssapp-backend/auth"
|
||||||
"bssapp-backend/models"
|
"bssapp-backend/models"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func UserFromClaims(c *auth.Claims) *models.User {
|
func UserFromClaims(c *auth.Claims) *models.User {
|
||||||
@@ -10,8 +12,20 @@ func UserFromClaims(c *auth.Claims) *models.User {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
v3Group := 0
|
||||||
|
if raw := strings.TrimSpace(c.V3UserGroup); raw != "" {
|
||||||
|
if parsed, err := strconv.Atoi(raw); err == nil {
|
||||||
|
v3Group = parsed
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return &models.User{
|
return &models.User{
|
||||||
ID: int(c.ID),
|
ID: int(c.ID),
|
||||||
Username: c.Username,
|
Username: c.Username,
|
||||||
|
RoleID: int(c.RoleID),
|
||||||
|
RoleCode: c.RoleCode,
|
||||||
|
V3Username: strings.TrimSpace(c.V3Username),
|
||||||
|
V3UserGroup: v3Group,
|
||||||
|
ForcePasswordChange: c.ForcePasswordChange,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,83 +0,0 @@
|
|||||||
/* eslint-disable */
|
|
||||||
/**
|
|
||||||
* THIS FILE IS GENERATED AUTOMATICALLY.
|
|
||||||
* 1. DO NOT edit this file directly as it won't do anything.
|
|
||||||
* 2. EDIT the original quasar.config file INSTEAD.
|
|
||||||
* 3. DO NOT git commit this file. It should be ignored.
|
|
||||||
*
|
|
||||||
* This file is still here because there was an error in
|
|
||||||
* the original quasar.config file and this allows you to
|
|
||||||
* investigate the Node.js stack error.
|
|
||||||
*
|
|
||||||
* After you fix the original file, this file will be
|
|
||||||
* deleted automatically.
|
|
||||||
**/
|
|
||||||
|
|
||||||
|
|
||||||
// quasar.config.js
|
|
||||||
import { defineConfig } from "@quasar/app-webpack/wrappers";
|
|
||||||
var quasar_config_default = defineConfig(() => {
|
|
||||||
return {
|
|
||||||
// ✅ UYGULAMA KİMLİĞİ (WEB'DE GÖRÜNEN İSİM)
|
|
||||||
productName: "Baggi BSS",
|
|
||||||
productDescription: "Baggi Tekstil Business Support System",
|
|
||||||
// 🔹 Boot dosyaları
|
|
||||||
boot: ["axios", "dayjs"],
|
|
||||||
// 🔹 Global CSS
|
|
||||||
css: ["app.css"],
|
|
||||||
// 🔹 Ekstra icon/font setleri
|
|
||||||
extras: [
|
|
||||||
"roboto-font",
|
|
||||||
"material-icons"
|
|
||||||
],
|
|
||||||
// 🔹 Derleme Ayarları
|
|
||||||
build: {
|
|
||||||
vueRouterMode: "hash",
|
|
||||||
env: {
|
|
||||||
VITE_API_BASE_URL: "http://localhost:8080/api"
|
|
||||||
},
|
|
||||||
esbuildTarget: {
|
|
||||||
browser: ["es2022", "firefox115", "chrome115", "safari14"],
|
|
||||||
node: "node20"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// 🔹 Geliştirme Sunucusu
|
|
||||||
devServer: {
|
|
||||||
server: { type: "http" },
|
|
||||||
port: 9e3,
|
|
||||||
open: true
|
|
||||||
},
|
|
||||||
// 🔹 Quasar Framework ayarları
|
|
||||||
framework: {
|
|
||||||
config: {
|
|
||||||
notify: { position: "top", timeout: 2500 }
|
|
||||||
},
|
|
||||||
lang: "tr",
|
|
||||||
plugins: ["Loading", "Dialog", "Notify"]
|
|
||||||
},
|
|
||||||
animations: [],
|
|
||||||
ssr: {
|
|
||||||
prodPort: 3e3,
|
|
||||||
middlewares: ["render"],
|
|
||||||
pwa: false
|
|
||||||
},
|
|
||||||
pwa: {
|
|
||||||
workboxMode: "GenerateSW"
|
|
||||||
},
|
|
||||||
capacitor: {
|
|
||||||
hideSplashscreen: true
|
|
||||||
},
|
|
||||||
electron: {
|
|
||||||
preloadScripts: ["electron-preload"],
|
|
||||||
inspectPort: 5858,
|
|
||||||
bundler: "packager",
|
|
||||||
builder: { appId: "baggisowtfaresystem" }
|
|
||||||
},
|
|
||||||
bex: {
|
|
||||||
extraScripts: []
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
export {
|
|
||||||
quasar_config_default as default
|
|
||||||
};
|
|
||||||
@@ -135,13 +135,6 @@ import { Dialog } from 'quasar'
|
|||||||
|
|
||||||
import { useAuthStore } from 'stores/authStore'
|
import { useAuthStore } from 'stores/authStore'
|
||||||
import { usePermissionStore } from 'stores/permissionStore'
|
import { usePermissionStore } from 'stores/permissionStore'
|
||||||
import { usePermission } from 'src/composables/usePermission'
|
|
||||||
|
|
||||||
const { canRead, canWrite, canUpdate } = usePermission()
|
|
||||||
|
|
||||||
const canReadOrder = canRead('order')
|
|
||||||
const canWriteOrder = canWrite('order')
|
|
||||||
const canUpdateOrder = canUpdate('order')
|
|
||||||
|
|
||||||
|
|
||||||
/* ================= STORES ================= */
|
/* ================= STORES ================= */
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-page class="act-page with-bg">
|
<q-page v-if="canReadUser" class="act-page with-bg">
|
||||||
|
|
||||||
<!-- =======================================================
|
<!-- =======================================================
|
||||||
🔍 FILTER BAR
|
🔍 FILTER BAR
|
||||||
@@ -83,6 +83,7 @@
|
|||||||
|
|
||||||
<!-- ✅ YENİ -->
|
<!-- ✅ YENİ -->
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="canUpdateUser"
|
||||||
outline
|
outline
|
||||||
color="secondary"
|
color="secondary"
|
||||||
label="Rol Değişimleri"
|
label="Rol Değişimleri"
|
||||||
@@ -206,6 +207,12 @@
|
|||||||
</q-table>
|
</q-table>
|
||||||
|
|
||||||
</q-page>
|
</q-page>
|
||||||
|
|
||||||
|
<q-page v-else class="q-pa-md flex flex-center">
|
||||||
|
<div class="text-negative text-subtitle1">
|
||||||
|
Bu module erisim yetkiniz yok.
|
||||||
|
</div>
|
||||||
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
@@ -217,11 +224,9 @@ import { useActivityLogStore } from 'src/stores/activityLogStore'
|
|||||||
import { useAuthStore } from 'stores/authStore.js'
|
import { useAuthStore } from 'stores/authStore.js'
|
||||||
import { usePermission } from 'src/composables/usePermission'
|
import { usePermission } from 'src/composables/usePermission'
|
||||||
|
|
||||||
const { canRead, canWrite, canUpdate } = usePermission()
|
const { canRead, canUpdate } = usePermission()
|
||||||
|
const canReadUser = canRead('user')
|
||||||
const canReadOrder = canRead('order')
|
const canUpdateUser = canUpdate('user')
|
||||||
const canWriteOrder = canWrite('order')
|
|
||||||
const canUpdateOrder = canUpdate('order')
|
|
||||||
|
|
||||||
const diffDialog = ref(false)
|
const diffDialog = ref(false)
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-page class="flex flex-center">
|
<q-page v-if="canUpdateSystem" class="flex flex-center">
|
||||||
|
|
||||||
<q-card style="width:420px; max-width:90vw">
|
<q-card style="width:420px; max-width:90vw">
|
||||||
<q-card-section>
|
<q-card-section>
|
||||||
@@ -45,6 +45,7 @@ class="bg-red-1 text-red q-mt-md"
|
|||||||
|
|
||||||
<q-card-actions align="right">
|
<q-card-actions align="right">
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="canUpdateSystem"
|
||||||
label="GÜNCELLE"
|
label="GÜNCELLE"
|
||||||
color="primary"
|
color="primary"
|
||||||
:loading="loading"
|
:loading="loading"
|
||||||
@@ -54,6 +55,11 @@ color="primary"
|
|||||||
</q-card-actions>
|
</q-card-actions>
|
||||||
</q-card>
|
</q-card>
|
||||||
|
|
||||||
|
</q-page>
|
||||||
|
<q-page v-else class="q-pa-md flex flex-center">
|
||||||
|
<div class="text-negative text-subtitle1">
|
||||||
|
Bu module erisim yetkiniz yok.
|
||||||
|
</div>
|
||||||
</q-page>
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -64,11 +70,8 @@ import api from 'src/services/api'
|
|||||||
import { useAuthStore } from 'stores/authStore.js'
|
import { useAuthStore } from 'stores/authStore.js'
|
||||||
import { usePermission } from 'src/composables/usePermission'
|
import { usePermission } from 'src/composables/usePermission'
|
||||||
|
|
||||||
const { canRead, canWrite, canUpdate } = usePermission()
|
const { canUpdate } = usePermission()
|
||||||
|
const canUpdateSystem = canUpdate('system')
|
||||||
const canReadOrder = canRead('order')
|
|
||||||
const canWriteOrder = canWrite('order')
|
|
||||||
const canUpdateOrder = canUpdate('order')
|
|
||||||
|
|
||||||
const $q = useQuasar()
|
const $q = useQuasar()
|
||||||
const auth = useAuthStore()
|
const auth = useAuthStore()
|
||||||
@@ -117,4 +120,3 @@ async function submit () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,17 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-page class="flex flex-center">
|
<q-page v-if="canReadSystem" class="flex flex-center">
|
||||||
<p>DashBoard</p>
|
<p>DashBoard</p>
|
||||||
</q-page>
|
</q-page>
|
||||||
|
<q-page v-else class="q-pa-md flex flex-center">
|
||||||
|
<div class="text-negative text-subtitle1">
|
||||||
|
Bu module erisim yetkiniz yok.
|
||||||
|
</div>
|
||||||
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
// buraya JS kodların gelecek
|
import { usePermission } from 'src/composables/usePermission'
|
||||||
|
|
||||||
|
const { canRead } = usePermission()
|
||||||
|
const canReadSystem = canRead('system')
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -59,13 +59,6 @@ import { ref } from 'vue'
|
|||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import api from 'src/services/api'
|
import api from 'src/services/api'
|
||||||
import { useAuthStore } from 'stores/authStore.js'
|
import { useAuthStore } from 'stores/authStore.js'
|
||||||
import { usePermission } from 'src/composables/usePermission'
|
|
||||||
|
|
||||||
const { canRead, canWrite, canUpdate } = usePermission()
|
|
||||||
|
|
||||||
const canReadOrder = canRead('order')
|
|
||||||
const canWriteOrder = canWrite('order')
|
|
||||||
const canUpdateOrder = canUpdate('order')
|
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const auth = useAuthStore()
|
const auth = useAuthStore()
|
||||||
@@ -117,4 +110,3 @@ async function submit () {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -123,13 +123,6 @@ import { useRouter } from 'vue-router'
|
|||||||
import { useAuthStore } from 'stores/authStore'
|
import { useAuthStore } from 'stores/authStore'
|
||||||
import { useQuasar } from 'quasar'
|
import { useQuasar } from 'quasar'
|
||||||
import api from 'src/services/api'
|
import api from 'src/services/api'
|
||||||
import { usePermission } from 'src/composables/usePermission'
|
|
||||||
|
|
||||||
const { canRead, canWrite, canUpdate } = usePermission()
|
|
||||||
|
|
||||||
const canReadOrder = canRead('order')
|
|
||||||
const canWriteOrder = canWrite('order')
|
|
||||||
const canUpdateOrder = canUpdate('order')
|
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const auth = useAuthStore()
|
const auth = useAuthStore()
|
||||||
|
|||||||
@@ -60,13 +60,6 @@
|
|||||||
import { ref, computed } from 'vue'
|
import { ref, computed } from 'vue'
|
||||||
import { useQuasar } from 'quasar'
|
import { useQuasar } from 'quasar'
|
||||||
import { useMePasswordStore } from 'stores/mePasswordStore'
|
import { useMePasswordStore } from 'stores/mePasswordStore'
|
||||||
import { usePermission } from 'src/composables/usePermission'
|
|
||||||
|
|
||||||
const { canRead, canWrite, canUpdate } = usePermission()
|
|
||||||
|
|
||||||
const canReadOrder = canRead('order')
|
|
||||||
const canWriteOrder = canWrite('order')
|
|
||||||
const canUpdateOrder = canUpdate('order')
|
|
||||||
|
|
||||||
const $q = useQuasar()
|
const $q = useQuasar()
|
||||||
const store = useMePasswordStore()
|
const store = useMePasswordStore()
|
||||||
|
|||||||
@@ -213,7 +213,7 @@
|
|||||||
<div class="text-subtitle2 text-weight-bold">Sipariş Formu</div>
|
<div class="text-subtitle2 text-weight-bold">Sipariş Formu</div>
|
||||||
<div>
|
<div>
|
||||||
<q-btn
|
<q-btn
|
||||||
v-if="isViewOnly && canReadOrder"
|
v-if="isViewOnly && canExportOrder"
|
||||||
label="🖨 SİPARİŞİ YAZDIR"
|
label="🖨 SİPARİŞİ YAZDIR"
|
||||||
color="primary"
|
color="primary"
|
||||||
icon="print"
|
icon="print"
|
||||||
@@ -766,11 +766,12 @@ import { useAuthStore } from 'src/stores/authStore'
|
|||||||
import { formatDateInput, formatDateDisplay } from 'src/utils/formatters'
|
import { formatDateInput, formatDateDisplay } from 'src/utils/formatters'
|
||||||
import { usePermission } from 'src/composables/usePermission'
|
import { usePermission } from 'src/composables/usePermission'
|
||||||
|
|
||||||
const { canRead, canWrite, canUpdate } = usePermission()
|
const { canRead, canWrite, canUpdate, canExport } = usePermission()
|
||||||
|
|
||||||
const canReadOrder = canRead('order')
|
const canReadOrder = canRead('order')
|
||||||
const canWriteOrder = canWrite('order')
|
const canWriteOrder = canWrite('order')
|
||||||
const canUpdateOrder = canUpdate('order')
|
const canUpdateOrder = canUpdate('order')
|
||||||
|
const canExportOrder = canExport('order')
|
||||||
|
|
||||||
// script setup içinde
|
// script setup içinde
|
||||||
const formatDate = formatDateDisplay
|
const formatDate = formatDateDisplay
|
||||||
@@ -889,8 +890,8 @@ function hasRowMutationPermission() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function onPrintOrder() {
|
function onPrintOrder() {
|
||||||
if (!canReadOrder.value) {
|
if (!canExportOrder.value) {
|
||||||
notifyNoPermission('Siparisi goruntuleme yetkiniz yok')
|
notifyNoPermission('Siparisi yazdirma yetkiniz yok')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
orderStore.downloadOrderPdf()
|
orderStore.downloadOrderPdf()
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-page class="ol-page">
|
<q-page v-if="canReadOrder" class="ol-page">
|
||||||
<!-- 🔍 Sticky Filter -->
|
<!-- 🔠Sticky Filter -->
|
||||||
<div class="ol-filter-bar">
|
<div class="ol-filter-bar">
|
||||||
|
|
||||||
<!-- 🔹 TEK SATIR FLEX -->
|
<!-- 🔹 TEK SATIR FLEX -->
|
||||||
<div class="ol-filter-row">
|
<div class="ol-filter-row">
|
||||||
|
|
||||||
<!-- 🔍 Arama -->
|
<!-- 🔠Arama -->
|
||||||
<q-input
|
<q-input
|
||||||
class="ol-filter-input ol-search"
|
class="ol-filter-input ol-search"
|
||||||
dense
|
dense
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
</template>
|
</template>
|
||||||
</q-input>
|
</q-input>
|
||||||
|
|
||||||
<!-- 🧾 Cari Kodu -->
|
<!-- 🧾 Cari Kodu -->
|
||||||
<q-input
|
<q-input
|
||||||
class="ol-filter-input"
|
class="ol-filter-input"
|
||||||
dense
|
dense
|
||||||
@@ -31,7 +31,7 @@
|
|||||||
clearable
|
clearable
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 📅 Sipariş Tarihi -->
|
<!-- 📅 Sipariş Tarihi -->
|
||||||
<q-input
|
<q-input
|
||||||
class="ol-filter-input"
|
class="ol-filter-input"
|
||||||
dense
|
dense
|
||||||
@@ -41,10 +41,11 @@
|
|||||||
type="date"
|
type="date"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<!-- 🔘 Butonlar -->
|
<!-- 🔘 Butonlar -->
|
||||||
<div class="ol-filter-actions">
|
<div class="ol-filter-actions">
|
||||||
|
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="canReadOrder"
|
||||||
label="Temizle"
|
label="Temizle"
|
||||||
icon="clear"
|
icon="clear"
|
||||||
color="grey-7"
|
color="grey-7"
|
||||||
@@ -58,6 +59,7 @@
|
|||||||
</q-btn>
|
</q-btn>
|
||||||
|
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="canReadOrder"
|
||||||
label="Yenile"
|
label="Yenile"
|
||||||
color="primary"
|
color="primary"
|
||||||
icon="refresh"
|
icon="refresh"
|
||||||
@@ -66,6 +68,7 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="canExportOrder"
|
||||||
label="Excel'e Aktar"
|
label="Excel'e Aktar"
|
||||||
icon="download"
|
icon="download"
|
||||||
color="primary"
|
color="primary"
|
||||||
@@ -77,13 +80,26 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- 💰 Toplam -->
|
<!-- 💰 Toplam -->
|
||||||
<div class="ol-filter-total">
|
<div class="ol-filter-total">
|
||||||
Toplam Görünen Sipariş Tutarı (USD):
|
<span>
|
||||||
|
Toplam USD:
|
||||||
<strong>
|
<strong>
|
||||||
{{ store.totalVisibleUSD.toLocaleString('tr-TR', { minimumFractionDigits: 2 }) }}
|
{{ store.totalVisibleUSD.toLocaleString('tr-TR', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) }}
|
||||||
USD
|
|
||||||
</strong>
|
</strong>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
Paketlenen USD:
|
||||||
|
<strong>
|
||||||
|
{{ store.totalPackedVisibleUSD.toLocaleString('tr-TR', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) }}
|
||||||
|
</strong>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
Paketlenme %:
|
||||||
|
<strong>
|
||||||
|
{{ store.packedVisibleRatePct.toLocaleString('tr-TR', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) }}
|
||||||
|
</strong>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
@@ -91,7 +107,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- 📋 ORDER LIST TABLE -->
|
<!-- 📋 ORDER LIST TABLE -->
|
||||||
<q-table
|
<q-table
|
||||||
title="Mevcut Siparişler"
|
title="Mevcut Siparişler"
|
||||||
class="ol-table"
|
class="ol-table"
|
||||||
@@ -103,16 +119,18 @@
|
|||||||
:rows="store.filteredOrders"
|
:rows="store.filteredOrders"
|
||||||
:columns="columns"
|
:columns="columns"
|
||||||
:loading="store.loading"
|
:loading="store.loading"
|
||||||
|
:table-style="tableStyle"
|
||||||
no-data-label="Sipariş bulunamadı"
|
no-data-label="Sipariş bulunamadı"
|
||||||
:rows-per-page-options="[0]"
|
:rows-per-page-options="[0]"
|
||||||
hide-bottom
|
hide-bottom
|
||||||
>
|
>
|
||||||
|
|
||||||
<!-- 📄 PDF + DURUM -->
|
<!-- 📄 PDF + DURUM -->
|
||||||
<template #body-cell-IsCreditableConfirmed="props">
|
<template #body-cell-IsCreditableConfirmed="props">
|
||||||
<q-td :props="props" class="text-center q-gutter-sm">
|
<q-td :props="props" class="text-center q-gutter-sm">
|
||||||
|
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="canExportOrder"
|
||||||
icon="picture_as_pdf"
|
icon="picture_as_pdf"
|
||||||
color="red"
|
color="red"
|
||||||
flat
|
flat
|
||||||
@@ -136,7 +154,7 @@
|
|||||||
</q-td>
|
</q-td>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 📅 Tarih -->
|
<!-- 📅 Tarih -->
|
||||||
<template #body-cell-OrderDate="props">
|
<template #body-cell-OrderDate="props">
|
||||||
<q-td :props="props" class="text-center">
|
<q-td :props="props" class="text-center">
|
||||||
{{ formatDate(props.row.OrderDate) }}
|
{{ formatDate(props.row.OrderDate) }}
|
||||||
@@ -149,7 +167,7 @@
|
|||||||
</q-td>
|
</q-td>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 🧾 Cari Adı — 2 Satır -->
|
<!-- 🧾 Cari Adı — 2 Satır -->
|
||||||
<template #body-cell-CurrAccDescription="props">
|
<template #body-cell-CurrAccDescription="props">
|
||||||
<q-td :props="props" class="ol-col-cari ol-col-multiline">
|
<q-td :props="props" class="ol-col-cari ol-col-multiline">
|
||||||
{{ props.value }}
|
{{ props.value }}
|
||||||
@@ -159,7 +177,7 @@
|
|||||||
</q-td>
|
</q-td>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 📝 Açıklama — 5 Satır -->
|
<!-- 📠Açıklama — 5 Satır -->
|
||||||
<template #body-cell-Description="props">
|
<template #body-cell-Description="props">
|
||||||
<q-td :props="props" class="ol-col-desc ol-col-multiline">
|
<q-td :props="props" class="ol-col-desc ol-col-multiline">
|
||||||
{{ props.value }}
|
{{ props.value }}
|
||||||
@@ -169,10 +187,11 @@
|
|||||||
</q-td>
|
</q-td>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<!-- 🔗 Aç -->
|
<!-- 🔗 aç -->
|
||||||
<template #body-cell-select="props">
|
<template #body-cell-select="props">
|
||||||
<q-td :props="props" class="text-center">
|
<q-td :props="props" class="text-center">
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="canUpdateOrder"
|
||||||
icon="open_in_new"
|
icon="open_in_new"
|
||||||
color="primary"
|
color="primary"
|
||||||
flat
|
flat
|
||||||
@@ -180,7 +199,7 @@
|
|||||||
dense
|
dense
|
||||||
@click="selectOrder(props.row)"
|
@click="selectOrder(props.row)"
|
||||||
>
|
>
|
||||||
<q-tooltip>Siparişi Aç</q-tooltip>
|
<q-tooltip>Siparişi aç</q-tooltip>
|
||||||
</q-btn>
|
</q-btn>
|
||||||
</q-td>
|
</q-td>
|
||||||
</template>
|
</template>
|
||||||
@@ -193,10 +212,16 @@
|
|||||||
</q-banner>
|
</q-banner>
|
||||||
|
|
||||||
</q-page>
|
</q-page>
|
||||||
|
|
||||||
|
<q-page v-else class="q-pa-md flex flex-center">
|
||||||
|
<div class="text-negative text-subtitle1">
|
||||||
|
Bu module erisim yetkiniz yok.
|
||||||
|
</div>
|
||||||
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { onMounted, watch } from 'vue'
|
import { computed, onMounted, watch } from 'vue'
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { useQuasar } from 'quasar'
|
import { useQuasar } from 'quasar'
|
||||||
|
|
||||||
@@ -204,11 +229,12 @@ import { useOrderListStore } from 'src/stores/OrdernewListStore'
|
|||||||
import { useAuthStore } from 'src/stores/authStore'
|
import { useAuthStore } from 'src/stores/authStore'
|
||||||
import { usePermission } from 'src/composables/usePermission'
|
import { usePermission } from 'src/composables/usePermission'
|
||||||
|
|
||||||
const { canRead, canWrite, canUpdate } = usePermission()
|
const { canRead, canWrite, canUpdate, canExport } = usePermission()
|
||||||
|
|
||||||
const canReadOrder = canRead('order')
|
const canReadOrder = canRead('order')
|
||||||
const canWriteOrder = canWrite('order')
|
const canWriteOrder = canWrite('order')
|
||||||
const canUpdateOrder = canUpdate('order')
|
const canUpdateOrder = canUpdate('order')
|
||||||
|
const canExportOrder = canExport('order')
|
||||||
|
|
||||||
/* =========================
|
/* =========================
|
||||||
INIT
|
INIT
|
||||||
@@ -217,9 +243,13 @@ const canUpdateOrder = canUpdate('order')
|
|||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const $q = useQuasar()
|
const $q = useQuasar()
|
||||||
|
|
||||||
// ⚠️ ÖNCE store tanımlanır
|
// âš ï¸ Ã–NCE store tanımlanır
|
||||||
const store = useOrderListStore()
|
const store = useOrderListStore()
|
||||||
|
|
||||||
|
const tableStyle = computed(() => ({
|
||||||
|
minWidth: $q.screen.lt.lg ? '1280px' : '100%'
|
||||||
|
}))
|
||||||
|
|
||||||
/* =========================
|
/* =========================
|
||||||
SEARCH DEBOUNCE
|
SEARCH DEBOUNCE
|
||||||
========================= */
|
========================= */
|
||||||
@@ -241,14 +271,15 @@ watch(
|
|||||||
HELPERS
|
HELPERS
|
||||||
========================= */
|
========================= */
|
||||||
function exportExcel () {
|
function exportExcel () {
|
||||||
|
if (!canExportOrder.value) {
|
||||||
|
$q.notify({ type: 'negative', message: 'Excel export yetkiniz yok', position: 'top-right' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const auth = useAuthStore()
|
const auth = useAuthStore()
|
||||||
|
|
||||||
if (!auth?.token) {
|
if (!auth?.token) {
|
||||||
$q.notify({
|
$q.notify({ type: 'negative', message: 'Oturum bulunamadı', position: 'top-right' })
|
||||||
type: 'negative',
|
|
||||||
message: 'Oturum bulunamadı',
|
|
||||||
position: 'top-right'
|
|
||||||
})
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,19 +292,43 @@ function exportExcel () {
|
|||||||
const url = `http://localhost:8080/api/orders/export?${params.toString()}`
|
const url = `http://localhost:8080/api/orders/export?${params.toString()}`
|
||||||
|
|
||||||
fetch(url, {
|
fetch(url, {
|
||||||
headers: {
|
method: 'GET',
|
||||||
Authorization: `Bearer ${auth.token}`
|
headers: { Authorization: `Bearer ${auth.token}` }
|
||||||
}
|
})
|
||||||
|
.then(async res => {
|
||||||
|
// ✅ 200 değilse EXCEL İNDİRME
|
||||||
|
if (!res.ok) {
|
||||||
|
const text = await res.text()
|
||||||
|
throw new Error(`HTTP ${res.status} - ${text}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ✅ Content-Type kontrol (debug için)
|
||||||
|
const ct = res.headers.get('content-type') || ''
|
||||||
|
if (!ct.includes('spreadsheetml.sheet')) {
|
||||||
|
const text = await res.text()
|
||||||
|
throw new Error(`Beklenmeyen Content-Type: ${ct} | Body: ${text}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res.blob()
|
||||||
})
|
})
|
||||||
.then(res => res.blob())
|
|
||||||
.then(blob => {
|
.then(blob => {
|
||||||
const link = document.createElement('a')
|
const link = document.createElement('a')
|
||||||
link.href = URL.createObjectURL(blob)
|
link.href = URL.createObjectURL(blob)
|
||||||
link.download = 'siparis_listesi.xlsx'
|
link.download = 'siparis_listesi.xlsx'
|
||||||
link.click()
|
link.click()
|
||||||
})
|
})
|
||||||
|
.catch(err => {
|
||||||
|
$q.notify({
|
||||||
|
type: 'negative',
|
||||||
|
message: 'Excel export hatası: ' + (err?.message || err),
|
||||||
|
position: 'top-right',
|
||||||
|
timeout: 8000
|
||||||
|
})
|
||||||
|
console.error(err)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function formatDate (s) {
|
function formatDate (s) {
|
||||||
if (!s) return ''
|
if (!s) return ''
|
||||||
const [y, m, d] = s.split('-')
|
const [y, m, d] = s.split('-')
|
||||||
@@ -285,12 +340,18 @@ function formatDate (s) {
|
|||||||
========================= */
|
========================= */
|
||||||
|
|
||||||
const columns = [
|
const columns = [
|
||||||
{ name: 'select', label: '', field: 'select', align: 'center', sortable: false },
|
{
|
||||||
|
name: 'select',
|
||||||
{ name: 'OrderNumber', label: 'Sipariş No', field: 'OrderNumber', align: 'left', sortable: true },
|
label: '',
|
||||||
{ name: 'OrderDate', label: 'Tarih', field: 'OrderDate', align: 'center', sortable: true },
|
field: 'select',
|
||||||
|
align: 'center',
|
||||||
{ name: 'CurrAccCode', label: 'Cari Kod', field: 'CurrAccCode', align: 'left', sortable: true },
|
sortable: false,
|
||||||
|
style: 'width:42px; min-width:42px; max-width:42px; padding:2px 4px;',
|
||||||
|
headerStyle: 'width:42px; min-width:42px; max-width:42px; padding:2px 4px;'
|
||||||
|
},
|
||||||
|
{ name: 'OrderNumber', label: 'Sipariş No', field: 'OrderNumber', align: 'left', sortable: true, style: 'width:108px; min-width:108px;', headerStyle: 'width:108px; min-width:108px;' },
|
||||||
|
{ name: 'OrderDate', label: 'Tarih', field: 'OrderDate', align: 'center', sortable: true, style: 'width:78px; min-width:78px;', headerStyle: 'width:78px; min-width:78px;' },
|
||||||
|
{ name: 'CurrAccCode', label: 'Cari Kod', field: 'CurrAccCode', align: 'left', sortable: true, style: 'width:78px; min-width:78px;', headerStyle: 'width:78px; min-width:78px;' },
|
||||||
|
|
||||||
{
|
{
|
||||||
name: 'CurrAccDescription',
|
name: 'CurrAccDescription',
|
||||||
@@ -300,14 +361,13 @@ const columns = [
|
|||||||
sortable: true,
|
sortable: true,
|
||||||
classes: 'ol-col-cari',
|
classes: 'ol-col-cari',
|
||||||
headerClasses: 'ol-col-cari',
|
headerClasses: 'ol-col-cari',
|
||||||
style: 'max-width:200px'
|
style: 'width:130px; min-width:130px; max-width:130px;',
|
||||||
|
headerStyle: 'width:130px; min-width:130px; max-width:130px;'
|
||||||
},
|
},
|
||||||
|
{ name: 'MusteriTemsilcisi', label: 'Temsilci', field: 'MusteriTemsilcisi', align: 'left', sortable: true, style: 'width:78px; min-width:78px;', headerStyle: 'width:78px; min-width:78px;' },
|
||||||
{ name: 'MusteriTemsilcisi', label: 'Temsilci', field: 'MusteriTemsilcisi', align: 'left', sortable: true },
|
{ name: 'Piyasa', label: 'Piyasa', field: 'Piyasa', align: 'left', sortable: true, style: 'width:74px; min-width:74px;', headerStyle: 'width:74px; min-width:74px;' },
|
||||||
{ name: 'Piyasa', label: 'Piyasa', field: 'Piyasa', align: 'left', sortable: true },
|
{ name: 'CreditableConfirmedDate', label: 'Onay', field: 'CreditableConfirmedDate', align: 'center', sortable: true, style: 'width:82px; min-width:82px;', headerStyle: 'width:82px; min-width:82px;' },
|
||||||
|
{ name: 'DocCurrencyCode', label: 'PB', field: 'DocCurrencyCode', align: 'center', sortable: true, style: 'width:46px; min-width:46px;', headerStyle: 'width:46px; min-width:46px;' },
|
||||||
{ name: 'CreditableConfirmedDate', label: 'Onay', field: 'CreditableConfirmedDate', align: 'center', sortable: true },
|
|
||||||
{ name: 'DocCurrencyCode', label: 'PB', field: 'DocCurrencyCode', align: 'center', sortable: true },
|
|
||||||
|
|
||||||
{
|
{
|
||||||
name: 'TotalAmount',
|
name: 'TotalAmount',
|
||||||
@@ -315,6 +375,8 @@ const columns = [
|
|||||||
field: 'TotalAmount',
|
field: 'TotalAmount',
|
||||||
align: 'right',
|
align: 'right',
|
||||||
sortable: true,
|
sortable: true,
|
||||||
|
style: 'width:94px; min-width:94px;',
|
||||||
|
headerStyle: 'width:94px; min-width:94px;',
|
||||||
format: (val, row) =>
|
format: (val, row) =>
|
||||||
Number(val || 0).toLocaleString('tr-TR', { minimumFractionDigits: 2 }) +
|
Number(val || 0).toLocaleString('tr-TR', { minimumFractionDigits: 2 }) +
|
||||||
' ' + row.DocCurrencyCode
|
' ' + row.DocCurrencyCode
|
||||||
@@ -326,11 +388,49 @@ const columns = [
|
|||||||
field: 'TotalAmountUSD',
|
field: 'TotalAmountUSD',
|
||||||
align: 'right',
|
align: 'right',
|
||||||
sortable: true,
|
sortable: true,
|
||||||
|
style: 'width:96px; min-width:96px;',
|
||||||
|
headerStyle: 'width:96px; min-width:96px;',
|
||||||
format: val =>
|
format: val =>
|
||||||
Number(val || 0).toLocaleString('tr-TR', { minimumFractionDigits: 2 }) + ' USD'
|
Number(val || 0).toLocaleString('tr-TR', { minimumFractionDigits: 2 }) + ' USD'
|
||||||
},
|
},
|
||||||
|
|
||||||
{ name: 'IsCreditableConfirmed', label: 'Durum', field: 'IsCreditableConfirmed', align: 'center', sortable: true },
|
{
|
||||||
|
name: 'PackedAmount',
|
||||||
|
label: 'Paket Tutar',
|
||||||
|
field: 'PackedAmount',
|
||||||
|
align: 'right',
|
||||||
|
sortable: true,
|
||||||
|
style: 'width:98px; min-width:98px;',
|
||||||
|
headerStyle: 'width:98px; min-width:98px;',
|
||||||
|
format: (val, row) =>
|
||||||
|
Number(val || 0).toLocaleString('tr-TR', { minimumFractionDigits: 2 }) +
|
||||||
|
' ' + (row.DocCurrencyCode || '')
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'PackedUSD',
|
||||||
|
label: 'Paket USD',
|
||||||
|
field: 'PackedUSD',
|
||||||
|
align: 'right',
|
||||||
|
sortable: true,
|
||||||
|
style: 'width:96px; min-width:96px;',
|
||||||
|
headerStyle: 'width:96px; min-width:96px;',
|
||||||
|
format: val =>
|
||||||
|
Number(val || 0).toLocaleString('tr-TR', { minimumFractionDigits: 2 }) + ' USD'
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
name: 'PackedRatePct',
|
||||||
|
label: 'Paket %',
|
||||||
|
field: 'PackedRatePct',
|
||||||
|
align: 'right',
|
||||||
|
sortable: true,
|
||||||
|
style: 'width:72px; min-width:72px;',
|
||||||
|
headerStyle: 'width:72px; min-width:72px;',
|
||||||
|
format: val =>
|
||||||
|
Number(val || 0).toLocaleString('tr-TR', { minimumFractionDigits: 2 }) + ' %'
|
||||||
|
},
|
||||||
|
{ name: 'IsCreditableConfirmed', label: 'Durum', field: 'IsCreditableConfirmed', align: 'center', sortable: true, style: 'width:66px; min-width:66px;', headerStyle: 'width:66px; min-width:66px;' },
|
||||||
|
|
||||||
{
|
{
|
||||||
name: 'Description',
|
name: 'Description',
|
||||||
@@ -340,10 +440,10 @@ const columns = [
|
|||||||
sortable: false,
|
sortable: false,
|
||||||
classes: 'ol-col-desc',
|
classes: 'ol-col-desc',
|
||||||
headerClasses: 'ol-col-desc',
|
headerClasses: 'ol-col-desc',
|
||||||
style: 'max-width:220px'
|
style: 'width:130px; min-width:130px; max-width:130px;',
|
||||||
|
headerStyle: 'width:130px; min-width:130px; max-width:130px;'
|
||||||
},
|
},
|
||||||
|
{ name: 'pdf', label: 'PDF', field: 'pdf', align: 'center', sortable: false, style: 'width:44px; min-width:44px;', headerStyle: 'width:44px; min-width:44px;' }
|
||||||
{ name: 'pdf', label: 'PDF', field: 'pdf', align: 'center', sortable: false }
|
|
||||||
]
|
]
|
||||||
|
|
||||||
/* =========================
|
/* =========================
|
||||||
@@ -351,6 +451,11 @@ const columns = [
|
|||||||
========================= */
|
========================= */
|
||||||
|
|
||||||
function selectOrder (row) {
|
function selectOrder (row) {
|
||||||
|
if (!canUpdateOrder.value) {
|
||||||
|
$q.notify({ type: 'negative', message: 'Siparis guncelleme yetkiniz yok' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (!row?.OrderHeaderID) {
|
if (!row?.OrderHeaderID) {
|
||||||
$q.notify({ type: 'warning', message: 'OrderHeaderID bulunamadı' })
|
$q.notify({ type: 'warning', message: 'OrderHeaderID bulunamadı' })
|
||||||
return
|
return
|
||||||
@@ -364,6 +469,11 @@ function selectOrder (row) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function printPDF (row) {
|
async function printPDF (row) {
|
||||||
|
if (!canExportOrder.value) {
|
||||||
|
$q.notify({ type: 'negative', message: 'PDF export yetkiniz yok' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (!row?.OrderHeaderID) return
|
if (!row?.OrderHeaderID) return
|
||||||
|
|
||||||
const token = useAuthStore().token
|
const token = useAuthStore().token
|
||||||
@@ -402,7 +512,55 @@ function clearFilters () {
|
|||||||
========================= */
|
========================= */
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
if (canReadOrder.value) {
|
||||||
store.fetchOrders()
|
store.fetchOrders()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.ol-page {
|
||||||
|
padding: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ol-table :deep(.q-table thead th) {
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 1.1;
|
||||||
|
font-weight: 700;
|
||||||
|
padding: 3px 6px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ol-table :deep(.q-table tbody td) {
|
||||||
|
font-size: 11px;
|
||||||
|
line-height: 1.15;
|
||||||
|
padding: 2px 6px;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ol-col-multiline {
|
||||||
|
white-space: normal !important;
|
||||||
|
word-break: break-word;
|
||||||
|
line-height: 1.1;
|
||||||
|
display: -webkit-box;
|
||||||
|
-webkit-line-clamp: 2;
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ol-filter-total {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 12px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
@media (max-width: 1600px) {
|
||||||
|
.ol-table :deep(.q-table thead th),
|
||||||
|
.ol-table :deep(.q-table tbody td) {
|
||||||
|
font-size: 10px;
|
||||||
|
padding: 2px 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1 +1,122 @@
|
|||||||
<template></template>
|
<template>
|
||||||
|
<q-page
|
||||||
|
v-if="canExportOrder"
|
||||||
|
class="q-pa-md"
|
||||||
|
>
|
||||||
|
<q-card flat bordered class="q-pa-md" style="max-width: 720px">
|
||||||
|
<q-card-section>
|
||||||
|
<div class="text-h6">Order PDF</div>
|
||||||
|
<div class="text-caption text-grey-7">Order ID: {{ orderId || '-' }}</div>
|
||||||
|
</q-card-section>
|
||||||
|
|
||||||
|
<q-card-actions align="right" class="q-gutter-sm">
|
||||||
|
<q-btn
|
||||||
|
v-if="canOpenPdf"
|
||||||
|
color="primary"
|
||||||
|
icon="picture_as_pdf"
|
||||||
|
label="PDF Ac"
|
||||||
|
:loading="loading"
|
||||||
|
:disable="loading || !orderId"
|
||||||
|
@click="openPdf"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<q-btn
|
||||||
|
v-if="canEditOrder"
|
||||||
|
flat
|
||||||
|
color="secondary"
|
||||||
|
label="Siparise Don"
|
||||||
|
:disable="!orderId"
|
||||||
|
@click="goToOrder"
|
||||||
|
/>
|
||||||
|
</q-card-actions>
|
||||||
|
</q-card>
|
||||||
|
</q-page>
|
||||||
|
|
||||||
|
<q-page
|
||||||
|
v-else
|
||||||
|
class="q-pa-md flex flex-center"
|
||||||
|
>
|
||||||
|
<div class="text-negative text-subtitle1">
|
||||||
|
Bu module erisim yetkiniz yok.
|
||||||
|
</div>
|
||||||
|
</q-page>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref } from 'vue'
|
||||||
|
import { useQuasar } from 'quasar'
|
||||||
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
import { usePermission } from 'src/composables/usePermission'
|
||||||
|
import { useOrderEntryStore } from 'src/stores/orderentryStore'
|
||||||
|
|
||||||
|
const { canWrite, canUpdate, canExport } = usePermission()
|
||||||
|
|
||||||
|
const canExportOrder = canExport('order')
|
||||||
|
const canWriteOrder = canWrite('order')
|
||||||
|
const canUpdateOrder = canUpdate('order')
|
||||||
|
|
||||||
|
const canEditOrder = computed(() => canWriteOrder.value || canUpdateOrder.value)
|
||||||
|
const canOpenPdf = computed(() => canExportOrder.value)
|
||||||
|
|
||||||
|
const $q = useQuasar()
|
||||||
|
const route = useRoute()
|
||||||
|
const router = useRouter()
|
||||||
|
const orderStore = useOrderEntryStore()
|
||||||
|
|
||||||
|
const loading = ref(false)
|
||||||
|
const orderId = computed(() => String(route.params.id || '').trim())
|
||||||
|
|
||||||
|
async function openPdf () {
|
||||||
|
if (!canOpenPdf.value) {
|
||||||
|
$q.notify({
|
||||||
|
type: 'negative',
|
||||||
|
message: 'Siparis PDF export yetkiniz yok'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!orderId.value) {
|
||||||
|
$q.notify({
|
||||||
|
type: 'warning',
|
||||||
|
message: 'Order ID bulunamadi'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
loading.value = true
|
||||||
|
try {
|
||||||
|
await orderStore.downloadOrderPdf(orderId.value)
|
||||||
|
} catch (err) {
|
||||||
|
$q.notify({
|
||||||
|
type: 'negative',
|
||||||
|
message: err?.message || 'PDF acilamadi'
|
||||||
|
})
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function goToOrder () {
|
||||||
|
if (!canEditOrder.value) {
|
||||||
|
$q.notify({
|
||||||
|
type: 'negative',
|
||||||
|
message: 'Siparis duzenleme yetkiniz yok'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!orderId.value) {
|
||||||
|
$q.notify({
|
||||||
|
type: 'warning',
|
||||||
|
message: 'Order ID bulunamadi'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const routeName = canUpdateOrder.value ? 'order-edit' : 'order-entry'
|
||||||
|
router.push({
|
||||||
|
name: routeName,
|
||||||
|
params: { orderHeaderID: orderId.value }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-page padding>
|
<q-page v-if="canReadSystem" padding>
|
||||||
|
|
||||||
<div class="text-h6 q-mb-md">
|
<div class="text-h6 q-mb-md">
|
||||||
Rol + Departman Yetkilendirme
|
Rol + Departman Yetkilendirme
|
||||||
@@ -76,6 +76,7 @@
|
|||||||
<div class="q-mt-md">
|
<div class="q-mt-md">
|
||||||
|
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="canUpdateUser"
|
||||||
color="primary"
|
color="primary"
|
||||||
icon="save"
|
icon="save"
|
||||||
label="Kaydet"
|
label="Kaydet"
|
||||||
@@ -86,6 +87,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</q-page>
|
</q-page>
|
||||||
|
|
||||||
|
<q-page v-else class="q-pa-md flex flex-center">
|
||||||
|
<div class="text-negative text-subtitle1">
|
||||||
|
Bu module erisim yetkiniz yok.
|
||||||
|
</div>
|
||||||
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
@@ -96,11 +103,9 @@ import { Notify } from 'quasar'
|
|||||||
import api from 'src/services/api'
|
import api from 'src/services/api'
|
||||||
import { usePermission } from 'src/composables/usePermission'
|
import { usePermission } from 'src/composables/usePermission'
|
||||||
|
|
||||||
const { canRead, canWrite, canUpdate } = usePermission()
|
const { canRead, canUpdate } = usePermission()
|
||||||
|
const canReadSystem = canRead('system')
|
||||||
const canReadOrder = canRead('order')
|
const canUpdateUser = canUpdate('user')
|
||||||
const canWriteOrder = canWrite('order')
|
|
||||||
const canUpdateOrder = canUpdate('order')
|
|
||||||
|
|
||||||
|
|
||||||
/* ================= STATE ================= */
|
/* ================= STATE ================= */
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-page class="workorder-page with-bg">
|
<q-page v-if="canReadOrder" class="workorder-page with-bg">
|
||||||
|
|
||||||
<!-- ===============================
|
<!-- ===============================
|
||||||
🔹 ÜST: İŞ EMRİ BİLGİLERİ
|
🔹 ÜST: İŞ EMRİ BİLGİLERİ
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<q-btn
|
<q-btn
|
||||||
v-if="isCreateMode"
|
v-if="isCreateMode && canWriteOrder"
|
||||||
label="Ana Görsel Seç"
|
label="Ana Görsel Seç"
|
||||||
icon="image"
|
icon="image"
|
||||||
class="q-mt-sm"
|
class="q-mt-sm"
|
||||||
@@ -113,7 +113,7 @@
|
|||||||
</q-card>
|
</q-card>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="isCreateMode" class="col-12">
|
<div v-if="isCreateMode && canWriteOrder" class="col-12">
|
||||||
<q-btn
|
<q-btn
|
||||||
label="Detay Görsel Ekle"
|
label="Detay Görsel Ekle"
|
||||||
icon="add"
|
icon="add"
|
||||||
@@ -143,7 +143,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<q-btn
|
<q-btn
|
||||||
v-if="isCreateMode"
|
v-if="isCreateMode && canWriteOrder"
|
||||||
label="Talimat Görseli Ekle"
|
label="Talimat Görseli Ekle"
|
||||||
icon="add"
|
icon="add"
|
||||||
flat
|
flat
|
||||||
@@ -161,7 +161,7 @@
|
|||||||
=============================== -->
|
=============================== -->
|
||||||
<div class="row justify-end q-mt-md">
|
<div class="row justify-end q-mt-md">
|
||||||
<q-btn
|
<q-btn
|
||||||
v-if="isCreateMode"
|
v-if="isCreateMode && canWriteOrder"
|
||||||
label="Kaydet"
|
label="Kaydet"
|
||||||
color="positive"
|
color="positive"
|
||||||
icon="save"
|
icon="save"
|
||||||
@@ -169,7 +169,7 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<q-btn
|
<q-btn
|
||||||
v-if="isViewMode"
|
v-if="isViewMode && canExportOrder"
|
||||||
label="PDF"
|
label="PDF"
|
||||||
color="primary"
|
color="primary"
|
||||||
icon="picture_as_pdf"
|
icon="picture_as_pdf"
|
||||||
@@ -178,17 +178,23 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</q-page>
|
</q-page>
|
||||||
|
|
||||||
|
<q-page v-else class="q-pa-md flex flex-center">
|
||||||
|
<div class="text-negative text-subtitle1">
|
||||||
|
Bu module erisim yetkiniz yok.
|
||||||
|
</div>
|
||||||
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
import { computed, ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { useRoute } from 'vue-router'
|
import { useRoute } from 'vue-router'
|
||||||
import { usePermission } from 'src/composables/usePermission'
|
import { usePermission } from 'src/composables/usePermission'
|
||||||
|
|
||||||
const { canRead, canWrite, canUpdate } = usePermission()
|
const { canRead, canWrite, canExport } = usePermission()
|
||||||
|
|
||||||
const canReadOrder = canRead('order')
|
const canReadOrder = canRead('order')
|
||||||
const canWriteOrder = canWrite('order')
|
const canWriteOrder = canWrite('order')
|
||||||
const canUpdateOrder = canUpdate('order')
|
const canExportOrder = canExport('order')
|
||||||
|
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
|
|
||||||
@@ -209,11 +215,15 @@ const detailImages = ref([])
|
|||||||
const instructionImages = ref([])
|
const instructionImages = ref([])
|
||||||
|
|
||||||
function openImagePicker(type) {
|
function openImagePicker(type) {
|
||||||
|
if (!canWriteOrder.value) return
|
||||||
|
|
||||||
// Şimdilik stub
|
// Şimdilik stub
|
||||||
console.log('Image picker:', type)
|
console.log('Image picker:', type)
|
||||||
}
|
}
|
||||||
|
|
||||||
function saveWorkOrder() {
|
function saveWorkOrder() {
|
||||||
|
if (!canWriteOrder.value) return
|
||||||
|
|
||||||
console.log('SAVE', {
|
console.log('SAVE', {
|
||||||
form: form.value,
|
form: form.value,
|
||||||
mainImage: mainImage.value,
|
mainImage: mainImage.value,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-page class="q-pa-md">
|
<q-page v-if="canReadOrder" class="q-pa-md">
|
||||||
|
|
||||||
<!-- =====================================================
|
<!-- =====================================================
|
||||||
🔹 BAŞLIK + AKSİYONLAR
|
🔹 BAŞLIK + AKSİYONLAR
|
||||||
@@ -10,6 +10,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="canWriteOrder"
|
||||||
color="primary"
|
color="primary"
|
||||||
icon="add"
|
icon="add"
|
||||||
label="Yeni İş Emri"
|
label="Yeni İş Emri"
|
||||||
@@ -83,6 +84,12 @@
|
|||||||
</q-table>
|
</q-table>
|
||||||
|
|
||||||
</q-page>
|
</q-page>
|
||||||
|
|
||||||
|
<q-page v-else class="q-pa-md flex flex-center">
|
||||||
|
<div class="text-negative text-subtitle1">
|
||||||
|
Bu module erisim yetkiniz yok.
|
||||||
|
</div>
|
||||||
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -90,11 +97,10 @@ import { ref, computed } from 'vue'
|
|||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { usePermission } from 'src/composables/usePermission'
|
import { usePermission } from 'src/composables/usePermission'
|
||||||
|
|
||||||
const { canRead, canWrite, canUpdate } = usePermission()
|
const { canRead, canWrite } = usePermission()
|
||||||
|
|
||||||
const canReadOrder = canRead('order')
|
const canReadOrder = canRead('order')
|
||||||
const canWriteOrder = canWrite('order')
|
const canWriteOrder = canWrite('order')
|
||||||
const canUpdateOrder = canUpdate('order')
|
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
@@ -192,10 +198,12 @@ const filteredRows = computed(() => {
|
|||||||
// 🔹 AKSİYONLAR
|
// 🔹 AKSİYONLAR
|
||||||
// =====================================================
|
// =====================================================
|
||||||
function goNew () {
|
function goNew () {
|
||||||
|
if (!canWriteOrder.value) return
|
||||||
router.push('/app/production-work-orders/new')
|
router.push('/app/production-work-orders/new')
|
||||||
}
|
}
|
||||||
|
|
||||||
function goView (evt, row) {
|
function goView (evt, row) {
|
||||||
|
if (!canReadOrder.value) return
|
||||||
router.push(`/app/production-work-orders/view/${row.id}`)
|
router.push(`/app/production-work-orders/view/${row.id}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -125,13 +125,6 @@ import { useQuasar } from 'quasar'
|
|||||||
|
|
||||||
import api, { post } from 'src/services/api'
|
import api, { post } from 'src/services/api'
|
||||||
import { useAuthStore } from 'stores/authStore.js'
|
import { useAuthStore } from 'stores/authStore.js'
|
||||||
import { usePermission } from 'src/composables/usePermission'
|
|
||||||
|
|
||||||
const { canRead, canWrite, canUpdate } = usePermission()
|
|
||||||
|
|
||||||
const canReadOrder = canRead('order')
|
|
||||||
const canWriteOrder = canWrite('order')
|
|
||||||
const canUpdateOrder = canUpdate('order')
|
|
||||||
|
|
||||||
/* -------------------------------------------------- */
|
/* -------------------------------------------------- */
|
||||||
/* INIT */
|
/* INIT */
|
||||||
@@ -261,4 +254,3 @@ async function submit () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<div v-if="!lookupsLoaded" class="q-pa-xl flex flex-center">
|
<div v-if="canUpdateUser && !lookupsLoaded" class="q-pa-xl flex flex-center">
|
||||||
|
|
||||||
<q-spinner
|
<q-spinner
|
||||||
color="primary"
|
color="primary"
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<q-page class="permissions-page">
|
<q-page v-if="canUpdateUser" class="permissions-page">
|
||||||
|
|
||||||
<!-- ================= STICKY STACK ================= -->
|
<!-- ================= STICKY STACK ================= -->
|
||||||
<div class="sticky-stack">
|
<div class="sticky-stack">
|
||||||
@@ -69,6 +69,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="canUpdateUser"
|
||||||
color="primary"
|
color="primary"
|
||||||
icon="save"
|
icon="save"
|
||||||
label="Kaydet"
|
label="Kaydet"
|
||||||
@@ -165,6 +166,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</q-page>
|
</q-page>
|
||||||
|
|
||||||
|
<q-page v-else class="q-pa-md flex flex-center">
|
||||||
|
<div class="text-negative text-subtitle1">
|
||||||
|
Bu module erisim yetkiniz yok.
|
||||||
|
</div>
|
||||||
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
||||||
@@ -175,11 +182,8 @@ import { Notify } from 'quasar'
|
|||||||
import api from 'src/services/api'
|
import api from 'src/services/api'
|
||||||
import { usePermission } from 'src/composables/usePermission'
|
import { usePermission } from 'src/composables/usePermission'
|
||||||
|
|
||||||
const { canRead, canWrite, canUpdate } = usePermission()
|
const { canUpdate } = usePermission()
|
||||||
|
const canUpdateUser = canUpdate('user')
|
||||||
const canReadOrder = canRead('order')
|
|
||||||
const canWriteOrder = canWrite('order')
|
|
||||||
const canUpdateOrder = canUpdate('order')
|
|
||||||
|
|
||||||
|
|
||||||
/* ================= STATE ================= */
|
/* ================= STATE ================= */
|
||||||
@@ -432,4 +436,3 @@ watch(deptCode, v => console.log('DEPT >>>', v))
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
<!-- src/pages/StatementHeaderReport.vue -->
|
<!-- src/pages/StatementHeaderReport.vue -->
|
||||||
<template>
|
<template>
|
||||||
<q-page class="q-pa-md page-col">
|
<q-page v-if="canReadFinance" class="q-pa-md page-col">
|
||||||
<!-- Başlık ve PDF butonu -->
|
<!-- Başlık ve PDF butonu -->
|
||||||
<div class="row justify-between items-center q-mb-md">
|
<div class="row justify-between items-center q-mb-md">
|
||||||
<div class="text-h6">📄 Cari Hesap Raporu</div>
|
<div class="text-h6">📄 Cari Hesap Raporu</div>
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="canExportFinance"
|
||||||
color="red"
|
color="red"
|
||||||
icon="picture_as_pdf"
|
icon="picture_as_pdf"
|
||||||
label="PDF Yazdır"
|
label="PDF Yazdır"
|
||||||
@@ -44,6 +45,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</q-card>
|
</q-card>
|
||||||
</q-page>
|
</q-page>
|
||||||
|
|
||||||
|
<q-page v-else class="q-pa-md flex flex-center">
|
||||||
|
<div class="text-negative text-subtitle1">
|
||||||
|
Bu module erisim yetkiniz yok.
|
||||||
|
</div>
|
||||||
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -53,11 +60,9 @@ import { useDownloadstHeadStore } from 'src/stores/downloadstHeadStore'
|
|||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { usePermission } from 'src/composables/usePermission'
|
import { usePermission } from 'src/composables/usePermission'
|
||||||
|
|
||||||
const { canRead, canWrite, canUpdate } = usePermission()
|
const { canRead, canExport } = usePermission()
|
||||||
|
const canReadFinance = canRead('finance')
|
||||||
const canReadOrder = canRead('order')
|
const canExportFinance = canExport('finance')
|
||||||
const canWriteOrder = canWrite('order')
|
|
||||||
const canUpdateOrder = canUpdate('order')
|
|
||||||
|
|
||||||
const $q = useQuasar()
|
const $q = useQuasar()
|
||||||
const downloadstHeadStore = useDownloadstHeadStore()
|
const downloadstHeadStore = useDownloadstHeadStore()
|
||||||
@@ -76,6 +81,15 @@ const selectedMonType = ref(monetaryTypeOptions[0].value)
|
|||||||
|
|
||||||
// indirme butonu
|
// indirme butonu
|
||||||
async function handlestHeadDownload() {
|
async function handlestHeadDownload() {
|
||||||
|
if (!canExportFinance.value) {
|
||||||
|
$q.notify({
|
||||||
|
type: 'negative',
|
||||||
|
message: 'PDF export yetkiniz yok',
|
||||||
|
position: 'top-right'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
console.log("▶️ [DEBUG] handlestHeadDownload:", accountCode.value, startDate.value, endDate.value, selectedMonType.value)
|
console.log("▶️ [DEBUG] handlestHeadDownload:", accountCode.value, startDate.value, endDate.value, selectedMonType.value)
|
||||||
|
|
||||||
if (!accountCode.value || !startDate.value || !endDate.value) {
|
if (!accountCode.value || !startDate.value || !endDate.value) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-page class="q-pa-md page-col">
|
<q-page v-if="canReadFinance" class="q-pa-md page-col">
|
||||||
|
|
||||||
<!-- 🔹 Cari Kod / İsim (sabit) -->
|
<!-- 🔹 Cari Kod / İsim (sabit) -->
|
||||||
<div class="filter-sticky">
|
<div class="filter-sticky">
|
||||||
@@ -135,6 +135,7 @@
|
|||||||
|
|
||||||
<!-- ✅ PDF Yazdır Dropdown -->
|
<!-- ✅ PDF Yazdır Dropdown -->
|
||||||
<q-btn-dropdown
|
<q-btn-dropdown
|
||||||
|
v-if="canExportFinance"
|
||||||
flat
|
flat
|
||||||
color="red"
|
color="red"
|
||||||
icon="picture_as_pdf"
|
icon="picture_as_pdf"
|
||||||
@@ -258,6 +259,12 @@
|
|||||||
</q-table>
|
</q-table>
|
||||||
</div>
|
</div>
|
||||||
</q-page>
|
</q-page>
|
||||||
|
|
||||||
|
<q-page v-else class="q-pa-md flex flex-center">
|
||||||
|
<div class="text-negative text-subtitle1">
|
||||||
|
Bu module erisim yetkiniz yok.
|
||||||
|
</div>
|
||||||
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -270,11 +277,9 @@ import { useDownloadstpdfStore } from 'src/stores/downloadstpdfStore'
|
|||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { usePermission } from 'src/composables/usePermission'
|
import { usePermission } from 'src/composables/usePermission'
|
||||||
|
|
||||||
const { canRead, canWrite, canUpdate } = usePermission()
|
const { canRead, canExport } = usePermission()
|
||||||
|
const canReadFinance = canRead('finance')
|
||||||
const canReadOrder = canRead('order')
|
const canExportFinance = canExport('finance')
|
||||||
const canWriteOrder = canWrite('order')
|
|
||||||
const canUpdateOrder = canUpdate('order')
|
|
||||||
|
|
||||||
const $q = useQuasar()
|
const $q = useQuasar()
|
||||||
|
|
||||||
@@ -436,6 +441,15 @@ function toggleLeftCols() {
|
|||||||
|
|
||||||
/* 🔹 PDF İndirme Butonuna bağla */
|
/* 🔹 PDF İndirme Butonuna bağla */
|
||||||
async function handleDownload() {
|
async function handleDownload() {
|
||||||
|
if (!canExportFinance.value) {
|
||||||
|
$q.notify({
|
||||||
|
type: 'negative',
|
||||||
|
message: 'PDF export yetkiniz yok',
|
||||||
|
position: 'top-right'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
console.log("▶️ [DEBUG] handleDownload:", selectedCari.value, dateFrom.value, dateTo.value)
|
console.log("▶️ [DEBUG] handleDownload:", selectedCari.value, dateFrom.value, dateTo.value)
|
||||||
|
|
||||||
if (!selectedCari.value || !dateFrom.value || !dateTo.value) {
|
if (!selectedCari.value || !dateFrom.value || !dateTo.value) {
|
||||||
@@ -468,6 +482,15 @@ import { useDownloadstHeadStore } from 'src/stores/downloadstHeadStore'
|
|||||||
const downloadstHeadStore = useDownloadstHeadStore()
|
const downloadstHeadStore = useDownloadstHeadStore()
|
||||||
|
|
||||||
async function CurrheadDownload() {
|
async function CurrheadDownload() {
|
||||||
|
if (!canExportFinance.value) {
|
||||||
|
$q.notify({
|
||||||
|
type: 'negative',
|
||||||
|
message: 'PDF export yetkiniz yok',
|
||||||
|
position: 'top-right'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
console.log("▶️ [DEBUG] CurrheadDownload:", selectedCari.value, dateFrom.value, dateTo.value)
|
console.log("▶️ [DEBUG] CurrheadDownload:", selectedCari.value, dateFrom.value, dateTo.value)
|
||||||
|
|
||||||
if (!selectedCari.value || !dateFrom.value || !dateTo.value) {
|
if (!selectedCari.value || !dateFrom.value || !dateTo.value) {
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-page class="q-pa-md">
|
<q-page
|
||||||
|
v-if="canSendTestMail"
|
||||||
|
class="q-pa-md"
|
||||||
|
>
|
||||||
<q-card flat bordered class="q-pa-md" style="max-width: 500px">
|
<q-card flat bordered class="q-pa-md" style="max-width: 500px">
|
||||||
<q-card-section>
|
<q-card-section>
|
||||||
<div class="text-h6">SMTP Test Mail</div>
|
<div class="text-h6">SMTP Test Mail</div>
|
||||||
@@ -9,7 +11,7 @@
|
|||||||
<q-card-section>
|
<q-card-section>
|
||||||
<q-input
|
<q-input
|
||||||
v-model="to"
|
v-model="to"
|
||||||
label="Gönderilecek mail"
|
label="Gonderilecek mail"
|
||||||
filled
|
filled
|
||||||
dense
|
dense
|
||||||
/>
|
/>
|
||||||
@@ -17,28 +19,36 @@
|
|||||||
|
|
||||||
<q-card-actions align="right">
|
<q-card-actions align="right">
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="canSendTestMail"
|
||||||
color="primary"
|
color="primary"
|
||||||
label="Test Mail Gönder"
|
label="Test Mail Gonder"
|
||||||
:loading="store.loading"
|
:loading="store.loading"
|
||||||
|
:disable="!canSendTestMail"
|
||||||
@click="send"
|
@click="send"
|
||||||
/>
|
/>
|
||||||
</q-card-actions>
|
</q-card-actions>
|
||||||
</q-card>
|
</q-card>
|
||||||
|
</q-page>
|
||||||
|
|
||||||
|
<q-page
|
||||||
|
v-else
|
||||||
|
class="q-pa-md flex flex-center"
|
||||||
|
>
|
||||||
|
<div class="text-negative text-subtitle1">
|
||||||
|
Bu module erisim yetkiniz yok.
|
||||||
|
</div>
|
||||||
</q-page>
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref } from 'vue'
|
import { computed, ref } from 'vue'
|
||||||
import { useQuasar } from 'quasar'
|
import { useQuasar } from 'quasar'
|
||||||
import { useMailTestStore } from 'src/stores/mailTestStore'
|
import { useMailTestStore } from 'src/stores/mailTestStore'
|
||||||
import { usePermission } from 'src/composables/usePermission'
|
import { usePermission } from 'src/composables/usePermission'
|
||||||
|
|
||||||
const { canRead, canWrite, canUpdate } = usePermission()
|
const { canWrite } = usePermission()
|
||||||
|
const canWriteUser = canWrite('user')
|
||||||
const canReadOrder = canRead('order')
|
const canSendTestMail = computed(() => canWriteUser.value)
|
||||||
const canWriteOrder = canWrite('order')
|
|
||||||
const canUpdateOrder = canUpdate('order')
|
|
||||||
|
|
||||||
const $q = useQuasar()
|
const $q = useQuasar()
|
||||||
const store = useMailTestStore()
|
const store = useMailTestStore()
|
||||||
@@ -46,17 +56,25 @@ const store = useMailTestStore()
|
|||||||
const to = ref('mehmet.kececi@baggi.com.tr')
|
const to = ref('mehmet.kececi@baggi.com.tr')
|
||||||
|
|
||||||
async function send () {
|
async function send () {
|
||||||
|
if (!canSendTestMail.value) {
|
||||||
|
$q.notify({
|
||||||
|
type: 'negative',
|
||||||
|
message: 'Test mail gonderme yetkiniz yok'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await store.sendTestMail(to.value)
|
await store.sendTestMail(to.value)
|
||||||
|
|
||||||
$q.notify({
|
$q.notify({
|
||||||
type: 'positive',
|
type: 'positive',
|
||||||
message: 'Test mail gönderildi'
|
message: 'Test mail gonderildi'
|
||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
$q.notify({
|
$q.notify({
|
||||||
type: 'negative',
|
type: 'negative',
|
||||||
message: err?.message || 'Mail gönderilemedi'
|
message: err?.message || 'Mail gonderilemedi'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-page class="user-detail-page">
|
<q-page v-if="canAccessPage" class="user-detail-page">
|
||||||
|
|
||||||
<!-- LOADING -->
|
<!-- LOADING -->
|
||||||
<q-inner-loading :showing="loading">
|
<q-inner-loading :showing="loading">
|
||||||
@@ -39,6 +39,7 @@
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="canSaveUser"
|
||||||
:label="saveLabel"
|
:label="saveLabel"
|
||||||
color="primary"
|
color="primary"
|
||||||
icon="save"
|
icon="save"
|
||||||
@@ -46,6 +47,7 @@
|
|||||||
@click="onSave"
|
@click="onSave"
|
||||||
/>
|
/>
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="canReadUser"
|
||||||
label="LİSTEYE DÖN"
|
label="LİSTEYE DÖN"
|
||||||
flat
|
flat
|
||||||
icon="arrow_back"
|
icon="arrow_back"
|
||||||
@@ -80,6 +82,7 @@
|
|||||||
|
|
||||||
<div class="row items-center">
|
<div class="row items-center">
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="canUpdateUser"
|
||||||
label="PAROLA MAİLİ GÖNDER"
|
label="PAROLA MAİLİ GÖNDER"
|
||||||
color="primary"
|
color="primary"
|
||||||
icon="mail"
|
icon="mail"
|
||||||
@@ -240,6 +243,12 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</q-page>
|
</q-page>
|
||||||
|
|
||||||
|
<q-page v-else class="q-pa-md flex flex-center">
|
||||||
|
<div class="text-negative text-subtitle1">
|
||||||
|
Bu module erisim yetkiniz yok.
|
||||||
|
</div>
|
||||||
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -251,10 +260,9 @@ import { useUserDetailStore } from 'src/stores/UserDetailStore'
|
|||||||
import { usePermission } from 'src/composables/usePermission'
|
import { usePermission } from 'src/composables/usePermission'
|
||||||
|
|
||||||
const { canRead, canWrite, canUpdate } = usePermission()
|
const { canRead, canWrite, canUpdate } = usePermission()
|
||||||
|
const canReadUser = canRead('user')
|
||||||
const canReadOrder = canRead('order')
|
const canWriteUser = canWrite('user')
|
||||||
const canWriteOrder = canWrite('order')
|
const canUpdateUser = canUpdate('user')
|
||||||
const canUpdateOrder = canUpdate('order')
|
|
||||||
|
|
||||||
const $q = useQuasar()
|
const $q = useQuasar()
|
||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
@@ -280,6 +288,12 @@ const mode = computed(() => route.meta.mode || 'edit')
|
|||||||
const isNew = computed(() => mode.value === 'new')
|
const isNew = computed(() => mode.value === 'new')
|
||||||
const isEdit = computed(() => mode.value === 'edit')
|
const isEdit = computed(() => mode.value === 'edit')
|
||||||
const isView = computed(() => mode.value === 'view')
|
const isView = computed(() => mode.value === 'view')
|
||||||
|
const canAccessPage = computed(() => {
|
||||||
|
if (isNew.value) return canWriteUser.value
|
||||||
|
if (isEdit.value) return canUpdateUser.value
|
||||||
|
return canReadUser.value
|
||||||
|
})
|
||||||
|
const canSaveUser = computed(() => isNew.value ? canWriteUser.value : canUpdateUser.value)
|
||||||
|
|
||||||
const userId = computed(() => (isEdit.value || isView.value) ? Number(route.params.id) : null)
|
const userId = computed(() => (isEdit.value || isView.value) ? Number(route.params.id) : null)
|
||||||
|
|
||||||
@@ -306,6 +320,8 @@ const canSendPasswordMail = computed(() => {
|
|||||||
watch(
|
watch(
|
||||||
() => userId.value,
|
() => userId.value,
|
||||||
async (id) => {
|
async (id) => {
|
||||||
|
if (!canAccessPage.value) return
|
||||||
|
|
||||||
await store.fetchLookups()
|
await store.fetchLookups()
|
||||||
|
|
||||||
if (!id) {
|
if (!id) {
|
||||||
@@ -320,6 +336,11 @@ watch(
|
|||||||
|
|
||||||
/* ================= ACTIONS ================= */
|
/* ================= ACTIONS ================= */
|
||||||
async function onSave () {
|
async function onSave () {
|
||||||
|
if (!canSaveUser.value) {
|
||||||
|
$q.notify({ type: 'negative', message: 'Kaydetme yetkiniz yok' })
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log('🟢 onSave() START', { mode: mode.value })
|
console.log('🟢 onSave() START', { mode: mode.value })
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-page class="user-gateway-page flex flex-center">
|
<q-page v-if="canReadUser" class="user-gateway-page flex flex-center">
|
||||||
|
|
||||||
<div class="gateway-container">
|
<div class="gateway-container">
|
||||||
|
|
||||||
@@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
<!-- ➕ YENİ KULLANICI -->
|
<!-- ➕ YENİ KULLANICI -->
|
||||||
<q-card
|
<q-card
|
||||||
|
v-if="canWriteUser"
|
||||||
class="gateway-card cursor-pointer"
|
class="gateway-card cursor-pointer"
|
||||||
flat
|
flat
|
||||||
bordered
|
bordered
|
||||||
@@ -30,6 +31,7 @@
|
|||||||
|
|
||||||
<!-- 👥 MEVCUT KULLANICILAR -->
|
<!-- 👥 MEVCUT KULLANICILAR -->
|
||||||
<q-card
|
<q-card
|
||||||
|
v-if="canReadUser"
|
||||||
class="gateway-card cursor-pointer"
|
class="gateway-card cursor-pointer"
|
||||||
flat
|
flat
|
||||||
bordered
|
bordered
|
||||||
@@ -49,21 +51,27 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
</q-page>
|
</q-page>
|
||||||
|
|
||||||
|
<q-page v-else class="q-pa-md flex flex-center">
|
||||||
|
<div class="text-negative text-subtitle1">
|
||||||
|
Bu module erisim yetkiniz yok.
|
||||||
|
</div>
|
||||||
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import { usePermission } from 'src/composables/usePermission'
|
import { usePermission } from 'src/composables/usePermission'
|
||||||
|
|
||||||
const { canRead, canWrite, canUpdate } = usePermission()
|
const { canRead, canWrite } = usePermission()
|
||||||
|
const canReadUser = canRead('user')
|
||||||
const canReadOrder = canRead('order')
|
const canWriteUser = canWrite('user')
|
||||||
const canWriteOrder = canWrite('order')
|
|
||||||
const canUpdateOrder = canUpdate('order')
|
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
function goCreate () {
|
function goCreate () {
|
||||||
|
if (!canWriteUser.value) return
|
||||||
|
|
||||||
router.push({
|
router.push({
|
||||||
path: '/app/users/new',
|
path: '/app/users/new',
|
||||||
query: { mode: 'new' }
|
query: { mode: 'new' }
|
||||||
@@ -72,6 +80,7 @@ function goCreate () {
|
|||||||
|
|
||||||
|
|
||||||
function goList () {
|
function goList () {
|
||||||
|
if (!canReadUser.value) return
|
||||||
router.push({ name: 'user-list' })
|
router.push({ name: 'user-list' })
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-page class="ol-page with-bg">
|
<q-page
|
||||||
|
v-if="canReadUser"
|
||||||
|
class="ol-page with-bg"
|
||||||
|
>
|
||||||
|
|
||||||
<!-- 🔍 Sticky Filter -->
|
<!-- 🔍 Sticky Filter -->
|
||||||
<div class="ol-filter-bar">
|
<div class="ol-filter-bar">
|
||||||
@@ -27,14 +30,17 @@
|
|||||||
|
|
||||||
<div class="ol-filter-actions">
|
<div class="ol-filter-actions">
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="canReadUser"
|
||||||
label="Yenile"
|
label="Yenile"
|
||||||
icon="refresh"
|
icon="refresh"
|
||||||
color="primary"
|
color="primary"
|
||||||
:loading="store.loading"
|
:loading="store.loading"
|
||||||
|
:disable="!canReadUser"
|
||||||
@click="store.fetchUsers"
|
@click="store.fetchUsers"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="canWriteUser"
|
||||||
label="Yeni Kullanıcı"
|
label="Yeni Kullanıcı"
|
||||||
icon="person_add"
|
icon="person_add"
|
||||||
color="primary"
|
color="primary"
|
||||||
@@ -68,6 +74,7 @@
|
|||||||
<template #body-cell-open="props">
|
<template #body-cell-open="props">
|
||||||
<q-td class="text-center">
|
<q-td class="text-center">
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="canReadUser"
|
||||||
icon="open_in_new"
|
icon="open_in_new"
|
||||||
color="primary"
|
color="primary"
|
||||||
flat
|
flat
|
||||||
@@ -149,6 +156,15 @@
|
|||||||
</q-banner>
|
</q-banner>
|
||||||
|
|
||||||
</q-page>
|
</q-page>
|
||||||
|
|
||||||
|
<q-page
|
||||||
|
v-else
|
||||||
|
class="q-pa-md flex flex-center"
|
||||||
|
>
|
||||||
|
<div class="text-negative text-subtitle1">
|
||||||
|
Bu module erisim yetkiniz yok.
|
||||||
|
</div>
|
||||||
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -159,9 +175,9 @@ import { usePermission } from 'src/composables/usePermission'
|
|||||||
|
|
||||||
const { canRead, canWrite, canUpdate } = usePermission()
|
const { canRead, canWrite, canUpdate } = usePermission()
|
||||||
|
|
||||||
const canReadOrder = canRead('order')
|
const canReadUser = canRead('user')
|
||||||
const canWriteOrder = canWrite('order')
|
const canWriteUser = canWrite('user')
|
||||||
const canUpdateOrder = canUpdate('order')
|
const canUpdateUser = canUpdate('user')
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const store = useUserListStore()
|
const store = useUserListStore()
|
||||||
@@ -247,14 +263,17 @@ function splitNames(val) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function openDetail(id) {
|
function openDetail(id) {
|
||||||
|
const routeName = canUpdateUser.value ? 'user-edit' : 'user-view'
|
||||||
router.push({
|
router.push({
|
||||||
path: `/app/users/edit/${id}`
|
name: routeName,
|
||||||
|
params: { id: String(id) }
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function goCreate() {
|
function goCreate() {
|
||||||
|
if (!canWriteUser.value) return
|
||||||
router.push({ name: 'user-new' })
|
router.push({ name: 'user-new' })
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,5 +287,9 @@ function splitPiyasalar (val) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
onMounted(store.fetchUsers)
|
onMounted(() => {
|
||||||
|
if (canReadUser.value) {
|
||||||
|
store.fetchUsers()
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
<template>
|
<template>
|
||||||
|
|
||||||
<div v-if="!lookupsLoaded" class="q-pa-xl flex flex-center">
|
<div v-if="canUpdateUser && !lookupsLoaded" class="q-pa-xl flex flex-center">
|
||||||
<q-spinner color="primary" size="48px" />
|
<q-spinner color="primary" size="48px" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<q-page class="permissions-page">
|
<q-page v-if="canUpdateUser" class="permissions-page">
|
||||||
|
|
||||||
<div class="sticky-stack">
|
<div class="sticky-stack">
|
||||||
|
|
||||||
@@ -36,6 +36,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="canUpdateUser"
|
||||||
color="primary"
|
color="primary"
|
||||||
icon="save"
|
icon="save"
|
||||||
label="Kaydet"
|
label="Kaydet"
|
||||||
@@ -115,6 +116,12 @@
|
|||||||
|
|
||||||
</q-page>
|
</q-page>
|
||||||
|
|
||||||
|
<q-page v-else class="q-pa-md flex flex-center">
|
||||||
|
<div class="text-negative text-subtitle1">
|
||||||
|
Bu module erisim yetkiniz yok.
|
||||||
|
</div>
|
||||||
|
</q-page>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
<script setup>
|
<script setup>
|
||||||
|
|
||||||
@@ -123,11 +130,8 @@ import { Notify } from 'quasar'
|
|||||||
import api from 'src/services/api'
|
import api from 'src/services/api'
|
||||||
import { usePermission } from 'src/composables/usePermission'
|
import { usePermission } from 'src/composables/usePermission'
|
||||||
|
|
||||||
const { canRead, canWrite, canUpdate } = usePermission()
|
const { canUpdate } = usePermission()
|
||||||
|
const canUpdateUser = canUpdate('user')
|
||||||
const canReadOrder = canRead('order')
|
|
||||||
const canWriteOrder = canWrite('order')
|
|
||||||
const canUpdateOrder = canUpdate('order')
|
|
||||||
|
|
||||||
|
|
||||||
/* ================= STATE ================= */
|
/* ================= STATE ================= */
|
||||||
|
|||||||
@@ -1,13 +1,18 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-page class="q-pa-md user-sync-page">
|
<q-page
|
||||||
|
v-if="canReadUser"
|
||||||
|
class="q-pa-md user-sync-page"
|
||||||
|
>
|
||||||
|
|
||||||
<div class="row items-center justify-between q-mb-md">
|
<div class="row items-center justify-between q-mb-md">
|
||||||
<div class="text-h6 text-primary">👤 Kullanıcı Yönetimi</div>
|
<div class="text-h6 text-primary">👤 Kullanıcı Yönetimi</div>
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="canUpdateUser"
|
||||||
color="primary"
|
color="primary"
|
||||||
icon="sync"
|
icon="sync"
|
||||||
label="Sync Now"
|
label="Sync Now"
|
||||||
:loading="store.loading"
|
:loading="store.loading"
|
||||||
|
:disable="store.loading || !canUpdateUser"
|
||||||
@click="store.syncNow"
|
@click="store.syncNow"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -46,18 +51,20 @@
|
|||||||
<template v-slot:body-cell-actions="props">
|
<template v-slot:body-cell-actions="props">
|
||||||
<q-td :props="props">
|
<q-td :props="props">
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="canUpdateUser"
|
||||||
dense flat icon="link"
|
dense flat icon="link"
|
||||||
color="primary"
|
color="primary"
|
||||||
size="sm"
|
size="sm"
|
||||||
@click="openMapDialog(props.row)"
|
@click="openMapDialog(props.row)"
|
||||||
:disable="store.loading"
|
:disable="store.loading || !canUpdateUser"
|
||||||
/>
|
/>
|
||||||
<q-btn
|
<q-btn
|
||||||
|
v-if="canUpdateUser"
|
||||||
dense flat icon="link_off"
|
dense flat icon="link_off"
|
||||||
color="negative"
|
color="negative"
|
||||||
size="sm"
|
size="sm"
|
||||||
@click="store.unmap(props.row.id)"
|
@click="store.unmap(props.row.id)"
|
||||||
:disable="!props.row.mssql_username"
|
:disable="store.loading || !props.row.mssql_username || !canUpdateUser"
|
||||||
/>
|
/>
|
||||||
</q-td>
|
</q-td>
|
||||||
</template>
|
</template>
|
||||||
@@ -97,6 +104,15 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</q-page>
|
</q-page>
|
||||||
|
|
||||||
|
<q-page
|
||||||
|
v-else
|
||||||
|
class="q-pa-md flex flex-center"
|
||||||
|
>
|
||||||
|
<div class="text-negative text-subtitle1">
|
||||||
|
Bu module erisim yetkiniz yok.
|
||||||
|
</div>
|
||||||
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -105,11 +121,9 @@ import { useUserSyncStore } from 'src/stores/userSyncStore'
|
|||||||
import { Dialog } from 'quasar'
|
import { Dialog } from 'quasar'
|
||||||
import { usePermission } from 'src/composables/usePermission'
|
import { usePermission } from 'src/composables/usePermission'
|
||||||
|
|
||||||
const { canRead, canWrite, canUpdate } = usePermission()
|
const { canRead, canUpdate } = usePermission()
|
||||||
|
const canReadUser = canRead('user')
|
||||||
const canReadOrder = canRead('order')
|
const canUpdateUser = canUpdate('user')
|
||||||
const canWriteOrder = canWrite('order')
|
|
||||||
const canUpdateOrder = canUpdate('order')
|
|
||||||
|
|
||||||
const store = useUserSyncStore()
|
const store = useUserSyncStore()
|
||||||
|
|
||||||
@@ -142,6 +156,10 @@ function statusColor(status) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function openMapDialog(pgUser) {
|
function openMapDialog(pgUser) {
|
||||||
|
if (!canUpdateUser.value) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
Dialog.create({
|
Dialog.create({
|
||||||
title: 'Kullanıcı Eşleme',
|
title: 'Kullanıcı Eşleme',
|
||||||
message: 'Bu PostgreSQL kullanıcısını hangi MSSQL kullanıcısına bağlamak istiyorsunuz?',
|
message: 'Bu PostgreSQL kullanıcısını hangi MSSQL kullanıcısına bağlamak istiyorsunuz?',
|
||||||
@@ -158,7 +176,9 @@ function openMapDialog(pgUser) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
if (canReadUser.value) {
|
||||||
store.loadDummy()
|
store.loadDummy()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<template>
|
<template>
|
||||||
<q-page class="q-pa-md page-col">
|
<q-page v-if="canReadFinance" class="q-pa-md page-col">
|
||||||
|
|
||||||
<!-- 🔹 Cari Kod / İsim (sabit) -->
|
<!-- 🔹 Cari Kod / İsim (sabit) -->
|
||||||
<div class="filter-sticky">
|
<div class="filter-sticky">
|
||||||
@@ -135,6 +135,7 @@
|
|||||||
|
|
||||||
<!-- ✅ PDF Yazdır Dropdown -->
|
<!-- ✅ PDF Yazdır Dropdown -->
|
||||||
<q-btn-dropdown
|
<q-btn-dropdown
|
||||||
|
v-if="canExportFinance"
|
||||||
flat
|
flat
|
||||||
color="red"
|
color="red"
|
||||||
icon="picture_as_pdf"
|
icon="picture_as_pdf"
|
||||||
@@ -258,6 +259,12 @@
|
|||||||
</q-table>
|
</q-table>
|
||||||
</div>
|
</div>
|
||||||
</q-page>
|
</q-page>
|
||||||
|
|
||||||
|
<q-page v-else class="q-pa-md flex flex-center">
|
||||||
|
<div class="text-negative text-subtitle1">
|
||||||
|
Bu module erisim yetkiniz yok.
|
||||||
|
</div>
|
||||||
|
</q-page>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
@@ -270,11 +277,9 @@ import { useDownloadstpdfStore } from 'src/stores/downloadstpdfStore'
|
|||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { usePermission } from 'src/composables/usePermission'
|
import { usePermission } from 'src/composables/usePermission'
|
||||||
|
|
||||||
const { canRead, canWrite, canUpdate } = usePermission()
|
const { canRead, canExport } = usePermission()
|
||||||
|
const canReadFinance = canRead('finance')
|
||||||
const canReadOrder = canRead('order')
|
const canExportFinance = canExport('finance')
|
||||||
const canWriteOrder = canWrite('order')
|
|
||||||
const canUpdateOrder = canUpdate('order')
|
|
||||||
|
|
||||||
const $q = useQuasar()
|
const $q = useQuasar()
|
||||||
|
|
||||||
@@ -458,6 +463,15 @@ function toggleLeftCols() {
|
|||||||
|
|
||||||
/* 🔹 PDF İndirme Butonuna bağla */
|
/* 🔹 PDF İndirme Butonuna bağla */
|
||||||
async function handleDownload() {
|
async function handleDownload() {
|
||||||
|
if (!canExportFinance.value) {
|
||||||
|
$q.notify({
|
||||||
|
type: 'negative',
|
||||||
|
message: 'PDF export yetkiniz yok',
|
||||||
|
position: 'top-right'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
console.log("▶️ [DEBUG] handleDownload:", selectedCari.value, dateFrom.value, dateTo.value)
|
console.log("▶️ [DEBUG] handleDownload:", selectedCari.value, dateFrom.value, dateTo.value)
|
||||||
|
|
||||||
if (!selectedCari.value || !dateFrom.value || !dateTo.value) {
|
if (!selectedCari.value || !dateFrom.value || !dateTo.value) {
|
||||||
@@ -490,6 +504,15 @@ import { useDownloadstHeadStore } from 'src/stores/downloadstHeadStore'
|
|||||||
const downloadstHeadStore = useDownloadstHeadStore()
|
const downloadstHeadStore = useDownloadstHeadStore()
|
||||||
|
|
||||||
async function CurrheadDownload() {
|
async function CurrheadDownload() {
|
||||||
|
if (!canExportFinance.value) {
|
||||||
|
$q.notify({
|
||||||
|
type: 'negative',
|
||||||
|
message: 'PDF export yetkiniz yok',
|
||||||
|
position: 'top-right'
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
console.log("▶️ [DEBUG] CurrheadDownload:", selectedCari.value, dateFrom.value, dateTo.value)
|
console.log("▶️ [DEBUG] CurrheadDownload:", selectedCari.value, dateFrom.value, dateTo.value)
|
||||||
|
|
||||||
if (!selectedCari.value || !dateFrom.value || !dateTo.value) {
|
if (!selectedCari.value || !dateFrom.value || !dateTo.value) {
|
||||||
|
|||||||
@@ -34,11 +34,23 @@ export const useOrderListStore = defineStore('orderlist', {
|
|||||||
return result
|
return result
|
||||||
},
|
},
|
||||||
|
|
||||||
totalVisibleUSD (state) {
|
totalVisibleUSD () {
|
||||||
return state.filteredOrders.reduce(
|
return this.filteredOrders.reduce((sum, o) => {
|
||||||
(sum, o) => sum + Number(o.TotalAmountUSD || 0),
|
const value = Number(o.TotalAmountUSD || 0)
|
||||||
0
|
return sum + (Number.isFinite(value) ? value : 0)
|
||||||
)
|
}, 0)
|
||||||
|
},
|
||||||
|
|
||||||
|
totalPackedVisibleUSD () {
|
||||||
|
return this.filteredOrders.reduce((sum, o) => {
|
||||||
|
const value = Number(o.PackedUSD || 0)
|
||||||
|
return sum + (Number.isFinite(value) ? value : 0)
|
||||||
|
}, 0)
|
||||||
|
},
|
||||||
|
|
||||||
|
packedVisibleRatePct () {
|
||||||
|
if (!this.totalVisibleUSD) return 0
|
||||||
|
return (this.totalPackedVisibleUSD / this.totalVisibleUSD) * 100
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -2557,6 +2557,52 @@ export const useOrderEntryStore = defineStore('orderentry', {
|
|||||||
// =======================================================
|
// =======================================================
|
||||||
this.debugOrderPayload?.(header, lines, 'PRE-VALIDATE')
|
this.debugOrderPayload?.(header, lines, 'PRE-VALIDATE')
|
||||||
|
|
||||||
|
// =======================================================
|
||||||
|
// 🧩 DUMMY CURRENCY PAYLOAD (model genişletmeden)
|
||||||
|
// - trOrderLineCurrency için gerekli alanları satıra basar
|
||||||
|
// - örnek satırdaki gibi: PriceVI/AmountVI = KDV dahil, Price/Amount = KDV hariç
|
||||||
|
// =======================================================
|
||||||
|
const r2 = (n) => Number((Number(n) || 0).toFixed(2))
|
||||||
|
const r4 = (n) => Number((Number(n) || 0).toFixed(4))
|
||||||
|
|
||||||
|
for (const ln of lines) {
|
||||||
|
const qty = Number(ln?.Qty1 || 0)
|
||||||
|
const unitBase = Number(ln?.Price || 0) // KDV hariç birim
|
||||||
|
const vatRate = Number(ln?.VatRate || 0)
|
||||||
|
const exRate = Number(ln?.PriceExchangeRate || header?.ExchangeRate || 1) || 1
|
||||||
|
|
||||||
|
const taxBase = r2(unitBase * qty) // Amount
|
||||||
|
const vat = r2((taxBase * vatRate) / 100) // Vat
|
||||||
|
const net = r2(taxBase + vat) // AmountVI / NetAmount
|
||||||
|
const unitWithVat = qty > 0 ? r4(net / qty) : r4(unitBase * (1 + vatRate / 100))
|
||||||
|
|
||||||
|
const docCurrency = String(ln?.DocCurrencyCode || header?.DocCurrencyCode || 'TRY').trim() || 'TRY'
|
||||||
|
|
||||||
|
// Backend model alanları
|
||||||
|
ln.RelationCurrencyCode = docCurrency
|
||||||
|
ln.DocPrice = unitWithVat
|
||||||
|
ln.DocAmount = net
|
||||||
|
ln.LocalPrice = unitBase
|
||||||
|
ln.LocalAmount = taxBase
|
||||||
|
ln.LineDiscount = Number(ln?.LineDiscount || 0)
|
||||||
|
ln.TotalDiscount = Number(ln?.TotalDiscount || 0)
|
||||||
|
ln.TaxBase = taxBase
|
||||||
|
ln.Pct = Number(ln?.Pct || 0)
|
||||||
|
ln.VatAmount = vat
|
||||||
|
ln.VatDeducation = 0
|
||||||
|
ln.NetAmount = net
|
||||||
|
|
||||||
|
// SQL kolonu isimleriyle dummy alias (decoder ignore etse de payload'da görünür)
|
||||||
|
ln.CurrencyCode = docCurrency
|
||||||
|
ln.ExchangeRate = exRate
|
||||||
|
ln.PriceVI = unitWithVat
|
||||||
|
ln.AmountVI = net
|
||||||
|
ln.Amount = taxBase
|
||||||
|
ln.LDiscount1 = Number(ln?.LDiscount1 || 0)
|
||||||
|
ln.TDiscount1 = Number(ln?.TDiscount1 || 0)
|
||||||
|
ln.Vat = vat
|
||||||
|
}
|
||||||
|
|
||||||
// =======================================================
|
// =======================================================
|
||||||
// 🧪 PRE-VALIDATE — prItemVariant ön kontrol
|
// 🧪 PRE-VALIDATE — prItemVariant ön kontrol
|
||||||
// - invalid varsa CREATE/UPDATE ÇALIŞMAZ
|
// - invalid varsa CREATE/UPDATE ÇALIŞMAZ
|
||||||
@@ -3337,4 +3383,3 @@ export const sharedOrderEntryRefs = {
|
|||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user