Merge remote-tracking branch 'origin/master'

This commit is contained in:
M_Kececi
2026-03-17 10:59:10 +03:00
parent ab236ec256
commit 8a8f384927
2 changed files with 411 additions and 60 deletions

View File

@@ -340,6 +340,78 @@ func drawCustomerBalancePDF(
pdf.SetFont("dejavu", "", 7.2)
pdf.SetTextColor(20, 20, 20)
totalUSD12, totalTRY12 := 0.0, 0.0
totalUSD13, totalTRY13 := 0.0, 0.0
totalPrBr12 := map[string]float64{}
totalPrBr13 := map[string]float64{}
totalVadeBase, totalVadeSum, totalVadeBelgeSum := 0.0, 0.0, 0.0
for _, s := range summaries {
totalUSD12 += s.USDBakiye12
totalTRY12 += s.TLBakiye12
totalUSD13 += s.USDBakiye13
totalTRY13 += s.TLBakiye13
for k, v := range s.Bakiye12Map {
totalPrBr12[k] += v
}
for k, v := range s.Bakiye13Map {
totalPrBr13[k] += v
}
w := absFloatExcel(s.USDBakiye12) + absFloatExcel(s.TLBakiye12) + absFloatExcel(s.USDBakiye13) + absFloatExcel(s.TLBakiye13)
if w > 0 {
totalVadeBase += w
totalVadeSum += s.VadeGun * w
totalVadeBelgeSum += s.VadeBelge * w
}
}
totalsRow := []string{
"TOPLAM",
"",
"",
"",
"",
formatCurrencyMapPDF(totalPrBr12),
formatCurrencyMapPDF(totalPrBr13),
formatMoneyPDF(totalUSD12),
formatMoneyPDF(totalTRY12),
formatMoneyPDF(totalUSD13),
formatMoneyPDF(totalTRY13),
}
if includeVadeColumns {
totalVade, totalVadeBelge := 0.0, 0.0
if totalVadeBase > 0 {
totalVade = totalVadeSum / totalVadeBase
totalVadeBelge = totalVadeBelgeSum / totalVadeBase
}
totalsRow = append(totalsRow, formatMoneyPDF(totalVade), formatMoneyPDF(totalVadeBelge))
}
totalH := calcPDFRowHeight(pdf, totalsRow, summaryW, map[int]bool{0: true, 1: true, 2: true, 3: true}, 6.2, 3.6)
if needPage(totalH) {
header()
drawSummaryHeader()
}
pdf.SetFont("dejavu", "B", 7.2)
pdf.SetFillColor(218, 193, 151)
pdf.SetTextColor(20, 20, 20)
totalY := pdf.GetY()
totalX := marginL
for i, v := range totalsRow {
pdf.Rect(totalX, totalY, summaryW[i], totalH, "FD")
align := "L"
if i >= 7 {
align = "R"
}
if includeVadeColumns && (i == len(totalsRow)-1 || i == len(totalsRow)-2) {
align = "C"
}
drawPDFCellWrapped(pdf, v, totalX, totalY, summaryW[i], totalH, align, 3.6)
totalX += summaryW[i]
}
pdf.SetY(totalY + totalH)
pdf.SetFont("dejavu", "", 7.2)
pdf.SetTextColor(20, 20, 20)
for _, s := range summaries {
row := []string{
s.AnaCariKodu,

View File

@@ -8,6 +8,7 @@ import (
"database/sql"
"fmt"
"net/http"
"sort"
"strconv"
"strings"
"time"
@@ -27,7 +28,7 @@ type agingScreenPDFRow struct {
OdemeDocDate string
EslesenTutar float64
UsdTutar float64
CurrencyTryRate float64
CurrencyUsdRate float64
GunSayisi float64
GunSayisiDocDate float64
Aciklama string
@@ -81,7 +82,7 @@ func ExportStatementAgingScreenPDFHandler(_ *sql.DB) http.HandlerFunc {
OdemeDocDate: pickString(r, "OdemeDocDate", "odeme_doc_date"),
EslesenTutar: pickFloat(r, "EslesenTutar", "eslesen_tutar"),
UsdTutar: pickFloat(r, "UsdTutar", "usd_tutar"),
CurrencyTryRate: pickFloat(r, "CurrencyTryRate", "currency_try_rate"),
CurrencyUsdRate: pickFloat(r, "CurrencyUsdRate", "currency_usd_rate", "CurrencyTryRate", "currency_try_rate"),
GunSayisi: pickFloat(r, "GunSayisi", "gun_sayisi"),
GunSayisiDocDate: pickFloat(r, "GunSayisi_DocDate", "gun_sayisi_docdate"),
Aciklama: pickString(r, "Aciklama", "aciklama"),
@@ -116,21 +117,54 @@ func ExportStatementAgingScreenPDFHandler(_ *sql.DB) http.HandlerFunc {
}
}
type agingScreenMasterPDF struct {
GroupKey string
Cari8 string
CariDetay string
SatirSayisi int
ToplamUSD float64
NormalUSD float64
AcikKalemUSD float64
KurWeightedBase float64
KurWeightedSum float64
KurFallback float64
WeightedBase float64
WeightedGunSum float64
WeightedGunDocSum float64
}
type agingScreenCurrencyPDF struct {
GroupKey string
MasterKey string
DocCurrencyCode string
SatirSayisi int
ToplamTutar float64
ToplamUSD float64
NormalTutar float64
AcikKalemTutar float64
KurWeightedBase float64
KurWeightedSum float64
KurFallback float64
WeightedBase float64
WeightedGunSum float64
WeightedGunDocSum float64
}
func drawStatementAgingScreenPDF(pdf *gofpdf.Fpdf, selectedDate, accountCode string, rows []agingScreenPDFRow) {
pageW, _ := pdf.GetPageSize()
masters, currenciesByMaster, detailsByCurrency := buildStatementAgingScreenPDFData(rows)
pageW, pageH := pdf.GetPageSize()
marginL, marginT, marginR, marginB := 8.0, 8.0, 8.0, 10.0
tableW := pageW - marginL - marginR
cols := []string{
"Ana Cari", "Ana Cari Detay", "Fatura Cari", "Odeme Cari", "Fatura Ref", "Odeme Ref",
"Fatura Tarihi", "Odeme Vade", "Odeme DocDate", "Eslesen Tutar", "USD Tutar", "Kur",
"Gun", "Gun (DocDate)", "Aciklama", "Doviz",
}
widths := normalizeWidths([]float64{
18, 34, 18, 18, 22, 22,
16, 16, 18, 19, 16, 12,
10, 13, 28, 11,
}, tableW)
masterCols := []string{"Ana Cari Kod", "Ana Cari Detay", "Satir", "Toplam USD", "Normal USD", "Acik Kalem USD", "Ort. Gun", "Ort. Gun (DocDate)", "Kur"}
masterW := normalizeWidths([]float64{22, 40, 12, 18, 18, 20, 14, 18, 12}, tableW)
currencyCols := []string{"Doviz", "Satir", "Toplam Tutar", "Toplam USD", "Normal", "Acik Kalem", "Kur", "Ort. Gun", "Ort. Gun (DocDate)"}
currencyW := normalizeWidths([]float64{16, 12, 20, 18, 18, 18, 12, 14, 18}, tableW)
detailCols := []string{"Fatura Cari", "Odeme Cari", "Fatura Ref", "Odeme Ref", "Fatura Tarihi", "Odeme Vade", "Odeme DocDate", "Eslesen Tutar", "USD Tutar", "Kur", "Gun", "Gun (DocDate)", "Aciklama", "Doviz"}
detailW := normalizeWidths([]float64{18, 18, 22, 22, 16, 16, 18, 18, 16, 12, 10, 13, 30, 11}, tableW)
header := func() {
pdf.AddPage()
@@ -142,7 +176,7 @@ func drawStatementAgingScreenPDF(pdf *gofpdf.Fpdf, selectedDate, accountCode str
pdf.SetFont("dejavu", "", 8.5)
pdf.SetTextColor(30, 30, 30)
pdf.SetXY(pageW-marginR-90, marginT+0.5)
pdf.CellFormat(90, 4.8, "Son Tarih: "+selectedDate, "", 0, "R", false, 0, "")
pdf.CellFormat(90, 4.8, "Son Tarih: "+formatDateTR(selectedDate), "", 0, "R", false, 0, "")
if strings.TrimSpace(accountCode) != "" {
pdf.SetXY(pageW-marginR-90, marginT+5)
pdf.CellFormat(90, 4.8, "Cari: "+accountCode, "", 0, "R", false, 0, "")
@@ -152,74 +186,319 @@ func drawStatementAgingScreenPDF(pdf *gofpdf.Fpdf, selectedDate, accountCode str
pdf.Line(marginL, marginT+10.5, pageW-marginR, marginT+10.5)
pdf.SetDrawColor(200, 200, 200)
pdf.SetY(marginT + 13)
pdf.SetFont("dejavu", "B", 7.2)
pdf.SetTextColor(255, 255, 255)
pdf.SetFillColor(149, 113, 22)
y := pdf.GetY()
x := marginL
for i, c := range cols {
pdf.Rect(x, y, widths[i], 6.2, "DF")
pdf.SetXY(x+0.8, y+1)
pdf.CellFormat(widths[i]-1.6, 4.2, c, "", 0, "C", false, 0, "")
x += widths[i]
}
pdf.SetY(y + 6.2)
}
needPage := func(needH float64) bool {
return pdf.GetY()+needH+marginB > 297.0
return pdf.GetY()+needH+marginB > pageH
}
drawHeaderRow := func(cols []string, widths []float64, h float64, r, g, b int, fontSize float64) {
pdf.SetFont("dejavu", "B", fontSize)
pdf.SetTextColor(255, 255, 255)
pdf.SetFillColor(r, g, b)
y := pdf.GetY()
x := marginL
for i, c := range cols {
pdf.Rect(x, y, widths[i], h, "DF")
pdf.SetXY(x+0.8, y+0.9)
pdf.CellFormat(widths[i]-1.6, h-1.8, c, "", 0, "C", false, 0, "")
x += widths[i]
}
pdf.SetY(y + h)
}
header()
pdf.SetFont("dejavu", "", 6.8)
drawHeaderRow(masterCols, masterW, 6.2, 149, 113, 22, 7.2)
pdf.SetFont("dejavu", "", 7)
pdf.SetTextColor(25, 25, 25)
for _, r := range rows {
if needPage(5.5) {
header()
pdf.SetFont("dejavu", "", 6.8)
pdf.SetTextColor(25, 25, 25)
for _, m := range masters {
masterLine := []string{
m.Cari8,
m.CariDetay,
strconv.Itoa(m.SatirSayisi),
formatMoneyPDF(m.ToplamUSD),
formatMoneyPDF(m.NormalUSD),
formatMoneyPDF(m.AcikKalemUSD),
fmt.Sprintf("%.0f", statementAgingAvg(m.WeightedGunSum, m.WeightedBase)),
fmt.Sprintf("%.0f", statementAgingAvg(m.WeightedGunDocSum, m.WeightedBase)),
formatMoneyPDF(statementAgingAvg(m.KurWeightedSum, m.KurWeightedBase, m.KurFallback)),
}
line := []string{
r.Cari8,
r.CariDetay,
r.FaturaCari,
r.OdemeCari,
r.FaturaRef,
r.OdemeRef,
r.FaturaTarihi,
r.OdemeTarihi,
r.OdemeDocDate,
formatMoneyPDF(r.EslesenTutar),
formatMoneyPDF(r.UsdTutar),
formatMoneyPDF(r.CurrencyTryRate),
fmt.Sprintf("%.0f", r.GunSayisi),
fmt.Sprintf("%.0f", r.GunSayisiDocDate),
r.Aciklama,
r.DocCurrencyCode,
rowH := calcPDFRowHeight(pdf, masterLine, masterW, map[int]bool{1: true}, 5.8, 3.3)
if needPage(rowH) {
header()
drawHeaderRow(masterCols, masterW, 6.2, 149, 113, 22, 7.2)
pdf.SetFont("dejavu", "", 7)
pdf.SetTextColor(25, 25, 25)
}
y := pdf.GetY()
x := marginL
for i, v := range line {
pdf.Rect(x, y, widths[i], 5.5, "")
for i, v := range masterLine {
pdf.Rect(x, y, masterW[i], rowH, "")
align := "L"
if i >= 9 && i <= 11 {
if i >= 2 {
align = "R"
}
if i == 12 || i == 13 {
if i == 6 || i == 7 {
align = "C"
}
pdf.SetXY(x+0.8, y+0.8)
pdf.CellFormat(widths[i]-1.6, 3.8, v, "", 0, align, false, 0, "")
x += widths[i]
drawPDFCellWrapped(pdf, v, x, y, masterW[i], rowH, align, 3.3)
x += masterW[i]
}
pdf.SetY(y + 5.5)
pdf.SetY(y + rowH)
for _, c := range currenciesByMaster[m.GroupKey] {
if needPage(11.2) {
header()
drawHeaderRow(masterCols, masterW, 6.2, 149, 113, 22, 7.2)
pdf.SetFont("dejavu", "", 7)
pdf.SetTextColor(25, 25, 25)
}
pdf.SetFont("dejavu", "B", 7)
drawHeaderRow(currencyCols, currencyW, 5.6, 76, 95, 122, 6.8)
pdf.SetFont("dejavu", "", 6.8)
pdf.SetTextColor(35, 35, 35)
currencyLine := []string{
c.DocCurrencyCode,
strconv.Itoa(c.SatirSayisi),
formatMoneyPDF(c.ToplamTutar),
formatMoneyPDF(c.ToplamUSD),
formatMoneyPDF(c.NormalTutar),
formatMoneyPDF(c.AcikKalemTutar),
formatMoneyPDF(statementAgingAvg(c.KurWeightedSum, c.KurWeightedBase, c.KurFallback)),
fmt.Sprintf("%.0f", statementAgingAvg(c.WeightedGunSum, c.WeightedBase)),
fmt.Sprintf("%.0f", statementAgingAvg(c.WeightedGunDocSum, c.WeightedBase)),
}
cRowH := 5.4
y := pdf.GetY()
x := marginL
for i, v := range currencyLine {
pdf.Rect(x, y, currencyW[i], cRowH, "")
align := "R"
if i == 0 {
align = "L"
}
if i == 7 || i == 8 {
align = "C"
}
drawPDFCellWrapped(pdf, v, x, y, currencyW[i], cRowH, align, 3.2)
x += currencyW[i]
}
pdf.SetY(y + cRowH)
drawHeaderRow(detailCols, detailW, 5.6, 31, 59, 91, 6.8)
pdf.SetFont("dejavu", "", 6.6)
pdf.SetTextColor(30, 30, 30)
for _, d := range detailsByCurrency[c.GroupKey] {
line := []string{
d.FaturaCari,
d.OdemeCari,
d.FaturaRef,
d.OdemeRef,
formatDateTR(d.FaturaTarihi),
formatDateTR(d.OdemeTarihi),
formatDateTR(d.OdemeDocDate),
formatMoneyPDF(d.EslesenTutar),
formatMoneyPDF(d.UsdTutar),
formatMoneyPDF(d.CurrencyUsdRate),
fmt.Sprintf("%.0f", d.GunSayisi),
fmt.Sprintf("%.0f", d.GunSayisiDocDate),
d.Aciklama,
d.DocCurrencyCode,
}
rowH := calcPDFRowHeight(pdf, line, detailW, map[int]bool{0: true, 1: true, 2: true, 3: true, 12: true}, 5.4, 3.1)
if needPage(rowH) {
header()
drawHeaderRow(masterCols, masterW, 6.2, 149, 113, 22, 7.2)
pdf.SetFont("dejavu", "B", 7)
drawHeaderRow(currencyCols, currencyW, 5.6, 76, 95, 122, 6.8)
pdf.SetFont("dejavu", "", 6.8)
pdf.SetTextColor(35, 35, 35)
y = pdf.GetY()
x = marginL
for i, v := range currencyLine {
pdf.Rect(x, y, currencyW[i], cRowH, "")
align := "R"
if i == 0 {
align = "L"
}
if i == 7 || i == 8 {
align = "C"
}
drawPDFCellWrapped(pdf, v, x, y, currencyW[i], cRowH, align, 3.2)
x += currencyW[i]
}
pdf.SetY(y + cRowH)
drawHeaderRow(detailCols, detailW, 5.6, 31, 59, 91, 6.8)
pdf.SetFont("dejavu", "", 6.6)
pdf.SetTextColor(30, 30, 30)
}
rowY := pdf.GetY()
rowX := marginL
for i, v := range line {
pdf.Rect(rowX, rowY, detailW[i], rowH, "")
align := "L"
if i >= 7 && i <= 9 {
align = "R"
}
if i == 10 || i == 11 {
align = "C"
}
drawPDFCellWrapped(pdf, v, rowX, rowY, detailW[i], rowH, align, 3.1)
rowX += detailW[i]
}
pdf.SetY(rowY + rowH)
}
pdf.Ln(1)
}
pdf.Ln(1.2)
}
}
func statementAgingAvg(sum, base float64, fallback ...float64) float64 {
if base > 0 {
return sum / base
}
if len(fallback) > 0 {
return fallback[0]
}
return 0
}
func buildStatementAgingScreenPDFData(rows []agingScreenPDFRow) ([]agingScreenMasterPDF, map[string][]agingScreenCurrencyPDF, map[string][]agingScreenPDFRow) {
masterMap := map[string]*agingScreenMasterPDF{}
currencyMap := map[string]*agingScreenCurrencyPDF{}
detailsByCurrency := map[string][]agingScreenPDFRow{}
for _, row := range rows {
masterKey := strings.TrimSpace(row.Cari8)
if masterKey == "" {
continue
}
curr := strings.ToUpper(strings.TrimSpace(row.DocCurrencyCode))
if curr == "" {
curr = "N/A"
}
currencyKey := masterKey + "|" + curr
aciklama := strings.ToUpper(strings.TrimSpace(row.Aciklama))
absUsd := absFloatExcel(row.UsdTutar)
m := masterMap[masterKey]
if m == nil {
m = &agingScreenMasterPDF{
GroupKey: masterKey,
Cari8: masterKey,
CariDetay: strings.TrimSpace(row.CariDetay),
}
masterMap[masterKey] = m
}
if m.CariDetay == "" {
m.CariDetay = strings.TrimSpace(row.CariDetay)
}
c := currencyMap[currencyKey]
if c == nil {
c = &agingScreenCurrencyPDF{
GroupKey: currencyKey,
MasterKey: masterKey,
DocCurrencyCode: curr,
}
currencyMap[currencyKey] = c
}
m.SatirSayisi++
m.ToplamUSD += row.UsdTutar
if aciklama == "ACIKKALEM" {
m.AcikKalemUSD += row.UsdTutar
} else {
m.NormalUSD += row.UsdTutar
}
if absUsd > 0 {
m.WeightedBase += absUsd
m.WeightedGunSum += absUsd * row.GunSayisi
m.WeightedGunDocSum += absUsd * row.GunSayisiDocDate
if row.CurrencyUsdRate > 0 {
m.KurWeightedBase += absUsd
m.KurWeightedSum += absUsd * row.CurrencyUsdRate
}
}
if row.CurrencyUsdRate > 0 {
m.KurFallback = row.CurrencyUsdRate
}
c.SatirSayisi++
c.ToplamTutar += row.EslesenTutar
c.ToplamUSD += row.UsdTutar
if aciklama == "ACIKKALEM" {
c.AcikKalemTutar += row.EslesenTutar
} else {
c.NormalTutar += row.EslesenTutar
}
if absUsd > 0 {
c.WeightedBase += absUsd
c.WeightedGunSum += absUsd * row.GunSayisi
c.WeightedGunDocSum += absUsd * row.GunSayisiDocDate
if row.CurrencyUsdRate > 0 {
c.KurWeightedBase += absUsd
c.KurWeightedSum += absUsd * row.CurrencyUsdRate
}
}
if row.CurrencyUsdRate > 0 {
c.KurFallback = row.CurrencyUsdRate
}
detailsByCurrency[currencyKey] = append(detailsByCurrency[currencyKey], row)
}
masterKeys := make([]string, 0, len(masterMap))
for k := range masterMap {
masterKeys = append(masterKeys, k)
}
sort.SliceStable(masterKeys, func(i, j int) bool {
return strings.ToUpper(masterKeys[i]) < strings.ToUpper(masterKeys[j])
})
masters := make([]agingScreenMasterPDF, 0, len(masterKeys))
currenciesByMaster := make(map[string][]agingScreenCurrencyPDF, len(masterKeys))
for _, mk := range masterKeys {
masters = append(masters, *masterMap[mk])
}
for _, c := range currencyMap {
currenciesByMaster[c.MasterKey] = append(currenciesByMaster[c.MasterKey], *c)
}
for mk := range currenciesByMaster {
sort.SliceStable(currenciesByMaster[mk], func(i, j int) bool {
return strings.ToUpper(currenciesByMaster[mk][i].DocCurrencyCode) < strings.ToUpper(currenciesByMaster[mk][j].DocCurrencyCode)
})
}
for k := range detailsByCurrency {
sort.SliceStable(detailsByCurrency[k], func(i, j int) bool {
a := detailsByCurrency[k][i]
b := detailsByCurrency[k][j]
if strings.TrimSpace(a.FaturaCari) == strings.TrimSpace(b.FaturaCari) {
if strings.TrimSpace(a.OdemeCari) == strings.TrimSpace(b.OdemeCari) {
if strings.TrimSpace(a.FaturaRef) == strings.TrimSpace(b.FaturaRef) {
return strings.TrimSpace(a.OdemeRef) < strings.TrimSpace(b.OdemeRef)
}
return strings.TrimSpace(a.FaturaRef) < strings.TrimSpace(b.FaturaRef)
}
return strings.TrimSpace(a.OdemeCari) < strings.TrimSpace(b.OdemeCari)
}
return strings.TrimSpace(a.FaturaCari) < strings.TrimSpace(b.FaturaCari)
})
}
return masters, currenciesByMaster, detailsByCurrency
}
func pickString(m map[string]interface{}, keys ...string) string {
for _, k := range keys {
if v, ok := m[k]; ok {