Skip to content

Instantly share code, notes, and snippets.

@ThomasG77
Last active June 18, 2022 02:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ThomasG77/f270ce3c932113b6ae391911884decdc to your computer and use it in GitHub Desktop.
Save ThomasG77/f270ce3c932113b6ae391911884decdc to your computer and use it in GitHub Desktop.
SIREN et autres traitements autour dont la validation VIES (TVA intracommunautaire)

SIREN et autres traitements autour dont la validation VIES (TVA intracommunautaire)

Formule SIREN vers TVA intracommunautaire

Approche Python

COUNTRIES = {
    "AT": "Autriche",
    "BE": "Belgique",
    "BG": "Bulgarie",
    "CY": "Chypre",
    "CZ": "République tchèque",
    "DE": "Allemagne",
    "DK": "Danemark",
    "EE": "Estonie",
    "EL": "Grèce",
    "ES": "Espagne",
    "EU": "MOSS Number",
    "FI": "Finlande",
    "FR": "France",
    "HR": "Croatie",
    "HU": "Hongrie",
    "IE": "Irlande",
    "IT": "Italie",
    "LT": "Lituanie",
    "LU": "Luxembourg",
    "LV": "Lettonie",
    "MT": "Malte",
    "NL": "Pays-Bas",
    "PL": "Pologne",
    "PT": "Portugal",
    "RO": "Roumanie",
    "SE": "Suède",
    "SI": "Slovénie",
    "SK": "Slovaquie",
    "XI": "Irlande du Nord"
}
SIREN = 449989573
print(f'FR{(12 + 3 * (SIREN % 97)) % 97}{SIREN}')

Approche JavaScript

const SIREN = 449989573
const countries = {
    "AT": "Autriche",
    "BE": "Belgique",
    "BG": "Bulgarie",
    "CY": "Chypre",
    "CZ": "République tchèque",
    "DE": "Allemagne",
    "DK": "Danemark",
    "EE": "Estonie",
    "EL": "Grèce",
    "ES": "Espagne",
    "EU": "MOSS Number",
    "FI": "Finlande",
    "FR": "France",
    "HR": "Croatie",
    "HU": "Hongrie",
    "IE": "Irlande",
    "IT": "Italie",
    "LT": "Lituanie",
    "LU": "Luxembourg",
    "LV": "Lettonie",
    "MT": "Malte",
    "NL": "Pays-Bas",
    "PL": "Pologne",
    "PT": "Portugal",
    "RO": "Roumanie",
    "SE": "Suède",
    "SI": "Slovénie",
    "SK": "Slovaquie",
    "XI": "Irlande du Nord"
}
console.log(`FR${String((12 + 3 * (SIREN % 97)) % 97)}${SIREN}`)

Vérifier le VIES (numéro intracommunautaire)

Approche Python

Via une lib SOAP Python nommée zeep

import requests
import logging
logging.basicConfig(level=logging.DEBUG)
from zeep import Client

client = Client('https://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl')
client.service.checkVat('FR', '40449989573')
client.service.checkVatApprox

Via requests

import xmltodict
import requests

headers = {
    'Content-Type': 'text/xml; charset=utf-8',
    'Connection': 'keep-alive',
    'User-Agent': 'Zeep/4.1.0 (www.python-zeep.org)',
}

# Avec un fichier (voir l'exemple bash plus bas si vous souhaitez un fichier exemple)
# with open('request.xml') as f:
#     data = f.read().replace('\n', '')

def generateXml(countrycode, vatnumber):
    return f'''<?xml version='1.0' encoding='utf-8'?>
    <soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"><soap-env:Body><ns0:checkVat xmlns:ns0="urn:ec.europa.eu:taxud:vies:services:checkVat:types"><ns0:countryCode>{countrycode}</ns0:countryCode><ns0:vatNumber>{vatnumber}</ns0:vatNumber></ns0:checkVat></soap-env:Body></soap-env:Envelope>'''
data = generateXml('FR', '40449989573')

response = requests.post('https://ec.europa.eu/taxation_customs/vies/services/checkVatService', headers=headers, data=data)
obj = xmltodict.parse(response.text)
result = dict([i for i in obj.get('soap:Envelope').get('soap:Body').get('checkVatResponse').items() if i[0] not in ('@xmlns', 'requestDate')])
print(result)

Approche JavaScript

Avec la lib request

const request = require('request')

