diff --git a/svc/models/orderproductionitem.go b/svc/models/orderproductionitem.go new file mode 100644 index 0000000..328de1c --- /dev/null +++ b/svc/models/orderproductionitem.go @@ -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"` +} diff --git a/svc/queries/orderproduction_items.go b/svc/queries/orderproduction_items.go new file mode 100644 index 0000000..74aa58f --- /dev/null +++ b/svc/queries/orderproduction_items.go @@ -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) +} diff --git a/svc/queries/orderproductionlist.go b/svc/queries/orderproductionlist.go new file mode 100644 index 0000000..2bb210e --- /dev/null +++ b/svc/queries/orderproductionlist.go @@ -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) +} diff --git a/svc/routes/orderproductionitems.go b/svc/routes/orderproductionitems.go new file mode 100644 index 0000000..ac195cd --- /dev/null +++ b/svc/routes/orderproductionitems.go @@ -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) + } + }) +} diff --git a/svc/routes/orderproductionlist.go b/svc/routes/orderproductionlist.go new file mode 100644 index 0000000..f34ad91 --- /dev/null +++ b/svc/routes/orderproductionlist.go @@ -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) + } + }) +} diff --git a/ui/quasar.config.js.temporary.compiled.1771513237059.mjs b/ui/quasar.config.js.temporary.compiled.1771513237059.mjs new file mode 100644 index 0000000..4a501bd --- /dev/null +++ b/ui/quasar.config.js.temporary.compiled.1771513237059.mjs @@ -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 +}; diff --git a/ui/src/pages/OrderProductionUpdate.vue b/ui/src/pages/OrderProductionUpdate.vue new file mode 100644 index 0000000..3ac51fd --- /dev/null +++ b/ui/src/pages/OrderProductionUpdate.vue @@ -0,0 +1,57 @@ + + + Üretime Verilen Ürünler + + OrderHeaderID: {{ orderHeaderID || '-' }} + + + + + + Hata: {{ store.error }} + + + + + diff --git a/ui/src/pages/OrderProductionUpdateList.vue b/ui/src/pages/OrderProductionUpdateList.vue new file mode 100644 index 0000000..8cb2bbe --- /dev/null +++ b/ui/src/pages/OrderProductionUpdateList.vue @@ -0,0 +1,357 @@ + + + + + + + + + + + + + + + + + Tüm filtreleri temizle + + + + + + + + + + Toplam USD: + + {{ totalVisibleUSD.toLocaleString('tr-TR', { minimumFractionDigits: 2, maximumFractionDigits: 2 }) }} + + + + + + + + + + + Siparişi Aç + + + + + + + + Siparişi PDF olarak aç + + + + + {{ props.row.IsCreditableConfirmed ? 'Onaylı' : 'Onaysız' }} + + + + + + + + {{ formatDate(props.row.OrderDate) }} + + + + + + {{ formatDate(props.row.CreditableConfirmedDate) }} + + + + + + + {{ props.value }} + + {{ props.value }} + + + + + + + {{ props.value }} + + {{ props.value }} + + + + + + + {{ props.value }} + + {{ props.value }} + + + + + + + {{ props.value }} + + {{ props.value }} + + + + + + + + + + + + + Hata: {{ store.error }} + + + + + + Bu modüle erişim yetkiniz yok. + + + + + diff --git a/ui/src/stores/OrderProductionItemStore.js b/ui/src/stores/OrderProductionItemStore.js new file mode 100644 index 0000000..3a96083 --- /dev/null +++ b/ui/src/stores/OrderProductionItemStore.js @@ -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 + } + } + } +}) diff --git a/ui/src/stores/OrderProductionUpdateStore.js b/ui/src/stores/OrderProductionUpdateStore.js new file mode 100644 index 0000000..928eb8a --- /dev/null +++ b/ui/src/stores/OrderProductionUpdateStore.js @@ -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 + } + + } + } + } +})