fix: CSV reports now include claim currency column, claim totals, and total claim header
This commit is contained in:
parent
f1b029949e
commit
22d2507d52
2 changed files with 76 additions and 73 deletions
|
|
@ -568,85 +568,64 @@ func generateCSV(eventName string, expenses []database.Expense, userName, userDe
|
|||
var buf bytes.Buffer
|
||||
writer := csv.NewWriter(&buf)
|
||||
|
||||
// Write user metadata row (prepared by).
|
||||
// Write user metadata row.
|
||||
if userName != "" {
|
||||
metaLine := fmt.Sprintf("Prepared by: %s", userName)
|
||||
if userDept != "" && userDept != "-" {
|
||||
metaLine += fmt.Sprintf(" | Department: %s", userDept)
|
||||
}
|
||||
writer.Write([]string{metaLine})
|
||||
writer.Write([]string{""}) // blank separator
|
||||
writer.Write([]string{""})
|
||||
}
|
||||
|
||||
// Determine if we need conversion columns.
|
||||
hasConversion := false
|
||||
// Total claim summary.
|
||||
var totalClaim float64
|
||||
claimCur := ""
|
||||
for _, exp := range expenses {
|
||||
if exp.ConvertedAmount > 0 && exp.BaseCurrency != "" && exp.BaseCurrency != exp.Currency {
|
||||
hasConversion = true
|
||||
break
|
||||
cAmt := exp.ConvertedAmount
|
||||
if cAmt <= 0 {
|
||||
cAmt = exp.Amount
|
||||
}
|
||||
totalClaim += cAmt
|
||||
if claimCur == "" && exp.BaseCurrency != "" {
|
||||
claimCur = exp.BaseCurrency
|
||||
}
|
||||
}
|
||||
if claimCur == "" && len(expenses) > 0 {
|
||||
claimCur = expenses[0].Currency
|
||||
}
|
||||
writer.Write([]string{fmt.Sprintf("Total Claim: %.2f %s", totalClaim, claimCur)})
|
||||
writer.Write([]string{""})
|
||||
|
||||
// Write header row.
|
||||
var header []string
|
||||
if hasConversion {
|
||||
header = []string{"#", "Date", "Merchant", "Amount", "Currency", "Converted", "Claim Currency", "Category", "Description"}
|
||||
} else {
|
||||
header = []string{"#", "Date", "Merchant", "Amount", "Currency", "Category", "Description"}
|
||||
}
|
||||
if err := writer.Write(header); err != nil {
|
||||
return nil, fmt.Errorf("write CSV header: %w", err)
|
||||
}
|
||||
// Write header row with both local and claim columns.
|
||||
header := []string{"#", "Date", "Merchant", "Local Amt", "Currency", "Claim Amt", "Claim Curr", "Category", "Description"}
|
||||
writer.Write(header)
|
||||
|
||||
// Write one data row per expense with item number.
|
||||
totalOrig := 0.0
|
||||
totalConv := 0.0
|
||||
// Write data rows.
|
||||
var tableLocal, tableClaim float64
|
||||
for i, exp := range expenses {
|
||||
itemNum := i + 1
|
||||
var row []string
|
||||
if hasConversion {
|
||||
row = []string{
|
||||
fmt.Sprintf("%d", itemNum),
|
||||
exp.Date,
|
||||
exp.Merchant,
|
||||
fmt.Sprintf("%.2f", exp.Amount),
|
||||
exp.Currency,
|
||||
fmt.Sprintf("%.2f", exp.ConvertedAmount),
|
||||
exp.BaseCurrency,
|
||||
exp.Category,
|
||||
exp.Description,
|
||||
claimAmt := exp.ConvertedAmount
|
||||
claimCur := exp.BaseCurrency
|
||||
if claimAmt <= 0 {
|
||||
claimAmt = exp.Amount
|
||||
}
|
||||
} else {
|
||||
row = []string{
|
||||
fmt.Sprintf("%d", itemNum),
|
||||
exp.Date,
|
||||
exp.Merchant,
|
||||
fmt.Sprintf("%.2f", exp.Amount),
|
||||
exp.Currency,
|
||||
exp.Category,
|
||||
exp.Description,
|
||||
if claimCur == "" {
|
||||
claimCur = exp.Currency
|
||||
}
|
||||
row := []string{
|
||||
fmt.Sprintf("%d", i+1),
|
||||
exp.Date, exp.Merchant,
|
||||
fmt.Sprintf("%.2f", exp.Amount), exp.Currency,
|
||||
fmt.Sprintf("%.2f", claimAmt), claimCur,
|
||||
exp.Category, exp.Description,
|
||||
}
|
||||
if err := writer.Write(row); err != nil {
|
||||
return nil, fmt.Errorf("write CSV row: %w", err)
|
||||
}
|
||||
totalOrig += exp.Amount
|
||||
totalConv += exp.ConvertedAmount
|
||||
writer.Write(row)
|
||||
tableLocal += exp.Amount
|
||||
tableClaim += claimAmt
|
||||
}
|
||||
|
||||
// Write totals row.
|
||||
if hasConversion {
|
||||
baseCur := ""
|
||||
for _, exp := range expenses {
|
||||
if exp.BaseCurrency != "" {
|
||||
baseCur = exp.BaseCurrency
|
||||
break
|
||||
}
|
||||
}
|
||||
writer.Write([]string{"TOTAL", "", "", fmt.Sprintf("%.2f", totalOrig), "", fmt.Sprintf("%.2f", totalConv), baseCur, "", ""})
|
||||
} else {
|
||||
writer.Write([]string{"TOTAL", "", "", fmt.Sprintf("%.2f", totalOrig), "", "", "", ""})
|
||||
}
|
||||
writer.Write([]string{"TOTAL", "", "", fmt.Sprintf("%.2f", tableLocal), "", fmt.Sprintf("%.2f", tableClaim), "", "", ""})
|
||||
|
||||
writer.Flush()
|
||||
if err := writer.Error(); err != nil {
|
||||
|
|
|
|||
|
|
@ -581,6 +581,25 @@ func generateMonthlyCSV(monthName string, events []database.Event, expenses []da
|
|||
}
|
||||
buf.WriteString("\r\n")
|
||||
|
||||
// Total claim summary.
|
||||
var totalClaim float64
|
||||
claimCur := ""
|
||||
for _, exp := range expenses {
|
||||
cAmt := exp.ConvertedAmount
|
||||
if cAmt <= 0 {
|
||||
cAmt = exp.Amount
|
||||
}
|
||||
totalClaim += cAmt
|
||||
if claimCur == "" && exp.BaseCurrency != "" {
|
||||
claimCur = exp.BaseCurrency
|
||||
}
|
||||
}
|
||||
if claimCur == "" && len(expenses) > 0 {
|
||||
claimCur = expenses[0].Currency
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf("Total Claim: %.2f %s\r\n", totalClaim, claimCur))
|
||||
buf.WriteString("\r\n")
|
||||
|
||||
// Group expenses by event.
|
||||
expensesByEvent := make(map[string][]database.Expense)
|
||||
eventNames := make(map[string]string)
|
||||
|
|
@ -592,7 +611,7 @@ func generateMonthlyCSV(monthName string, events []database.Event, expenses []da
|
|||
}
|
||||
|
||||
itemNum := 1
|
||||
var grandTotalOrig, grandTotalConv float64
|
||||
var grandLocal, grandClaim float64
|
||||
|
||||
for _, evt := range events {
|
||||
evtExpenses := expensesByEvent[evt.ID]
|
||||
|
|
@ -601,24 +620,29 @@ func generateMonthlyCSV(monthName string, events []database.Event, expenses []da
|
|||
}
|
||||
|
||||
buf.WriteString(fmt.Sprintf("\r\n--- %s ---\r\n", eventNames[evt.ID]))
|
||||
buf.WriteString("#,Date,Merchant,Amount,Currency,Category,Description\r\n")
|
||||
buf.WriteString("#,Date,Merchant,Local Amt,Currency,Claim Amt,Claim Curr,Category,Description\r\n")
|
||||
|
||||
var evtTotal float64
|
||||
var evtLocal, evtClaim float64
|
||||
for _, exp := range evtExpenses {
|
||||
buf.WriteString(fmt.Sprintf("%d,%s,%s,%.2f,%s,%s,%s\r\n",
|
||||
itemNum, exp.Date, exp.Merchant, exp.Amount, exp.Currency, exp.Category, exp.Description))
|
||||
evtTotal += exp.Amount
|
||||
if exp.ConvertedAmount > 0 {
|
||||
grandTotalConv += exp.ConvertedAmount
|
||||
} else {
|
||||
grandTotalConv += exp.Amount
|
||||
claimAmt := exp.ConvertedAmount
|
||||
claimCur := exp.BaseCurrency
|
||||
if claimAmt <= 0 {
|
||||
claimAmt = exp.Amount
|
||||
}
|
||||
if claimCur == "" {
|
||||
claimCur = exp.Currency
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf("%d,%s,%s,%.2f,%s,%.2f,%s,%s,%s\r\n",
|
||||
itemNum, exp.Date, exp.Merchant, exp.Amount, exp.Currency, claimAmt, claimCur, exp.Category, exp.Description))
|
||||
evtLocal += exp.Amount
|
||||
evtClaim += claimAmt
|
||||
itemNum++
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf("Event Total,,,,%.2f,,\r\n", evtTotal))
|
||||
grandTotalOrig += evtTotal
|
||||
buf.WriteString(fmt.Sprintf("Event Total,,,%.2f,,%.2f,,\r\n", evtLocal, evtClaim))
|
||||
grandLocal += evtLocal
|
||||
grandClaim += evtClaim
|
||||
}
|
||||
buf.WriteString(fmt.Sprintf("\r\nGrand Total,,,,%.2f,,\r\n", grandTotalOrig))
|
||||
buf.WriteString(fmt.Sprintf("\r\nGrand Total,,,%.2f,,%.2f,,\r\n", grandLocal, grandClaim))
|
||||
|
||||
filename := fmt.Sprintf("monthly-%s-report.csv", sanitiseFilename(monthName))
|
||||
return &email.Attachment{
|
||||
|
|
|
|||
Loading…
Reference in a new issue