diff --git a/svc/main.go b/svc/main.go index 558db79..3c4d306 100644 --- a/svc/main.go +++ b/svc/main.go @@ -508,6 +508,7 @@ func InitRoutes(pgDB *sql.DB, mssql *sql.DB, ml *mailer.GraphMailer) *mux.Router {"/api/orders/close-ready", "GET", "update", routes.OrderCloseReadyListRoute(mssql)}, {"/api/orders/bulk-close", "POST", "update", routes.OrderBulkCloseRoute(mssql)}, {"/api/orders/export", "GET", "export", routes.OrderListExcelRoute(mssql)}, + {"/api/orders/export-pdf", "GET", "export", routes.OrderListPDFRoute(mssql)}, {"/api/order/check/{id}", "GET", "view", routes.OrderExistsHandler(mssql)}, {"/api/order/validate", "POST", "insert", routes.ValidateOrderHandler(mssql)}, {"/api/order/pdf/{id}", "GET", "export", routes.OrderPDFHandler(mssql)}, diff --git a/svc/models/orderlist.go b/svc/models/orderlist.go index 7e19fd5..6ded8da 100644 --- a/svc/models/orderlist.go +++ b/svc/models/orderlist.go @@ -9,6 +9,7 @@ type OrderList struct { OrderHeaderID string `json:"OrderHeaderID"` OrderNumber string `json:"OrderNumber"` OrderDate string `json:"OrderDate"` + TerminTarihi string `json:"TerminTarihi"` // 🧾 Cari Bilgileri CurrAccCode string `json:"CurrAccCode"` diff --git a/svc/queries/get_order_list_excel.go b/svc/queries/get_order_list_excel.go index b66d4fa..285d2bb 100644 --- a/svc/queries/get_order_list_excel.go +++ b/svc/queries/get_order_list_excel.go @@ -17,6 +17,7 @@ SELECT CAST(h.OrderHeaderID AS NVARCHAR(50)) AS OrderHeaderID, ISNULL(h.OrderNumber,'') AS OrderNumber, CONVERT(varchar,h.OrderDate,23) AS OrderDate, + CONVERT(varchar,h.AverageDueDate,23) AS TerminTarihi, ISNULL(h.CurrAccCode,'') AS CurrAccCode, ISNULL(ca.CurrAccDescription,'') AS CurrAccDescription, @@ -73,6 +74,17 @@ SELECT ELSE 0 END AS PackedRatePct, + CASE + WHEN EXISTS ( + SELECT 1 + FROM dbo.trOrderLine l2 + WHERE l2.OrderHeaderID = h.OrderHeaderID + AND ISNULL(l2.ItemCode,'') LIKE 'U%%' + ) + THEN CAST(1 AS bit) + ELSE CAST(0 AS bit) + END AS HasUretimUrunu, + ISNULL(h.Description,'') AS Description, usd.Rate AS ExchangeRateUSD diff --git a/svc/queries/orderlist.go b/svc/queries/orderlist.go index b9af840..b6e27fb 100644 --- a/svc/queries/orderlist.go +++ b/svc/queries/orderlist.go @@ -57,6 +57,7 @@ SELECT CAST(h.OrderHeaderID AS NVARCHAR(50)) AS OrderHeaderID, ISNULL(h.OrderNumber, '') AS OrderNumber, CONVERT(varchar, h.OrderDate, 23) AS OrderDate, + CONVERT(varchar, h.AverageDueDate, 23) AS TerminTarihi, ISNULL(h.CurrAccCode, '') AS CurrAccCode, ISNULL(ca.CurrAccDescription, '') AS CurrAccDescription, diff --git a/svc/routes/order_list_excel.go b/svc/routes/order_list_excel.go index e27abdf..99007c7 100644 --- a/svc/routes/order_list_excel.go +++ b/svc/routes/order_list_excel.go @@ -12,41 +12,29 @@ import ( func OrderListExcelRoute(db *sql.DB) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Cache-Control", "no-store") - // ====================== - // PARAMS - // ====================== search := r.URL.Query().Get("search") currAcc := r.URL.Query().Get("CurrAccCode") orderDate := r.URL.Query().Get("OrderDate") - // ====================== - // QUERY - // ====================== rows, err := queries.GetOrderListExcel(db, search, currAcc, orderDate) if err != nil { - http.Error(w, err.Error(), 500) + http.Error(w, err.Error(), http.StatusInternalServerError) return } defer rows.Close() - // ====================== - // EXCEL INIT - // ====================== f := excelize.NewFile() sheet := "Orders" f.SetSheetName("Sheet1", sheet) - // ====================== - // HEADERS - // ====================== headers := []string{ - "Sipariş No", + "Siparis No", "Tarih", + "Termin Tarihi", "Cari Kod", - "Cari Adı", + "Cari Adi", "Temsilci", "Piyasa", "PB", @@ -55,8 +43,9 @@ func OrderListExcelRoute(db *sql.DB) http.Handler { "Paketlenen Tutar", "Paketlenen (USD)", "Paketlenme (%)", + "Uretim", "USD Kur", - "Açıklama", + "Aciklama", } for i, h := range headers { @@ -64,58 +53,55 @@ func OrderListExcelRoute(db *sql.DB) http.Handler { f.SetCellValue(sheet, cell, h) } - // ====================== - // ROWS - // ====================== row := 2 - for rows.Next() { - - // 🔴 15 KOLON = 15 DEĞİŞKEN var ( - id, no, date, code, name string - rep, piyasa, cur string + id, no, date, termin, code, name string + rep, piyasa, cur string total float64 totalUSD float64 packedAmount float64 packedUSD float64 packedRatePct float64 + hasUretim bool + desc string usdRate float64 - - desc string ) - // 🔴 SELECT SIRASIYLA BİREBİR err := rows.Scan( &id, // 1 &no, // 2 &date, // 3 - &code, // 4 - &name, // 5 - &rep, // 6 - &piyasa, // 7 - &cur, // 8 - &total, // 9 - &totalUSD, // 10 - &packedAmount, // 11 - &packedUSD, // 12 - &packedRatePct, // 13 - &desc, // 14 - &usdRate, // 15 + &termin, // 4 + &code, // 5 + &name, // 6 + &rep, // 7 + &piyasa, // 8 + &cur, // 9 + &total, // 10 + &totalUSD, // 11 + &packedAmount, // 12 + &packedUSD, // 13 + &packedRatePct, // 14 + &hasUretim, // 15 + &desc, // 16 + &usdRate, // 17 ) - if err != nil { - http.Error(w, "Scan error: "+err.Error(), 500) + http.Error(w, "Scan error: "+err.Error(), http.StatusInternalServerError) return } - // ====================== - // WRITE ROW - // ====================== + uretim := "" + if hasUretim { + uretim = "VAR" + } + f.SetSheetRow(sheet, fmt.Sprintf("A%d", row), &[]any{ no, date, + termin, code, name, rep, @@ -126,6 +112,7 @@ func OrderListExcelRoute(db *sql.DB) http.Handler { packedAmount, packedUSD, packedRatePct, + uretim, usdRate, desc, }) @@ -133,38 +120,17 @@ func OrderListExcelRoute(db *sql.DB) http.Handler { row++ } - // ====================== - // BUFFER WRITE - // ====================== buf, err := f.WriteToBuffer() if err != nil { - http.Error(w, err.Error(), 500) + http.Error(w, err.Error(), http.StatusInternalServerError) return } - filename := fmt.Sprintf( - "siparis_listesi_%s.xlsx", - time.Now().Format("20060102_150405"), - ) - - // ====================== - // RESPONSE - // ====================== - w.Header().Set( - "Content-Type", - "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", - ) - - w.Header().Set( - "Content-Disposition", - "attachment; filename=\""+filename+"\"", - ) - - w.Header().Set( - "Content-Length", - fmt.Sprint(len(buf.Bytes())), - ) + filename := fmt.Sprintf("siparis_listesi_%s.xlsx", time.Now().Format("20060102_150405")) + w.Header().Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") + 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()) }) diff --git a/svc/routes/order_list_pdf.go b/svc/routes/order_list_pdf.go new file mode 100644 index 0000000..de45dd1 --- /dev/null +++ b/svc/routes/order_list_pdf.go @@ -0,0 +1,211 @@ +package routes + +import ( + "bssapp-backend/queries" + "bytes" + "database/sql" + "fmt" + "net/http" + "strings" + "time" + + "github.com/jung-kurt/gofpdf" +) + +type orderListPDFRow struct { + OrderNumber string + OrderDate string + TerminTarihi string + CurrAccCode string + CurrAccDescription string + MusteriTemsilcisi string + Piyasa string + DocCurrencyCode string + TotalAmount float64 + TotalAmountUSD float64 + PackedUSD float64 + PackedRatePct float64 + HasUretimUrunu bool + Description string +} + +func OrderListPDFRoute(db *sql.DB) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + search := strings.TrimSpace(r.URL.Query().Get("search")) + currAcc := strings.TrimSpace(r.URL.Query().Get("CurrAccCode")) + orderDate := strings.TrimSpace(r.URL.Query().Get("OrderDate")) + + rows, err := queries.GetOrderListExcel(db, search, currAcc, orderDate) + if err != nil { + http.Error(w, "db error: "+err.Error(), http.StatusInternalServerError) + return + } + defer rows.Close() + + out := make([]orderListPDFRow, 0, 256) + for rows.Next() { + var ( + id, no, date, termin, code, name string + rep, piyasa, cur string + total float64 + totalUSD float64 + packedAmount float64 + packedUSD float64 + packedRatePct float64 + hasUretim bool + desc string + usdRate float64 + ) + + if err := rows.Scan( + &id, + &no, + &date, + &termin, + &code, + &name, + &rep, + &piyasa, + &cur, + &total, + &totalUSD, + &packedAmount, + &packedUSD, + &packedRatePct, + &hasUretim, + &desc, + &usdRate, + ); err != nil { + http.Error(w, "scan error: "+err.Error(), http.StatusInternalServerError) + return + } + + _ = packedAmount + _ = usdRate + + out = append(out, orderListPDFRow{ + OrderNumber: no, + OrderDate: date, + TerminTarihi: termin, + CurrAccCode: code, + CurrAccDescription: name, + MusteriTemsilcisi: rep, + Piyasa: piyasa, + DocCurrencyCode: cur, + TotalAmount: total, + TotalAmountUSD: totalUSD, + PackedUSD: packedUSD, + PackedRatePct: packedRatePct, + HasUretimUrunu: hasUretim, + Description: desc, + }) + } + + pdf := gofpdf.New("L", "mm", "A4", "") + pdf.SetMargins(8, 8, 8) + pdf.SetAutoPageBreak(true, 10) + if err := registerDejavuFonts(pdf, "dejavu"); err != nil { + http.Error(w, "pdf font error: "+err.Error(), http.StatusInternalServerError) + return + } + + drawOrderListPDF(pdf, out, search, currAcc, orderDate) + if err := pdf.Error(); err != nil { + http.Error(w, "pdf render error: "+err.Error(), http.StatusInternalServerError) + return + } + + var buf bytes.Buffer + if err := pdf.Output(&buf); err != nil { + http.Error(w, "pdf output error: "+err.Error(), http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/pdf") + w.Header().Set("Content-Disposition", "inline; filename=\"siparis-listesi.pdf\"") + _, _ = w.Write(buf.Bytes()) + }) +} + +func drawOrderListPDF(pdf *gofpdf.Fpdf, rows []orderListPDFRow, search, currAcc, orderDate string) { + headers := []string{ + "Siparis No", "Tarih", "Termin", "Cari Kod", "Cari Adi", "Temsilci", "Piyasa", + "PB", "Tutar", "USD", "Paket USD", "%", "Uretim", "Aciklama", + } + widths := []float64{24, 14, 14, 18, 34, 16, 12, 8, 18, 18, 18, 10, 14, 43} + + pdf.AddPage() + pdf.SetFont("dejavu", "B", 12) + pdf.CellFormat(0, 7, "Siparis Listesi", "", 1, "L", false, 0, "") + + pdf.SetFont("dejavu", "", 8) + filterLine := fmt.Sprintf( + "Filtreler -> Arama: %s | Cari: %s | Siparis Tarihi: %s | Uretim: %s", + emptyDash(search), emptyDash(currAcc), emptyDash(orderDate), time.Now().Format("2006-01-02 15:04"), + ) + pdf.CellFormat(0, 5, filterLine, "", 1, "L", false, 0, "") + pdf.Ln(1) + + pdf.SetFont("dejavu", "B", 8) + pdf.SetFillColor(240, 240, 240) + for i, h := range headers { + pdf.CellFormat(widths[i], 6, h, "1", 0, "C", true, 0, "") + } + pdf.Ln(-1) + + pdf.SetFont("dejavu", "", 7) + for _, row := range rows { + uretim := "" + if row.HasUretimUrunu { + uretim = "VAR" + } + + cells := []string{ + row.OrderNumber, + row.OrderDate, + row.TerminTarihi, + row.CurrAccCode, + shorten(row.CurrAccDescription, 24), + shorten(row.MusteriTemsilcisi, 12), + shorten(row.Piyasa, 10), + row.DocCurrencyCode, + fmt.Sprintf("%.2f", row.TotalAmount), + fmt.Sprintf("%.2f", row.TotalAmountUSD), + fmt.Sprintf("%.2f", row.PackedUSD), + fmt.Sprintf("%.2f", row.PackedRatePct), + uretim, + shorten(row.Description, 34), + } + + for i, v := range cells { + align := "L" + if i >= 8 && i <= 11 { + align = "R" + } + if i == 1 || i == 2 || i == 7 || i == 12 { + align = "C" + } + pdf.CellFormat(widths[i], 5, v, "1", 0, align, false, 0, "") + } + pdf.Ln(-1) + } +} + +func emptyDash(v string) string { + if strings.TrimSpace(v) == "" { + return "-" + } + return v +} + +func shorten(v string, max int) string { + s := strings.TrimSpace(v) + if len([]rune(s)) <= max { + return s + } + r := []rune(s) + if max <= 1 { + return string(r[:1]) + } + return string(r[:max-1]) + "…" +} diff --git a/svc/routes/orderlist.go b/svc/routes/orderlist.go index bf74494..1c1dd21 100644 --- a/svc/routes/orderlist.go +++ b/svc/routes/orderlist.go @@ -68,27 +68,28 @@ func OrderListRoute(mssql *sql.DB) http.Handler { &o.OrderHeaderID, // 1 &o.OrderNumber, // 2 &o.OrderDate, // 3 + &o.TerminTarihi, // 4 - &o.CurrAccCode, // 4 - &o.CurrAccDescription, // 5 + &o.CurrAccCode, // 5 + &o.CurrAccDescription, // 6 - &o.MusteriTemsilcisi, // 6 - &o.Piyasa, // 7 + &o.MusteriTemsilcisi, // 7 + &o.Piyasa, // 8 - &o.CreditableConfirmedDate, // 8 - &o.DocCurrencyCode, // 9 + &o.CreditableConfirmedDate, // 9 + &o.DocCurrencyCode, // 10 - &o.TotalAmount, // 10 - &o.TotalAmountUSD, // 11 - &o.PackedAmount, // 12 - &o.PackedUSD, // 13 - &o.PackedRatePct, // 14 + &o.TotalAmount, // 11 + &o.TotalAmountUSD, // 12 + &o.PackedAmount, // 13 + &o.PackedUSD, // 14 + &o.PackedRatePct, // 15 - &o.IsCreditableConfirmed, // 15 - &o.HasUretimUrunu, // 16 - &o.Description, // 17 + &o.IsCreditableConfirmed, // 16 + &o.HasUretimUrunu, // 17 + &o.Description, // 18 - &o.ExchangeRateUSD, // 18 + &o.ExchangeRateUSD, // 19 ) if err != nil { diff --git a/ui/quasar.config.js.temporary.compiled.1772692887548.mjs b/ui/quasar.config.js.temporary.compiled.1772696562168.mjs similarity index 100% rename from ui/quasar.config.js.temporary.compiled.1772692887548.mjs rename to ui/quasar.config.js.temporary.compiled.1772696562168.mjs diff --git a/ui/src/pages/OrderList.vue b/ui/src/pages/OrderList.vue index 21ab9b9..584bd11 100644 --- a/ui/src/pages/OrderList.vue +++ b/ui/src/pages/OrderList.vue @@ -62,6 +62,15 @@ :disable="store.loading || store.filteredOrders.length === 0" @click="exportExcel" /> + +
@@ -102,8 +111,21 @@ :rows-per-page-options="[0]" hide-bottom > -