Merge remote-tracking branch 'origin/master'

This commit is contained in:
M_Kececi
2026-03-05 11:21:56 +03:00
parent dc63a59249
commit 9097b5af2d
2 changed files with 243 additions and 68 deletions

View File

@@ -6,6 +6,8 @@ import (
"database/sql" "database/sql"
"fmt" "fmt"
"net/http" "net/http"
"sort"
"strconv"
"strings" "strings"
"time" "time"
@@ -29,11 +31,21 @@ type orderListPDFRow struct {
Description string Description string
} }
type pdfColumn struct {
Header string
Width float64
Align string
Wrap bool
MaxLines int
}
func OrderListPDFRoute(db *sql.DB) http.Handler { func OrderListPDFRoute(db *sql.DB) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
search := strings.TrimSpace(r.URL.Query().Get("search")) search := strings.TrimSpace(r.URL.Query().Get("search"))
currAcc := strings.TrimSpace(r.URL.Query().Get("CurrAccCode")) currAcc := strings.TrimSpace(r.URL.Query().Get("CurrAccCode"))
orderDate := strings.TrimSpace(r.URL.Query().Get("OrderDate")) 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) rows, err := queries.GetOrderListExcel(db, search, currAcc, orderDate)
if err != nil { if err != nil {
@@ -58,28 +70,14 @@ func OrderListPDFRoute(db *sql.DB) http.Handler {
) )
if err := rows.Scan( if err := rows.Scan(
&id, &id, &no, &date, &termin, &code, &name, &rep, &piyasa, &cur,
&no, &total, &totalUSD, &packedAmount, &packedUSD, &packedRatePct,
&date, &hasUretim, &desc, &usdRate,
&termin,
&code,
&name,
&rep,
&piyasa,
&cur,
&total,
&totalUSD,
&packedAmount,
&packedUSD,
&packedRatePct,
&hasUretim,
&desc,
&usdRate,
); err != nil { ); err != nil {
http.Error(w, "scan error: "+err.Error(), http.StatusInternalServerError) http.Error(w, "scan error: "+err.Error(), http.StatusInternalServerError)
return return
} }
_ = id
_ = packedAmount _ = packedAmount
_ = usdRate _ = usdRate
@@ -101,15 +99,17 @@ func OrderListPDFRoute(db *sql.DB) http.Handler {
}) })
} }
applyOrderListSort(out, sortBy, descending)
pdf := gofpdf.New("L", "mm", "A4", "") pdf := gofpdf.New("L", "mm", "A4", "")
pdf.SetMargins(8, 8, 8) pdf.SetMargins(8, 8, 8)
pdf.SetAutoPageBreak(true, 10) pdf.SetAutoPageBreak(false, 10)
if err := registerDejavuFonts(pdf, "dejavu"); err != nil { if err := registerDejavuFonts(pdf, "dejavu"); err != nil {
http.Error(w, "pdf font error: "+err.Error(), http.StatusInternalServerError) http.Error(w, "pdf font error: "+err.Error(), http.StatusInternalServerError)
return return
} }
drawOrderListPDF(pdf, out, search, currAcc, orderDate) drawOrderListPDF(pdf, out, search, currAcc, orderDate, sortBy, descending)
if err := pdf.Error(); err != nil { if err := pdf.Error(); err != nil {
http.Error(w, "pdf render error: "+err.Error(), http.StatusInternalServerError) http.Error(w, "pdf render error: "+err.Error(), http.StatusInternalServerError)
return return
@@ -127,68 +127,234 @@ func OrderListPDFRoute(db *sql.DB) http.Handler {
}) })
} }
func drawOrderListPDF(pdf *gofpdf.Fpdf, rows []orderListPDFRow, search, currAcc, orderDate string) { func drawOrderListPDF(
headers := []string{ pdf *gofpdf.Fpdf,
"Siparis No", "Tarih", "Termin", "Cari Kod", "Cari Adi", "Temsilci", "Piyasa", rows []orderListPDFRow,
"PB", "Tutar", "USD", "Paket USD", "%", "Uretim", "Aciklama", 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}
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
drawHeader := func() {
pdf.AddPage() pdf.AddPage()
pdf.SetFont("dejavu", "B", 12) pdf.SetFont("dejavu", "B", 12)
pdf.CellFormat(0, 7, "Siparis Listesi", "", 1, "L", false, 0, "") pdf.CellFormat(0, 7, "Siparis Listesi", "", 1, "L", false, 0, "")
pdf.SetFont("dejavu", "", 8) 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( filterLine := fmt.Sprintf(
"Filtreler -> Arama: %s | Cari: %s | Siparis Tarihi: %s | Uretim: %s", "Filtreler -> Arama: %s | Cari: %s | Siparis Tarihi: %s | Siralama: %s | Olusturma: %s",
emptyDash(search), emptyDash(currAcc), emptyDash(orderDate), time.Now().Format("2006-01-02 15:04"), 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.CellFormat(0, 5, filterLine, "", 1, "L", false, 0, "")
pdf.Ln(1) pdf.Ln(1)
pdf.SetFont("dejavu", "B", 8) pdf.SetFont("dejavu", "B", 8)
pdf.SetFillColor(240, 240, 240) pdf.SetFillColor(240, 240, 240)
for i, h := range headers { for _, c := range cols {
pdf.CellFormat(widths[i], 6, h, "1", 0, "C", true, 0, "") pdf.CellFormat(c.Width, 6, c.Header, "1", 0, "C", true, 0, "")
} }
pdf.Ln(-1) pdf.Ln(-1)
pdf.SetFont("dejavu", "", 7) pdf.SetFont("dejavu", "", 7)
for _, row := range rows {
uretim := ""
if row.HasUretimUrunu {
uretim = "VAR"
} }
cells := []string{ buildCells := func(row orderListPDFRow) []string {
uretim := ""
if row.HasUretimUrunu {
uretim = "Uretime Verilecek Urunu Var"
}
return []string{
row.OrderNumber, row.OrderNumber,
row.OrderDate, row.OrderDate,
row.TerminTarihi, row.TerminTarihi,
row.CurrAccCode, row.CurrAccCode,
shorten(row.CurrAccDescription, 24), row.CurrAccDescription,
shorten(row.MusteriTemsilcisi, 12), row.MusteriTemsilcisi,
shorten(row.Piyasa, 10), row.Piyasa,
row.DocCurrencyCode, row.DocCurrencyCode,
fmt.Sprintf("%.2f", row.TotalAmount), fmt.Sprintf("%.2f", row.TotalAmount),
fmt.Sprintf("%.2f", row.TotalAmountUSD), fmt.Sprintf("%.2f", row.TotalAmountUSD),
fmt.Sprintf("%.2f", row.PackedUSD), fmt.Sprintf("%.2f", row.PackedUSD),
fmt.Sprintf("%.2f", row.PackedRatePct), fmt.Sprintf("%.2f", row.PackedRatePct),
uretim, uretim,
shorten(row.Description, 34), row.Description,
}
} }
for i, v := range cells { calcLineCount := func(col pdfColumn, text string) int {
align := "L" if !col.Wrap {
if i >= 8 && i <= 11 { return 1
align = "R"
} }
if i == 1 || i == 2 || i == 7 || i == 12 { lines := pdf.SplitLines([]byte(strings.TrimSpace(text)), col.Width-(cellPadX*2))
align = "C" n := len(lines)
if n < 1 {
n = 1
} }
pdf.CellFormat(widths[i], 5, v, "1", 0, align, false, 0, "") if col.MaxLines > 0 && n > col.MaxLines {
n = col.MaxLines
} }
pdf.Ln(-1) 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()
}
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, "")
}
x += c.Width
}
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 { func emptyDash(v string) string {
@@ -198,14 +364,15 @@ func emptyDash(v string) string {
return v return v
} }
func shorten(v string, max int) string { func parseBool(v string) bool {
s := strings.TrimSpace(v) b, err := strconv.ParseBool(strings.TrimSpace(v))
if len([]rune(s)) <= max { if err == nil {
return s return b
} }
r := []rune(s) switch strings.TrimSpace(strings.ToLower(v)) {
if max <= 1 { case "1", "yes", "on":
return string(r[:1]) return true
default:
return false
} }
return string(r[:max-1]) + "…"
} }

View File

@@ -109,6 +109,7 @@
:loading="store.loading" :loading="store.loading"
no-data-label="Sipariş bulunamadı" no-data-label="Sipariş bulunamadı"
:rows-per-page-options="[0]" :rows-per-page-options="[0]"
v-model:pagination="pagination"
hide-bottom hide-bottom
> >
<template #body-cell-IsCreditableConfirmed="props"> <template #body-cell-IsCreditableConfirmed="props">
@@ -252,7 +253,7 @@
</template> </template>
<script setup> <script setup>
import { onMounted, watch } from 'vue' import { onMounted, ref, watch } from 'vue'
import { useRouter } from 'vue-router' import { useRouter } from 'vue-router'
import { useQuasar } from 'quasar' import { useQuasar } from 'quasar'
import { useOrderListStore } from 'src/stores/OrdernewListStore' import { useOrderListStore } from 'src/stores/OrdernewListStore'
@@ -266,6 +267,11 @@ const canReadOrder = canRead('order')
const router = useRouter() const router = useRouter()
const $q = useQuasar() const $q = useQuasar()
const store = useOrderListStore() const store = useOrderListStore()
const pagination = ref({
sortBy: 'TotalAmountUSD',
descending: true,
rowsPerPage: 0
})
let searchTimer = null let searchTimer = null
watch( watch(
@@ -320,7 +326,9 @@ async function exportListPdf () {
const blob = await download('/orders/export-pdf', { const blob = await download('/orders/export-pdf', {
search: store.filters.search || '', search: store.filters.search || '',
CurrAccCode: store.filters.CurrAccCode || '', CurrAccCode: store.filters.CurrAccCode || '',
OrderDate: store.filters.OrderDate || '' OrderDate: store.filters.OrderDate || '',
sort_by: pagination.value?.sortBy || 'TotalAmountUSD',
descending: String(pagination.value?.descending ?? true)
}) })
const blobUrl = URL.createObjectURL(blob) const blobUrl = URL.createObjectURL(blob)