VAT XMLs first working version
This commit is contained in:
parent
9684daedb6
commit
fcc4d96660
209
bookkeeper.go
209
bookkeeper.go
|
|
@ -100,7 +100,7 @@ func calculateVAT(vat_code string, amount float64) float64 {
|
||||||
vat_type := string(vat_code[0])
|
vat_type := string(vat_code[0])
|
||||||
vat_perc, err := strconv.Atoi(vat_code[1:])
|
vat_perc, err := strconv.Atoi(vat_code[1:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Printf("ERROR: %v\n", err)
|
fmt.Fprintf(os.Stderr, "ERROR: %v\n", err)
|
||||||
return 0.0
|
return 0.0
|
||||||
}
|
}
|
||||||
vat_perc_f64 := float64(vat_perc)
|
vat_perc_f64 := float64(vat_perc)
|
||||||
|
|
@ -109,7 +109,7 @@ func calculateVAT(vat_code string, amount float64) float64 {
|
||||||
} else if vat_type == "I" {
|
} else if vat_type == "I" {
|
||||||
return roundRappen(amount / (1000.0 + vat_perc_f64) * vat_perc_f64)
|
return roundRappen(amount / (1000.0 + vat_perc_f64) * vat_perc_f64)
|
||||||
} else {
|
} 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
|
return 0.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -119,7 +119,7 @@ func addTransaction(document_number string, date string, text string, account_nu
|
||||||
mydate, error := time.Parse(dateString, date)
|
mydate, error := time.Parse(dateString, date)
|
||||||
|
|
||||||
if error != nil {
|
if error != nil {
|
||||||
fmt.Printf("ERROR: %v\n", error)
|
fmt.Fprintf(os.Stderr, "ERROR: %v\n", error)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -128,7 +128,7 @@ func addTransaction(document_number string, date string, text string, account_nu
|
||||||
balanceYear = date[6:10]
|
balanceYear = date[6:10]
|
||||||
} else {
|
} else {
|
||||||
if date[6:10] != balanceYear {
|
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
|
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 {
|
if s, err := strconv.ParseFloat(amount, 64); err == nil {
|
||||||
myItem.Amount = roundRappen(s)
|
myItem.Amount = roundRappen(s)
|
||||||
} else {
|
} 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
|
return
|
||||||
}
|
}
|
||||||
myItem.Vat_code = vat_code
|
myItem.Vat_code = vat_code
|
||||||
|
|
@ -209,7 +209,7 @@ func readAccountData(filename string) {
|
||||||
line := scanner.Text()
|
line := scanner.Text()
|
||||||
matched, _ := regexp.MatchString(`^[0-9][0-9][0-9][0-9],[ALEI]:.*`, line)
|
matched, _ := regexp.MatchString(`^[0-9][0-9][0-9][0-9],[ALEI]:.*`, line)
|
||||||
if !matched {
|
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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -218,7 +218,7 @@ func readAccountData(filename string) {
|
||||||
account_type_and_description := token[1]
|
account_type_and_description := token[1]
|
||||||
|
|
||||||
if accountExists(account_number) {
|
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
|
continue
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -240,7 +240,7 @@ func floatToString(f float64, sep string) string {
|
||||||
s = "-.-"
|
s = "-.-"
|
||||||
} else {
|
} else {
|
||||||
s = strings.ReplaceAll(p.Sprintf("%.2f", f), ",", sep)
|
s = strings.ReplaceAll(p.Sprintf("%.2f", f), ",", sep)
|
||||||
//fmt.Printf("--- s: @%s@\n", s)
|
//fmt.Fprintf(os.Stderr,"--- s: @%s@\n", s)
|
||||||
}
|
}
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
@ -249,7 +249,7 @@ func str2float64(f string) float64 {
|
||||||
if s, err := strconv.ParseFloat(f, 64); err == nil {
|
if s, err := strconv.ParseFloat(f, 64); err == nil {
|
||||||
return roundRappen(s)
|
return roundRappen(s)
|
||||||
} else {
|
} 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
|
return 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -277,11 +277,11 @@ func readTransactionData(filename string) {
|
||||||
vat_code := token[6]
|
vat_code := token[6]
|
||||||
|
|
||||||
if !accountExists(account_number_debit) {
|
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
|
continue
|
||||||
}
|
}
|
||||||
if !accountExists(account_number_credit) {
|
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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -294,7 +294,7 @@ func readTransactionData(filename string) {
|
||||||
account_number := token[0]
|
account_number := token[0]
|
||||||
balance := token[1]
|
balance := token[1]
|
||||||
if !accountExists(account_number) {
|
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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -306,7 +306,7 @@ func readTransactionData(filename string) {
|
||||||
account_balance[account_number] = myBalance
|
account_balance[account_number] = myBalance
|
||||||
|
|
||||||
} else {
|
} 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
|
continue
|
||||||
}
|
}
|
||||||
line_number++
|
line_number++
|
||||||
|
|
@ -367,7 +367,7 @@ func printSection(section string) {
|
||||||
case "I":
|
case "I":
|
||||||
title = "ERTRAG"
|
title = "ERTRAG"
|
||||||
default:
|
default:
|
||||||
fmt.Printf("WARNING: invalid section: %s\n", section)
|
fmt.Fprintf(os.Stderr, "WARNING: invalid section: %s\n", section)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -462,9 +462,9 @@ func createBalanceSheet() {
|
||||||
printSection("I")
|
printSection("I")
|
||||||
err := pdf.OutputFileAndClose("output.pdf")
|
err := pdf.OutputFileAndClose("output.pdf")
|
||||||
if err == nil {
|
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 {
|
} 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)
|
res = roundRappen(res)
|
||||||
fmt.Printf("INFO: Calculated Profit: %v\n", res)
|
fmt.Fprintf(os.Stderr, "INFO: Calculated Profit: %v\n", res)
|
||||||
return 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) {
|
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()
|
tm := time.Now()
|
||||||
gmt_location := time.FixedZone("GMT", 0)
|
gmt_location := time.FixedZone("GMT", 0)
|
||||||
|
const refidPrefix = "ef1q2024_"
|
||||||
|
var refid string
|
||||||
|
|
||||||
var data Data
|
var data Data
|
||||||
data.GenerationTime = fmt.Sprintf("%s", tm.In(gmt_location).Format("2006-01-02T15:04:05Z"))
|
data.GenerationTime = fmt.Sprintf("%s", tm.In(gmt_location).Format("2006-01-02T15:04:05Z"))
|
||||||
data.ReportingPeriodFrom = "2022-01-01"
|
switch whatquarter {
|
||||||
data.ReportingPeriodFrom = "2022-03-31"
|
case "mwst1":
|
||||||
data.BusinessReferenceId = "ef1q2024_20220101_20220331_1"
|
data.ReportingPeriodFrom = balanceYear + "-01-01"
|
||||||
data.TotalConsideration = "43517.04"
|
data.ReportingPeriodTill = balanceYear + "-03-31"
|
||||||
data.DataTaxRates = map[string]string{"7.70": "43517.04", "8.0": "Test only"}
|
refid = refidPrefix + balanceYear + "0101_" + balanceYear + "0331_1"
|
||||||
data.InputTaxInvestments = "174.09"
|
case "mwst2":
|
||||||
data.PayableTax = "3176.72"
|
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")
|
tmp, err := template.ParseFiles("vat_xml.tmpl")
|
||||||
|
|
||||||
|
|
@ -517,9 +654,9 @@ func outputMwst(whatquarter string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func usage() {
|
func usage() {
|
||||||
fmt.Printf("usage: bookkeeper <action> <accounts file> <transactions file>\n")
|
fmt.Fprintf(os.Stderr, "usage: bookkeeper <action> <accounts file> <transactions file>\n")
|
||||||
fmt.Printf("\n")
|
fmt.Fprintf(os.Stderr, "\n")
|
||||||
fmt.Printf("Valid actions: check, balance, journal, mwst1, mwst2, mwst3, mwst4, new_year\n")
|
fmt.Fprintf(os.Stderr, "Valid actions: check, balance, journal, mwst1, mwst2, mwst3, mwst4, new_year\n")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -532,23 +669,23 @@ func main() {
|
||||||
readTransactionData(os.Args[3])
|
readTransactionData(os.Args[3])
|
||||||
profit = calculateProfit()
|
profit = calculateProfit()
|
||||||
|
|
||||||
//fmt.Printf("accounts: %#v\n", accounts)
|
//fmt.Fprintf(os.Stderr,"accounts: %#v\n", accounts)
|
||||||
//fmt.Printf("transactions: %#v\n", transactions)
|
//fmt.Fprintf(os.Stderr,"transactions: %#v\n", transactions)
|
||||||
//fmt.Printf("account_balance: %#v\n", account_balance)
|
//fmt.Fprintf(os.Stderr,"account_balance: %#v\n", account_balance)
|
||||||
|
|
||||||
switch action := os.Args[1]; action {
|
switch action := os.Args[1]; action {
|
||||||
case "check":
|
case "check":
|
||||||
fmt.Println("Check Data")
|
fmt.Fprintln(os.Stderr, "Check Data")
|
||||||
case "balance":
|
case "balance":
|
||||||
fmt.Println("Create Balance Sheet")
|
fmt.Fprintln(os.Stderr, "INFO: Create Balance Sheet")
|
||||||
createBalanceSheet()
|
createBalanceSheet()
|
||||||
case "journal":
|
case "journal":
|
||||||
fmt.Println("Create Journal")
|
fmt.Fprintln(os.Stderr, "INFO: Create Journal")
|
||||||
case "mwst1", "mwst2", "mwst3", "mwst4":
|
case "mwst1", "mwst2", "mwst3", "mwst4":
|
||||||
fmt.Println("Create Mwst Quarterly Report")
|
fmt.Fprintln(os.Stderr, "INFO: Create Mwst Quarterly Report")
|
||||||
outputMwst(action)
|
outputMwst(action)
|
||||||
case "new_year":
|
case "new_year":
|
||||||
fmt.Println("Create New Year")
|
fmt.Fprintln(os.Stderr, "INFO: Create New Year")
|
||||||
default:
|
default:
|
||||||
usage()
|
usage()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?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: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">
|
|
||||||
<eCH-0217:generalInformation>
|
<eCH-0217:generalInformation>
|
||||||
<eCH-0217:uid>
|
<eCH-0217:uid>
|
||||||
<eCH-0097:uidOrganisationIdCategorie>CHE</eCH-0097:uidOrganisationIdCategorie>
|
<eCH-0097:uidOrganisationIdCategorie>CHE</eCH-0097:uidOrganisationIdCategorie>
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue