Merge remote-tracking branch 'origin/master'

This commit is contained in:
M_Kececi
2026-03-05 10:45:12 +03:00
parent 5564dbfbd3
commit 4a6ca5a4d2
9 changed files with 334 additions and 99 deletions

View File

@@ -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)},

View File

@@ -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"`

View File

@@ -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

View File

@@ -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,

View File

@@ -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())
})

View File

@@ -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]) + "…"
}

View File

@@ -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 {