2013-06-08 15:17:03 -07:00

182 lines
5.3 KiB
Go

// Copyright © 2011-12 Qtrac Ltd.
//
// This program or package and any associated files are licensed under the
// Apache License, Version 2.0 (the "License"); you may not use these files
// except in compliance with the License. You can get a copy of the License
// at: http://www.apache.org/licenses/LICENSE-2.0.
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package main
import (
"encoding/xml"
"fmt"
"io"
"strings"
"time"
)
type XMLMarshaler struct{}
type XMLInvoices struct {
XMLName xml.Name `xml:"INVOICES"`
Version int `xml:"version,attr"`
Invoice []*XMLInvoice `xml:"INVOICE"`
}
type XMLInvoice struct {
XMLName xml.Name `xml:"INVOICE"`
Id int `xml:",attr"`
CustomerId int `xml:",attr"`
DepartmentId string `xml:",attr"`
Raised string `xml:",attr"`
Due string `xml:",attr"`
Paid bool `xml:",attr"`
Note string `xml:"NOTE"`
Item []*XMLItem `xml:"ITEM"`
}
type XMLItem struct {
XMLName xml.Name `xml:"ITEM"`
Id string `xml:",attr"`
Price float64 `xml:",attr"`
Quantity int `xml:",attr"`
TaxBand int `xml:",attr"`
Note string `xml:"NOTE"`
}
func XMLInvoicesForInvoices(invoices []*Invoice) *XMLInvoices {
xmlInvoices := &XMLInvoices{
Version: fileVersion,
Invoice: make([]*XMLInvoice, 0, len(invoices)),
}
for _, invoice := range invoices {
xmlInvoices.Invoice = append(xmlInvoices.Invoice,
XMLInvoiceForInvoice(invoice))
}
return xmlInvoices
}
func XMLInvoiceForInvoice(invoice *Invoice) *XMLInvoice {
xmlInvoice := &XMLInvoice{
Id: invoice.Id,
CustomerId: invoice.CustomerId,
DepartmentId: invoice.DepartmentId,
Raised: invoice.Raised.Format(dateFormat),
Due: invoice.Due.Format(dateFormat),
Paid: invoice.Paid,
Note: invoice.Note,
Item: make([]*XMLItem, 0, len(invoice.Items)),
}
for _, item := range invoice.Items {
xmlItem := &XMLItem{
Id: item.Id,
Price: item.Price,
Quantity: item.Quantity,
TaxBand: item.TaxBand,
Note: item.Note,
}
xmlInvoice.Item = append(xmlInvoice.Item, xmlItem)
}
return xmlInvoice
}
func (xmlInvoices *XMLInvoices) Invoices(version int) (invoices []*Invoice,
err error) {
invoices = make([]*Invoice, 0, len(xmlInvoices.Invoice))
for _, xmlInvoice := range xmlInvoices.Invoice {
invoice, err := xmlInvoice.Invoice(version)
if err != nil {
return nil, err
}
invoices = append(invoices, invoice)
}
return invoices, nil
}
func (xmlInvoice *XMLInvoice) Invoice(version int) (invoice *Invoice,
err error) {
invoice = &Invoice{
Id: xmlInvoice.Id,
CustomerId: xmlInvoice.CustomerId,
Paid: xmlInvoice.Paid,
Note: strings.TrimSpace(xmlInvoice.Note),
Items: make([]*Item, 0, len(xmlInvoice.Item)),
}
if version == fileVersion {
invoice.DepartmentId = xmlInvoice.DepartmentId
}
if invoice.Raised, err = time.Parse(dateFormat, xmlInvoice.Raised);
err != nil {
return nil, err
}
if invoice.Due, err = time.Parse(dateFormat, xmlInvoice.Due);
err != nil {
return nil, err
}
if invoice.Items, err = itemsForXMLItems(version, xmlInvoice.Item);
err != nil {
return nil, err
}
if version < fileVersion {
updateInvoice(invoice)
}
return invoice, nil
}
func itemsForXMLItems(version int, xmlItems []*XMLItem) (items []*Item,
err error) {
for _, xmlItem := range xmlItems {
item := &Item{
Id: xmlItem.Id,
Price: xmlItem.Price,
Quantity: xmlItem.Quantity,
Note: strings.TrimSpace(xmlItem.Note),
}
if version == fileVersion {
item.TaxBand = xmlItem.TaxBand
} else if version < fileVersion {
if err = updateItem(item); err != nil {
return nil, err
}
}
items = append(items, item)
}
return items, nil
}
func (XMLMarshaler) MarshalInvoices(writer io.Writer,
invoices []*Invoice) error {
if _, err := writer.Write([]byte(xml.Header)); err != nil {
return err
}
xmlInvoices := XMLInvoicesForInvoices(invoices)
encoder := xml.NewEncoder(writer)
return encoder.Encode(xmlInvoices)
}
func (XMLMarshaler) UnmarshalInvoices(reader io.Reader) ([]*Invoice,
error) {
xmlInvoices := &XMLInvoices{}
decoder := xml.NewDecoder(reader)
if err := decoder.Decode(xmlInvoices); err != nil {
return nil, err
}
if xmlInvoices.Version > fileVersion {
return nil, fmt.Errorf("version %d is too new to read",
xmlInvoices.Version)
}
return xmlInvoices.Invoices(xmlInvoices.Version)
}