Skip to content

Commit

Permalink
Merge branch 'issue-64/using-vies-test-service'
Browse files Browse the repository at this point in the history
Fixes #64 and closes PR #109, with many thanks to @MPablo for reporting this issue. 馃憦
  • Loading branch information
DragonBe committed May 27, 2020
2 parents 46c9de6 + 81102b3 commit b61ecd4
Show file tree
Hide file tree
Showing 3 changed files with 253 additions and 0 deletions.
33 changes: 33 additions & 0 deletions src/Vies/Vies.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ class Vies
const VIES_PROTO = 'http';
const VIES_DOMAIN = 'ec.europa.eu';
const VIES_WSDL = '/taxation_customs/vies/checkVatService.wsdl';
const VIES_TEST_WSDL = '/taxation_customs/vies/checkVatTestService.wsdl';
const VIES_EU_COUNTRY_TOTAL = 28;
const VIES_TEST_VAT_NRS = [100, 200];

protected const VIES_EU_COUNTRY_LIST = [
'AT' => ['name' => 'Austria', 'validator' => Validator\ValidatorAT::class],
Expand Down Expand Up @@ -248,6 +250,11 @@ public function validateVat(
if (! isset(self::VIES_EU_COUNTRY_LIST[$countryCode])) {
throw new ViesException(sprintf('Invalid country code "%s" provided', $countryCode));
}

if (in_array((int) $vatNumber, self::VIES_TEST_VAT_NRS, true)) {
return $this->validateTestVat($countryCode, $vatNumber);
}

$vatNumber = self::filterVat($vatNumber);

if (! $this->validateVatSum($countryCode, $vatNumber)) {
Expand Down Expand Up @@ -406,4 +413,30 @@ private function validateArgument(string $argumentValue): bool
}
return true;
}

private function validateTestVat($countryCode, $testVatNumber): CheckVatResponse
{
$wsdl = sprintf('%s://%s%s', self::VIES_PROTO, self::VIES_DOMAIN, self::VIES_TEST_WSDL);
$this->setWsdl($wsdl);
$requestParams = [
'countryCode' => $countryCode,
'vatNumber' => $testVatNumber,
];
try {
return new CheckVatResponse(
$this->getSoapClient()->__soapCall('checkVat', [$requestParams])
);
} catch (SoapFault $e) {
$message = sprintf(
'Back-end VIES service cannot validate the VAT number "%s%s" at this moment. '
. 'The service responded with the critical error "%s". This is probably a temporary '
. 'problem. Please try again later.',
$countryCode,
$testVatNumber,
$e->getMessage()
);

throw new ViesServiceException($message, 0, $e);
}
}
}
56 changes: 56 additions & 0 deletions tests/Vies/ViesTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -636,4 +636,60 @@ public function testSoapVersionsAreDefined(int $soapVersion, string $expectedVal

$this->assertInstanceOf(SoapClient::class, $vies->getSoapClient());
}

public function vatTestNumberProvider(): array
{
return [
'Belgian VAT ID that tests valid' => ['BE', '100', true],
'Irish VAT ID that tests invalid' => ['IE', '200', false],
'German VAT ID that tests valid' => ['DE', '100', true],
];
}

/**
* Testing the test VAT SOAP service
*
* @param string $countryCode
* @param string $vatNumber
* @param bool $expectation
* @throws ViesException
* @throws ViesServiceException
*
* @covers ::validateTestVat
* @covers ::validateVat
* @covers ::setWsdl
*
* @dataProvider vatTestNumberProvider
*/
public function testViesTestService(string $countryCode, string $vatNumber, bool $expectation)
{
$result = (new Vies())->validateVat($countryCode, $vatNumber);
$this->assertSame($expectation, $result->isValid());
}

/**
* Testing if we can catch soap exceptions when trying
* to make VIES test calls
*
* @throws ViesException
* @throws ViesServiceException
* @throws \ReflectionException
*
* @covers ::validateVat
* @covers ::validateTestVat
*/
public function testExceptionIsRaisedWhenSoapCallFailsForTestService()
{
$this->expectException(ViesServiceException::class);
$stub = $this->getMockFromWsdl(dirname(__FILE__) . '/_files/checkVatTestService.wsdl');
$stub->expects($this->any())
->method('__soapCall')
->will($this->throwException(new SoapFault("test", "myMessage")));

(new Vies())
->setSoapClient($stub)
->validateVat('BE', '100')
;
$this->fail('Expected exception was not raised');
}
}
164 changes: 164 additions & 0 deletions tests/Vies/_files/checkVatTestService.wsdl
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions targetNamespace="urn:ec.europa.eu:taxud:vies:services:checkVat" xmlns:tns1="urn:ec.europa.eu:taxud:vies:services:checkVat:types" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:impl="urn:ec.europa.eu:taxud:vies:services:checkVat" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/">
<xsd:documentation>
Specific disclaimer for this service -----------------------------------------
Here is the list of VAT Number to use to receive each kind of answer :
100 = Valid request with Valid VAT Number
200 = Valid request with an Invalid VAT Number
201 = Error : INVALID_INPUT
202 = Error : INVALID_REQUESTER_INFO
300 = Error : SERVICE_UNAVAILABLE
301 = Error : MS_UNAVAILABLE
302 = Error : TIMEOUT
400 = Error : VAT_BLOCKED
401 = Error : IP_BLOCKED
500 = Error : GLOBAL_MAX_CONCURRENT_REQ
501 = Error : GLOBAL_MAX_CONCURRENT_REQ_TIME
600 = Error : MS_MAX_CONCURRENT_REQ
601 = Error : MS_MAX_CONCURRENT_REQ_TIME

