validate-vat
Version:
A Europe VAT number validation lib
135 lines (122 loc) • 5.29 kB
JavaScript
// Generated by CoffeeScript 1.12.7
(function() {
var ERROR_MSG, EU_COUNTRIES_CODES, exports, getReadableErrorMsg, headers, https, parseSoapResponse, parsedUrl, serviceUrl, soapBodyTemplate, url,
indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
url = require('url');
https = require('https');
serviceUrl = 'https://ec.europa.eu/taxation_customs/vies/services/checkVatService';
parsedUrl = url.parse(serviceUrl);
soapBodyTemplate = '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"\n xmlns:tns1="urn:ec.europa.eu:taxud:vies:services:checkVat:types"\n xmlns:impl="urn:ec.europa.eu:taxud:vies:services:checkVat">\n <soap:Header>\n </soap:Header>\n <soap:Body>\n <tns1:checkVat xmlns:tns1="urn:ec.europa.eu:taxud:vies:services:checkVat:types"\n xmlns="urn:ec.europa.eu:taxud:vies:services:checkVat:types">\n <tns1:countryCode>_country_code_placeholder_</tns1:countryCode>\n <tns1:vatNumber>_vat_number_placeholder_</tns1:vatNumber>\n </tns1:checkVat>\n </soap:Body>\n</soap:Envelope>';
EU_COUNTRIES_CODES = ['AT', 'BE', 'BG', 'HR', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR', 'DE', 'EL', 'HU', 'IE', 'IT', 'LV', 'LT', 'LU', 'MT', 'NL', 'PL', 'PT', 'RO', 'SK', 'SI', 'ES', 'SE', 'XI'];
ERROR_MSG = {
'INVALID_INPUT': 'The provided CountryCode is invalid or the VAT number is empty',
'SERVICE_UNAVAILABLE': 'The VIES VAT service is unavailable, please try again later',
'MS_UNAVAILABLE': 'The VAT database of the requested member country is unavailable, please try again later',
'MS_MAX_CONCURRENT_REQ': 'The VAT database of the requested member country has had too many requests, please try again later',
'TIMEOUT': 'The request to VAT database of the requested member country has timed out, please try again later',
'SERVER_BUSY': 'The service cannot process your request, please try again later',
'UNKNOWN': 'Unknown error'
};
headers = {
'Content-Type': 'text/xml; charset=utf-8',
'User-Agent': 'node-soap',
'Accept': 'text/html,application/xhtml+xml,application/xml,text/xml;q=0.9,*/*;q=0.8',
'Accept-Encoding': 'none',
'Accept-Charset': 'utf-8',
'Connection': 'close',
'Host': parsedUrl.hostname
};
getReadableErrorMsg = function(faultstring) {
if (ERROR_MSG[faultstring] != null) {
return ERROR_MSG[faultstring];
} else {
return ERROR_MSG['UNKNOWN'];
}
};
parseSoapResponse = function(soapMessage) {
var hasFault, parseField, ret;
parseField = function(field) {
var err, match, regex;
regex = new RegExp("<" + field + ">\((\.|\\s)\*?\)</" + field + ">", 'gm');
match = regex.exec(soapMessage);
if (!match) {
err = new Error("Failed to parseField " + field);
err.soapMessage = soapMessage;
throw err;
}
return match[1];
};
hasFault = soapMessage.match(/<env:Fault>\S+<\/env:Fault>/g);
if (hasFault) {
ret = {
faultCode: parseField('faultcode'),
faultString: parseField('faultstring')
};
} else {
ret = {
countryCode: parseField('ns2:countryCode'),
vatNumber: parseField('ns2:vatNumber'),
requestDate: parseField('ns2:requestDate'),
valid: parseField('ns2:valid') === 'true',
name: parseField('ns2:name'),
address: parseField('ns2:address').replace(/\n/g, ', ')
};
}
return ret;
};
module.exports = exports = function(countryCode, vatNumber, timeout, callback) {
var options, req, xml;
if (typeof countryCode === 'string') {
countryCode = countryCode.toUpperCase();
}
if (typeof timeout === 'function') {
callback = timeout;
timeout = null;
}
if (indexOf.call(EU_COUNTRIES_CODES, countryCode) < 0 || !(vatNumber != null ? vatNumber.length : void 0)) {
return process.nextTick(function() {
return callback(new Error(ERROR_MSG['INVALID_INPUT']));
});
}
xml = soapBodyTemplate.replace('_country_code_placeholder_', countryCode).replace('_vat_number_placeholder_', vatNumber).replace('\n', '').trim();
headers['Content-Length'] = Buffer.byteLength(xml, 'utf8');
options = {
host: parsedUrl.host,
method: 'POST',
path: parsedUrl.path,
headers: headers,
family: 4
};
req = https.request(options, function(res) {
var str;
res.setEncoding('utf8');
str = '';
res.on('data', function(chunk) {
return str += chunk;
});
return res.on('end', function() {
var data, err, ref;
try {
data = parseSoapResponse(str);
} catch (error) {
err = error;
return callback(err);
}
if ((ref = data.faultString) != null ? ref.length : void 0) {
err = new Error(getReadableErrorMsg(data.faultString));
err.code = data.faultCode;
return callback(err);
}
return callback(null, data);
});
});
if (timeout) {
req.setTimeout(timeout, function() {
return req.abort();
});
}
req.on('error', callback);
req.write(xml);
return req.end();
};
}).call(this);