Merge remote-tracking branch 'origin/master'
This commit is contained in:
19
svc/models/orderproductionitem.go
Normal file
19
svc/models/orderproductionitem.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package models
|
||||
|
||||
// ========================================================
|
||||
// 📌 OrderProductionItem — U ile başlayan ürün satırı
|
||||
// ========================================================
|
||||
type OrderProductionItem struct {
|
||||
OrderHeaderID string `json:"OrderHeaderID"`
|
||||
OrderLineID string `json:"OrderLineID"`
|
||||
|
||||
OldItemCode string `json:"OldItemCode"`
|
||||
OldColor string `json:"OldColor"`
|
||||
OldDim2 string `json:"OldDim2"`
|
||||
OldDesc string `json:"OldDesc"`
|
||||
|
||||
NewItemCode string `json:"NewItemCode"`
|
||||
NewColor string `json:"NewColor"`
|
||||
NewDim2 string `json:"NewDim2"`
|
||||
NewDesc string `json:"NewDesc"`
|
||||
}
|
||||
31
svc/queries/orderproduction_items.go
Normal file
31
svc/queries/orderproduction_items.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package queries
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
)
|
||||
|
||||
// ========================================================
|
||||
// 📌 GetOrderProductionItems — OrderHeaderID için U ürünleri
|
||||
// ========================================================
|
||||
func GetOrderProductionItems(mssql *sql.DB, orderHeaderID string) (*sql.Rows, error) {
|
||||
return mssql.Query(`
|
||||
SELECT
|
||||
CAST(l.OrderHeaderID AS NVARCHAR(50)) AS OrderHeaderID,
|
||||
CAST(l.OrderLineID AS NVARCHAR(50)) AS OrderLineID,
|
||||
|
||||
-- Şimdilik eski alanlar boş döndürülür
|
||||
CAST('' AS NVARCHAR(50)) AS OldItemCode,
|
||||
CAST('' AS NVARCHAR(50)) AS OldColor,
|
||||
CAST('' AS NVARCHAR(50)) AS OldDim2,
|
||||
CAST('' AS NVARCHAR(250)) AS OldDesc,
|
||||
|
||||
ISNULL(l.ItemCode,'') AS NewItemCode,
|
||||
ISNULL(l.ColorCode,'') AS NewColor,
|
||||
ISNULL(l.ItemDim2Code,'') AS NewDim2,
|
||||
ISNULL(l.LineDescription,'') AS NewDesc
|
||||
FROM dbo.trOrderLine l
|
||||
WHERE l.OrderHeaderID = @p1
|
||||
AND ISNULL(l.ItemCode,'') LIKE 'U%'
|
||||
ORDER BY l.SortOrder, l.OrderLineID
|
||||
`, orderHeaderID)
|
||||
}
|
||||
269
svc/queries/orderproductionlist.go
Normal file
269
svc/queries/orderproductionlist.go
Normal file
@@ -0,0 +1,269 @@
|
||||
package queries
|
||||
|
||||
import (
|
||||
"bssapp-backend/auth"
|
||||
"bssapp-backend/internal/authz"
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// ========================================================
|
||||
// 📌 GetOrderProductionList — Üretime verilecek ürün içeren siparişler
|
||||
// ========================================================
|
||||
func GetOrderProductionList(
|
||||
ctx context.Context,
|
||||
mssql *sql.DB,
|
||||
pg *sql.DB,
|
||||
search string,
|
||||
) (*sql.Rows, error) {
|
||||
|
||||
claims, ok := auth.GetClaimsFromContext(ctx)
|
||||
if !ok || claims == nil {
|
||||
return nil, fmt.Errorf("unauthorized: claims not found")
|
||||
}
|
||||
|
||||
// ----------------------------------------------------
|
||||
// 🔐 PIYASA FILTER (ADMIN BYPASS)
|
||||
// ----------------------------------------------------
|
||||
piyasaWhere := "1=1"
|
||||
|
||||
if !claims.IsAdmin() {
|
||||
|
||||
codes, err := authz.GetUserPiyasaCodes(pg, int(claims.ID))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("piyasa codes load error: %w", err)
|
||||
}
|
||||
|
||||
if len(codes) == 0 {
|
||||
piyasaWhere = "1=0"
|
||||
} else {
|
||||
piyasaWhere = authz.BuildINClause(
|
||||
"UPPER(f2.CustomerAtt01)",
|
||||
codes,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------
|
||||
// 📄 BASE QUERY (orderlist.go ile aynı kolonlar)
|
||||
// ----------------------------------------------------
|
||||
baseQuery := fmt.Sprintf(`
|
||||
SELECT
|
||||
CAST(h.OrderHeaderID AS NVARCHAR(50)) AS OrderHeaderID,
|
||||
ISNULL(h.OrderNumber, '') AS OrderNumber,
|
||||
CONVERT(varchar, h.OrderDate, 23) AS OrderDate,
|
||||
|
||||
ISNULL(h.CurrAccCode, '') AS CurrAccCode,
|
||||
ISNULL(ca.CurrAccDescription, '') AS CurrAccDescription,
|
||||
|
||||
ISNULL(mt.AttributeDescription, '') AS MusteriTemsilcisi,
|
||||
ISNULL(py.AttributeDescription, '') AS Piyasa,
|
||||
|
||||
CONVERT(varchar, h.CreditableConfirmedDate,23) AS CreditableConfirmedDate,
|
||||
ISNULL(h.DocCurrencyCode,'TRY') AS DocCurrencyCode,
|
||||
|
||||
ISNULL(l.TotalAmount,0) AS TotalAmount,
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- USD HESABI (TRY / EUR / GBP / USD DESTEKLİ)
|
||||
----------------------------------------------------------------
|
||||
CASE
|
||||
WHEN h.DocCurrencyCode = 'USD'
|
||||
THEN ISNULL(l.TotalAmount,0)
|
||||
|
||||
WHEN h.DocCurrencyCode = 'TRY'
|
||||
AND usd.Rate > 0
|
||||
THEN ISNULL(l.TotalAmount,0) / usd.Rate
|
||||
|
||||
WHEN h.DocCurrencyCode IN ('EUR','GBP')
|
||||
AND cur.Rate > 0
|
||||
AND usd.Rate > 0
|
||||
THEN (ISNULL(l.TotalAmount,0) * cur.Rate) / usd.Rate
|
||||
|
||||
ELSE 0
|
||||
END AS TotalAmountUSD,
|
||||
|
||||
ISNULL(l.PackedAmount,0) AS PackedAmount,
|
||||
|
||||
CASE
|
||||
WHEN h.DocCurrencyCode = 'USD'
|
||||
THEN ISNULL(l.PackedAmount,0)
|
||||
|
||||
WHEN h.DocCurrencyCode = 'TRY'
|
||||
AND usd.Rate > 0
|
||||
THEN ISNULL(l.PackedTRY,0) / usd.Rate
|
||||
|
||||
WHEN cur.Rate > 0
|
||||
AND usd.Rate > 0
|
||||
THEN (ISNULL(l.PackedAmount,0) * cur.Rate) / usd.Rate
|
||||
|
||||
ELSE 0
|
||||
END AS PackedUSD,
|
||||
|
||||
CASE
|
||||
WHEN ISNULL(l.TotalAmount,0) > 0
|
||||
THEN (ISNULL(l.PackedAmount,0) * 100.0) / NULLIF(l.TotalAmount,0)
|
||||
ELSE 0
|
||||
END AS PackedRatePct,
|
||||
|
||||
ISNULL(h.IsCreditableConfirmed,0) AS IsCreditableConfirmed,
|
||||
CAST(1 AS bit) AS HasUretimUrunu,
|
||||
ISNULL(h.Description,'') AS Description,
|
||||
|
||||
usd.Rate AS ExchangeRateUSD
|
||||
|
||||
FROM dbo.trOrderHeader h
|
||||
|
||||
-- ✅ TOPLAM ARTIK trOrderLineCurrency'den: CurrencyCode = DocCurrencyCode
|
||||
JOIN (
|
||||
SELECT
|
||||
l.OrderHeaderID,
|
||||
SUM(ISNULL(c.NetAmount,0)) AS TotalAmount,
|
||||
SUM(
|
||||
CASE
|
||||
WHEN ISNULL(c.CurrencyCode,'') = 'TRY'
|
||||
THEN ISNULL(c.NetAmount,0)
|
||||
ELSE 0
|
||||
END
|
||||
) AS TotalTRY,
|
||||
SUM(
|
||||
CASE
|
||||
WHEN ISNULL(l.IsClosed,0) = 1
|
||||
THEN ISNULL(c.NetAmount,0)
|
||||
ELSE 0
|
||||
END
|
||||
) AS PackedAmount,
|
||||
SUM(
|
||||
CASE
|
||||
WHEN ISNULL(l.IsClosed,0) = 1
|
||||
AND ISNULL(c.CurrencyCode,'') = 'TRY'
|
||||
THEN ISNULL(c.NetAmount,0)
|
||||
ELSE 0
|
||||
END
|
||||
) AS PackedTRY
|
||||
FROM dbo.trOrderLine l
|
||||
JOIN dbo.trOrderHeader h2
|
||||
ON h2.OrderHeaderID = l.OrderHeaderID
|
||||
LEFT JOIN dbo.trOrderLineCurrency c
|
||||
ON c.OrderLineID = l.OrderLineID
|
||||
AND c.CurrencyCode = ISNULL(h2.DocCurrencyCode,'TRY')
|
||||
GROUP BY l.OrderHeaderID
|
||||
) l
|
||||
ON l.OrderHeaderID = h.OrderHeaderID
|
||||
|
||||
LEFT JOIN dbo.cdCurrAccDesc ca
|
||||
ON ca.CurrAccCode = h.CurrAccCode
|
||||
AND ca.LangCode = 'TR'
|
||||
|
||||
-- müşteri temsilcisi + piyasa açıklamaları
|
||||
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
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- ORDER PB → 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
|
||||
-- 🔐 PIYASA AUTHZ (EXISTS — SAĞLAM YOL)
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM dbo.CustomerAttributesFilter f2
|
||||
WHERE f2.CurrAccCode = h.CurrAccCode
|
||||
AND %s
|
||||
)
|
||||
-- ✅ Üretime verilecek ürün filtresi
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM dbo.trOrderLine l2
|
||||
WHERE l2.OrderHeaderID = h.OrderHeaderID
|
||||
AND ISNULL(l2.ItemCode,'') LIKE 'U%%'
|
||||
)
|
||||
`, piyasaWhere)
|
||||
|
||||
// ----------------------------------------------------
|
||||
// 🔍 SEARCH FILTER (CASE + TR SAFE)
|
||||
// ----------------------------------------------------
|
||||
if search != "" {
|
||||
baseQuery += `
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM dbo.trOrderHeader h2
|
||||
LEFT JOIN dbo.cdCurrAccDesc ca2
|
||||
ON ca2.CurrAccCode = h2.CurrAccCode
|
||||
AND ca2.LangCode = 'TR'
|
||||
WHERE h2.OrderHeaderID = h.OrderHeaderID
|
||||
AND (
|
||||
LOWER(REPLACE(REPLACE(h2.OrderNumber,'İ','I'),'ı','i'))
|
||||
COLLATE Latin1_General_CI_AI LIKE LOWER(@p1)
|
||||
|
||||
OR LOWER(REPLACE(REPLACE(h2.CurrAccCode,'İ','I'),'ı','i'))
|
||||
COLLATE Latin1_General_CI_AI LIKE LOWER(@p1)
|
||||
|
||||
OR LOWER(REPLACE(REPLACE(ca2.CurrAccDescription,'İ','I'),'ı','i'))
|
||||
COLLATE Latin1_General_CI_AI LIKE LOWER(@p1)
|
||||
|
||||
OR LOWER(REPLACE(REPLACE(h2.Description,'İ','I'),'ı','i'))
|
||||
COLLATE Latin1_General_CI_AI LIKE LOWER(@p1)
|
||||
)
|
||||
)
|
||||
`
|
||||
}
|
||||
|
||||
// ----------------------------------------------------
|
||||
// 📌 ORDER
|
||||
// ----------------------------------------------------
|
||||
baseQuery += `
|
||||
ORDER BY h.CreatedDate DESC
|
||||
`
|
||||
|
||||
// ----------------------------------------------------
|
||||
// ▶ EXECUTE
|
||||
// ----------------------------------------------------
|
||||
if search != "" {
|
||||
searchLike := fmt.Sprintf("%%%s%%", search)
|
||||
return mssql.Query(baseQuery, searchLike)
|
||||
}
|
||||
|
||||
return mssql.Query(baseQuery)
|
||||
}
|
||||
66
svc/routes/orderproductionitems.go
Normal file
66
svc/routes/orderproductionitems.go
Normal file
@@ -0,0 +1,66 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"bssapp-backend/models"
|
||||
"bssapp-backend/queries"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
|
||||
// ======================================================
|
||||
// 📌 OrderProductionItemsRoute — U ürün satırları
|
||||
// ======================================================
|
||||
func OrderProductionItemsRoute(mssql *sql.DB) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
|
||||
id := mux.Vars(r)["id"]
|
||||
if id == "" {
|
||||
http.Error(w, "OrderHeaderID bulunamadı", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
rows, err := queries.GetOrderProductionItems(mssql, id)
|
||||
if err != nil {
|
||||
log.Printf("❌ SQL sorgu hatası: %v", err)
|
||||
http.Error(w, "Veritabanı hatası", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
list := make([]models.OrderProductionItem, 0, 100)
|
||||
|
||||
for rows.Next() {
|
||||
var o models.OrderProductionItem
|
||||
if err := rows.Scan(
|
||||
&o.OrderHeaderID,
|
||||
&o.OrderLineID,
|
||||
&o.OldItemCode,
|
||||
&o.OldColor,
|
||||
&o.OldDim2,
|
||||
&o.OldDesc,
|
||||
&o.NewItemCode,
|
||||
&o.NewColor,
|
||||
&o.NewDim2,
|
||||
&o.NewDesc,
|
||||
); err != nil {
|
||||
log.Printf("⚠️ SCAN HATASI: %v", err)
|
||||
continue
|
||||
}
|
||||
list = append(list, o)
|
||||
}
|
||||
|
||||
if err := rows.Err(); err != nil {
|
||||
log.Printf("⚠️ rows.Err(): %v", err)
|
||||
}
|
||||
|
||||
if err := json.NewEncoder(w).Encode(list); err != nil {
|
||||
log.Printf("❌ encode error: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
130
svc/routes/orderproductionlist.go
Normal file
130
svc/routes/orderproductionlist.go
Normal file
@@ -0,0 +1,130 @@
|
||||
package routes
|
||||
|
||||
import (
|
||||
"bssapp-backend/auth"
|
||||
"bssapp-backend/db"
|
||||
"bssapp-backend/models"
|
||||
"bssapp-backend/queries"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ======================================================
|
||||
// 📌 OrderProductionListRoute — Üretime verilecek siparişler
|
||||
// ======================================================
|
||||
func OrderProductionListRoute(mssql *sql.DB) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
|
||||
// --------------------------------------------------
|
||||
// 🔍 Query Param (RAW + TRIM)
|
||||
// --------------------------------------------------
|
||||
raw := r.URL.Query().Get("search")
|
||||
search := strings.TrimSpace(raw)
|
||||
|
||||
log.Printf(
|
||||
"📥 /api/orders/production-list search raw=%q trimmed=%q lenRaw=%d lenTrim=%d",
|
||||
raw,
|
||||
search,
|
||||
len(raw),
|
||||
len(search),
|
||||
)
|
||||
|
||||
// --------------------------------------------------
|
||||
// 🗄 SQL CALL (WITH CONTEXT)
|
||||
// --------------------------------------------------
|
||||
rows, err := queries.GetOrderProductionList(
|
||||
r.Context(),
|
||||
mssql,
|
||||
db.PgDB,
|
||||
search,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
log.Printf("❌ SQL sorgu hatası: %v", err)
|
||||
http.Error(w, "Veritabanı hatası", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
// --------------------------------------------------
|
||||
// 📦 Sonuç Listesi
|
||||
// --------------------------------------------------
|
||||
list := make([]models.OrderList, 0, 100)
|
||||
count := 0
|
||||
|
||||
// ==================================================
|
||||
// 🧠 SCAN — SQL SELECT ile BİRE BİR (18 kolon)
|
||||
// ==================================================
|
||||
for rows.Next() {
|
||||
|
||||
var o models.OrderList
|
||||
|
||||
err = rows.Scan(
|
||||
&o.OrderHeaderID, // 1
|
||||
&o.OrderNumber, // 2
|
||||
&o.OrderDate, // 3
|
||||
|
||||
&o.CurrAccCode, // 4
|
||||
&o.CurrAccDescription, // 5
|
||||
|
||||
&o.MusteriTemsilcisi, // 6
|
||||
&o.Piyasa, // 7
|
||||
|
||||
&o.CreditableConfirmedDate, // 8
|
||||
&o.DocCurrencyCode, // 9
|
||||
|
||||
&o.TotalAmount, // 10
|
||||
&o.TotalAmountUSD, // 11
|
||||
&o.PackedAmount, // 12
|
||||
&o.PackedUSD, // 13
|
||||
&o.PackedRatePct, // 14
|
||||
|
||||
&o.IsCreditableConfirmed, // 15
|
||||
&o.HasUretimUrunu, // 16
|
||||
&o.Description, // 17
|
||||
|
||||
&o.ExchangeRateUSD, // 18
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
log.Printf(
|
||||
"⚠️ SCAN HATASI | OrderHeaderID=%v | err=%v",
|
||||
o.OrderHeaderID,
|
||||
err,
|
||||
)
|
||||
continue
|
||||
}
|
||||
|
||||
list = append(list, o)
|
||||
count++
|
||||
}
|
||||
|
||||
if err := rows.Err(); err != nil {
|
||||
log.Printf("⚠️ rows.Err(): %v", err)
|
||||
}
|
||||
|
||||
// --------------------------------------------------
|
||||
// 📊 RESULT LOG
|
||||
// --------------------------------------------------
|
||||
claims, _ := auth.GetClaimsFromContext(r.Context())
|
||||
|
||||
log.Printf(
|
||||
"✅ Order production list DONE | user=%d | search=%q | resultCount=%d",
|
||||
claims.ID,
|
||||
search,
|
||||
count,
|
||||
)
|
||||
|
||||
// --------------------------------------------------
|
||||
// ✅ JSON RESPONSE
|
||||
// --------------------------------------------------
|
||||
if err := json.NewEncoder(w).Encode(list); err != nil {
|
||||
log.Printf("❌ encode error: %v", err)
|
||||
}
|
||||
})
|
||||
}
|
||||
125
ui/quasar.config.js.temporary.compiled.1771513237059.mjs
Normal file
125
ui/quasar.config.js.temporary.compiled.1771513237059.mjs
Normal file
@@ -0,0 +1,125 @@
|
||||
/* 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(() => {
|
||||
const apiBaseUrl = (process.env.VITE_API_BASE_URL || "/api").trim();
|
||||
return {
|
||||
/* =====================================================
|
||||
APP INFO
|
||||
===================================================== */
|
||||
productName: "Baggi BSS",
|
||||
productDescription: "Baggi Tekstil Business Support System",
|
||||
/* =====================================================
|
||||
BOOT FILES
|
||||
===================================================== */
|
||||
boot: ["dayjs"],
|
||||
/* =====================================================
|
||||
GLOBAL CSS
|
||||
===================================================== */
|
||||
css: ["app.css"],
|
||||
/* =====================================================
|
||||
ICONS / FONTS
|
||||
===================================================== */
|
||||
extras: [
|
||||
"roboto-font",
|
||||
"material-icons"
|
||||
],
|
||||
/* =====================================================
|
||||
BUILD (PRODUCTION)
|
||||
===================================================== */
|
||||
build: {
|
||||
vueRouterMode: "hash",
|
||||
env: {
|
||||
VITE_API_BASE_URL: apiBaseUrl
|
||||
},
|
||||
esbuildTarget: {
|
||||
browser: ["es2022", "firefox115", "chrome115", "safari14"],
|
||||
node: "node20"
|
||||
},
|
||||
// Cache & performance
|
||||
gzip: true,
|
||||
preloadChunks: true
|
||||
},
|
||||
/* =====================================================
|
||||
DEV SERVER (LOCAL)
|
||||
===================================================== */
|
||||
devServer: {
|
||||
server: { type: "http" },
|
||||
port: 9e3,
|
||||
open: true,
|
||||
// DEV proxy (CORS'suz)
|
||||
proxy: [
|
||||
{
|
||||
context: ["/api"],
|
||||
target: "http://localhost:8080",
|
||||
changeOrigin: true,
|
||||
secure: false
|
||||
}
|
||||
]
|
||||
},
|
||||
/* =====================================================
|
||||
QUASAR FRAMEWORK
|
||||
===================================================== */
|
||||
framework: {
|
||||
config: {
|
||||
notify: {
|
||||
position: "top",
|
||||
timeout: 2500
|
||||
}
|
||||
},
|
||||
lang: "tr",
|
||||
plugins: [
|
||||
"Loading",
|
||||
"Dialog",
|
||||
"Notify"
|
||||
]
|
||||
},
|
||||
animations: [],
|
||||
/* =====================================================
|
||||
SSR / PWA (DISABLED)
|
||||
===================================================== */
|
||||
ssr: {
|
||||
prodPort: 3e3,
|
||||
middlewares: ["render"],
|
||||
pwa: false
|
||||
},
|
||||
pwa: {
|
||||
workboxMode: "GenerateSW"
|
||||
},
|
||||
/* =====================================================
|
||||
MOBILE / DESKTOP
|
||||
===================================================== */
|
||||
capacitor: {
|
||||
hideSplashscreen: true
|
||||
},
|
||||
electron: {
|
||||
preloadScripts: ["electron-preload"],
|
||||
inspectPort: 5858,
|
||||
bundler: "packager",
|
||||
builder: {
|
||||
appId: "baggisowtfaresystem"
|
||||
}
|
||||
},
|
||||
bex: {
|
||||
extraScripts: []
|
||||
}
|
||||
};
|
||||
});
|
||||
export {
|
||||
quasar_config_default as default
|
||||
};
|
||||
57
ui/src/pages/OrderProductionUpdate.vue
Normal file
57
ui/src/pages/OrderProductionUpdate.vue
Normal file
@@ -0,0 +1,57 @@
|
||||
<template>
|
||||
<q-page class="q-pa-md">
|
||||
<div class="text-h6 text-weight-bold">Üretime Verilen Ürünler</div>
|
||||
<div class="text-caption text-grey-7 q-mt-xs">
|
||||
OrderHeaderID: {{ orderHeaderID || '-' }}
|
||||
</div>
|
||||
|
||||
<q-table
|
||||
class="q-mt-md"
|
||||
flat
|
||||
bordered
|
||||
dense
|
||||
separator="cell"
|
||||
row-key="OrderLineID"
|
||||
:rows="store.items"
|
||||
:columns="columns"
|
||||
:loading="store.loading"
|
||||
no-data-label="Üretime verilecek ürün bulunamadı"
|
||||
:rows-per-page-options="[0]"
|
||||
hide-bottom
|
||||
/>
|
||||
|
||||
<q-banner v-if="store.error" class="bg-red text-white q-mt-sm">
|
||||
Hata: {{ store.error }}
|
||||
</q-banner>
|
||||
</q-page>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useRoute } from 'vue-router'
|
||||
import { useOrderProductionItemStore } from 'src/stores/OrderProductionItemStore'
|
||||
|
||||
const route = useRoute()
|
||||
const store = useOrderProductionItemStore()
|
||||
|
||||
const orderHeaderID = computed(() => String(route.params.orderHeaderID || '').trim())
|
||||
|
||||
const columns = [
|
||||
{ name: 'OldItemCode', label: 'Eski Ürün Kodu', field: 'OldItemCode', align: 'left', sortable: true, style: 'min-width:140px;white-space:nowrap', headerStyle: 'min-width:140px;white-space:nowrap' },
|
||||
{ name: 'OldColor', label: 'Eski Ürün Rengi', field: 'OldColor', align: 'left', sortable: true, style: 'min-width:120px;white-space:nowrap', headerStyle: 'min-width:120px;white-space:nowrap' },
|
||||
{ name: 'OldDim2', label: 'Eski 2. Renk', field: 'OldDim2', align: 'left', sortable: true, style: 'min-width:110px;white-space:nowrap', headerStyle: 'min-width:110px;white-space:nowrap' },
|
||||
{ name: 'OldDesc', label: 'Eski Açıklama', field: 'OldDesc', align: 'left', sortable: false, style: 'min-width:180px;white-space:nowrap', headerStyle: 'min-width:180px;white-space:nowrap' },
|
||||
{ name: 'NewItemCode', label: 'Yeni Ürün Kodu', field: 'NewItemCode', align: 'left', sortable: true, style: 'min-width:140px;white-space:nowrap', headerStyle: 'min-width:140px;white-space:nowrap' },
|
||||
{ name: 'NewColor', label: 'Yeni Ürün Rengi', field: 'NewColor', align: 'left', sortable: true, style: 'min-width:120px;white-space:nowrap', headerStyle: 'min-width:120px;white-space:nowrap' },
|
||||
{ name: 'NewDim2', label: 'Yeni 2. Renk', field: 'NewDim2', align: 'left', sortable: true, style: 'min-width:110px;white-space:nowrap', headerStyle: 'min-width:110px;white-space:nowrap' },
|
||||
{ name: 'NewDesc', label: 'Yeni Açıklama', field: 'NewDesc', align: 'left', sortable: false, style: 'min-width:180px;white-space:nowrap', headerStyle: 'min-width:180px;white-space:nowrap' }
|
||||
]
|
||||
|
||||
onMounted(() => {
|
||||
store.fetchItems(orderHeaderID.value)
|
||||
})
|
||||
|
||||
watch(orderHeaderID, (id) => {
|
||||
store.fetchItems(id)
|
||||
})
|
||||
</script>
|
||||
357
ui/src/pages/OrderProductionUpdateList.vue
Normal file
357
ui/src/pages/OrderProductionUpdateList.vue
Normal file
@@ -0,0 +1,357 @@
|
||||
<template>
|
||||
<q-page v-if="canReadOrder" class="ol-page">
|
||||
<div class="ol-filter-bar">
|
||||
<div class="ol-filter-row">
|
||||
<q-input
|
||||
v-model="store.filters.search"
|
||||
class="ol-filter-input ol-search"
|
||||
dense
|
||||
filled
|
||||
debounce="300"
|
||||
clearable
|
||||
label="Arama (Sipariş No / Cari / Açıklama)"
|
||||
>
|
||||
<template #append>
|
||||
<q-icon name="search" />
|
||||
</template>
|
||||
</q-input>
|
||||
|
||||
<q-input
|
||||
v-model="store.filters.CurrAccCode"
|
||||
class="ol-filter-input"
|
||||
dense
|
||||
filled
|
||||
clearable
|
||||
label="Cari Kodu"
|
||||
/>
|
||||
|
||||
<q-input
|
||||
v-model="store.filters.OrderDate"
|
||||
class="ol-filter-input"
|
||||
dense
|
||||
filled
|
||||
type="date"
|
||||
label="Sipariş Tarihi"
|
||||
/>
|
||||
|
||||
<div class="ol-filter-actions">
|
||||
<q-btn
|
||||
label="Temizle"
|
||||
icon="clear"
|
||||
color="grey-7"
|
||||
flat
|
||||
:disable="store.loading"
|
||||
@click="clearFilters"
|
||||
>
|
||||
<q-tooltip>Tüm filtreleri temizle</q-tooltip>
|
||||
</q-btn>
|
||||
|
||||
<q-btn
|
||||
label="Yenile"
|
||||
color="primary"
|
||||
icon="refresh"
|
||||
:loading="store.loading"
|
||||
@click="store.fetchOrders"
|
||||
/>
|
||||
|
||||
<q-btn
|
||||
label="Excel'e Aktar"
|
||||
icon="download"
|
||||
color="primary"
|
||||
outline
|
||||
:disable="store.loading || productionOrders.length === 0"
|
||||
@click="exportExcel"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="ol-filter-total">
|
||||
<div class="ol-total-line">
|
||||
<span class="ol-total-label">Toplam USD:</span>
|
||||
<strong class="ol-total-value">
|
||||
{{ totalVisibleUSD.toLocaleString('tr-TR', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) }}
|
||||
</strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<q-table
|
||||
title="Üretime Verilecek Ürünleri Olan Siparişler"
|
||||
class="ol-table"
|
||||
flat
|
||||
bordered
|
||||
dense
|
||||
separator="cell"
|
||||
row-key="OrderHeaderID"
|
||||
:rows="productionOrders"
|
||||
:columns="columns"
|
||||
:loading="store.loading"
|
||||
no-data-label="Üretime verilecek sipariş bulunamadı"
|
||||
:rows-per-page-options="[0]"
|
||||
hide-bottom
|
||||
>
|
||||
<template #body-cell-open="props">
|
||||
<q-td :props="props" class="text-center">
|
||||
<q-btn
|
||||
icon="open_in_new"
|
||||
color="primary"
|
||||
flat
|
||||
round
|
||||
dense
|
||||
@click="selectOrder(props.row)"
|
||||
>
|
||||
<q-tooltip>Siparişi Aç</q-tooltip>
|
||||
</q-btn>
|
||||
</q-td>
|
||||
</template>
|
||||
|
||||
<template #body-cell-IsCreditableConfirmed="props">
|
||||
<q-td :props="props" class="text-center q-gutter-sm">
|
||||
<q-btn
|
||||
icon="picture_as_pdf"
|
||||
color="red"
|
||||
flat
|
||||
round
|
||||
dense
|
||||
@click="printPDF(props.row)"
|
||||
>
|
||||
<q-tooltip>Siparişi PDF olarak aç</q-tooltip>
|
||||
</q-btn>
|
||||
|
||||
<q-icon
|
||||
:name="props.row.IsCreditableConfirmed ? 'check_circle' : 'cancel'"
|
||||
:color="props.row.IsCreditableConfirmed ? 'green' : 'red'"
|
||||
size="20px"
|
||||
>
|
||||
<q-tooltip>
|
||||
{{ props.row.IsCreditableConfirmed ? 'Onaylı' : 'Onaysız' }}
|
||||
</q-tooltip>
|
||||
</q-icon>
|
||||
</q-td>
|
||||
</template>
|
||||
|
||||
<template #body-cell-OrderDate="props">
|
||||
<q-td :props="props" class="text-center">
|
||||
{{ formatDate(props.row.OrderDate) }}
|
||||
</q-td>
|
||||
</template>
|
||||
|
||||
<template #body-cell-CreditableConfirmedDate="props">
|
||||
<q-td :props="props" class="text-center">
|
||||
{{ formatDate(props.row.CreditableConfirmedDate) }}
|
||||
</q-td>
|
||||
</template>
|
||||
|
||||
|
||||
<template #body-cell-CurrAccDescription="props">
|
||||
<q-td :props="props" class="ol-col-cari">
|
||||
<div class="ol-col-multiline">{{ props.value }}</div>
|
||||
<q-tooltip v-if="props.value">
|
||||
{{ props.value }}
|
||||
</q-tooltip>
|
||||
</q-td>
|
||||
</template>
|
||||
|
||||
<template #body-cell-MusteriTemsilcisi="props">
|
||||
<q-td :props="props" class="ol-col-short">
|
||||
<div class="ol-col-multiline">{{ props.value }}</div>
|
||||
<q-tooltip v-if="props.value">
|
||||
{{ props.value }}
|
||||
</q-tooltip>
|
||||
</q-td>
|
||||
</template>
|
||||
|
||||
<template #body-cell-Piyasa="props">
|
||||
<q-td :props="props" class="ol-col-short">
|
||||
<div class="ol-col-multiline">{{ props.value }}</div>
|
||||
<q-tooltip v-if="props.value">
|
||||
{{ props.value }}
|
||||
</q-tooltip>
|
||||
</q-td>
|
||||
</template>
|
||||
|
||||
<template #body-cell-Description="props">
|
||||
<q-td :props="props" class="ol-col-desc">
|
||||
<div class="ol-col-multiline">{{ props.value }}</div>
|
||||
<q-tooltip v-if="props.value">
|
||||
{{ props.value }}
|
||||
</q-tooltip>
|
||||
</q-td>
|
||||
</template>
|
||||
|
||||
<template #body-cell-HasUretimUrunu="props">
|
||||
<q-td :props="props" class="text-center">
|
||||
<q-icon
|
||||
:name="props.row.HasUretimUrunu ? 'check_circle' : 'cancel'"
|
||||
:color="props.row.HasUretimUrunu ? 'green' : 'grey-5'"
|
||||
size="18px"
|
||||
/>
|
||||
</q-td>
|
||||
</template>
|
||||
</q-table>
|
||||
|
||||
<q-banner v-if="store.error" class="bg-red text-white q-mt-sm">
|
||||
Hata: {{ store.error }}
|
||||
</q-banner>
|
||||
</q-page>
|
||||
|
||||
<q-page v-else class="q-pa-md flex flex-center">
|
||||
<div class="text-negative text-subtitle1">
|
||||
Bu modüle erişim yetkiniz yok.
|
||||
</div>
|
||||
</q-page>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, onMounted, watch } from 'vue'
|
||||
import { useRouter } from 'vue-router'
|
||||
import { useQuasar } from 'quasar'
|
||||
import { useOrderProductionUpdateStore } from 'src/stores/OrderProductionUpdateStore'
|
||||
import { useAuthStore } from 'src/stores/authStore'
|
||||
import { usePermission } from 'src/composables/usePermission'
|
||||
import api, { extractApiErrorDetail } from 'src/services/api'
|
||||
|
||||
const { canRead } = usePermission()
|
||||
const canReadOrder = canRead('order')
|
||||
|
||||
const router = useRouter()
|
||||
const $q = useQuasar()
|
||||
const store = useOrderProductionUpdateStore()
|
||||
|
||||
let searchTimer = null
|
||||
watch(
|
||||
() => store.filters.search,
|
||||
() => {
|
||||
clearTimeout(searchTimer)
|
||||
searchTimer = setTimeout(() => {
|
||||
store.fetchOrders()
|
||||
}, 400)
|
||||
}
|
||||
)
|
||||
|
||||
const productionOrders = computed(() => store.filteredOrders)
|
||||
|
||||
const totalVisibleUSD = computed(() =>
|
||||
productionOrders.value.reduce((sum, o) => {
|
||||
const v = Number(o.TotalAmountUSD || 0)
|
||||
return sum + (Number.isFinite(v) ? v : 0)
|
||||
}, 0)
|
||||
)
|
||||
|
||||
function clearFilters () {
|
||||
store.filters.search = ''
|
||||
store.filters.CurrAccCode = ''
|
||||
store.filters.OrderDate = ''
|
||||
store.fetchOrders()
|
||||
}
|
||||
|
||||
function formatDate (v) {
|
||||
if (!v) return ''
|
||||
return String(v)
|
||||
}
|
||||
|
||||
function selectOrder (row) {
|
||||
if (!row?.OrderHeaderID) {
|
||||
$q.notify({ type: 'warning', message: 'OrderHeaderID bulunamadı' })
|
||||
return
|
||||
}
|
||||
|
||||
router.push({
|
||||
name: 'orderproductionupdate',
|
||||
params: { orderHeaderID: row.OrderHeaderID }
|
||||
})
|
||||
}
|
||||
|
||||
async function printPDF (row) {
|
||||
try {
|
||||
const auth = useAuthStore()
|
||||
if (!auth?.token) {
|
||||
$q.notify({ type: 'warning', message: 'Oturum bulunamadı' })
|
||||
return
|
||||
}
|
||||
|
||||
const res = await api.get(`/order/pdf/${row.OrderHeaderID}`, {
|
||||
responseType: 'blob'
|
||||
})
|
||||
|
||||
const blob = new Blob([res.data], { type: 'application/pdf' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
window.open(url, '_blank')
|
||||
setTimeout(() => URL.revokeObjectURL(url), 2000)
|
||||
} catch (err) {
|
||||
const status = err?.response?.status
|
||||
const detail = extractApiErrorDetail(err)
|
||||
console.error(`PDF load error [${status}] /order/pdf/${row?.OrderHeaderID}: ${detail}`)
|
||||
$q.notify({ type: 'negative', message: `PDF alınamadı: ${detail}` })
|
||||
}
|
||||
}
|
||||
|
||||
function exportExcel () {
|
||||
const auth = useAuthStore()
|
||||
|
||||
if (!auth?.token) {
|
||||
$q.notify({
|
||||
type: 'negative',
|
||||
message: 'Oturum bulunamadı'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
const params = new URLSearchParams()
|
||||
if (store.filters.search) params.append('search', store.filters.search)
|
||||
|
||||
api.get(`/orders/production-list?${params.toString()}`, {
|
||||
responseType: 'blob'
|
||||
}).then((res) => {
|
||||
const blob = new Blob([res.data], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' })
|
||||
const url = URL.createObjectURL(blob)
|
||||
const a = document.createElement('a')
|
||||
a.href = url
|
||||
a.download = 'uretime_verilecek_siparisler.xlsx'
|
||||
a.click()
|
||||
URL.revokeObjectURL(url)
|
||||
}).catch((err) => {
|
||||
const detail = extractApiErrorDetail(err)
|
||||
$q.notify({ type: 'negative', message: `Excel alınamadı: ${detail}` })
|
||||
})
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
store.fetchOrders()
|
||||
})
|
||||
|
||||
const columns = [
|
||||
{ name: 'open', label: '', field: 'open', align: 'center', sortable: false },
|
||||
{ name: 'OrderNumber', label: 'Sipariş No', field: 'OrderNumber', align: 'left', sortable: true, style: 'min-width:108px;white-space:nowrap', headerStyle: 'min-width:108px;white-space:nowrap' },
|
||||
{ name: 'OrderDate', label: 'Tarih', field: 'OrderDate', align: 'center', sortable: true, style: 'min-width:82px;white-space:nowrap', headerStyle: 'min-width:82px;white-space:nowrap' },
|
||||
{ name: 'CurrAccCode', label: 'Cari Kod', field: 'CurrAccCode', align: 'left', sortable: true, style: 'min-width:82px;white-space:nowrap', headerStyle: 'min-width:82px;white-space:nowrap' },
|
||||
{ name: 'CurrAccDescription', label: 'Cari Adı', field: 'CurrAccDescription', align: 'left', sortable: true, classes: 'ol-col-cari', headerClasses: 'ol-col-cari', style: 'width:160px;max-width:160px', headerStyle: 'width:160px;max-width:160px' },
|
||||
{ name: 'MusteriTemsilcisi', label: 'Temsilci', field: 'MusteriTemsilcisi', align: 'left', sortable: true, classes: 'ol-col-short', headerClasses: 'ol-col-short', style: 'width:88px;max-width:88px', headerStyle: 'width:88px;max-width:88px' },
|
||||
{ name: 'Piyasa', label: 'Piyasa', field: 'Piyasa', align: 'left', sortable: true, classes: 'ol-col-short', headerClasses: 'ol-col-short', style: 'width:72px;max-width:72px', headerStyle: 'width:72px;max-width:72px' },
|
||||
{ name: 'CreditableConfirmedDate', label: 'Onay', field: 'CreditableConfirmedDate', align: 'center', sortable: true, style: 'min-width:86px;white-space:nowrap', headerStyle: 'min-width:86px;white-space:nowrap' },
|
||||
{ name: 'DocCurrencyCode', label: 'PB', field: 'DocCurrencyCode', align: 'center', sortable: true, style: 'min-width:46px;white-space:nowrap', headerStyle: 'min-width:46px;white-space:nowrap' },
|
||||
{
|
||||
name: 'TotalAmount',
|
||||
label: 'Tutar',
|
||||
field: 'TotalAmount',
|
||||
align: 'right',
|
||||
sortable: true,
|
||||
style: 'min-width:120px;white-space:nowrap',
|
||||
headerStyle: 'min-width:120px;white-space:nowrap',
|
||||
format: (val, row) => Number(val || 0).toLocaleString('tr-TR', { minimumFractionDigits: 2 }) + ' ' + row.DocCurrencyCode
|
||||
},
|
||||
{
|
||||
name: 'TotalAmountUSD',
|
||||
label: 'Tutar (USD)',
|
||||
field: 'TotalAmountUSD',
|
||||
align: 'right',
|
||||
sortable: true,
|
||||
style: 'min-width:120px;white-space:nowrap',
|
||||
headerStyle: 'min-width:120px;white-space:nowrap',
|
||||
format: val => Number(val || 0).toLocaleString('tr-TR', { minimumFractionDigits: 2 }) + ' USD'
|
||||
},
|
||||
{ name: 'IsCreditableConfirmed', label: 'Durum', field: 'IsCreditableConfirmed', align: 'center', sortable: true },
|
||||
{ name: 'HasUretimUrunu', label: 'Üretim', field: 'HasUretimUrunu', align: 'left', sortable: true, style: 'min-width:190px;white-space:nowrap', headerStyle: 'min-width:190px;white-space:nowrap' },
|
||||
{ name: 'Description', label: 'Açıklama', field: 'Description', align: 'left', sortable: false, classes: 'ol-col-desc', headerClasses: 'ol-col-desc', style: 'width:160px;max-width:160px', headerStyle: 'width:160px;max-width:160px' }
|
||||
]
|
||||
</script>
|
||||
34
ui/src/stores/OrderProductionItemStore.js
Normal file
34
ui/src/stores/OrderProductionItemStore.js
Normal file
@@ -0,0 +1,34 @@
|
||||
// src/stores/OrderProductionItemStore.js
|
||||
import { defineStore } from 'pinia'
|
||||
import api from 'src/services/api'
|
||||
|
||||
export const useOrderProductionItemStore = defineStore('orderproductionitems', {
|
||||
state: () => ({
|
||||
items: [],
|
||||
loading: false,
|
||||
error: null
|
||||
}),
|
||||
|
||||
actions: {
|
||||
async fetchItems (orderHeaderID) {
|
||||
if (!orderHeaderID) {
|
||||
this.items = []
|
||||
return
|
||||
}
|
||||
|
||||
this.loading = true
|
||||
this.error = null
|
||||
|
||||
try {
|
||||
const res = await api.get(`/orders/production-items/${encodeURIComponent(orderHeaderID)}`)
|
||||
const data = res?.data
|
||||
this.items = Array.isArray(data) ? data : []
|
||||
} catch (err) {
|
||||
this.items = []
|
||||
this.error = err?.response?.data || err?.message || 'Liste alınamadı'
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
166
ui/src/stores/OrderProductionUpdateStore.js
Normal file
166
ui/src/stores/OrderProductionUpdateStore.js
Normal file
@@ -0,0 +1,166 @@
|
||||
// src/stores/OrderProductionUpdateStore.js
|
||||
import { defineStore } from 'pinia'
|
||||
import api from 'src/services/api'
|
||||
|
||||
let lastRequestId = 0
|
||||
|
||||
export const useOrderProductionUpdateStore = defineStore('orderproductionupdate', {
|
||||
state: () => ({
|
||||
orders: [],
|
||||
loading: false,
|
||||
error: null,
|
||||
|
||||
filters: {
|
||||
search: '',
|
||||
CurrAccCode: '',
|
||||
OrderDate: ''
|
||||
}
|
||||
}),
|
||||
|
||||
getters: {
|
||||
filteredOrders (state) {
|
||||
let result = state.orders
|
||||
|
||||
if (state.filters.CurrAccCode) {
|
||||
result = result.filter(o => o.CurrAccCode === state.filters.CurrAccCode)
|
||||
}
|
||||
|
||||
if (state.filters.OrderDate) {
|
||||
result = result.filter(o =>
|
||||
o.OrderDate?.startsWith(state.filters.OrderDate)
|
||||
)
|
||||
}
|
||||
|
||||
return result
|
||||
},
|
||||
|
||||
totalVisibleUSD () {
|
||||
return this.filteredOrders.reduce((sum, o) => {
|
||||
const value = Number(o.TotalAmountUSD || 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
|
||||
}
|
||||
},
|
||||
|
||||
actions: {
|
||||
async fetchOrders () {
|
||||
|
||||
// ==============================
|
||||
// 📌 REQUEST ID
|
||||
// ==============================
|
||||
const rid = ++lastRequestId
|
||||
|
||||
// ==============================
|
||||
// 📌 SEARCH SNAPSHOT
|
||||
// ==============================
|
||||
const raw = this.filters.search ?? ''
|
||||
const trimmed = String(raw).trim()
|
||||
|
||||
// ==============================
|
||||
// 📌 REQUEST LOG
|
||||
// ==============================
|
||||
console.groupCollapsed(
|
||||
`%c[orders-prod] FETCH rid=${rid}`,
|
||||
'color:#1976d2;font-weight:bold'
|
||||
)
|
||||
|
||||
console.log('raw =', JSON.stringify(raw), 'len=', String(raw).length)
|
||||
console.log('trimmed =', JSON.stringify(trimmed), 'len=', trimmed.length)
|
||||
console.log('filters =', JSON.parse(JSON.stringify(this.filters)))
|
||||
console.log('lastRID =', lastRequestId)
|
||||
|
||||
console.groupEnd()
|
||||
|
||||
this.loading = true
|
||||
this.error = null
|
||||
|
||||
try {
|
||||
|
||||
// ==============================
|
||||
// 📌 PARAMS
|
||||
// ==============================
|
||||
const params = {}
|
||||
if (trimmed) params.search = trimmed
|
||||
|
||||
// ==============================
|
||||
// 📌 API CALL
|
||||
// ==============================
|
||||
const res = await api.get('/orders/production-list', { params })
|
||||
|
||||
// ==============================
|
||||
// 📌 STALE CHECK
|
||||
// ==============================
|
||||
if (rid !== lastRequestId) {
|
||||
console.warn(
|
||||
`[orders-prod] IGNORE stale response rid=${rid} last=${lastRequestId}`
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
// ==============================
|
||||
// 📌 DATA
|
||||
// ==============================
|
||||
const data = res?.data
|
||||
this.orders = Array.isArray(data) ? data : []
|
||||
|
||||
// ==============================
|
||||
// 📌 RESPONSE LOG
|
||||
// ==============================
|
||||
console.groupCollapsed(
|
||||
`%c[orders-prod] RESPONSE rid=${rid} count=${this.orders.length}`,
|
||||
'color:#2e7d32;font-weight:bold'
|
||||
)
|
||||
|
||||
console.log('status =', res?.status)
|
||||
|
||||
console.log(
|
||||
'sample =',
|
||||
this.orders.slice(0, 5).map(o => ({
|
||||
id: o.OrderHeaderID,
|
||||
no: o.OrderNumber,
|
||||
code: o.CurrAccCode,
|
||||
name: o.CurrAccDescription
|
||||
}))
|
||||
)
|
||||
|
||||
console.groupEnd()
|
||||
|
||||
} catch (err) {
|
||||
|
||||
if (rid !== lastRequestId) return
|
||||
|
||||
console.error(
|
||||
'[orders-prod] FETCH FAILED',
|
||||
err?.response?.status,
|
||||
err?.response?.data || err
|
||||
)
|
||||
|
||||
this.orders = []
|
||||
|
||||
this.error =
|
||||
err?.response?.data ||
|
||||
err?.message ||
|
||||
'Sipariş listesi alınamadı'
|
||||
|
||||
} finally {
|
||||
|
||||
if (rid === lastRequestId) {
|
||||
this.loading = false
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user