VAT check with gorilla-xmlrpc

Hi, I am trying to make a post to a xmlrpc server in this format:

https://evatr.bff-online.de/evatrRPC?UstId_1=DE123456789&UstId_2=AB1234567890
&Firmenname=Firmenname einschl. Rechtsform&Ort=Ort der Firma&PLZ=12345&Strasse=Strasse der Firma
&Druck=ja

Read the results and access them in go lang by name:

An example result xml looks like this:

<params>
  <param>
    <value><array><data>
      <value><string>Datum</string></value>
      <value><string>27.07.2006</string></value>
    </data></array></value>
  </param>
  <param>
    <value><array><data>
      <value><string>Uhrzeit</string></value>
      <value><string>13:35:53</string></value>
    </data></array></value>
  </param>
  <param>
    <value><array><data>
      <value><string>ErrorCode</string></value>
      <value><string>200</string></value>
    </data></array></value>
  </param>
  <param>
    <value><array><data>
      <value><string>UstId_1</string></value>
      <value><string>DE123456789</string></value>
    </data></array></value>
  </param>
  <param>
    <value><array><data>
      <value><string>UstId_2</string></value>
      <value><string>AB1234567890</string></value>
    </data></array></value>
  </param>
  <param>
    <value><array><data>
      <value><string>Firmenname</string></value>
      <value><string>Firma XY Rechtsform</string></value>
    </data></array></value>
  </param>
  <param>
    <value><array><data>
      <value><string>Ort</string></value>
      <value><string>Firmenort</string></value>
    </data></array></value>
  </param>
  <param>
    <value><array><data>
      <value><string>PLZ</string></value>
      <value><string>1234</string></value>
    </data></array></value>
  </param>
  <param>
    <value><array><data>
      <value><string>Strasse</string></value>
      <value><string>Firmenstrasse</string></value>
    </data></array></value>
  </param>
  <param>
    <value><array><data>
      <value><string>Erg_Name</string></value>
      <value><string>A</string></value>
    </data></array></value>
  </param>
  <param>
    <value><array><data>
      <value><string>Erg_Ort</string></value>
      <value><string>A</string></value>
    </data></array></value>
  </param>
  <param>
    <value><array><data>
      <value><string>Erg_PLZ</string></value>
      <value><string>A</string></value>
    </data></array></value>
  </param>
  <param>
    <value><array><data>
      <value><string>Erg_Str</string></value>
      <value><string>A</string></value>
    </data></array></value>
  </param>
  <param>
    <value><array><data>
      <value><string>Gueltig_ab</string></value>
      <value><string></string></value>
    </data></array></value>
  </param>
  <param>
    <value><array><data>
      <value><string>Gueltig_bis</string></value>
      <value><string></string></value>
    </data></array></value>
  </param>
  <param>
    <value><array><data>
      <value><string>Druck</string></value>
      <value><string>ja</string></value>
    </data></array></value>
  </param>
</params>

I got this far:

type Params struct {
	XMLName xml2.Name   `xml:"params"`
	Text    string   `xml:",chardata"`
	Param   []struct {
		Text  string `xml:",chardata"`
		Value struct {
			Text  string `xml:",chardata"`
			Array struct {
				Text string `xml:",chardata"`
				Data struct {
					Text  string `xml:",chardata"`
					Value []struct {
						Text   string `xml:",chardata"`
						String string `xml:"string"`
					} `xml:"value"`
				} `xml:"data"`
			} `xml:"array"`
		} `xml:"value"`
	} `xml:"param"`
}

func XmlRpcCall(method string, args struct{UstId_1,UstId_2,Firmenname,Ort,PLZ,Strasse,Druck string}) (reply struct{Message string}, err error) {
	buf, _ := xml.EncodeClientRequest(method, &args)	
	resp, err := http.Post("https://evatr.bff-online.de/", "text/xml", bytes.NewBuffer(buf))
	if err != nil {
		return
	}
	defer resp.Body.Close()
	err = xml.DecodeClientResponse(resp.Body, &reply)
	return
}

func main() {

	reply, err := XmlRpcCall("evatrRPC", struct{UstId_1,UstId_2,Firmenname,Ort,PLZ,Strasse,Druck string}{"VAT1","VAT2","Name","Town","ZIP","Street","No"})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(reply.Message)
}

My code prints the xml message, but how do get it into the struct and access for example. The Error Code value of 200?

I am pretty new to go , so anything will be helpful.

Hi

You should use Unmarshal from the encoding/xml package https://golang.org/pkg/encoding/xml/#Unmarshal

See this page for an example. You could use the same technice and define the big struct by using smaller parts otherwise will it be too complex and hard to understand.

