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