VAT XMLs first working version

This commit is contained in:
Joerg Lehmann 2024-01-09 19:15:31 +01:00
parent 9684daedb6
commit fcc4d96660
2 changed files with 175 additions and 39 deletions

View File

@ -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 <document number>,<date>,<text>,<account number debit>,<account number credit>,<amount>,<vat code> and will be ignored.\n", line_number, filename, line)
fmt.Fprintf(os.Stderr, "WARNING: Line %v in Transactionfile %s is not of the form <document number>,<date>,<text>,<account number debit>,<account number credit>,<amount>,<vat code> 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 <action> <accounts file> <transactions file>\n")
fmt.Printf("\n")
fmt.Printf("Valid actions: check, balance, journal, mwst1, mwst2, mwst3, mwst4, new_year\n")
fmt.Fprintf(os.Stderr, "usage: bookkeeper <action> <accounts file> <transactions file>\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()
}

View File

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<eCH-0217:VATDeclaration xsi:schemaLocation="http://www.ech.ch/xmlns/eCH-0217/1 eCH-0217-1-0.xsd" xmlns:eCH-0217="http://www.ech.ch/xmlns/eCH-0217/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:eCH-0097="http://www.ech.ch/xmlns/eCH-0097/3" xmlns:eCH-0058="http://www.ech.ch/xmlns/eCH-0058/5">
<?xml version="1.0" encoding="UTF-8"?>
<eCH-0217:VATDeclaration xsi:schemaLocation="http://www.ech.ch/xmlns/eCH-0217/1/eCH-0217-1-0.xsd" xmlns:eCH-0058="http://www.ech.ch/xmlns/eCH-0058/5" xmlns:eCH-0097="http://www.ech.ch/xmlns/eCH-0097/3" xmlns:eCH-0217="http://www.ech.ch/xmlns/eCH-0217/1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<eCH-0217:generalInformation>
<eCH-0217:uid>
<eCH-0097:uidOrganisationIdCategorie>CHE</eCH-0097:uidOrganisationIdCategorie>