diff --git a/bookkeeper.go b/bookkeeper.go index bd50617..ce8e922 100644 --- a/bookkeeper.go +++ b/bookkeeper.go @@ -100,7 +100,7 @@ func calculateVAT(vat_code string, amount float64) float64 { vat_type := string(vat_code[0]) vat_perc, err := strconv.Atoi(vat_code[1:]) if err != nil { - fmt.Printf("ERROR: %v\n", err) + fmt.Fprintf(os.Stderr, "ERROR: %v\n", err) return 0.0 } vat_perc_f64 := float64(vat_perc) @@ -109,7 +109,7 @@ func calculateVAT(vat_code string, amount float64) float64 { } else if vat_type == "I" { return roundRappen(amount / (1000.0 + vat_perc_f64) * vat_perc_f64) } else { - fmt.Printf("WARNING: Invalid Vat Type: %s\n", vat_type) + fmt.Fprintf(os.Stderr, "WARNING: Invalid Vat Type: %s\n", vat_type) return 0.0 } } @@ -119,7 +119,7 @@ func addTransaction(document_number string, date string, text string, account_nu mydate, error := time.Parse(dateString, date) if error != nil { - fmt.Printf("ERROR: %v\n", error) + fmt.Fprintf(os.Stderr, "ERROR: %v\n", error) return } @@ -128,7 +128,7 @@ func addTransaction(document_number string, date string, text string, account_nu balanceYear = date[6:10] } else { if date[6:10] != balanceYear { - fmt.Printf("WARNING: transaction with Document Number %s is not in same year as first transaction: %s and will be ignored\n", document_number, balanceYear) + fmt.Fprintf(os.Stderr, "WARNING: transaction with Document Number %s is not in same year as first transaction: %s and will be ignored\n", document_number, balanceYear) return } } @@ -146,7 +146,7 @@ func addTransaction(document_number string, date string, text string, account_nu if s, err := strconv.ParseFloat(amount, 64); err == nil { myItem.Amount = roundRappen(s) } else { - fmt.Printf("WARNING: Document %s, cannot convert Amount to Float64: %s and will be ignored\n", document_number, amount) + fmt.Fprintf(os.Stderr, "WARNING: Document %s, cannot convert Amount to Float64: %s and will be ignored\n", document_number, amount) return } myItem.Vat_code = vat_code @@ -209,7 +209,7 @@ func readAccountData(filename string) { line := scanner.Text() 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 followed by ALEI (one of those), Colon and description: %s and will be ignored.\n", line_number, filename, line) + fmt.Fprintf(os.Stderr, "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 } @@ -218,7 +218,7 @@ func readAccountData(filename string) { 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) + fmt.Fprintf(os.Stderr, "WARNING: Line %v in Accountfile %s: Account Number %s already exists and will be ignored\n", line_number, filename, account_number) continue } @@ -240,7 +240,7 @@ func floatToString(f float64, sep string) string { s = "-.-" } else { s = strings.ReplaceAll(p.Sprintf("%.2f", f), ",", sep) - //fmt.Printf("--- s: @%s@\n", s) + //fmt.Fprintf(os.Stderr,"--- s: @%s@\n", s) } return s } @@ -249,7 +249,7 @@ func str2float64(f string) float64 { if s, err := strconv.ParseFloat(f, 64); err == nil { return roundRappen(s) } else { - fmt.Printf("WARNING: cannot convert Amount to Float64: %s and will be ignored\n", f) + fmt.Fprintf(os.Stderr, "WARNING: cannot convert Amount to Float64: %s and will be ignored\n", f) return 0 } } @@ -277,11 +277,11 @@ func readTransactionData(filename string) { vat_code := token[6] if !accountExists(account_number_debit) { - fmt.Printf("WARNING: Line %v in Transactionfile %s: Account Number Debit %s does not exist, and will be ignored\n", line_number, filename, account_number_debit) + fmt.Fprintf(os.Stderr, "WARNING: Line %v in Transactionfile %s: Account Number Debit %s does not exist, and will be ignored\n", line_number, filename, account_number_debit) continue } if !accountExists(account_number_credit) { - fmt.Printf("WARNING: Line %v in Transactionfile %s: Account Number Credit %s does not exist and will be ignored\n", line_number, filename, account_number_credit) + fmt.Fprintf(os.Stderr, "WARNING: Line %v in Transactionfile %s: Account Number Credit %s does not exist and will be ignored\n", line_number, filename, account_number_credit) continue } @@ -294,7 +294,7 @@ func readTransactionData(filename string) { account_number := token[0] balance := token[1] if !accountExists(account_number) { - fmt.Printf("WARNING: Line %v in Transactionfile %s: Account Number %s does not exist and will be ignored\n", line_number, filename, account_number) + fmt.Fprintf(os.Stderr, "WARNING: Line %v in Transactionfile %s: Account Number %s does not exist and will be ignored\n", line_number, filename, account_number) continue } @@ -306,7 +306,7 @@ func readTransactionData(filename string) { account_balance[account_number] = myBalance } else { - fmt.Printf("WARNING: Line %v in Transactionfile %s is not of the form ,,,,,, and will be ignored.\n", line_number, filename, line) + fmt.Fprintf(os.Stderr, "WARNING: Line %v in Transactionfile %s is not of the form ,,,,,, and will be ignored.\n", line_number, filename, line) continue } line_number++ @@ -367,7 +367,7 @@ func printSection(section string) { case "I": title = "ERTRAG" default: - fmt.Printf("WARNING: invalid section: %s\n", section) + fmt.Fprintf(os.Stderr, "WARNING: invalid section: %s\n", section) return } @@ -462,9 +462,9 @@ func createBalanceSheet() { printSection("I") err := pdf.OutputFileAndClose("output.pdf") if err == nil { - fmt.Printf("INFO: Successfully created Balance Sheet in file output.pdf\n") + fmt.Fprintf(os.Stderr, "INFO: Successfully created Balance Sheet in file output.pdf\n") } else { - fmt.Printf("ERROR: %v\n", err) + fmt.Fprintf(os.Stderr, "ERROR: %v\n", err) } } @@ -482,26 +482,163 @@ func calculateProfit() float64 { } res = roundRappen(res) - fmt.Printf("INFO: Calculated Profit: %v\n", res) + fmt.Fprintf(os.Stderr, "INFO: Calculated Profit: %v\n", res) return res } +func transactionInQuarter(date time.Time, whatquarter string) bool { + month := date.Month() + switch month { + case 1, 2, 3: + return whatquarter == "mwst1" + case 4, 5, 6: + return whatquarter == "mwst2" + case 7, 8, 9: + return whatquarter == "mwst3" + case 10, 11, 12: + return whatquarter == "mwst4" + } + return false +} + +func getTotalConsideration(whatquarter string) float64 { + //"43517.04" + var res float64 = 0.0 + + for key := range transactions { + if transactionInQuarter(transactions[key].Date, whatquarter) { + for _, item := range transactions[key].Items { + if strings.HasPrefix(item.Vat_code, "V") { + res = res + item.Amount + item.Amount_Vat + } + } + } + + } + + res = roundRappen(res) + fmt.Fprintf(os.Stderr, "INFO: Calculated Total Consideration: %v\n", res) + return res + +} + +func getVat(vat_code string) string { + // strip first letter, divide by 10 + // ie.: V77 => 7.7, V80 => 8.0 + if s, err := strconv.ParseFloat(vat_code[1:], 64); err == nil { + return fmt.Sprintf("%.2f", s/10.0) + } else { + fmt.Fprintf(os.Stderr, "WARNING: Invalid VAT Code %s\n", vat_code) + return vat_code + } +} + +func getDataTaxRates(whatquarter string) map[string]string { + //map[string]string{"7.70": "43517.04", "8.0": "Test only"} + //var m = map[string]string{ + // "7.70": "43517.04", + // "8.0": "Test only", + // } + var m = map[string]string{} + var mn = map[string]float64{} + + for key := range transactions { + if transactionInQuarter(transactions[key].Date, whatquarter) { + for _, item := range transactions[key].Items { + if strings.HasPrefix(item.Vat_code, "V") { + vat := getVat(item.Vat_code) + if val, found := mn[vat]; found { + mn[vat] = val + item.Amount + item.Amount_Vat + } else { + mn[vat] = item.Amount + item.Amount_Vat + } + } + } + } + + } + + for key, value := range mn { + m[key] = floatToString(roundRappen(value), "") + } + + fmt.Fprintf(os.Stderr, "INFO: getDataTaxRates: %v\n", m) + return m + +} + +func getTaxInvestments(whatquarter string) float64 { + // "174.09" + var res float64 = 0.0 + + for key := range transactions { + if transactionInQuarter(transactions[key].Date, whatquarter) { + for _, item := range transactions[key].Items { + if strings.HasPrefix(item.Vat_code, "I") { + res = res + item.Amount_Vat + } + } + } + + } + + res = roundRappen(res) + fmt.Fprintf(os.Stderr, "INFO: Calculated Tax Investments: %v\n", res) + return res +} + +func getPayableTax(whatquarter string) float64 { + // "3176.72" + var res float64 = 0.0 + + for key := range transactions { + if transactionInQuarter(transactions[key].Date, whatquarter) { + for _, item := range transactions[key].Items { + res = res + item.Amount_Vat + } + } + + } + + res = roundRappen(res) + fmt.Fprintf(os.Stderr, "INFO: Calculated Payable Tax: %v\n", res) + return 0 - res +} + func outputMwst(whatquarter string) { - fmt.Printf("Create Mwst Report for %s\n", whatquarter) + fmt.Fprintf(os.Stderr, "INFO: Create Mwst Report for %s\n", whatquarter) tm := time.Now() gmt_location := time.FixedZone("GMT", 0) + const refidPrefix = "ef1q2024_" + var refid string var data Data data.GenerationTime = fmt.Sprintf("%s", tm.In(gmt_location).Format("2006-01-02T15:04:05Z")) - data.ReportingPeriodFrom = "2022-01-01" - data.ReportingPeriodFrom = "2022-03-31" - data.BusinessReferenceId = "ef1q2024_20220101_20220331_1" - data.TotalConsideration = "43517.04" - data.DataTaxRates = map[string]string{"7.70": "43517.04", "8.0": "Test only"} - data.InputTaxInvestments = "174.09" - data.PayableTax = "3176.72" + switch whatquarter { + case "mwst1": + data.ReportingPeriodFrom = balanceYear + "-01-01" + data.ReportingPeriodTill = balanceYear + "-03-31" + refid = refidPrefix + balanceYear + "0101_" + balanceYear + "0331_1" + case "mwst2": + data.ReportingPeriodFrom = balanceYear + "-04-01" + data.ReportingPeriodTill = balanceYear + "-06-30" + refid = refidPrefix + balanceYear + "0401_" + balanceYear + "0630_1" + case "mwst3": + data.ReportingPeriodFrom = balanceYear + "-07-01" + data.ReportingPeriodTill = balanceYear + "-09-30" + refid = refidPrefix + balanceYear + "0701_" + balanceYear + "0930_1" + case "mwst4": + data.ReportingPeriodFrom = balanceYear + "-10-01" + data.ReportingPeriodTill = balanceYear + "-12-31" + refid = refidPrefix + balanceYear + "1001_" + balanceYear + "1231_1" + } + data.BusinessReferenceId = refid + data.TotalConsideration = floatToString(getTotalConsideration(whatquarter), "") + data.DataTaxRates = getDataTaxRates(whatquarter) + data.InputTaxInvestments = floatToString(getTaxInvestments(whatquarter), "") + data.PayableTax = floatToString(getPayableTax(whatquarter), "") tmp, err := template.ParseFiles("vat_xml.tmpl") @@ -517,9 +654,9 @@ func outputMwst(whatquarter string) { } func usage() { - fmt.Printf("usage: bookkeeper \n") - fmt.Printf("\n") - fmt.Printf("Valid actions: check, balance, journal, mwst1, mwst2, mwst3, mwst4, new_year\n") + fmt.Fprintf(os.Stderr, "usage: bookkeeper \n") + fmt.Fprintf(os.Stderr, "\n") + fmt.Fprintf(os.Stderr, "Valid actions: check, balance, journal, mwst1, mwst2, mwst3, mwst4, new_year\n") os.Exit(1) } @@ -532,23 +669,23 @@ func main() { readTransactionData(os.Args[3]) profit = calculateProfit() - //fmt.Printf("accounts: %#v\n", accounts) - //fmt.Printf("transactions: %#v\n", transactions) - //fmt.Printf("account_balance: %#v\n", account_balance) + //fmt.Fprintf(os.Stderr,"accounts: %#v\n", accounts) + //fmt.Fprintf(os.Stderr,"transactions: %#v\n", transactions) + //fmt.Fprintf(os.Stderr,"account_balance: %#v\n", account_balance) switch action := os.Args[1]; action { case "check": - fmt.Println("Check Data") + fmt.Fprintln(os.Stderr, "Check Data") case "balance": - fmt.Println("Create Balance Sheet") + fmt.Fprintln(os.Stderr, "INFO: Create Balance Sheet") createBalanceSheet() case "journal": - fmt.Println("Create Journal") + fmt.Fprintln(os.Stderr, "INFO: Create Journal") case "mwst1", "mwst2", "mwst3", "mwst4": - fmt.Println("Create Mwst Quarterly Report") + fmt.Fprintln(os.Stderr, "INFO: Create Mwst Quarterly Report") outputMwst(action) case "new_year": - fmt.Println("Create New Year") + fmt.Fprintln(os.Stderr, "INFO: Create New Year") default: usage() } diff --git a/vat_xml.tmpl b/vat_xml.tmpl index 148c490..442873f 100644 --- a/vat_xml.tmpl +++ b/vat_xml.tmpl @@ -1,6 +1,5 @@ - - - + + CHE