diff --git a/svc/routes/order_list_pdf.go b/svc/routes/order_list_pdf.go
index de45dd1..4e3e4b4 100644
--- a/svc/routes/order_list_pdf.go
+++ b/svc/routes/order_list_pdf.go
@@ -6,6 +6,8 @@ import (
"database/sql"
"fmt"
"net/http"
+ "sort"
+ "strconv"
"strings"
"time"
@@ -29,11 +31,21 @@ type orderListPDFRow struct {
Description string
}
+type pdfColumn struct {
+ Header string
+ Width float64
+ Align string
+ Wrap bool
+ MaxLines int
+}
+
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"))
+ sortBy := strings.TrimSpace(r.URL.Query().Get("sort_by"))
+ descending := parseBool(r.URL.Query().Get("descending"))
rows, err := queries.GetOrderListExcel(db, search, currAcc, orderDate)
if err != nil {
@@ -58,28 +70,14 @@ func OrderListPDFRoute(db *sql.DB) http.Handler {
)
if err := rows.Scan(
- &id,
- &no,
- &date,
- &termin,
- &code,
- &name,
- &rep,
- &piyasa,
- &cur,
- &total,
- &totalUSD,
- &packedAmount,
- &packedUSD,
- &packedRatePct,
- &hasUretim,
- &desc,
- &usdRate,
+ &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
}
-
+ _ = id
_ = packedAmount
_ = usdRate
@@ -101,15 +99,17 @@ func OrderListPDFRoute(db *sql.DB) http.Handler {
})
}
+ applyOrderListSort(out, sortBy, descending)
+
pdf := gofpdf.New("L", "mm", "A4", "")
pdf.SetMargins(8, 8, 8)
- pdf.SetAutoPageBreak(true, 10)
+ pdf.SetAutoPageBreak(false, 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)
+ drawOrderListPDF(pdf, out, search, currAcc, orderDate, sortBy, descending)
if err := pdf.Error(); err != nil {
http.Error(w, "pdf render error: "+err.Error(), http.StatusInternalServerError)
return
@@ -127,68 +127,234 @@ func OrderListPDFRoute(db *sql.DB) http.Handler {
})
}
-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",
+func drawOrderListPDF(
+ pdf *gofpdf.Fpdf,
+ rows []orderListPDFRow,
+ search, currAcc, orderDate, sortBy string,
+ desc bool,
+) {
+ cols := []pdfColumn{
+ {Header: "Siparis No", Width: 20, Align: "L", Wrap: false, MaxLines: 1},
+ {Header: "Tarih", Width: 12, Align: "C", Wrap: false, MaxLines: 1},
+ {Header: "Termin", Width: 12, Align: "C", Wrap: false, MaxLines: 1},
+ {Header: "Cari Kod", Width: 15, Align: "L", Wrap: true, MaxLines: 2},
+ {Header: "Cari Adi", Width: 27, Align: "L", Wrap: true, MaxLines: 3},
+ {Header: "Temsilci", Width: 18, Align: "L", Wrap: true, MaxLines: 2},
+ {Header: "Piyasa", Width: 13, Align: "L", Wrap: true, MaxLines: 2},
+ {Header: "PB", Width: 8, Align: "C", Wrap: false, MaxLines: 1},
+ {Header: "Tutar", Width: 15, Align: "R", Wrap: false, MaxLines: 1},
+ {Header: "USD", Width: 15, Align: "R", Wrap: false, MaxLines: 1},
+ {Header: "Paket USD", Width: 15, Align: "R", Wrap: false, MaxLines: 1},
+ {Header: "%", Width: 8, Align: "R", Wrap: false, MaxLines: 1},
+ {Header: "Uretim", Width: 24, Align: "L", Wrap: true, MaxLines: 3},
+ {Header: "Aciklama", Width: 52, Align: "L", Wrap: true, MaxLines: 3},
}
- 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, "")
+ pageW, pageH := pdf.GetPageSize()
+ marginL, marginT, marginR := 8.0, 8.0, 8.0
+ bottomLimit := pageH - 10.0
+ lineH := 3.8
+ cellPadX := 1.1
+ cellPadY := 0.6
- 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)
+ drawHeader := func() {
+ pdf.AddPage()
+ pdf.SetFont("dejavu", "B", 12)
+ pdf.CellFormat(0, 7, "Siparis Listesi", "", 1, "L", false, 0, "")
- 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.SetFont("dejavu", "", 8)
+ sortText := "TotalAmountUSD DESC (varsayilan)"
+ if sortBy != "" {
+ dir := "ASC"
+ if desc {
+ dir = "DESC"
+ }
+ sortText = fmt.Sprintf("%s %s", sortBy, dir)
+ }
+ filterLine := fmt.Sprintf(
+ "Filtreler -> Arama: %s | Cari: %s | Siparis Tarihi: %s | Siralama: %s | Olusturma: %s",
+ emptyDash(search),
+ emptyDash(currAcc),
+ emptyDash(orderDate),
+ sortText,
+ 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 _, c := range cols {
+ pdf.CellFormat(c.Width, 6, c.Header, "1", 0, "C", true, 0, "")
+ }
+ pdf.Ln(-1)
+ pdf.SetFont("dejavu", "", 7)
}
- pdf.Ln(-1)
- pdf.SetFont("dejavu", "", 7)
- for _, row := range rows {
+ buildCells := func(row orderListPDFRow) []string {
uretim := ""
if row.HasUretimUrunu {
- uretim = "VAR"
+ uretim = "Uretime Verilecek Urunu Var"
}
-
- cells := []string{
+ return []string{
row.OrderNumber,
row.OrderDate,
row.TerminTarihi,
row.CurrAccCode,
- shorten(row.CurrAccDescription, 24),
- shorten(row.MusteriTemsilcisi, 12),
- shorten(row.Piyasa, 10),
+ row.CurrAccDescription,
+ row.MusteriTemsilcisi,
+ row.Piyasa,
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),
+ row.Description,
+ }
+ }
+
+ calcLineCount := func(col pdfColumn, text string) int {
+ if !col.Wrap {
+ return 1
+ }
+ lines := pdf.SplitLines([]byte(strings.TrimSpace(text)), col.Width-(cellPadX*2))
+ n := len(lines)
+ if n < 1 {
+ n = 1
+ }
+ if col.MaxLines > 0 && n > col.MaxLines {
+ n = col.MaxLines
+ }
+ return n
+ }
+
+ drawWrappedCell := func(x, y, w, h float64, text, align string, maxLines int) {
+ pdf.Rect(x, y, w, h, "D")
+ lines := pdf.SplitLines([]byte(strings.TrimSpace(text)), w-(cellPadX*2))
+ if len(lines) == 0 {
+ lines = [][]byte{[]byte("")}
+ }
+ if maxLines > 0 && len(lines) > maxLines {
+ lines = lines[:maxLines]
+ }
+ ty := y + cellPadY + 2.8
+ for _, ln := range lines {
+ pdf.SetXY(x+cellPadX, ty-2.8)
+ pdf.CellFormat(w-(cellPadX*2), 3.8, string(ln), "", 0, align, false, 0, "")
+ ty += 3.8
+ }
+ }
+
+ drawHeader()
+
+ for _, row := range rows {
+ cells := buildCells(row)
+ maxLines := 1
+ for i, c := range cols {
+ n := calcLineCount(c, cells[i])
+ if n > maxLines {
+ maxLines = n
+ }
+ }
+ rowH := (float64(maxLines) * lineH) + (cellPadY * 2)
+
+ if pdf.GetY()+rowH > bottomLimit {
+ drawHeader()
}
- for i, v := range cells {
- align := "L"
- if i >= 8 && i <= 11 {
- align = "R"
+ x := marginL
+ y := pdf.GetY()
+ for i, c := range cols {
+ if c.Wrap {
+ drawWrappedCell(x, y, c.Width, rowH, cells[i], c.Align, c.MaxLines)
+ } else {
+ pdf.SetXY(x, y)
+ pdf.CellFormat(c.Width, rowH, cells[i], "1", 0, c.Align, false, 0, "")
}
- if i == 1 || i == 2 || i == 7 || i == 12 {
- align = "C"
- }
- pdf.CellFormat(widths[i], 5, v, "1", 0, align, false, 0, "")
+ x += c.Width
}
- pdf.Ln(-1)
+ pdf.SetXY(marginL, y+rowH)
}
+
+ _ = pageW
+ _ = marginT
+ _ = marginR
+}
+
+func applyOrderListSort(rows []orderListPDFRow, sortBy string, desc bool) {
+ if len(rows) <= 1 {
+ return
+ }
+
+ field := strings.TrimSpace(sortBy)
+ if field == "" {
+ field = "TotalAmountUSD"
+ desc = true
+ }
+
+ lessText := func(a, b string) bool {
+ aa := strings.ToLower(strings.TrimSpace(a))
+ bb := strings.ToLower(strings.TrimSpace(b))
+ if desc {
+ return aa > bb
+ }
+ return aa < bb
+ }
+ lessNum := func(a, b float64) bool {
+ if desc {
+ return a > b
+ }
+ return a < b
+ }
+ lessBool := func(a, b bool) bool {
+ av, bv := 0, 0
+ if a {
+ av = 1
+ }
+ if b {
+ bv = 1
+ }
+ if desc {
+ return av > bv
+ }
+ return av < bv
+ }
+
+ sort.SliceStable(rows, func(i, j int) bool {
+ a := rows[i]
+ b := rows[j]
+ switch field {
+ case "OrderNumber":
+ return lessText(a.OrderNumber, b.OrderNumber)
+ case "OrderDate":
+ return lessText(a.OrderDate, b.OrderDate)
+ case "TerminTarihi":
+ return lessText(a.TerminTarihi, b.TerminTarihi)
+ case "CurrAccCode":
+ return lessText(a.CurrAccCode, b.CurrAccCode)
+ case "CurrAccDescription":
+ return lessText(a.CurrAccDescription, b.CurrAccDescription)
+ case "MusteriTemsilcisi":
+ return lessText(a.MusteriTemsilcisi, b.MusteriTemsilcisi)
+ case "Piyasa":
+ return lessText(a.Piyasa, b.Piyasa)
+ case "DocCurrencyCode":
+ return lessText(a.DocCurrencyCode, b.DocCurrencyCode)
+ case "TotalAmount":
+ return lessNum(a.TotalAmount, b.TotalAmount)
+ case "PackedUSD":
+ return lessNum(a.PackedUSD, b.PackedUSD)
+ case "PackedRatePct":
+ return lessNum(a.PackedRatePct, b.PackedRatePct)
+ case "HasUretimUrunu":
+ return lessBool(a.HasUretimUrunu, b.HasUretimUrunu)
+ case "Description":
+ return lessText(a.Description, b.Description)
+ default:
+ return lessNum(a.TotalAmountUSD, b.TotalAmountUSD)
+ }
+ })
}
func emptyDash(v string) string {
@@ -198,14 +364,15 @@ func emptyDash(v string) string {
return v
}
-func shorten(v string, max int) string {
- s := strings.TrimSpace(v)
- if len([]rune(s)) <= max {
- return s
+func parseBool(v string) bool {
+ b, err := strconv.ParseBool(strings.TrimSpace(v))
+ if err == nil {
+ return b
}
- r := []rune(s)
- if max <= 1 {
- return string(r[:1])
+ switch strings.TrimSpace(strings.ToLower(v)) {
+ case "1", "yes", "on":
+ return true
+ default:
+ return false
}
- return string(r[:max-1]) + "…"
}
diff --git a/ui/src/pages/OrderList.vue b/ui/src/pages/OrderList.vue
index 584bd11..de45796 100644
--- a/ui/src/pages/OrderList.vue
+++ b/ui/src/pages/OrderList.vue
@@ -109,6 +109,7 @@
:loading="store.loading"
no-data-label="Sipariş bulunamadı"
:rows-per-page-options="[0]"
+ v-model:pagination="pagination"
hide-bottom
>
@@ -252,7 +253,7 @@