diff --git a/README.md b/README.md index 98236f8..dbbdefb 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ action can be one of the following: is a text file with the following format (example line): -1020,Kontokorrent UBS 235-566236.01G +1020,A:Kontokorrent UBS 235-566236.01G 1020: Account number: 1XXX => Assets 2XXX => Liabilities @@ -28,6 +28,8 @@ action can be one of the following: 6XXX => Operating Expenses 8XXX => Expense +A: Type (A)ssets, (L)iabilities, (E)xpenses, (I)ncome + Kontokorrent UBS 235-566236.01G: Account Text is a CSV file with the following format (example line): diff --git a/bookkeeper.go b/bookkeeper.go index a65be18..b90781d 100644 --- a/bookkeeper.go +++ b/bookkeeper.go @@ -9,6 +9,7 @@ import ( "log" "os" "regexp" + "sort" "strconv" "strings" "time" @@ -43,13 +44,14 @@ var account_balance = make(map[string]Balance) var balanceYear = "UNDEFINED" const reportTitle = "Jahresrechnung - nbit Informatik GmbH" +const MWST_ACCOUNT = "2201" const defaultFontSize = 9 const smallFontSize = 7 const marginTop = 10 const smallLineSpacing = 4 const lineSpacing = 5 -const tabstopLeft = 25 -const tabstopRight = 100 +const tabstopLeft = 35 +const tabstopRight = 160 const widthAmount = 28 const dashCorrectionXleft = 1.2 const dashCorrectionXright = -1.3 @@ -64,8 +66,24 @@ func accountExists(s string) bool { return ok } +func accountType(s string) string { + return accounts[s][0:1] +} + +func accountDescription(s string) string { + return accounts[s][2:] +} + +func accountBalanceExists(s string) bool { + _, ok := account_balance[s] + return ok +} + +func calculateVAT(vat_code string, amount float64) float64 { + return 0.0 +} + 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) @@ -101,6 +119,45 @@ func addTransaction(document_number string, date string, text string, account_nu return } myItem.Vat_code = vat_code + myItem.Amount_Vat = calculateVAT(vat_code, myItem.Amount) + + // adjust balance values + var myBalance Balance + myBalance = account_balance[account_number_debit] + account_type := accountType(account_number_debit) + + if (account_type == "A") || (account_type == "E") || (account_type == "L") { + myBalance.balance_end = myBalance.balance_end + myItem.Amount + } else { + myBalance.balance_end = myBalance.balance_end - myItem.Amount + } + account_balance[account_number_debit] = myBalance + if account_number_debit == "2202" { + fmt.Printf("DEBUG DEBIT: %s,%s,%v,%v\n", account_number_debit, account_type, myItem.Amount, myBalance) + } + + myBalance = account_balance[account_number_credit] + account_type2 := accountType(account_number_credit) + if (account_type2 == "A") || (account_type2 == "E") || (account_type2 == "L") { + myBalance.balance_end = myBalance.balance_end - myItem.Amount + } else { + myBalance.balance_end = myBalance.balance_end + myItem.Amount + } + account_balance[account_number_credit] = myBalance + if account_number_credit == "2202" { + fmt.Printf("DEBUG CREDIT: %s,%s,%v,%v\n", account_number_credit, account_type2, myItem.Amount, myBalance) + } + + myBalance = account_balance[MWST_ACCOUNT] + myBalance.balance_end = myBalance.balance_end + myItem.Amount_Vat + account_balance[MWST_ACCOUNT] = myBalance + + //if account_number_debit == "3400" { + // fmt.Printf("DEBUG DEBIT: Document %s, found 3400 transaction: %v\n", document_number, amount) + // } + // if account_number_credit == "3400" { + // fmt.Printf("DEBUG CREDIT: Document %s, found 3400 transaction: %v\n", document_number, account_balance["3400"]) + // } _, ok := transactions[uint16(document_number_i)] if ok { @@ -126,15 +183,15 @@ func readAccountData(filename string) { line_number := 1 for scanner.Scan() { line := scanner.Text() - matched, _ := regexp.MatchString(`^[0-9][0-9][0-9][0-9],.*`, line) + matched, _ := regexp.MatchString(`^[0-9][0-9][0-9][0-9],[ALEI]:.*`, line) if !matched { - fmt.Printf("WARNING: Line %v in Accountfile %s: line not four digits followed by a comma: %s and will be ignored.\n", line_number, filename, line) + fmt.Printf("WARNING: Line %v in Accountfile %s: line not four digits followed by a comma followed by ALEI (one of those), Colon and description: %s and will be ignored.\n", line_number, filename, line) continue } token := strings.SplitN(line, ",", 2) account_number := token[0] - account_description := token[1] + account_type_and_description := token[1] if accountExists(account_number) { fmt.Printf("WARNING: Line %v in Accountfile %s: Account Number %s already exists and will be ignored\n", line_number, filename, account_number) @@ -142,7 +199,7 @@ func readAccountData(filename string) { } - accounts[account_number] = account_description + accounts[account_number] = account_type_and_description line_number++ } @@ -230,6 +287,7 @@ func readTransactionData(filename string) { if err := scanner.Err(); err != nil { log.Fatal(err) } + //fmt.Printf("DEBUG BLABLA: %v\n", account_balance["3400"]) } func writeText(x float64, y float64, w float64, text string, alignStr ...string) { @@ -265,20 +323,21 @@ func printPageHeader() { func printSection(section string) { var title string - var chars string + var change_sign bool = false switch section { - case "assets": + // Assets + case "A": title = "AKTIVEN" - chars = "1" - case "liabilities": + // Liabilities + case "L": title = "PASSIVEN" - chars = "2" - case "expense": + change_sign = true + // Expense + case "E": title = "AUFWAND" - chars = "568" - case "income": + // Income + case "I": title = "ERTRAG" - chars = "4" default: fmt.Printf("WARNING: invalid section: %s\n", section) return @@ -291,12 +350,26 @@ func printSection(section string) { yPos = yPos + smallLineSpacing pdf.SetFont("Dejavusans", "", smallFontSize) pdf.SetDashPattern([]float64{0.2, 0.2}, 0) - for key, element := range account_balance { - if strings.Contains(chars, key[0:1]) { - writeText(tabstopLeft, yPos, 0, accounts[key]) - writeText(tabstopRight, yPos, widthAmount, floatToString(element.balance_end, "'"), "TR") + + // Extract keys from map + keys := make([]string, 0, len(account_balance)) + for k := range account_balance { + keys = append(keys, k) + } + + // Sort keys + sort.Strings(keys) + + for _, key := range keys { + if accountType(key) == section { + writeText(tabstopLeft, yPos, 0, key+": "+accountDescription(key)) + balance_end := account_balance[key].balance_end + if change_sign { + balance_end = 0 - balance_end + } + writeText(tabstopRight, yPos, widthAmount, floatToString(balance_end, "'"), "TR") pdf.Line(tabstopLeft+dashCorrectionXleft, yPos+dashCorrectionY, tabstopRight+widthAmount+dashCorrectionXright, yPos+dashCorrectionY) - total = total + element.balance_end + total = total + balance_end yPos = yPos + smallLineSpacing } } @@ -310,10 +383,10 @@ func printSection(section string) { func createBalanceSheet() { setupBalanceSheet() printPageHeader() - printSection("assets") - printSection("liabilities") - printSection("expense") - printSection("income") + printSection("A") + printSection("L") + printSection("E") + printSection("I") err := pdf.OutputFileAndClose("output.pdf") if err == nil { fmt.Printf("Successfully created Balance Sheet in file output.pdf\n") @@ -339,6 +412,7 @@ func main() { //fmt.Printf("accounts: %#v\n", accounts) //fmt.Printf("transactions: %#v\n", transactions) + fmt.Printf("transactions: %#v\n", transactions[18]) //fmt.Printf("account_balance: %#v\n", account_balance) switch action := os.Args[1]; action {