288 lines
7.0 KiB
Go
288 lines
7.0 KiB
Go
package main
|
|
|
|
import (
|
|
"bufio"
|
|
"fmt"
|
|
"github.com/go-pdf/fpdf"
|
|
"log"
|
|
"os"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
/* own types */
|
|
type TransactionItem struct {
|
|
Description string
|
|
Debit string
|
|
Credit string
|
|
Amount float64
|
|
Vat_code string
|
|
Amount_Vat float64
|
|
}
|
|
|
|
type Transaction struct {
|
|
Date time.Time
|
|
Items []TransactionItem
|
|
}
|
|
|
|
/* global variable declaration */
|
|
var pdf *fpdf.Fpdf
|
|
var yPos float64
|
|
var accounts = make(map[string]string)
|
|
var transactions = make(map[uint16]Transaction)
|
|
var account_balance = make(map[string]string)
|
|
var yearEndDate = "YEARENDDATE"
|
|
|
|
const reportTitle = "Jahresrechnung - nbit Informatik GmbH"
|
|
const defaultFontSize = 9
|
|
const marginTop = 10
|
|
const lineSpacing = 5
|
|
const tabstopLeft = 20
|
|
|
|
//func round5rappen(f float64) float64 {
|
|
// return (math.Round(f*20) / 20)
|
|
//}
|
|
|
|
func accountExists(s string) bool {
|
|
_, ok := accounts[s]
|
|
return ok
|
|
}
|
|
|
|
func addTransaction(document_number string, date string, text string, account_number_debit string, account_number_credit string, amount string, vat_code string) {
|
|
//fmt.Printf("Calling addTransaction with amount: %s\n", amount)
|
|
dateString := "02.01.2006"
|
|
mydate, error := time.Parse(dateString, date)
|
|
|
|
if error != nil {
|
|
fmt.Println(error)
|
|
return
|
|
}
|
|
|
|
var myItem TransactionItem
|
|
|
|
document_number_i, err := strconv.ParseInt(document_number, 0, 16)
|
|
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
myItem.Description = text
|
|
myItem.Debit = account_number_debit
|
|
myItem.Credit = account_number_credit
|
|
if s, err := strconv.ParseFloat(amount, 64); err == nil {
|
|
myItem.Amount = s
|
|
} else {
|
|
fmt.Printf("Cannot convert Amount to Float64: %s\n", amount)
|
|
}
|
|
myItem.Vat_code = vat_code
|
|
|
|
_, ok := transactions[uint16(document_number_i)]
|
|
if ok {
|
|
newtransactions := transactions[uint16(document_number_i)]
|
|
newtransactions.Items = append(newtransactions.Items, myItem)
|
|
transactions[uint16(document_number_i)] = newtransactions
|
|
} else {
|
|
var t Transaction
|
|
t.Date = mydate
|
|
t.Items = append(t.Items, myItem)
|
|
transactions[uint16(document_number_i)] = t
|
|
}
|
|
}
|
|
|
|
func readAccountData(filename string) {
|
|
file, err := os.Open(filename)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defer file.Close()
|
|
|
|
scanner := bufio.NewScanner(file)
|
|
line_number := 1
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
matched, _ := regexp.MatchString(`^[0-9][0-9][0-9][0-9],.*`, line)
|
|
if !matched {
|
|
fmt.Printf("Line %v in Accountfile %s: line not four digits followed by a comma: %s.\n", line_number, filename, line)
|
|
os.Exit(3)
|
|
}
|
|
|
|
token := strings.SplitN(line, ",", 2)
|
|
account_number := token[0]
|
|
account_description := token[1]
|
|
|
|
if accountExists(account_number) {
|
|
fmt.Printf("Line %v in Accountfile %s: Account Number %s already exists\n", line_number, filename, account_number)
|
|
os.Exit(4)
|
|
|
|
}
|
|
|
|
accounts[account_number] = account_description
|
|
|
|
line_number++
|
|
}
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func readTransactionData(filename string) {
|
|
file, err := os.Open(filename)
|
|
if err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
defer file.Close()
|
|
|
|
scanner := bufio.NewScanner(file)
|
|
line_number := 1
|
|
for scanner.Scan() {
|
|
line := scanner.Text()
|
|
matched, _ := regexp.MatchString(`^[0-9]+,[0-9][0-9]\.[0-9][0-9]\.[0-9][0-9][0-9][0-9],.*,[0-9][0-9][0-9][0-9],[0-9][0-9][0-9][0-9],-?[0-9]+\.[0-9][0-9],.*`, line)
|
|
if matched {
|
|
token := strings.Split(line, ",")
|
|
document_number := token[0]
|
|
date := token[1]
|
|
text := strings.Replace(token[2], "@", ",", -1)
|
|
account_number_debit := token[3]
|
|
account_number_credit := token[4]
|
|
amount := token[5]
|
|
vat_code := token[6]
|
|
|
|
if !accountExists(account_number_debit) {
|
|
fmt.Printf("Line %v in Transactionfile %s: Account Number Debit %s does not exist\n", line_number, filename, account_number_debit)
|
|
os.Exit(4)
|
|
}
|
|
if !accountExists(account_number_credit) {
|
|
fmt.Printf("Line %v in Transactionfile %s: Account Number Credit %s does not exist\n", line_number, filename, account_number_credit)
|
|
os.Exit(4)
|
|
}
|
|
|
|
addTransaction(document_number, date, text, account_number_debit, account_number_credit, amount, vat_code)
|
|
|
|
} else {
|
|
matched2, _ := regexp.MatchString(`^[0-9][0-9][0-9][0-9]:-?[0-9]+\.[0-9][0-9]$`, line)
|
|
if matched2 {
|
|
token := strings.Split(line, ":")
|
|
account_number := token[0]
|
|
balance := token[1]
|
|
if !accountExists(account_number) {
|
|
fmt.Printf("Line %v in Transactionfile %s: Account Number %s does not exist\n", line_number, filename, account_number)
|
|
os.Exit(4)
|
|
}
|
|
|
|
account_balance[account_number] = balance
|
|
|
|
} else {
|
|
fmt.Printf("Line %v in Transactionfile %s is not of the form <document number>,<date>,<text>,<account number debit>,<account number credit>,<amount>,<vat code>.\n", line_number, filename, line)
|
|
os.Exit(3)
|
|
}
|
|
line_number++
|
|
}
|
|
}
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
log.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func writeText(x float64, y float64, w float64, text string, alignStr ...string) {
|
|
tr := pdf.UnicodeTranslatorFromDescriptor("")
|
|
align := "LT"
|
|
if len(alignStr) > 0 {
|
|
align = alignStr[0]
|
|
}
|
|
pdf.SetXY(x, y)
|
|
pdf.CellFormat(w, 11, tr(text), "", 0, align, false, 0, "")
|
|
}
|
|
|
|
func setupBalanceSheet() {
|
|
pdf = fpdf.New("P", "mm", "A4", "")
|
|
pdf.SetMargins(0, 0, 0)
|
|
pdf.SetAutoPageBreak(false, 0)
|
|
pdf.SetFontLocation("fonts")
|
|
pdf.AddFont("Dejavusans", "", "DejaVuSans.json")
|
|
pdf.AddFont("Dejavusans-Bold", "", "DejaVuSans-Bold.json")
|
|
pdf.SetFont("Dejavusans", "", defaultFontSize)
|
|
}
|
|
|
|
func printPageHeader() {
|
|
pdf.AddPage()
|
|
yPos = marginTop
|
|
pdf.SetFont("Dejavusans-Bold", "", defaultFontSize)
|
|
writeText(tabstopLeft, yPos, 0, reportTitle)
|
|
yPos = yPos + lineSpacing
|
|
pdf.SetFont("Dejavusans", "", defaultFontSize)
|
|
writeText(tabstopLeft, yPos, 0, "per "+yearEndDate)
|
|
}
|
|
|
|
func printAssets() {
|
|
}
|
|
|
|
func printLiabilities() {
|
|
}
|
|
|
|
func printExpenses() {
|
|
}
|
|
|
|
func printIncome() {
|
|
}
|
|
|
|
func createBalanceSheet() {
|
|
setupBalanceSheet()
|
|
printPageHeader()
|
|
printAssets()
|
|
printLiabilities()
|
|
printExpenses()
|
|
printIncome()
|
|
err := pdf.OutputFileAndClose("output.pdf")
|
|
if err == nil {
|
|
fmt.Printf("Successfully created Balance Sheet in file output.pdf\n")
|
|
} else {
|
|
fmt.Printf("Error: %v\n", err)
|
|
}
|
|
}
|
|
|
|
func usage() {
|
|
fmt.Printf("usage: bookkeeper <action> <accounts file> <transactions file>\n")
|
|
fmt.Printf("\n")
|
|
fmt.Printf("Valid actions: check, balance, journal, mwst1, mwst2, mwst3, mwst4, new_year\n")
|
|
os.Exit(1)
|
|
}
|
|
|
|
func main() {
|
|
if len(os.Args) != 4 {
|
|
usage()
|
|
}
|
|
|
|
readAccountData(os.Args[2])
|
|
readTransactionData(os.Args[3])
|
|
|
|
//fmt.Printf("accounts: %#v\n", accounts)
|
|
//fmt.Printf("transactions: %#v\n", transactions)
|
|
//fmt.Printf("account_balance: %#v\n", account_balance)
|
|
|
|
switch action := os.Args[1]; action {
|
|
case "check":
|
|
fmt.Println("Check Data")
|
|
case "balance":
|
|
fmt.Println("Create Balance Sheet")
|
|
createBalanceSheet()
|
|
case "journal":
|
|
fmt.Println("Create Journal")
|
|
case "mwst1":
|
|
fmt.Println("Create Mwst1")
|
|
case "mstw2":
|
|
fmt.Println("Create Mwst2")
|
|
case "mwst3":
|
|
fmt.Println("Create Mwst3")
|
|
case "mwst4":
|
|
fmt.Println("Create Mwst4")
|
|
case "new_year":
|
|
fmt.Println("Create New Year")
|
|
default:
|
|
usage()
|
|
}
|
|
|
|
}
|