https://larry-price.com/blog/2015/12/04/xml-parsing-in-go/

2 Likes

So, I tried to follow that example, with this code, but I am still not managing, to access the values singly. eg, CodeError = 200 …

package main

import (
	"encoding/xml"
	"fmt"
)

var reply string

type Params struct {
	XMLName xml.Name `xml:"params"`
	Text    string   `xml:",chardata"`
	Param   []struct {
		Text  string `xml:",chardata"`
		Value struct {
			Text  string `xml:",chardata"`
			Array struct {
				Text string `xml:",chardata"`
				Data struct {
					Text  string `xml:",chardata"`
					Value []struct {
						Text   string `xml:",chardata"`
						String string `xml:"string"`
					} `xml:"value"`
				} `xml:"data"`
			} `xml:"array"`
		} `xml:"value"`
	} `xml:"param"`
}

func main() {
	reply = `
<params>
<param>
<value><array><data>
<value><string>Datum</string></value>
<value><string>27.07.2006</string></value>
</data></array></value>
</param>
<param>
<value><array><data>
<value><string>Uhrzeit</string></value>
<value><string>13:35:53</string></value>
</data></array></value>
</param>
<param>
<value><array><data>
<value><string>ErrorCode</string></value>
<value><string>200</string></value>
</data></array></value>
</param>
<param>
<value><array><data>
<value><string>UstId_1</string></value>
<value><string>DE123456789</string></value>
</data></array></value>
</param>
<param>
<value><array><data>
<value><string>UstId_2</string></value>
<value><string>AB1234567890</string></value>
</data></array></value>
</param>
<param>
<value><array><data>
<value><string>Firmenname</string></value>
<value><string>Firma XY Rechtsform</string></value>
</data></array></value>
</param>
<param>
<value><array><data>
<value><string>Ort</string></value>
<value><string>Firmenort</string></value>
</data></array></value>
</param>
<param>
<value><array><data>
<value><string>PLZ</string></value>
<value><string>1234</string></value>
</data></array></value>
</param>
<param>
<value><array><data>
<value><string>Strasse</string></value>
<value><string>Firmenstrasse</string></value>
</data></array></value>
</param>
<param>
<value><array><data>
<value><string>Erg_Name</string></value>
<value><string>A</string></value>
</data></array></value>
</param>
<param>
<value><array><data>
<value><string>Erg_Ort</string></value>
<value><string>A</string></value>
</data></array></value>
</param>
<param>
<value><array><data>
<value><string>Erg_PLZ</string></value>
<value><string>A</string></value>
</data></array></value>
</param>
<param>
<value><array><data>
<value><string>Erg_Str</string></value>
<value><string>A</string></value>
</data></array></value>
</param>
<param>
<value><array><data>
<value><string>Gueltig_ab</string></value>
<value><string></string></value>
</data></array></value>
</param>
<param>
<value><array><data>
<value><string>Gueltig_bis</string></value>
<value><string></string></value>
</data></array></value>
</param>
<param>
<value><array><data>
<value><string>Druck</string></value>
<value><string>ja</string></value>
</data></array></value>
</param>
</params>
`

	container := Params{}
	err := xml.Unmarshal([]byte(reply), &container)

	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println(container)
	}

}

Result:

{{ params}

[{

{ { {

[{ Datum} { 27.07.2006}]}}}} {

{ { {

[{ Uhrzeit} { 13:35:53}]}}}} {

{ { {

[{ ErrorCode} { 200}]}}}} {

{ { {

[{ UstId_1} { DE123456789}]}}}} {

{ { {

[{ UstId_2} { AB1234567890}]}}}} {

{ { {

[{ Firmenname} { Firma XY Rechtsform}]}}}} {

{ { {

[{ Ort} { Firmenort}]}}}} {

{ { {

[{ PLZ} { 1234}]}}}} {

{ { {

[{ Strasse} { Firmenstrasse}]}}}} {

{ { {

[{ Erg_Name} { A}]}}}} {

{ { {

[{ Erg_Ort} { A}]}}}} {

{ { {

[{ Erg_PLZ} { A}]}}}} {

{ { {

[{ Erg_Str} { A}]}}}} {

{ { {

[{ Gueltig_ab} { }]}}}} {

{ { {

[{ Gueltig_bis} { }]}}}} {

{ { {

[{ Druck} { ja}]}}}}]}

Hi

Good work with this large structure!
Lines below will print ErrorCode and 200. I get a member of a struct by using the dot notation and works my way down into the structures.

		fmt.Println(container.Param[2].Value.Array.Data.Value[0].String)
		fmt.Println(container.Param[2].Value.Array.Data.Value[1].String)
1 Like

If you want to iterate over all values can you do like this

	for _, p := range container.Param {
		for _, v := range p.Value.Array.Data.Value {
			fmt.Println(v.String)
		}
	}

then iterating over a slice with for range will the first value be the index but I want the value which is optionally the second value. Here I use the placeholder variable _ (underscore) because I’m not interested in the index just the value.

1 Like

Do you need these? If you skip them will the struct be much smaller

type Params struct {
	Param []struct {
		Value struct {
			Array struct {
				Data struct {
					Value []struct {
						String string `xml:"string"`
					} `xml:"value"`
				} `xml:"data"`
			} `xml:"array"`
		} `xml:"value"`
	} `xml:"param"`
}

And it works as good what I can see

1 Like

You could even use the > instruction in the xml tags to make the struct even simpler

type Params struct {
	Param []struct {
		String []string `xml:"value>array>data>value>string"`	
	} `xml:"param"`
}

and print ErrorCode and 300 like this

fmt.Println(container.Param[2].String[0])
fmt.Println(container.Param[2].String[1])

I just found this then reading the documentation

1 Like

That’s brilliant, thank you very much. I will post the finished function, once I have completed it, in case somebody else needs to check VAT-Id´s in the future.

1 Like

Here are the final functions to check a European VAT ID number:

package main

import (import (
	"bytes"
	xml2 "encoding/xml"
	"fmt"
	"github.com/dannyvankooten/vat"	
	"github.com/divan/gorilla-xmlrpc/xml"
)

func checkVat(UstId_1, UstId_2, Firmenname, Ort, PLZ, Strasse, Druck string) {

	validity, err := vat.ValidateNumberFormat(UstId_2)
	if err != nil {
		fmt.Println("Format der Umsatzsteuer ID unzulässig")
	}
	if validity == true {
		fmt.Println("Format der Umsatzsteuer ID zulässig")
	}
	validity2, err2 := vat.ValidateNumberExistence(UstId_2)
	if err2 != nil {
		fmt.Println("Umsatzsteuer ID ist unzulässig")
	}
	if validity2 == true {
		fmt.Println("Umsatzsteuer ID zulässig")
	}
	if validity && validity2 == true {
		XmlRpcCall("evatrRPC", struct{ UstId_1, UstId_2, Firmenname, Ort, PLZ, Strasse, Druck string }{UstId_1, UstId_2, Firmenname, Ort, PLZ, Strasse, Druck})
	}
}

func XmlRpcCall(method string, args struct{ UstId_1, UstId_2, Firmenname, Ort, PLZ, Strasse, Druck string }) {

	type Params struct {
		Param []struct {
			Value struct {
				Array struct {
					Data struct {
						Value []struct {
							String string `xml:"string"`
						} `xml:"value"`
					} `xml:"data"`
				} `xml:"array"`
			} `xml:"value"`
		} `xml:"param"`
	}

	type rep struct {
		Message string
	}

	var reply rep
	result := make(map[string]string)
	var Key string

	buf, _ := xml.EncodeClientRequest(method, &args)
	resp, err := http.Post("https://evatr.bff-online.de/", "text/xml", bytes.NewBuffer(buf))
	defer resp.Body.Close()
	err = xml.DecodeClientResponse(resp.Body, &reply)
	container := Params{}
	err = xml2.Unmarshal([]byte(reply.Message), &container)

	if err != nil {
		fmt.Println("Error:", err)
	}
	for _, p := range container.Param {

		for i, v := range p.Value.Array.Data.Value {
			if i == 0 {
				Key = v.String
			}
			if i == 1 {
				result[Key] = v.String
			}
		}
	}
	if result["ErrorCode"] == "200" {
		fmt.Println("Die angefragte USt-IdNr. ist gültig.")
	} else {
		fmt.Println("Die angefragte USt-IdNr. ist ungültig!")
	}
	fmt.Println(result)
	return

}

func main() {

	checkVat("YourVATId", "CustomerVATId", "Customer Company Name", "Customer City", "Customer Postcode", "Customer Street", "Print Yes/No")

}

The function checkVat first checks if the VAT Id number format is correct, then if the number has been issued, then if both checks are ok, it will ask for the Number to be checked against the customer address. The Print Yes/No, triggers the letter from the German TAX Department with the official result of your query. The result of the query are saved in a map called result, which keys are according to the fields (UstId_1, UstId_2, Firmenname, Ort, PLZ, Strasse, Druck).

Hope somebody else will also find some use for it. If there are any comments on how to streamline the code. Please let me know.

1 Like