Add the date of the last payment/collection to ODS export
Requested by Clara, that she wanted to know that date for internal processes. We agreed on adding only the most recent payment/collection date, instead of adding all of them, for multiple payments/collections, and she can know whether that date is for a partial or a complete payment/collection with the status column.
This commit is contained in:
parent
cfd7a0c701
commit
f1534e6cd2
|
@ -663,9 +663,10 @@ func HandleBatchExpenseAction(w http.ResponseWriter, r *http.Request, _ httprout
|
|||
}
|
||||
entries := mustCollectExpenseEntries(r.Context(), conn, locale, filters)
|
||||
vatin := mustCollectExpenseEntriesVATIN(r.Context(), conn, entries)
|
||||
lastPaymentDate := mustCollectExpenseEntriesLastPaymentDate(r.Context(), conn, entries)
|
||||
taxes := mustCollectExpenseEntriesTaxes(r.Context(), conn, entries)
|
||||
taxColumns := mustCollectTaxColumns(r.Context(), conn, company)
|
||||
ods := mustWriteExpensesOds(entries, vatin, taxes, taxColumns, locale, company)
|
||||
ods := mustWriteExpensesOds(entries, vatin, lastPaymentDate, taxes, taxColumns, locale, company)
|
||||
writeOdsResponse(w, ods, gettext("expenses.ods", locale))
|
||||
default:
|
||||
http.Error(w, gettext("Invalid action", locale), http.StatusBadRequest)
|
||||
|
@ -700,6 +701,20 @@ func mustCollectExpenseEntriesVATIN(ctx context.Context, conn *Conn, entries []*
|
|||
`)
|
||||
}
|
||||
|
||||
func mustCollectExpenseEntriesLastPaymentDate(ctx context.Context, conn *Conn, entries []*ExpenseEntry) map[int]time.Time {
|
||||
ids := mustMakeIDArray(entries, func(entry *ExpenseEntry) int {
|
||||
return entry.ID
|
||||
})
|
||||
return mustMakeDateMap(ctx, conn, ids, `
|
||||
select expense_id
|
||||
, max(payment_date)
|
||||
from expense_payment
|
||||
join payment using (payment_id)
|
||||
where expense_id = any ($1)
|
||||
group by expense_id
|
||||
`)
|
||||
}
|
||||
|
||||
func handleRemoveExpense(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
|
||||
slug := params[0].Value
|
||||
if !ValidUuid(slug) {
|
||||
|
|
|
@ -673,9 +673,10 @@ func HandleBatchInvoiceAction(w http.ResponseWriter, r *http.Request, _ httprout
|
|||
}
|
||||
entries := mustCollectInvoiceEntries(r.Context(), conn, locale, filters)
|
||||
vatin := mustCollectInvoiceEntriesVATIN(r.Context(), conn, entries)
|
||||
lastCollectionDate := mustCollectInvoiceEntriesLastCollectionDate(r.Context(), conn, entries)
|
||||
taxes := mustCollectInvoiceEntriesTaxes(r.Context(), conn, entries)
|
||||
taxColumns := mustCollectTaxColumns(r.Context(), conn, company)
|
||||
ods := mustWriteInvoicesOds(entries, vatin, taxes, taxColumns, locale, company)
|
||||
ods := mustWriteInvoicesOds(entries, vatin, lastCollectionDate, taxes, taxColumns, locale, company)
|
||||
writeOdsResponse(w, ods, gettext("invoices.ods", locale))
|
||||
default:
|
||||
http.Error(w, gettext("Invalid action", locale), http.StatusBadRequest)
|
||||
|
@ -806,6 +807,43 @@ func mustMakeVATINMap(ctx context.Context, conn *Conn, ids *pgtype.Int4Array, sq
|
|||
return vatin
|
||||
}
|
||||
|
||||
func mustCollectInvoiceEntriesLastCollectionDate(ctx context.Context, conn *Conn, entries []*InvoiceEntry) map[int]time.Time {
|
||||
ids := mustMakeIDArray(entries, func(entry *InvoiceEntry) int {
|
||||
return entry.ID
|
||||
})
|
||||
return mustMakeDateMap(ctx, conn, ids, `
|
||||
select invoice_id
|
||||
, max(collection_date)
|
||||
from invoice_collection
|
||||
join collection using (collection_id)
|
||||
where invoice_id = any ($1)
|
||||
group by invoice_id
|
||||
`)
|
||||
}
|
||||
|
||||
func mustMakeDateMap(ctx context.Context, conn *Conn, ids *pgtype.Int4Array, sql string) map[int]time.Time {
|
||||
rows, err := conn.Query(ctx, sql, ids)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
dates := make(map[int]time.Time)
|
||||
for rows.Next() {
|
||||
var entryID int
|
||||
var date time.Time
|
||||
if err := rows.Scan(&entryID, &date); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
dates[entryID] = date
|
||||
}
|
||||
if rows.Err() != nil {
|
||||
panic(rows.Err())
|
||||
}
|
||||
return dates
|
||||
}
|
||||
|
||||
func mustWriteInvoicesPdf(r *http.Request, slugs []string) []byte {
|
||||
conn := getConn(r)
|
||||
company := mustGetCompany(r)
|
||||
|
|
31
pkg/ods.go
31
pkg/ods.go
|
@ -53,15 +53,16 @@ func extractTaxIDs(taxColumns map[int]string) []int {
|
|||
return taxIDs
|
||||
}
|
||||
|
||||
func mustWriteInvoicesOds(invoices []*InvoiceEntry, vatin map[int]string, taxes map[int]taxMap, taxColumns map[int]string, locale *Locale, company *Company) []byte {
|
||||
func mustWriteInvoicesOds(invoices []*InvoiceEntry, vatin map[int]string, lastCollectionDate map[int]time.Time, taxes map[int]taxMap, taxColumns map[int]string, locale *Locale, company *Company) []byte {
|
||||
taxIDs := extractTaxIDs(taxColumns)
|
||||
columns := make([]string, 7+len(taxIDs))
|
||||
columns := make([]string, 8+len(taxIDs))
|
||||
columns[0] = "Date"
|
||||
columns[1] = "Invoice Num."
|
||||
columns[2] = "Customer"
|
||||
columns[3] = pgettext("title", "VAT number", locale)
|
||||
columns[4] = "Status"
|
||||
i := 5
|
||||
columns[4] = "Payment Date"
|
||||
columns[5] = "Status"
|
||||
i := 6
|
||||
for _, taxID := range taxIDs {
|
||||
columns[i] = taxColumns[taxID]
|
||||
i++
|
||||
|
@ -73,6 +74,11 @@ func mustWriteInvoicesOds(invoices []*InvoiceEntry, vatin map[int]string, taxes
|
|||
writeCellString(sb, invoice.Number)
|
||||
writeCellString(sb, invoice.CustomerName)
|
||||
writeCellString(sb, vatin[invoice.ID])
|
||||
if date, ok := lastCollectionDate[invoice.ID]; ok {
|
||||
writeCellDate(sb, date)
|
||||
} else {
|
||||
writeCellString(sb, "")
|
||||
}
|
||||
writeCellString(sb, invoice.StatusLabel)
|
||||
writeTaxes(sb, taxes[invoice.ID], taxIDs, locale, company)
|
||||
writeCellFloat(sb, invoice.Total, locale, company)
|
||||
|
@ -99,16 +105,17 @@ func mustWriteQuotesOds(quotes []*QuoteEntry, locale *Locale, company *Company)
|
|||
})
|
||||
}
|
||||
|
||||
func mustWriteExpensesOds(expenses []*ExpenseEntry, vatin map[int]string, taxes map[int]taxMap, taxColumns map[int]string, locale *Locale, company *Company) []byte {
|
||||
func mustWriteExpensesOds(expenses []*ExpenseEntry, vatin map[int]string, lastPaymentDate map[int]time.Time, taxes map[int]taxMap, taxColumns map[int]string, locale *Locale, company *Company) []byte {
|
||||
taxIDs := extractTaxIDs(taxColumns)
|
||||
columns := make([]string, 8+len(taxIDs))
|
||||
columns := make([]string, 9+len(taxIDs))
|
||||
columns[0] = "Contact"
|
||||
columns[1] = pgettext("title", "VAT number", locale)
|
||||
columns[2] = "Invoice Date"
|
||||
columns[3] = "Invoice Number"
|
||||
columns[4] = "Status"
|
||||
columns[5] = "Amount"
|
||||
i := 6
|
||||
columns[4] = "Payment Date"
|
||||
columns[5] = "Status"
|
||||
columns[6] = "Amount"
|
||||
i := 7
|
||||
for _, taxID := range taxIDs {
|
||||
columns[i] = taxColumns[taxID]
|
||||
i++
|
||||
|
@ -116,11 +123,15 @@ func mustWriteExpensesOds(expenses []*ExpenseEntry, vatin map[int]string, taxes
|
|||
columns[i] = "Total"
|
||||
columns[i+1] = "Tags"
|
||||
return mustWriteTableOds(expenses, columns, locale, func(sb *strings.Builder, expense *ExpenseEntry) {
|
||||
|
||||
writeCellString(sb, expense.InvoicerName)
|
||||
writeCellString(sb, vatin[expense.ID])
|
||||
writeCellDate(sb, expense.InvoiceDate)
|
||||
writeCellString(sb, expense.InvoiceNumber)
|
||||
if date, ok := lastPaymentDate[expense.ID]; ok {
|
||||
writeCellDate(sb, date)
|
||||
} else {
|
||||
writeCellString(sb, "")
|
||||
}
|
||||
writeCellString(sb, expense.StatusLabel)
|
||||
writeCellFloat(sb, expense.Amount, locale, company)
|
||||
writeTaxes(sb, taxes[expense.ID], taxIDs, locale, company)
|
||||
|
|
Loading…
Reference in New Issue