Versions du mapping
Comment les noms de champs d’un ERP deviennent notre facture, et comment les versions évoluent.
- Dans le bac à sable
En termes simples
Un mapping traduit les noms de champs d’un ERP dans notre modèle de facture : c’est ainsi qu’une erreur peut nommer le champ dans l’export propre au client. Quand les noms de champs d’un client changent, nous ajoutons une nouvelle version et conservons l’ancienne, pour pouvoir revenir en arrière. Business Central et SAP Business One sont mappés, chacun d’après la forme publiée de l’ERP et pas encore d’après un export propre à un client.
Un mapping transforme un export ERP en notre facture canonique. Quand les noms de champs d’un client changent, nous ajoutons une nouvelle version et déplaçons le pointeur de la version en vigueur. L’ancienne version reste, pour que le pointeur puisse revenir en arrière.
Ce qui existe aujourd’hui
Deux ERP sont mappés : Business Central (la facture de vente de l’API v2.0) et SAP Business One (une facture ou un avoir tel que le renvoie le Service Layer). Chacun a une version en vigueur, et les versions plus anciennes restent.
Remarque
Les deux mappings ont été rédigés d’après la forme publiée de l’ERP et testés sur des exports fictifs, car aucun export client n’existe encore. Un client dont l’export utilise d’autres noms obtient une nouvelle version. Rien ici ne demande au client de modifier l’ERP.
Un export passe par POST /validate ou POST /invoices, avec connector et export à la place de document.
Envoyer un export
POST /validate reçoit connector (business-central ou sap-b1) et export (l’objet de l’export) à la place de document ; POST /invoices reçoit les mêmes deux champs. Les champs que le mapping ne connaît pas sont ignorés. Le rapport indique quelle version a été exécutée, dans mapping_version. La requête est validate-export-ok.json, un export avec des parties fictives.
curl -X POST "https://api-sandbox-eu.eurinvoice.com/validate" \
-H "Authorization: Bearer <your-api-key>" \
-H "Content-Type: application/json" \
--data-binary @validate-export-ok.jsonimport java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Path;
public class Example {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder(URI.create("https://api-sandbox-eu.eurinvoice.com/validate"))
.header("Authorization", "Bearer <your-api-key>")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofFile(Path.of("validate-export-ok.json")))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
}
}import { readFile } from 'node:fs/promises';
const response = await fetch('https://api-sandbox-eu.eurinvoice.com/validate', {
method: 'POST',
headers: {
Authorization: 'Bearer <your-api-key>',
'Content-Type': 'application/json',
},
body: await readFile('validate-export-ok.json'),
});
console.log(response.status);
console.log(await response.text());{
"valid": true,
"route": "DE-XRECHNUNG",
"documents": [
{
"sha256": "3e7f648bdc6c6d6f5ad78cd356b39c3020595bb7f0896b78a8510ec6969db317",
"kind": "xrechnung-ubl",
"content_base64": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgi... (5,900 characters, shortened for these docs)"
}
],
"layers": [
{
"findings": [],
"passed": true,
"layer": "schema"
},
{
"findings": [],
"passed": true,
"layer": "mapping"
},
{
"findings": [],
"passed": true,
"layer": "pre-check"
},
{
"findings": [],
"passed": true,
"layer": "kosit"
}
],
"mapping_version": "v2"
}Essayer une autre version
mapping_version dans la requête choisit une version pour cet appel. Le pointeur ne bouge pas. Pour une version qui n’existe pas, la réponse est 400. La requête est validate-export-bad-version.json, le même export avec "mapping_version": "v9".
curl -X POST "https://api-sandbox-eu.eurinvoice.com/validate" \
-H "Authorization: Bearer <your-api-key>" \
-H "Content-Type: application/json" \
--data-binary @validate-export-bad-version.jsonimport java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Path;
public class Example {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder(URI.create("https://api-sandbox-eu.eurinvoice.com/validate"))
.header("Authorization", "Bearer <your-api-key>")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofFile(Path.of("validate-export-bad-version.json")))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
}
}import { readFile } from 'node:fs/promises';
const response = await fetch('https://api-sandbox-eu.eurinvoice.com/validate', {
method: 'POST',
headers: {
Authorization: 'Bearer <your-api-key>',
'Content-Type': 'application/json',
},
body: await readFile('validate-export-bad-version.json'),
});
console.log(response.status);
console.log(await response.text());{
"detail": "That mapping version does not exist. The live pointer was left unchanged.",
"type": "https://eurinvoice.com/problems/bad-request",
"title": "The request could not be read",
"status": 400
}Trouver le champ dans l’ERP
Un constat nomme le champ de l’ERP, et non notre champ canonique. Une unité que le mapping ne connaît pas relève de nous : nous l’ajoutons à la table des unités et publions une nouvelle version. La requête est validate-export-bad-unit.json, où Kiste ne figure pas dans la table.
curl -X POST "https://api-sandbox-eu.eurinvoice.com/validate" \
-H "Authorization: Bearer <your-api-key>" \
-H "Content-Type: application/json" \
--data-binary @validate-export-bad-unit.jsonimport java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Path;
public class Example {
public static void main(String[] args) throws Exception {
HttpRequest request = HttpRequest.newBuilder(URI.create("https://api-sandbox-eu.eurinvoice.com/validate"))
.header("Authorization", "Bearer <your-api-key>")
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofFile(Path.of("validate-export-bad-unit.json")))
.build();
HttpResponse<String> response = HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(response.statusCode());
System.out.println(response.body());
}
}import { readFile } from 'node:fs/promises';
const response = await fetch('https://api-sandbox-eu.eurinvoice.com/validate', {
method: 'POST',
headers: {
Authorization: 'Bearer <your-api-key>',
'Content-Type': 'application/json',
},
body: await readFile('validate-export-bad-unit.json'),
});
console.log(response.status);
console.log(await response.text());{
"valid": false,
"route": "DE-XRECHNUNG",
"layers": [
{
"findings": [],
"passed": true,
"layer": "schema"
},
{
"findings": [
{
"code": "BR-CL-23",
"field": "salesInvoiceLines[0].unitOfMeasureCode",
"fix_hint": "Add the ERP's unit to the client's unit mapping table (for example 'Std.' to HUR).",
"who_fixes": "us",
"source": "mapping",
"message": "A unit of measure on a line is not recognised. We are adding it to your mapping."
}
],
"passed": false,
"layer": "mapping"
},
{
"findings": [],
"passed": true,
"layer": "pre-check"
}
],
"mapping_version": "v2"
}Les données manquantes relèvent de l’intégrateur. Le constat correspondant a who_fixes égal à erp et nomme le champ de l’ERP à compléter.
Comment un changement est déployé
- Nous copions la version en vigueur dans une nouvelle version et la modifions. L’ancienne reste.
- Nous envoyons les exports d’exemple du client avec
mapping_versionréglé sur la nouvelle version, pendant que l’ancienne reste en vigueur. - Nous faisons pointer la version en vigueur vers la nouvelle version.
- En cas de problème, nous la ramenons à l’ancienne version.