fix: PDF reports show local+claim columns, totals in claim currency, remove grand total
This commit is contained in:
parent
a7f7dca41d
commit
47fb82d109
2 changed files with 67 additions and 83 deletions
|
|
@ -684,26 +684,10 @@ func generatePDF(eventName string, expenses []database.Expense, userName, userDe
|
|||
pdf.Ln(10)
|
||||
}
|
||||
|
||||
// Determine if we need conversion columns.
|
||||
hasConversion := false
|
||||
for _, exp := range expenses {
|
||||
if exp.ConvertedAmount > 0 && exp.BaseCurrency != "" && exp.BaseCurrency != exp.Currency {
|
||||
hasConversion = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Landscape A4: 297mm wide, 10mm margins → 277mm usable.
|
||||
// Table header.
|
||||
pdf.SetFont("Helvetica", "B", 8)
|
||||
var headers []string
|
||||
var colWidths []float64
|
||||
if hasConversion {
|
||||
headers = []string{"#", "Date", "Merchant", "Amount", "Curr.", "Converted", "Claim", "Category", "Description"}
|
||||
colWidths = []float64{7, 24, 44, 20, 14, 20, 14, 40, 94}
|
||||
} else {
|
||||
headers = []string{"#", "Date", "Merchant", "Amount", "Currency", "Category", "Description"}
|
||||
colWidths = []float64{8, 28, 58, 24, 18, 48, 93}
|
||||
}
|
||||
headers := []string{"#", "Date", "Merchant", "Local Amt", "Cur", "Claim Amt", "Claim", "Category", "Description"}
|
||||
colWidths := []float64{7, 22, 40, 18, 12, 18, 12, 38, 110}
|
||||
for i, h := range headers {
|
||||
pdf.Cell(colWidths[i], 7, h)
|
||||
}
|
||||
|
|
@ -712,7 +696,7 @@ func generatePDF(eventName string, expenses []database.Expense, userName, userDe
|
|||
// Table data rows.
|
||||
pdf.SetFont("Helvetica", "", 8)
|
||||
marginBottom := 18.0
|
||||
var totalOrig, totalConv float64
|
||||
var totalLocal, totalClaim float64
|
||||
for i, exp := range expenses {
|
||||
if pdf.GetY() > 210-marginBottom {
|
||||
pdf.AddPage()
|
||||
|
|
@ -723,63 +707,54 @@ func generatePDF(eventName string, expenses []database.Expense, userName, userDe
|
|||
pdf.Ln(7)
|
||||
pdf.SetFont("Helvetica", "", 8)
|
||||
}
|
||||
itemNum := i + 1
|
||||
if hasConversion {
|
||||
pdf.Cell(colWidths[0], 6, fmt.Sprintf("%d", itemNum))
|
||||
pdf.Cell(colWidths[1], 6, exp.Date)
|
||||
pdf.Cell(colWidths[2], 6, exp.Merchant)
|
||||
pdf.Cell(colWidths[3], 6, fmt.Sprintf("%.2f", exp.Amount))
|
||||
pdf.Cell(colWidths[4], 6, exp.Currency)
|
||||
pdf.Cell(colWidths[5], 6, fmt.Sprintf("%.2f", exp.ConvertedAmount))
|
||||
pdf.Cell(colWidths[6], 6, exp.BaseCurrency)
|
||||
pdf.Cell(colWidths[7], 6, exp.Category)
|
||||
pdf.Cell(colWidths[8], 6, exp.Description)
|
||||
totalOrig += exp.Amount
|
||||
totalConv += exp.ConvertedAmount
|
||||
} else {
|
||||
pdf.Cell(colWidths[0], 6, fmt.Sprintf("%d", itemNum))
|
||||
pdf.Cell(colWidths[1], 6, exp.Date)
|
||||
pdf.Cell(colWidths[2], 6, exp.Merchant)
|
||||
pdf.Cell(colWidths[3], 6, fmt.Sprintf("%.2f", exp.Amount))
|
||||
pdf.Cell(colWidths[4], 6, exp.Currency)
|
||||
pdf.Cell(colWidths[5], 6, exp.Category)
|
||||
pdf.Cell(colWidths[6], 6, exp.Description)
|
||||
totalOrig += exp.Amount
|
||||
// Compute claim amount (auto-calc if not set).
|
||||
claimAmt := exp.ConvertedAmount
|
||||
claimCur := exp.BaseCurrency
|
||||
if claimAmt <= 0 {
|
||||
claimAmt = exp.Amount
|
||||
}
|
||||
if claimCur == "" {
|
||||
claimCur = exp.Currency
|
||||
}
|
||||
itemNum := i + 1
|
||||
pdf.Cell(colWidths[0], 6, fmt.Sprintf("%d", itemNum))
|
||||
pdf.Cell(colWidths[1], 6, exp.Date)
|
||||
pdf.Cell(colWidths[2], 6, exp.Merchant)
|
||||
pdf.Cell(colWidths[3], 6, fmt.Sprintf("%.2f", exp.Amount))
|
||||
pdf.Cell(colWidths[4], 6, exp.Currency)
|
||||
pdf.Cell(colWidths[5], 6, fmt.Sprintf("%.2f", claimAmt))
|
||||
pdf.Cell(colWidths[6], 6, claimCur)
|
||||
pdf.Cell(colWidths[7], 6, exp.Category)
|
||||
pdf.Cell(colWidths[8], 6, exp.Description)
|
||||
pdf.Ln(6)
|
||||
totalLocal += exp.Amount
|
||||
totalClaim += claimAmt
|
||||
}
|
||||
|
||||
// Totals row.
|
||||
// Totals row in claim currency.
|
||||
pdf.SetDrawColor(71, 85, 105)
|
||||
pdf.Line(10, pdf.GetY()+1, 287, pdf.GetY()+1)
|
||||
pdf.Ln(3)
|
||||
pdf.SetFont("Helvetica", "B", 9)
|
||||
if hasConversion {
|
||||
baseCur := ""
|
||||
for _, exp := range expenses {
|
||||
if exp.BaseCurrency != "" {
|
||||
baseCur = exp.BaseCurrency
|
||||
break
|
||||
}
|
||||
claimTotalCur := ""
|
||||
for _, exp := range expenses {
|
||||
if exp.BaseCurrency != "" {
|
||||
claimTotalCur = exp.BaseCurrency
|
||||
break
|
||||
}
|
||||
pdf.Cell(colWidths[0], 8, "")
|
||||
pdf.Cell(colWidths[1], 8, "")
|
||||
pdf.Cell(colWidths[2], 8, "TOTAL")
|
||||
pdf.Cell(colWidths[3], 8, fmt.Sprintf("%.2f", totalOrig))
|
||||
pdf.Cell(colWidths[4], 8, "")
|
||||
pdf.Cell(colWidths[5], 8, fmt.Sprintf("%.2f", totalConv))
|
||||
pdf.Cell(colWidths[6], 8, baseCur)
|
||||
pdf.Cell(colWidths[7], 8, "")
|
||||
pdf.Cell(colWidths[8], 8, "")
|
||||
} else {
|
||||
pdf.Cell(colWidths[0], 8, "")
|
||||
pdf.Cell(colWidths[1], 8, "")
|
||||
pdf.Cell(colWidths[2], 8, "TOTAL")
|
||||
pdf.Cell(colWidths[3], 8, fmt.Sprintf("%.2f", totalOrig))
|
||||
pdf.Cell(colWidths[4], 8, "")
|
||||
pdf.Cell(colWidths[5], 8, "")
|
||||
pdf.Cell(colWidths[6], 8, "")
|
||||
}
|
||||
if claimTotalCur == "" {
|
||||
claimTotalCur = expenses[0].Currency
|
||||
}
|
||||
pdf.Cell(colWidths[0], 8, "")
|
||||
pdf.Cell(colWidths[1], 8, "")
|
||||
pdf.Cell(colWidths[2], 8, "TOTAL")
|
||||
pdf.Cell(colWidths[3], 8, fmt.Sprintf("%.2f", totalLocal))
|
||||
pdf.Cell(colWidths[4], 8, "")
|
||||
pdf.Cell(colWidths[5], 8, fmt.Sprintf("%.2f", totalClaim))
|
||||
pdf.Cell(colWidths[6], 8, claimTotalCur)
|
||||
pdf.Cell(colWidths[7], 8, "")
|
||||
pdf.Cell(colWidths[8], 8, "")
|
||||
|
||||
// Write to buffer.
|
||||
var buf bytes.Buffer
|
||||
|
|
|
|||
|
|
@ -661,11 +661,10 @@ func generateMonthlyPDF(monthName string, events []database.Event, expenses []da
|
|||
|
||||
itemNum := 1
|
||||
// Landscape A4: 297mm wide, 10mm margins → 277mm usable.
|
||||
colWidths := []float64{8, 28, 55, 22, 16, 50, 98}
|
||||
headers := []string{"#", "Date", "Merchant", "Amount", "Curr.", "Category", "Description"}
|
||||
colWidths := []float64{7, 22, 38, 18, 12, 18, 12, 36, 114}
|
||||
headers := []string{"#", "Date", "Merchant", "Local Amt", "Cur", "Claim Amt", "Claim", "Category", "Description"}
|
||||
marginBottom := 18.0
|
||||
|
||||
var grandTotal float64
|
||||
for _, evt := range events {
|
||||
evtExpenses := expensesByEvent[evt.ID]
|
||||
if len(evtExpenses) == 0 {
|
||||
|
|
@ -687,7 +686,7 @@ func generateMonthlyPDF(monthName string, events []database.Event, expenses []da
|
|||
}
|
||||
pdf.Ln(7)
|
||||
|
||||
var evtTotal float64
|
||||
var evtLocal, evtClaim float64
|
||||
pdf.SetFont("Helvetica", "", 8)
|
||||
for _, exp := range evtExpenses {
|
||||
if pdf.GetY() > 210-marginBottom {
|
||||
|
|
@ -699,36 +698,46 @@ func generateMonthlyPDF(monthName string, events []database.Event, expenses []da
|
|||
pdf.Ln(7)
|
||||
pdf.SetFont("Helvetica", "", 8)
|
||||
}
|
||||
claimAmt := exp.ConvertedAmount
|
||||
claimCur := exp.BaseCurrency
|
||||
if claimAmt <= 0 {
|
||||
claimAmt = exp.Amount
|
||||
}
|
||||
if claimCur == "" {
|
||||
claimCur = exp.Currency
|
||||
}
|
||||
pdf.Cell(colWidths[0], 6, fmt.Sprintf("%d", itemNum))
|
||||
pdf.Cell(colWidths[1], 6, exp.Date)
|
||||
pdf.Cell(colWidths[2], 6, exp.Merchant)
|
||||
pdf.Cell(colWidths[3], 6, fmt.Sprintf("%.2f", exp.Amount))
|
||||
pdf.Cell(colWidths[4], 6, exp.Currency)
|
||||
pdf.Cell(colWidths[5], 6, exp.Category)
|
||||
pdf.Cell(colWidths[6], 6, exp.Description)
|
||||
pdf.Cell(colWidths[5], 6, fmt.Sprintf("%.2f", claimAmt))
|
||||
pdf.Cell(colWidths[6], 6, claimCur)
|
||||
pdf.Cell(colWidths[7], 6, exp.Category)
|
||||
pdf.Cell(colWidths[8], 6, exp.Description)
|
||||
pdf.Ln(6)
|
||||
evtTotal += exp.Amount
|
||||
evtLocal += exp.Amount
|
||||
evtClaim += claimAmt
|
||||
itemNum++
|
||||
}
|
||||
|
||||
// Event subtotal.
|
||||
// Event subtotal in both local and claim currency.
|
||||
pdf.SetDrawColor(71, 85, 105)
|
||||
pdf.Line(10, pdf.GetY()+1, 287, pdf.GetY()+1)
|
||||
pdf.Ln(3)
|
||||
pdf.SetFont("Helvetica", "B", 9)
|
||||
pdf.Cell(colWidths[0], 8, "")
|
||||
pdf.Cell(colWidths[1], 8, "")
|
||||
pdf.Cell(colWidths[2], 8, "Event Total")
|
||||
pdf.Cell(colWidths[3], 8, fmt.Sprintf("%.2f", evtTotal))
|
||||
pdf.Cell(colWidths[2], 8, fmt.Sprintf("%s Total", eventNames[evt.ID]))
|
||||
pdf.Cell(colWidths[3], 8, fmt.Sprintf("%.2f", evtLocal))
|
||||
pdf.Cell(colWidths[4], 8, "")
|
||||
pdf.Cell(colWidths[5], 8, fmt.Sprintf("%.2f", evtClaim))
|
||||
pdf.Cell(colWidths[6], 8, "")
|
||||
pdf.Cell(colWidths[7], 8, "")
|
||||
pdf.Cell(colWidths[8], 8, "")
|
||||
pdf.Ln(10)
|
||||
grandTotal += evtTotal
|
||||
}
|
||||
|
||||
// Grand total.
|
||||
pdf.SetFont("Helvetica", "B", 11)
|
||||
pdf.Cell(0, 8, fmt.Sprintf("Grand Total: %.2f", grandTotal))
|
||||
pdf.Ln(10)
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := pdf.Output(&buf); err != nil {
|
||||
return nil, fmt.Errorf("PDF output: %w", err)
|
||||
|
|
|
|||
Loading…
Reference in a new issue