const headers = {
    'Content-Type': 'text/xml; charset=utf-8',
    'Connection': 'keep-alive',
    'Soapaction': '""',
    'User-Agent': 'Zeep/4.1.0 (www.python-zeep.org)'
};

const url = 'https://ec.europa.eu/taxation_customs/vies/services/checkVatService'

const vatnumber = "40449989573"
const country = "FR"
const body = `<?xml version="1.0" encoding="utf-8"?><soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"><soap-env:Body><ns0:checkVat xmlns:ns0="urn:ec.europa.eu:taxud:vies:services:checkVat:types"><ns0:countryCode>${country}</ns0:countryCode><ns0:vatNumber>${vatnumber}</ns0:vatNumber></ns0:checkVat></soap-env:Body></soap-env:Envelope>`

var options = {
    url,
    method: 'POST',
    headers,
    body
};

function callback(error, response, body) {
    if (!error && response.statusCode == 200) {
        console.log(body);
    }
}

Avec la lib node-fetch

import fetch from 'node-fetch'
import xml2js from 'xml2js'

const url = 'https://ec.europa.eu/taxation_customs/vies/services/checkVatService'
const vatnumber = "40449989573"
const country = "FR"
const body = `<?xml version="1.0" encoding="utf-8"?><soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"><soap-env:Body><ns0:checkVat xmlns:ns0="urn:ec.europa.eu:taxud:vies:services:checkVat:types"><ns0:countryCode>${country}</ns0:countryCode><ns0:vatNumber>${vatnumber}</ns0:vatNumber></ns0:checkVat></soap-env:Body></soap-env:Envelope>`

const response = await fetch(url, {
  method: 'POST',
  headers: {
    'Content-Type': 'text/xml; charset=utf-8',
    'Connection': 'keep-alive',
    'Soapaction': '""',
    'User-Agent': 'Zeep/4.1.0 (www.python-zeep.org)'
  },
  body
}).then(async (response) => {
  const xml = await response.text()
  return await xml2js.parseStringPromise(xml, { mergeAttrs: true }).then(content => content)
})

const json_main_content = response['soap:Envelope']['soap:Body'][0].checkVatResponse[0]
const content = Object.fromEntries(
  Object.entries(json_main_content)
    .filter(([k, v]) => {
      return !(['xmlns', 'requestDate'].includes(k))
    })
    .map(([k, v]) => {
      return [k, v[0]]
    })
)
console.log(content)

Approche bash

Utilise curl, xq (utilitaire lié à yq) et jq

Body du POST dans l'appel CURL

vatnumber="40449989573"
country="FR"
curl --header "Content-Type: text/xml; charset=utf-8" \
     --compressed \
     --header "Connection: keep-alive" \
     --header "Soapaction: """ \
     --user-agent "Zeep/4.1.0 (www.python-zeep.org)" \
     --data '<?xml version="1.0" encoding="utf-8"?><soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"><soap-env:Body><ns0:checkVat xmlns:ns0="urn:ec.europa.eu:taxud:vies:services:checkVat:types"><ns0:countryCode>'${country}'</ns0:countryCode><ns0:vatNumber>'${vatnumber}'</ns0:vatNumber></ns0:checkVat></soap-env:Body></soap-env:Envelope>' \
     https://ec.europa.eu/taxation_customs/vies/services/checkVatService \
     | xq '."soap:Envelope"."soap:Body"."checkVatResponse"' \
     | jq 'del(."@xmlns", ."requestDate")'

Body du POST dans un fichier externe

curl --header "Content-Type: text/xml; charset=utf-8" \
     --compressed \
     --header "Connection: keep-alive" \
     --header "Soapaction: """ \
     --user-agent "Zeep/4.1.0 (www.python-zeep.org)" \
     --data @request.xml \
     https://ec.europa.eu/taxation_customs/vies/services/checkVatService \
     | xq '."soap:Envelope"."soap:Body"."checkVatResponse"' \
     | jq 'del(."@xmlns", ."requestDate")'

où le contenu de request.xml est le suivant:

<?xml version='1.0' encoding='utf-8'?>
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/"><soap-env:Body><ns0:checkVat xmlns:ns0="urn:ec.europa.eu:taxud:vies:services:checkVat:types"><ns0:countryCode>FR</ns0:countryCode><ns0:vatNumber>40449989573</ns0:vatNumber></ns0:checkVat></soap-env:Body></soap-env:Envelope>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment