HaLe Blog twitter
HaLe Blog Rss

VAT number validation with VIES

Posted by Kim | Posted in Coding, Drupal, PHP | Posted on 15-03-2010

17

For a couple of our clients we implemented a webshop with Drupal and Ubercart. One feature which was missing from the default Ubercart setup, was a VAT number field, and the accompanying validation.

After some googling I found out about the VAT number module . This module adds a VAT field to the checkout billing fieldset, depending on which country you have selected. Because only european corporate visitors should be able to fill in a VAT number, it’s useless for other countries and can be hidden.

Now there are 2 ways of validating a VAT number:

1. Through a fixed preg-match scheme, which validates the format of the VAT number depending on the country. This method ensures you have a valid formatted VAT number but it does not validate if this VAT number belongs to an actual company. Hence method 2.

2. You can also validate a VAT number through the European VAT validation service, in short “VIES”. They allow for a developer to do a Soap call to their service, providing the country code and VAT number. The Drupal module already provides this Soap call, but there has been an update to the VIES services, and the endpoint url of the Soap service has moved.

So to get your VAT checker up and running again, here’s The Fix:

Just replace the existing endpoint by the new one:

$client = new SoapClient("http://ec.europa.eu/taxation_customs/vies/api/checkVatPort?wsdl");

By

$client = new SoapClient("http://ec.europa.eu/taxation_customs/vies/services/checkVatService.wsdl");

For a full implementation on how to do a VAT validation through SOAP:

function hale_validate_vat($args = array()) {
	if ( '' != $args['vatnumber'] ) {
		$vat_number 	= str_replace(array(' ', '.', '-', ',', ', '), '', $args['vatnumber']);
		$countryCode 	= substr($vat_number, 0, 2);
		$vatNumber 		= substr($vat_number, 2);
 
		if ( strlen($countryCode) != 2 || is_numeric(substr($countryCode, 0, 1)) || is_numeric(substr($countryCode, 1, 2)) ) {
			$error = array('result' => false, 'message' => 'Your VAT Number syntax is not correct. You should have something like this: BE805670816B01');
			return $error;
		}
 
		if ( $args['country'] != $countryCode ) {
			$error = array('result' => false, 'message' => 'Your VAT Number is not valid for the selected country.');
			return $error;
		}
 
		$client = new SoapClient("http://ec.europa.eu/taxation_customs/vies/services/checkVatService.wsdl");
		$params = array('countryCode' => $countryCode, 'vatNumber' => $vatNumber);
 
		$result = $client->checkVat($params);
 
		if ( !$result->valid ) {
			$error = array('result' =&gt; false, 'message' =&gt; sprintf('Invalid VAT Number. Check the validity on the customer VAT Number via <a href="%s">Europa VAT Number validation webservice</a>', 'http://ec.europa.eu/taxation_customs/vies/lang.do?fromWhichPage=vieshome'));
			return $error;
		} else {
			return true;
		}
	}
	return false;
}

Use it like this:

$result = hale_validate_vat(array(‘vatnumber’ => ‘BE0123456789′, ‘country’ => ‘BE’));

Where the result is either TRUE or contains the error message in $result['message']

Update: Like promised in the comments below I have created a txt file with the code of this post and some comments. Download it here.

Greets,
Kim

CakePHP created and modified fields

Posted by Kim | Posted in Coding, PHP | Posted on 08-02-2010

1

For a project of a client of ours, we had to create a custom web-application. After some online investigation Googling, CakePHP came out as the best-value-for-money PHP framework, and it comes with a super-duper handbook.

After implementing the outlines of the application, we had a first evaluation round which attended us at a small bug (?) in the system…

The “created” and “modified” (or “updated” as alternative) columns in the database scheme should, according to the CakePHP book, be updated automagically when using the built-in model->save() method.

After a few test-rounds we noticed that these values were initialised when first adding the data to the database, but were not updated afterwards when editing the model data.

The traceback lead me to the /cakeframework/cake/libs/model/model.php line 1204:

1204
if ($this->hasField($updateCol) && !in_array($updateCol, $fields)) {

This if checks if a model has access to a database column “created”, “modified” or “updated” with the hasField() model-method and also does a simple in_array() check and here’s the caveat: The second check requires the datetime-field NOT to be in a preset array with the following values “created”, “modified” or “updated”.

Rather tricky to result in both requirements returning “true” and update the datetimefields if available ^^.

So to fix it and have your modified / updated datetime-fields kept up-to-date change the line to the following:

1204
if ($this->hasField($updateCol) && in_array($updateCol, $fields)) {

Hoping to be of any assistance!

Solving the ‘An illegal choice has been detected. Please contact the site administrator.’ error

Posted by Kim | Posted in Drupal, PHP | Posted on 13-08-2009

12

After upgrading a couple of client websites to Drupal 6.13, we suddenly noticed several “An illegal choice has been detected. Please contact the site administrator.” errors. These errors popped up all around: Performance settings, User adding, u name it.

Research thought me that the illegal choice error was returned when the posted! value of a checkbox, select or radio form field was not available in the original form-structure array. It all sounds logical as an valid input filter, because you don’t want people posting illegal values in your forms now do you?

I found out that the code generating the radio buttons was the following:

We were able to trace it back to the following piece of code in /includes/form.inc line 1733

1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
/**
 * Roll out a single radios element to a list of radios,
 * using the options array as index.
 */
function expand_radios($element) {
  if (count($element['#options']) &gt; 0) {
    foreach ($element['#options'] as $key =&gt; $choice) {
      if (!isset($element[$key])) {
        // Generate the parents as the autogenerator does, so we will have a
        // unique id for each radio button.
        $parents_for_id = array_merge($element['#parents'], array($key));
        $element[$key] = array(
          '#type' =&gt; 'radio',
          '#title' =&gt; $choice,
          '#return_value' =&gt; check_plain($key),
          '#default_value' =&gt; isset($element['#default_value']) ? $element['#default_value'] : NULL,
          '#attributes' =&gt; $element['#attributes'],
          '#parents' =&gt; $element['#parents'],
          '#id' =&gt; form_clean_id('edit-'. implode('-', $parents_for_id)),
          '#ahah' =&gt; isset($element['#ahah']) ? $element['#ahah'] : NULL,
        );
      }
    }
  }
  return $element;
}

and more specifically this line (1747):

1747
'#return_value' => check_plain($key),

Tracking down further learns us the source of all evil hides in bootstrap.inc line 728!

728
729
730
731
732
733
734
735
736
/**
 * Encode special characters in a plain-text string for display as HTML.
 *
 * Uses drupal_validate_utf8 to prevent cross site scripting attacks on
 * Internet Explorer 6.
 */
function check_plain($text) {
  return drupal_validate_utf8($text) ? htmlspecialchars($text, ENT_QUOTES) : '';
}

This little piece checks if the passed argument is a valid UTF8 string, and if so htmlspecialchars it, or if not, returns nothing! This causes the return values of our radio button items to have an empty value=”" attribute, causing the validation to fail because of the empty value you posted.

Change it to this code to get it back up on it’s feet:

728
729
730
731
732
733
734
735
736
/**
 * Encode special characters in a plain-text string for display as HTML.
 *
 * Uses drupal_validate_utf8 to prevent cross site scripting attacks on
 * Internet Explorer 6.
 */
function check_plain($text) {
  return drupal_validate_utf8($text) ? htmlspecialchars($text, ENT_QUOTES) : $text;
}

Hope to be of any service!