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