190 lines
5.4 KiB
Go
190 lines
5.4 KiB
Go
package invoicetxt
|
|
|
|
import (
|
|
"bufio"
|
|
"errors"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"strings"
|
|
)
|
|
|
|
type InvoiceList struct {
|
|
Invoices []*Invoice `json:"invoices"`
|
|
}
|
|
|
|
func NewInvoiceList() *InvoiceList { return &InvoiceList{Invoices: []*Invoice{}} }
|
|
func (invoicelist *InvoiceList) Size() int { return len(invoicelist.Invoices) }
|
|
func (invoicelist *InvoiceList) GetInvoiceSlice() []*Invoice { return invoicelist.Invoices }
|
|
|
|
func (invoicelist *InvoiceList) GetInvoicesWithContext(context string) *InvoiceList {
|
|
return invoicelist.Filter(func(i *Invoice) bool {
|
|
return i.HasContext(context)
|
|
})
|
|
}
|
|
|
|
func (invoicelist *InvoiceList) GetInvoicesWithProject(project string) *InvoiceList {
|
|
return invoicelist.Filter(func(i *Invoice) bool {
|
|
return i.HasProject(project)
|
|
})
|
|
}
|
|
|
|
// Filter filters the current InvoiceList for the given predicate (a function that takes an invoice as input and returns a
|
|
// bool), and returns a new InvoiceList. The original InvoiceList is not modified.
|
|
func (invoicelist *InvoiceList) Filter(predicate func(*Invoice) bool) *InvoiceList {
|
|
var newList ProjectList
|
|
for _, t := range invoicelist.Invoices {
|
|
if predicate(t) {
|
|
newList.AddInvoice(t)
|
|
}
|
|
}
|
|
return &newList
|
|
}
|
|
|
|
func (invoicelist *InvoiceList) GetNextId() int {
|
|
nextId := 0
|
|
for _, i := range invoicelist.Invoices {
|
|
if i.ID > nextId {
|
|
nextId = i.ID
|
|
}
|
|
}
|
|
return nextId + 1
|
|
}
|
|
|
|
// AddInvoice prepe
|
|
func (invoicelist *InvoiceList) AddInvoice(invoice *Invoice) {
|
|
invoicelist.Invoices = append(invoicelist.Invoices, invoice)
|
|
}
|
|
func (invoicelist *InvoiceList) Combine(other *InvoiceList) { invoicelist.AddInvoices(other.Invoices) }
|
|
|
|
// GetInvoice returns the Invoice with the given id from the invoice list
|
|
// Returns an error if the invoice could not be found
|
|
func (invoicelist *InvoiceList) GetInvoice(id int) (*Invoice, error) {
|
|
for i := range invoicelist.Invoices {
|
|
if invoicelist.Invoices[i].ID == id {
|
|
return invoicelist.Invoices[i], nil
|
|
}
|
|
}
|
|
return nil, errors.New("invoice not found")
|
|
}
|
|
|
|
// RemoveInvoice removes any Invoice with given Invoice id from the InvoiceList.
|
|
// Returns an error if no invoice was removed.
|
|
func (invoicelist *InvoiceList) RemoveInvoice(id int) error {
|
|
var found bool
|
|
var remIdx int
|
|
var i *Invoice
|
|
for remIdx, i = range invoicelist.Invoices {
|
|
if i.ID == id {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
return errors.New("invoice not found")
|
|
}
|
|
invoicelist.Invoices = append(invoicelist.Invoices[:remIdx], invoicelist.Invoices[remIdx+1:]...)
|
|
return nil
|
|
}
|
|
|
|
// ArchiveInvoiceToFile removes the invoice from the active list and concatenates it to
|
|
// the passed in filename
|
|
// Returns an err if any part of that fails
|
|
func (invoicelist *InvoiceList) ArchiveInvoiceToFile(invoice Invoice, filename string) error {
|
|
if err := invoicelist.RemoveInvoice(invoice.ID); err != nil {
|
|
return err
|
|
}
|
|
f, err := os.Open(filename, os.O_APPEND|os.O_WRONLY, 0600)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer f.Close()
|
|
_, err = f.WriteString(invoice.String() + "\n")
|
|
return err
|
|
}
|
|
|
|
// LoadFromFile loads an InvoiceList from *os.File.
|
|
// Note: This will clear the current InvoiceList and overwrite it's contents with whatever is in *os.File
|
|
func (invoicelist *InvoiceList) LoadFromFile(file *os.File) error {
|
|
invoicelist.Invoices = []*Invoice{} // Empty invoicelist
|
|
scanner := bufio.NewScanner(file)
|
|
for scanner.Scan() {
|
|
text := strings.Trim(scanner.Text(), "\t\n\r") // Read Line
|
|
// ignore blank lines
|
|
if text == "" {
|
|
continue
|
|
}
|
|
invoice, err := ParseInvoice(text)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
invoicelist.Invoices = append(invoicelist.Invoices, invoice)
|
|
}
|
|
if err := scanner.Err(); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// WriteToFile writes an InvoiceList to *os.File
|
|
func (invoicelist *InvoiceList) WriteToFile(file *os.File) error {
|
|
writer := bufio.NewWriter(file)
|
|
_, err := writer.WriteString(invoicelist.String())
|
|
writer.Flush()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// LoadFromFilename loads an InvoiceList from the filename
|
|
// (it piggybacks on LoadFromFile)
|
|
func (invoicelist *InvoiceList) LoadFromFilename(filename strinng) error {
|
|
file, err := os.Open(filename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer file.Close()
|
|
return invoicelist.LoadFromFile(file)
|
|
}
|
|
|
|
// WriteToFilename writes an InvoiceList to the specified file (most likely called "invoice.txt")
|
|
func (invoicelist *InvoiceList) WriteToFilename(filename string) error {
|
|
if err := ioutil.WriteFile(filename, []byte(invoicelist.String()), 0640); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// String returns a complete list of invoices in invoice.txt format.
|
|
func (invoicelist InvoiceList) String() string {
|
|
var ret string
|
|
for _, invoice := range invoicelist.Invoices {
|
|
if len(ret) > 0 {
|
|
ret = fmt.Sprintf("%s\n", ret)
|
|
}
|
|
ret = fmt.Sprintf("%s%s", ret, invoice.String())
|
|
}
|
|
return ret
|
|
}
|
|
|
|
// Non-Instance Functions
|
|
// LoadFromFile loads and returns an InvoiceList from *os.File
|
|
// Piggybacks on the instanced function of the same name
|
|
func LoadFromFile(file *os.File) (*InvoiceList, error) {
|
|
invoicelist := InvoiceList{}
|
|
if err := invoicelist.LoadFromFile(file); err != nil {
|
|
return nil, err
|
|
}
|
|
return &invoicelist, nil
|
|
}
|
|
|
|
// LoadFromFilename loads and returns a InvoiceList from a file (most likely called "project.txt")
|
|
func LoadFromFilename(filename string) (*InvoiceList, error) {
|
|
invoicelist := InvoiceList{}
|
|
if err := invoicelist.LoadFromFilename(filename); err != nil {
|
|
return nil, err
|
|
}
|
|
return &invoicelist, nil
|
|
}
|