For all the other cases, The web service will responds with a "SERVICE_UNAVAILABLE" error.
</xsd:documentation>

<wsdl:types>
<xsd:schema attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="urn:ec.europa.eu:taxud:vies:services:checkVat:types" xmlns="urn:ec.europa.eu:taxud:vies:services:checkVat:types">
<xsd:element name="checkVat">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="countryCode" type="xsd:string"/>
<xsd:element name="vatNumber" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="checkVatResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="countryCode" type="xsd:string"/>
<xsd:element name="vatNumber" type="xsd:string"/>
<xsd:element name="requestDate" type="xsd:date"/>
<xsd:element name="valid" type="xsd:boolean"/>
<xsd:element maxOccurs="1" minOccurs="0" name="name" nillable="true" type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="0" name="address" nillable="true" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="checkVatApprox">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="countryCode" type="xsd:string"/>
<xsd:element name="vatNumber" type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="0" name="traderName" type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="0" name="traderCompanyType" type="tns1:companyTypeCode"/>
<xsd:element maxOccurs="1" minOccurs="0" name="traderStreet" type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="0" name="traderPostcode" type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="0" name="traderCity" type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="0" name="requesterCountryCode" type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="0" name="requesterVatNumber" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="checkVatApproxResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="countryCode" type="xsd:string"/>
<xsd:element name="vatNumber" type="xsd:string"/>
<xsd:element name="requestDate" type="xsd:date"/>
<xsd:element name="valid" type="xsd:boolean"/>
<xsd:element maxOccurs="1" minOccurs="0" name="traderName" nillable="true" type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="0" name="traderCompanyType" nillable="true" type="tns1:companyTypeCode"/>
<xsd:element maxOccurs="1" minOccurs="0" name="traderAddress" type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="0" name="traderStreet" type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="0" name="traderPostcode" type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="0" name="traderCity" type="xsd:string"/>
<xsd:element maxOccurs="1" minOccurs="0" name="traderNameMatch" type="tns1:matchCode"/>
<xsd:element maxOccurs="1" minOccurs="0" name="traderCompanyTypeMatch" type="tns1:matchCode"/>
<xsd:element maxOccurs="1" minOccurs="0" name="traderStreetMatch" type="tns1:matchCode"/>
<xsd:element maxOccurs="1" minOccurs="0" name="traderPostcodeMatch" type="tns1:matchCode"/>
<xsd:element maxOccurs="1" minOccurs="0" name="traderCityMatch" type="tns1:matchCode"/>
<xsd:element name="requestIdentifier" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:simpleType name="companyTypeCode">
<xsd:restriction base="xsd:string">
<xsd:pattern value="[A-Z]{2}\-[1-9][0-9]?"/>
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="matchCode">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="1">
<xsd:annotation>
<xsd:documentation>VALID</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="2">
<xsd:annotation>
<xsd:documentation>INVALID</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
<xsd:enumeration value="3">
<xsd:annotation>
<xsd:documentation>NOT_PROCESSED</xsd:documentation>
</xsd:annotation>
</xsd:enumeration>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
</wsdl:types>
<wsdl:message name="checkVatRequest">
<wsdl:part name="parameters" element="tns1:checkVat">
</wsdl:part>
</wsdl:message>
<wsdl:message name="checkVatApproxResponse">
<wsdl:part name="parameters" element="tns1:checkVatApproxResponse">
</wsdl:part>
</wsdl:message>
<wsdl:message name="checkVatApproxRequest">
<wsdl:part name="parameters" element="tns1:checkVatApprox">
</wsdl:part>
</wsdl:message>
<wsdl:message name="checkVatResponse">
<wsdl:part name="parameters" element="tns1:checkVatResponse">
</wsdl:part>
</wsdl:message>
<wsdl:portType name="checkVatPortType">
<wsdl:operation name="checkVat">
<wsdl:input name="checkVatRequest" message="impl:checkVatRequest">
</wsdl:input>
<wsdl:output name="checkVatResponse" message="impl:checkVatResponse">
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="checkVatApprox">
<wsdl:input name="checkVatApproxRequest" message="impl:checkVatApproxRequest">
</wsdl:input>
<wsdl:output name="checkVatApproxResponse" message="impl:checkVatApproxResponse">
</wsdl:output>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="checkVatTestBinding" type="impl:checkVatPortType">
<wsdlsoap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="checkVat">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="checkVatRequest">
<wsdlsoap:body use="literal"/>
</wsdl:input>
<wsdl:output name="checkVatResponse">
<wsdlsoap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
<wsdl:operation name="checkVatApprox">
<wsdlsoap:operation soapAction=""/>
<wsdl:input name="checkVatApproxRequest">
<wsdlsoap:body use="literal"/>
</wsdl:input>
<wsdl:output name="checkVatApproxResponse">
<wsdlsoap:body use="literal"/>
</wsdl:output>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="checkVatTestService">
<wsdl:port name="checkVatPort" binding="impl:checkVatTestBinding">
<wsdlsoap:address location="http://ec.europa.eu/taxation_customs/vies/services/checkVatTestService"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

0 comments on commit b61ecd4

Please sign in to comment.