Compare commits
2 Commits
4ae9fc5cfa
...
f1534e6cd2
Author | SHA1 | Date |
---|---|---|
jordi fita mas | f1534e6cd2 | |
jordi fita mas | cfd7a0c701 |
|
@ -663,9 +663,10 @@ func HandleBatchExpenseAction(w http.ResponseWriter, r *http.Request, _ httprout
|
||||||
}
|
}
|
||||||
entries := mustCollectExpenseEntries(r.Context(), conn, locale, filters)
|
entries := mustCollectExpenseEntries(r.Context(), conn, locale, filters)
|
||||||
vatin := mustCollectExpenseEntriesVATIN(r.Context(), conn, entries)
|
vatin := mustCollectExpenseEntriesVATIN(r.Context(), conn, entries)
|
||||||
|
lastPaymentDate := mustCollectExpenseEntriesLastPaymentDate(r.Context(), conn, entries)
|
||||||
taxes := mustCollectExpenseEntriesTaxes(r.Context(), conn, entries)
|
taxes := mustCollectExpenseEntriesTaxes(r.Context(), conn, entries)
|
||||||
taxColumns := mustCollectTaxColumns(r.Context(), conn, company)
|
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))
|
writeOdsResponse(w, ods, gettext("expenses.ods", locale))
|
||||||
default:
|
default:
|
||||||
http.Error(w, gettext("Invalid action", locale), http.StatusBadRequest)
|
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) {
|
func handleRemoveExpense(w http.ResponseWriter, r *http.Request, params httprouter.Params) {
|
||||||
slug := params[0].Value
|
slug := params[0].Value
|
||||||
if !ValidUuid(slug) {
|
if !ValidUuid(slug) {
|
||||||
|
|
|
@ -673,9 +673,10 @@ func HandleBatchInvoiceAction(w http.ResponseWriter, r *http.Request, _ httprout
|
||||||
}
|
}
|
||||||
entries := mustCollectInvoiceEntries(r.Context(), conn, locale, filters)
|
entries := mustCollectInvoiceEntries(r.Context(), conn, locale, filters)
|
||||||
vatin := mustCollectInvoiceEntriesVATIN(r.Context(), conn, entries)
|
vatin := mustCollectInvoiceEntriesVATIN(r.Context(), conn, entries)
|
||||||
|
lastCollectionDate := mustCollectInvoiceEntriesLastCollectionDate(r.Context(), conn, entries)
|
||||||
taxes := mustCollectInvoiceEntriesTaxes(r.Context(), conn, entries)
|
taxes := mustCollectInvoiceEntriesTaxes(r.Context(), conn, entries)
|
||||||
taxColumns := mustCollectTaxColumns(r.Context(), conn, company)
|
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))
|
writeOdsResponse(w, ods, gettext("invoices.ods", locale))
|
||||||
default:
|
default:
|
||||||
http.Error(w, gettext("Invalid action", locale), http.StatusBadRequest)
|
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
|
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 {
|
func mustWriteInvoicesPdf(r *http.Request, slugs []string) []byte {
|
||||||
conn := getConn(r)
|
conn := getConn(r)
|
||||||
company := mustGetCompany(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
|
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)
|
taxIDs := extractTaxIDs(taxColumns)
|
||||||
columns := make([]string, 7+len(taxIDs))
|
columns := make([]string, 8+len(taxIDs))
|
||||||
columns[0] = "Date"
|
columns[0] = "Date"
|
||||||
columns[1] = "Invoice Num."
|
columns[1] = "Invoice Num."
|
||||||
columns[2] = "Customer"
|
columns[2] = "Customer"
|
||||||
columns[3] = pgettext("title", "VAT number", locale)
|
columns[3] = pgettext("title", "VAT number", locale)
|
||||||
columns[4] = "Status"
|
columns[4] = "Payment Date"
|
||||||
i := 5
|
columns[5] = "Status"
|
||||||
|
i := 6
|
||||||
for _, taxID := range taxIDs {
|
for _, taxID := range taxIDs {
|
||||||
columns[i] = taxColumns[taxID]
|
columns[i] = taxColumns[taxID]
|
||||||
i++
|
i++
|
||||||
|
@ -73,6 +74,11 @@ func mustWriteInvoicesOds(invoices []*InvoiceEntry, vatin map[int]string, taxes
|
||||||
writeCellString(sb, invoice.Number)
|
writeCellString(sb, invoice.Number)
|
||||||
writeCellString(sb, invoice.CustomerName)
|
writeCellString(sb, invoice.CustomerName)
|
||||||
writeCellString(sb, vatin[invoice.ID])
|
writeCellString(sb, vatin[invoice.ID])
|
||||||
|
if date, ok := lastCollectionDate[invoice.ID]; ok {
|
||||||
|
writeCellDate(sb, date)
|
||||||
|
} else {
|
||||||
|
writeCellString(sb, "")
|
||||||
|
}
|
||||||
writeCellString(sb, invoice.StatusLabel)
|
writeCellString(sb, invoice.StatusLabel)
|
||||||
writeTaxes(sb, taxes[invoice.ID], taxIDs, locale, company)
|
writeTaxes(sb, taxes[invoice.ID], taxIDs, locale, company)
|
||||||
writeCellFloat(sb, invoice.Total, 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)
|
taxIDs := extractTaxIDs(taxColumns)
|
||||||
columns := make([]string, 8+len(taxIDs))
|
columns := make([]string, 9+len(taxIDs))
|
||||||
columns[0] = "Contact"
|
columns[0] = "Contact"
|
||||||
columns[1] = pgettext("title", "VAT number", locale)
|
columns[1] = pgettext("title", "VAT number", locale)
|
||||||
columns[2] = "Invoice Date"
|
columns[2] = "Invoice Date"
|
||||||
columns[3] = "Invoice Number"
|
columns[3] = "Invoice Number"
|
||||||
columns[4] = "Status"
|
columns[4] = "Payment Date"
|
||||||
columns[5] = "Amount"
|
columns[5] = "Status"
|
||||||
i := 6
|
columns[6] = "Amount"
|
||||||
|
i := 7
|
||||||
for _, taxID := range taxIDs {
|
for _, taxID := range taxIDs {
|
||||||
columns[i] = taxColumns[taxID]
|
columns[i] = taxColumns[taxID]
|
||||||
i++
|
i++
|
||||||
|
@ -116,11 +123,15 @@ func mustWriteExpensesOds(expenses []*ExpenseEntry, vatin map[int]string, taxes
|
||||||
columns[i] = "Total"
|
columns[i] = "Total"
|
||||||
columns[i+1] = "Tags"
|
columns[i+1] = "Tags"
|
||||||
return mustWriteTableOds(expenses, columns, locale, func(sb *strings.Builder, expense *ExpenseEntry) {
|
return mustWriteTableOds(expenses, columns, locale, func(sb *strings.Builder, expense *ExpenseEntry) {
|
||||||
|
|
||||||
writeCellString(sb, expense.InvoicerName)
|
writeCellString(sb, expense.InvoicerName)
|
||||||
writeCellString(sb, vatin[expense.ID])
|
writeCellString(sb, vatin[expense.ID])
|
||||||
writeCellDate(sb, expense.InvoiceDate)
|
writeCellDate(sb, expense.InvoiceDate)
|
||||||
writeCellString(sb, expense.InvoiceNumber)
|
writeCellString(sb, expense.InvoiceNumber)
|
||||||
|
if date, ok := lastPaymentDate[expense.ID]; ok {
|
||||||
|
writeCellDate(sb, date)
|
||||||
|
} else {
|
||||||
|
writeCellString(sb, "")
|
||||||
|
}
|
||||||
writeCellString(sb, expense.StatusLabel)
|
writeCellString(sb, expense.StatusLabel)
|
||||||
writeCellFloat(sb, expense.Amount, locale, company)
|
writeCellFloat(sb, expense.Amount, locale, company)
|
||||||
writeTaxes(sb, taxes[expense.ID], taxIDs, locale, company)
|
writeTaxes(sb, taxes[expense.ID], taxIDs, locale, company)
|
||||||
|
|
|
@ -314,6 +314,7 @@ header nav a[aria-current] {
|
||||||
main {
|
main {
|
||||||
padding: 2rem 3rem;
|
padding: 2rem 3rem;
|
||||||
overflow-y: scroll;
|
overflow-y: scroll;
|
||||||
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input {
|
.input {
|
||||||
|
|
Loading…
Reference in New Issue