diff --git a/.gitattributes b/.gitattributes
index 06a4051..169923f 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -3,13 +3,14 @@
/.gitignore export-ignore
/CHANGELOG.md export-ignore
/CONTRIBUTING.md export-ignore
-/doc export-ignore
+/docs export-ignore
/tools export-ignore
-/Makefile export-ignore
/phpunit.xml.dist export-ignore
+/phpunit.xml export-ignore
/tests export-ignore
/VERSIONING.md export-ignore
/.php-cs-fixer.php export-ignore
/rector.php export-ignore
/phpstan.neon.dist export-ignore
-/phpstan-baseline.neon export-ignore
\ No newline at end of file
+/phpstan-baseline.neon export-ignore
+/Dockerfile export-ignore
\ No newline at end of file
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index f9f8342..8d87bee 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -21,6 +21,32 @@ jobs:
with:
php-version: ${{ matrix.php-versions }}
+ - name: Cache Saxon HE
+ uses: actions/cache@v5
+ id: saxon-cache
+ with:
+ path: saxon
+ key: saxon-he-12.9
+
+ - name: Download Saxon HE 12.9
+ id: saxon_download
+ if: steps.saxon-cache.outputs.cache-hit != 'true'
+ run: |
+ SAXON_ZIP_URL="https://github.com/Saxonica/Saxon-HE/releases/download/SaxonHE12-9/SaxonHE12-9J.zip"
+ curl -L -o saxon.zip "$SAXON_ZIP_URL"
+ unzip -q saxon.zip -d saxon
+ rm saxon.zip
+
+ - name: Set Saxon JAR path
+ run: |
+ SAXON_JAR=$(find saxon -type f -name "saxon-he-12.9.jar" | head -n 1)
+ if [ -z "$SAXON_JAR" ]; then
+ echo "⚠️ JAR Saxon not found!"
+ exit 1
+ fi
+ echo "SAXON_JAR=$SAXON_JAR" >> $GITHUB_ENV
+ echo "Saxon JAR path: $SAXON_JAR"
+
- uses: "ramsey/composer-install@v3"
- name: Run test suite
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..5d072e6
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,36 @@
+# Use PHP 8.3 CLI as base image
+FROM php:8.3-cli
+
+# Install system dependencies and PHP extensions
+RUN apt-get update \
+ && apt-get install -y --no-install-recommends \
+ git \
+ unzip \
+ curl \
+ ca-certificates \
+ libzip-dev \
+ libicu-dev \
+ libxml2-dev \
+ default-jre \
+ wget \
+ && docker-php-ext-install intl zip dom xml \
+ && rm -rf /var/lib/apt/lists/*
+
+# Install Composer
+COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
+
+# Set working directory
+WORKDIR /app
+
+# Install Saxon Home edition for Java
+RUN wget -nv "https://github.com/Saxonica/Saxon-HE/releases/download/SaxonHE12-9/SaxonHE12-9J.zip" -O /tmp/saxon.zip && \
+ unzip /tmp/saxon.zip -d /opt/saxon && \
+ rm /tmp/saxon.zip
+
+ENV PATH="/opt/saxon/bin:${PATH}"
+
+ENV SAXON_JAR="/opt/saxon/saxon-he-12.9.jar"
+
+
+
+
diff --git a/composer.json b/composer.json
index b08f00c..0789956 100644
--- a/composer.json
+++ b/composer.json
@@ -22,7 +22,8 @@
"friendsofphp/php-cs-fixer": "^3.93",
"phpunit/phpunit": "^12.5",
"ext-libxml": "*",
- "ext-dom": "*"
+ "ext-dom": "*",
+ "symfony/process": "^7.4"
},
"scripts": {
"cs-fix": "php-cs-fixer fix",
diff --git a/docs/.gitkeep b/docs/.gitkeep
deleted file mode 100644
index e69de29..0000000
diff --git a/docs/SaxonJarSchematronValidator.md b/docs/SaxonJarSchematronValidator.md
new file mode 100644
index 0000000..2cfa236
--- /dev/null
+++ b/docs/SaxonJarSchematronValidator.md
@@ -0,0 +1,80 @@
+# SaxonJarSchematronValidator
+
+The `SaxonJarSchematronValidator` is a Schematron validator implementation that uses the Saxon XSLT processor (Java edition) to validate XML documents against Schematron rules compiled as XSLT stylesheets.
+
+## Overview
+
+Schematron is a rule-based validation language for XML documents. Unlike XSD (XML Schema Definition), which validates structure, Schematron validates business rules and constraints using XPath expressions.
+
+In this implementation:
+1. Schematron rules are pre-compiled into an XSLT stylesheet
+2. Saxon XSLT processor transforms the XML document using the XSLT rules
+3. The output is an SVRL (Schematron Validation Report Language) document
+4. Failed assertions are extracted and reported as validation errors
+
+## Requirements
+
+### System Requirements
+
+- **Java Runtime Environment (JRE)** 8 or higher
+ - The `java` command must be available in your system PATH
+ - Check with: `java -version`
+
+- **Saxon-HE JAR file** (Home Edition, version 9.x or higher)
+ - Download from: [Saxonica Downloads](https://www.saxonica.com/download/java.xml)
+
+### PHP Requirements
+
+- **PHP 8.3** or higher
+- **Required PHP extensions:**
+ - `dom` - for parsing SVRL XML output
+ - `libxml` - for XML handling
+
+### Composer Dependencies
+
+```bash
+composer require symfony/process
+```
+
+The `symfony/process` component is used to execute the Java Saxon processor as a subprocess.
+
+## Usage
+
+### Basic Usage
+
+```php
+validate(
+ xmlFilepath: '/path/to/document.xml',
+ xsltFilepath: '/path/to/schematron-rules.xsl'
+ );
+
+ echo "Validation successful!\n";
+
+} catch (ValidationFailedException $e) {
+ echo "Validation failed: " . $e->getMessage() . "\n";
+
+ // Access validation errors
+ foreach ($e->errors as $error) {
+ echo sprintf(
+ "Error [%s]: %s\n Location: %s\n Test: %s\n",
+ $error->getId(),
+ $error->getText(),
+ $error->getLocation(),
+ $error->getTest()
+ );
+ }
+}
+```
+
diff --git a/src/Schematron/SaxonJarSchematronValidator.php b/src/Schematron/SaxonJarSchematronValidator.php
new file mode 100644
index 0000000..bb97d1e
--- /dev/null
+++ b/src/Schematron/SaxonJarSchematronValidator.php
@@ -0,0 +1,95 @@
+saxonJar,
+ '-s:'.$xmlFilepath,
+ '-xsl:'.$xsltFilepath,
+ ]);
+
+ $process->setTimeout(3600);
+ $process->run();
+
+ if (false === $process->isSuccessful()) {
+ throw new ValidationFailedException(message: $process->getErrorOutput(), code: $process->getExitCode() ?? 1);
+ }
+
+ $output = trim($process->getOutput());
+
+ $doc = new \DOMDocument();
+
+ try {
+ if (false === $doc->loadXML($output)) {
+ throw new ValidationFailedException(message: 'Failed to parse Schematron validation output: invalid XML.');
+ }
+ } catch (\Throwable $throwable) {
+ throw new ValidationFailedException(message: 'Failed to parse Schematron validation output: '.$throwable->getMessage(), previous: $throwable);
+ }
+
+ $xpath = new \DOMXPath($doc);
+ $xpath->registerNamespace('svrl', 'http://purl.oclc.org/dsdl/svrl');
+
+ $failedAsserts = $xpath->query('//svrl:failed-assert');
+
+ if (false === $failedAsserts) {
+ throw new ValidationFailedException(message: 'Failed to parse Schematron validation output');
+ }
+
+ $errors = [];
+
+ /** @var \DOMNode $fa */
+ foreach ($failedAsserts as $fa) {
+ if (!$fa instanceof \DOMElement) {
+ continue;
+ }
+
+ $location = $fa->getAttribute('location');
+ $test = $fa->getAttribute('test');
+
+ $text = null;
+ $textElements = $fa->getElementsByTagName('text');
+ if (0 !== $textElements->length && $textElements->item(0) instanceof \DOMElement) {
+ $text = $textElements->item(0)->nodeValue;
+ }
+
+ $errors[] = new ValidationError(
+ test: $test,
+ id: $fa->getAttribute('id'),
+ flag: $fa->getAttribute('flag'),
+ location: $location,
+ text: $text,
+ );
+ }
+
+ if ([] === $errors) {
+ return;
+ }
+
+ throw new ValidationFailedException(errors: $errors, message: 'Schematron validation failed');
+ }
+}
diff --git a/src/Schematron/SchematronValidatorInterface.php b/src/Schematron/SchematronValidatorInterface.php
new file mode 100644
index 0000000..82c61fc
--- /dev/null
+++ b/src/Schematron/SchematronValidatorInterface.php
@@ -0,0 +1,16 @@
+test = $test;
+ $this->id = $id;
+ $this->flag = $flag;
+ $this->location = $location;
+ $this->text = $text;
+ }
+
+ public function getTest(): string
+ {
+ return $this->test;
+ }
+
+ public function getId(): string
+ {
+ return $this->id;
+ }
+
+ public function getFlag(): string
+ {
+ return $this->flag;
+ }
+
+ public function getLocation(): string
+ {
+ return $this->location;
+ }
+
+ public function getText(): ?string
+ {
+ return $this->text;
+ }
+}
diff --git a/src/Schematron/ValidationFailedException.php b/src/Schematron/ValidationFailedException.php
new file mode 100644
index 0000000..1ef038c
--- /dev/null
+++ b/src/Schematron/ValidationFailedException.php
@@ -0,0 +1,20 @@
+expectNotToPerformAssertions();
+
+ // Act
+ $validator->validate(
+ xmlFilepath: __DIR__.'/../data/UC1_F202500003_01-CDV-200_Deposee.xml',
+ xsltFilepath: __DIR__.'/../data/20260216_BR-FR-CDV-Schematron-CDAR_V1.3.0.xsl',
+ );
+ }
+
+ public function testValidateWithErrors(): void
+ {
+ // Arrange
+ /** @var string $saxonJar */
+ $saxonJar = getenv('SAXON_JAR');
+ $validator = new SaxonJarSchematronValidator(saxonJar: $saxonJar);
+
+ // Act
+ try {
+ $validator->validate(
+ xmlFilepath: __DIR__.'/../data/invalid_cdar.xml',
+ xsltFilepath: __DIR__.'/../data/20260216_BR-FR-CDV-Schematron-CDAR_V1.3.0.xsl',
+ );
+
+ $this->fail('Expected ValidationFailedException was not thrown.');
+ } catch (ValidationFailedException $validationFailedException) {
+ $this->assertCount(4, $validationFailedException->errors);
+ $error1 = $validationFailedException->errors[0];
+ $this->assertNotNull($error1->getText());
+ $this->assertStringContainsString('L\'identifiant du document (ram:ID) est obligatoire', $error1->getText());
+ $error2 = $validationFailedException->errors[1];
+ $this->assertNotNull($error2->getText());
+ $this->assertStringContainsString('Lorsque le rôle du destinataire (MDT-59) est différent de "WK" ou "DFH"', $error2->getText());
+ }
+ }
+}
diff --git a/tests/Serializer/SerializerTest.php b/tests/Serializer/SerializerTest.php
index 5c32ff1..64bc94b 100644
--- a/tests/Serializer/SerializerTest.php
+++ b/tests/Serializer/SerializerTest.php
@@ -58,7 +58,7 @@ public function testDeserialize(): void
$this->assertSame('REGULATED', $exchangedDocumentContext->getBusinessProcessSpecifiedDocumentContextParameter()?->getID()->getValue());
$this->assertSame('urn.cpro.gouv.fr:1p0:CDV:invoice', $exchangedDocumentContext->getGuidelineSpecifiedDocumentContextParameter()->getID()->getValue());
- $this->assertSame('UC1_F202500003_01-CDV-200_Déposée', $cdar->getExchangedDocument()->getName()?->getValue());
+ $this->assertSame('UC1_F202500003_01-CDV-200_Deposee', $cdar->getExchangedDocument()->getName()?->getValue());
$this->assertCount(2, $cdar->getExchangedDocument()->getRecipientTradeParty());
$recipientTradeParty1 = $cdar->getExchangedDocument()->getRecipientTradeParty()[0];
$this->assertNotNull($recipientTradeParty1->getGlobalID());
diff --git a/tests/data/20260216_BR-FR-CDV-Schematron-CDAR_V1.3.0.xsl b/tests/data/20260216_BR-FR-CDV-Schematron-CDAR_V1.3.0.xsl
new file mode 100644
index 0000000..d921472
--- /dev/null
+++ b/tests/data/20260216_BR-FR-CDV-Schematron-CDAR_V1.3.0.xsl
@@ -0,0 +1,1754 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ /
+
+
+
+
+
+ *:
+
+ [namespace-uri()='
+
+ ']
+
+
+
+ [
+
+ ]
+
+
+
+ /
+
+ @
+
+
+ @*[local-name()='
+
+ ' and namespace-uri()='
+
+ ']
+
+
+
+
+
+
+
+ /
+
+
+ [
+
+ ]
+
+
+
+ /@
+
+
+
+
+
+
+ /
+
+
+ [
+
+ ]
+
+
+
+ /@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ .
+
+
+
+ U
+
+ U
+
+
+
+ U.
+
+ n
+
+
+
+ U.
+
+ _
+
+ _
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-04
+ BR-FR-04 — Validation des codes de type de document
+
+
+
+
+
+
+
+ BR-FR-CDV-01
+ BR-FR-CDV-01 — Présence obligatoire de MDG-3
+
+
+
+
+
+
+
+ BR-FR-CDV-02
+ BR-FR-CDV-02 — Vérification de la valeur de MDT-3
+
+
+
+
+
+
+
+ BR-FR-CDV-03
+ BR-FR-CDV-03 — Présence obligatoire de MDT-4
+
+
+
+
+
+
+
+ BR-FR-CDV-04
+ BR-FR-CDV-04 — Présence obligatoire de MDG-4
+
+
+
+
+
+
+
+ BR-FR-CDV-05
+ BR-FR-CDV-05 — Présence obligatoire de MDG-9
+
+
+
+
+
+
+
+ BR-FR-CDV-06
+ BR-FR-CDV-06 — Présence obligatoire de MDT-21
+
+
+
+
+
+
+
+ BR-FR-CDV-07
+ BR-FR-CDV-07 — Validation conditionnelle de MDT-38 selon MDT-77
+
+
+
+
+
+
+
+ BR-FR-CDV-08
+ BR-FR-CDV-08 — Obligation conditionnelle de MDT-73
+
+
+
+
+
+
+
+ BR-FR-CDV-09
+ BR-FR-CDV-09 — Présence et valeur de MDT-77
+
+
+
+
+
+
+
+ BR-FR-CDV-10
+ BR-FR-CDV-10 — Présence obligatoire de MDT-87
+
+
+
+
+
+
+
+ BR-FR-CDV-11
+ BR-FR-CDV-11 — Présence obligatoire de MDG-35
+
+
+
+
+
+
+
+ BR-FR-CDV-12
+ BR-FR-CDV-12 — Présence obligatoire de MDT-105
+
+
+
+
+
+
+
+ BR-FR-CDV-13
+ BR-FR-CDV-13 — Présence obligatoire de MDT-129
+
+
+
+
+
+
+
+ BR-FR-CDV-14
+ BR-FR-CDV-14 — Vérification des caractéristiques en cas de statut "Encaissé"
+
+
+
+
+
+
+
+ BR-FR-CDV-15
+ BR-FR-CDV-14 — Vérification des caractéristiques en cas de statut "Encaissé"
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-01
+ BR-FR-CDV-CL-01 — Liste fermée de valeurs pour MDT-2
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-02
+ BR-FR-CDV-CL-02 — Contrôle de cohérence entre MDT-77 et MDT-21
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-03
+ BR-FR-CDV-CL-03 — Contrôle de cohérence entre MDT-77 et MDT-40
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-04
+ BR-FR-CDV-CL-04 — Liste fermée de valeurs pour MDT-59
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-05
+ BR-FR-CDV-CL-05 — Contrôle des statuts MDT-88 selon MDT-77
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-06
+ BR-FR-CDV-CL-06 — Liste fermée de codes statuts de facture
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-07
+ BR-FR-CDV-CL-07 — Vérification de la valeur de MDT-132
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-08
+ BR-FR-CDV-CL-08 — Liste fermée de valeurs pour MDT-158
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-09
+ BR-FR-CDV-CL-09 — Liste fermée de codes motifs de statuts
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-10
+ BR-FR-CDV-CL-10 — Liste fermée de codes actions de facture
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-11
+ BR-FR-CDV-CL-11 — Liste fermée de codes pour MDT-207
+
+
+
+
+
+
+
+
+ BR-FR-04 — Validation des codes de type de document
+
+
+
+
+
+
+
+
+ BR-FR-04_MDT-91
+ warning
+
+
+
+
+ [BR-FR-04/MDT-91] : Le code de type de document "
+
+ " n'est pas autorisé selon les spécifications françaises.
+ Veuillez utiliser un code parmi ceux définis dans la documentation (ex. : 380, 389, 393, etc.).
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-01 — Présence obligatoire de MDG-3
+
+
+
+
+
+
+
+
+ BR-FR-CDV-01_MDG-3
+ warning
+
+
+
+
+ [BR-FR-CDV-01/MDG-3] : Le paramètre de contexte MDG-3 est obligatoire dans le document.
+ Veuillez vous assurer que l'élément ram:GuidelineSpecifiedDocumentContextParameter est bien présent et correctement renseigné.
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-02 — Vérification de la valeur de MDT-3
+
+
+
+
+
+
+
+
+ BR-FR-CDV-02_MDT-3
+ warning
+
+
+
+
+ [BR-FR-CDV-02/MDT-3] : La valeur de MDT-3 doit être :
+ - "urn.cpro.gouv.fr:1p0:CDV:invoice", ou
+ - "urn.cpro.gouv.fr:1p0:CDV:einvoicingF2" **uniquement si** il y a un unique Destinataire (Recipent) et que c'est le PPF : GlobalID = 9998 avec @shemeId = 0238 et CodeRole = DFH.
+ Valeurs actuelles : "
+
+ ". Nombre de Recipient : "
+
+ " - GlobalID : "
+
+ " - @shemeID : "
+
+ " - CodeRole : "
+
+ "
+ Veuillez corriger cette valeur pour respecter les spécifications du format CDV.
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-03 — Présence obligatoire de MDT-4
+
+
+
+
+
+
+
+
+ BR-FR-CDV-03_MDT-4
+ warning
+
+
+
+
+ [BR-FR-CDV-03/MDT-4] : L'identifiant du document (ram:ID) est obligatoire.
+ Veuillez vous assurer que l'élément "ram:ID" est bien présent dans "rsm:ExchangedDocument".
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-04 — Présence obligatoire de MDG-4
+
+
+
+
+
+
+
+
+ BR-FR-CDV-04_MDG-4
+ warning
+
+
+
+
+ [BR-FR-CDV-04/MDG-4] : La date d’émission du document (MDG-4) est obligatoire.
+ Veuillez vous assurer que l’élément "ram:IssueDateTime" est bien présent dans "rsm:ExchangedDocument".
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-05 — Présence obligatoire de MDG-9
+
+
+
+
+
+
+
+
+ BR-FR-CDV-05_MDG-9
+ warning
+
+
+
+
+ [BR-FR-CDV-05/MDG-9] : Le partenaire commercial émetteur (MDG-9) est obligatoire.
+ Veuillez vous assurer que l’élément "ram:SenderTradeParty" est bien présent dans "rsm:ExchangedDocument".
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-06 — Présence obligatoire de MDT-21
+
+
+
+
+
+
+
+
+ BR-FR-CDV-06_MDT-21
+ warning
+
+
+
+
+ [BR-FR-CDV-06/MDT-21] : Le rôle du partenaire commercial émetteur (MDT-21) est obligatoire.
+ Veuillez vous assurer que l’élément "ram:RoleCode" est bien présent dans "rsm:ExchangedDocument/ram:SenderTradeParty".
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-07 — Validation conditionnelle de MDT-38 selon MDT-77
+
+
+
+
+
+
+
+
+ BR-FR-CDV-07_MDT-38_yes
+ warning
+
+
+
+
+ [BR-FR-CDV-07/MDT-38] : Lorsque le rôle du partenaire commercial émetteur (MDT-77) est égal à "23", l'identifiant (MDT-38) doit être renseigné.
+ Veuillez vous assurer que l'élément "ram:GlobalID" est présent dans "ram:IssuerTradeParty".
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-07_MDT-38_no
+ warning
+
+
+
+
+ [BR-FR-CDV-07/MDT-38] : Lorsque le rôle du partenaire commercial émetteur (MDT-77) est égal à "305", l'identifiant (MDT-38) ne doit pas être renseigné.
+ Veuillez retirer l'élément "ram:GlobalID" de "ram:IssuerTradeParty" dans ce cas.
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-08 — Obligation conditionnelle de MDT-73
+
+
+
+
+
+
+
+
+ BR-FR-CDV-08_MDT-73
+ warning
+
+
+
+
+ [BR-FR-CDV-08/MDT-73] : Lorsque le rôle du destinataire (MDT-59) est différent de "WK" ou "DFH", l'adresse électronique du destinataire (MDT-73) est obligatoire.
+ Veuillez vous assurer que l’élément "ram:URIID" est bien présent dans "ram:URIUniversalCommunication".
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-09 — Présence et valeur de MDT-77
+
+
+
+
+
+
+
+
+ BR-FR-CDV-09_MDT-77
+ warning
+
+
+
+
+ [BR-FR-CDV-09/MDT-77] : Le code de type de document (MDT-77) est obligatoire et doit être égal à "23" ou "305".
+ Valeur actuelle : "
+
+ ". Veuillez corriger cette valeur si nécessaire.
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-10 — Présence obligatoire de MDT-87
+
+
+
+
+
+
+
+
+ BR-FR-CDV-10_MDT-87
+ warning
+
+
+
+
+ [BR-FR-CDV-10/MDT-87] : L'identifiant de la facture référencée (MDT-87) est obligatoire.
+ Veuillez vous assurer que l’élément "ram:IssuerAssignedID" est bien présent dans "rsm:ReferenceReferencedDocument".
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-11 — Présence obligatoire de MDG-35
+
+
+
+
+
+
+
+
+ BR-FR-CDV-11_MDG-35
+ warning
+
+
+
+
+ [BR-FR-CDV-11/MDG-35] : La date d’émission formatée de la facture référencée (MDG-35) est obligatoire,
+ sauf si MDT-105 (code statut) est égal à "501" (IRRECEVABLE).
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-12 — Présence obligatoire de MDT-105
+
+
+
+
+
+
+
+
+ BR-FR-CDV-12_MDT-105
+ warning
+
+
+
+
+ [BR-FR-CDV-12/MDT-105] : Le code de condition de traitement (MDT-105) est obligatoire.
+ Veuillez vous assurer que l’élément "ram:ProcessConditionCode" est bien présent dans "rsm:ReferenceReferencedDocument".
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-13 — Présence obligatoire de MDT-129
+
+
+
+
+
+
+
+
+ BR-FR-CDV-13_MDT-129
+ warning
+
+
+
+
+ [BR-FR-CDV-13/MDT-129] : L'identifiant du partenaire commercial émetteur (MDT-129) est obligatoire,
+ sauf si MDT-105 (ram:ID dans BusinessProcessSpecifiedDocumentContextParameter) est égal à "501".
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-14 — Vérification des caractéristiques en cas de statut "Encaissé"
+
+
+
+
+
+
+
+
+ BR-FR-CDV-14_MDT-207
+ warning
+
+
+
+
+ [BR-FR-CDV-14/MDT-207] : Lorsque le statut de traitement (MDT-105) est "212" (encaissé), il doit exister au moins un bloc "ram:SpecifiedDocumentCharacteristic" avec :
+ - un "ram:TypeCode" égal à "MEN"
+ - et une valeur "ram:ValueAmount" renseignée.
+ Veuillez vérifier la présence et le contenu de ces éléments.
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-14 — Vérification des caractéristiques en cas de statut "Encaissé"
+
+
+
+
+
+
+
+
+ BR-FR-CDV-15_MDT-113
+ warning
+
+
+
+
+ [BR-FR-CDV-15/MDT-113] : Code Statut : "
+
+ " : lorsque le statut (MDT-105 ou MDT-115) est égal à 210 (Refusée), 123 (Rejetée), 501 (Irrecevable), 207 (Litige), 206 (Suspendue) pu 208 (Approuvée Partiellement), lors un MOTIF (MDT-113) DOIT être présent.
+ Veuillez vérifier la présence et le contenu du MOTIF (MDT-113).
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-01 — Liste fermée de valeurs pour MDT-2
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-01_MDT-2
+ warning
+
+
+
+
+ [BR-FR-CDV-CL-01/MDT-2] : La valeur de MDT-2 doit être l'une des suivantes : "REGULATED", "NON_REGULATED", "B2C", "B2BINT", "OUTOFSCOPE" sauf pour un CDV pour le PPF pourlequel le nombre de caractères DOIT être inférieur à 3.
+ Valeur actuelle : CDV PPF ? (true) : "
+
+ " - Valeur MDT-2 : "
+
+ ". Veuillez corriger cette valeur si nécessaire.
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-02 — Contrôle de cohérence entre MDT-77 et MDT-21
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-02_MDT-21_305
+ warning
+
+
+
+
+ [BR-FR-CDV-CL-02/MDT-21] : Lorsque le statut (MDT-77) est "305", le rôle du partenaire commercial émetteur (MDT-21) doit être "WK".
+ Valeur actuelle : "
+
+ ".
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-02_MDT-21_23
+ warning
+
+
+
+
+ [BR-FR-CDV-CL-02/MDT-21] : Lorsque le statut (MDT-77) est "23", le rôle du partenaire commercial émetteur (MDT-21) doit être dans la liste suivante :
+ "BY", "AB", "DL", "SE", "SR", "WK", "PE", "PR", "II", "IV".
+ Valeur actuelle : "
+
+ ".
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-03 — Contrôle de cohérence entre MDT-77 et MDT-40
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-03_MDT-40_305
+ warning
+
+
+
+
+ [BR-FR-CDV-CL-03/MDT-40] : Lorsque le statut (MDT-77) est "305", le rôle du partenaire commercial émetteur (MDT-40) doit être "WK".
+ Valeur actuelle : "
+
+ ".
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-03_MDT-40_23
+ warning
+
+
+
+
+ [BR-FR-CDV-CL-03/MDT-40] : Lorsque le statut (MDT-77) est "23", le rôle du partenaire commercial émetteur (MDT-40) doit être dans la liste suivante :
+ "BY", "AB", "DL", "SE", "SR", "PE", "PR", "II", "IV".
+ Valeur actuelle : "
+
+ ".
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-04 — Liste fermée de valeurs pour MDT-59
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-04_MDT-59
+ warning
+
+
+
+
+ [BR-FR-CDV-CL-04/MDT-59] : Le rôle du partenaire commercial destinataire (MDT-59) doit être dans la liste suivante :
+ "BY", "AB", "DL", "SE", "SR", "PE", "PR", "II", "IV", "WK", "DFH".
+ Valeur actuelle : "
+
+ ". Veuillez corriger cette valeur si nécessaire.
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-05 — Contrôle des statuts MDT-88 selon MDT-77
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-05_MDT-88_305
+ warning
+
+
+
+
+ [BR-FR-CDV-CL-05/MDT-88] : Lorsque MDT-77 = "305" (Phase Transmission), siprésent, MDT-88 doit être l’un des codes suivants :
+ "10", "51", "43", "8", "48".
+ Valeur actuelle : "
+
+ ".
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-05_MDT-88_23
+ warning
+
+
+
+
+ [BR-FR-CDV-CL-05/MDT-88] : Lorsque MDT-77 = "23" (Phase Traitement), si présent, MDT-88 doit être l’un des codes suivants :
+ "45", "39", "37", "50", "49", "47", "46", "1".
+ Valeur actuelle : "
+
+ ".
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-06 — Liste fermée de codes statuts de facture
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-06_MDT-105
+ warning
+
+
+
+
+ [BR-FR-CDV-CL-06/MDT-105] : Le code de statut de facture (MDT-105) doit être dans la liste des codes autorisés :
+ "200", "201", ..., "228".
+ Valeur actuelle : "
+
+ ".
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-06_MDT-115
+ warning
+
+
+
+
+ [BR-FR-CDV-CL-06/MDT-115] : Le code de statut de facture (MDT-115) doit être dans la liste des codes autorisés :
+ "200", "201", ..., "228".
+ Valeur actuelle : "
+
+ ".
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-07 — Vérification de la valeur de MDT-132
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-07_MDT-132
+ warning
+
+
+
+
+ [BR-FR-CDV-CL-07/MDT-132] : Le rôle du partenaire commercial émetteur (MDT-132) doit être "SE" (Vendeur).
+ Valeur actuelle : "
+
+ ". Veuillez corriger cette valeur si nécessaire.
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-08 — Liste fermée de valeurs pour MDT-158
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-08_MDT-158
+ warning
+
+
+
+
+ [BR-FR-CDV-CL-08/MDT-158] : Le rôle du partenaire commercial destinataire (MDT-158) doit être dans la liste suivante :
+ "BY", "AB", "DL", "SE", "SR", "WK", "DFH", "PE", "PR", "II", "IV".
+ Valeur actuelle : "
+
+ ". Veuillez corriger cette valeur si nécessaire.
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-09 — Liste fermée de codes motifs de statuts
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-09_MDT-113
+ warning
+
+
+
+
+ [BR-FR-CDV-CL-09/MDT-113] : Le code motif de statut (MDT-113) : "
+
+ " n'est pas dans la liste des codes autorisés :
+ "NON_TRANSMISE", "JUSTIF_ABS", "ROUTAGE_ERR", "AUTRE", "COORD_BANC_ERR", "TX_TVA_ERR", "MONTANTTOTAL_ERR", "CALCUL_ERR", "NON_CONFORME", "DOUBLON", "DEST_INC", "DEST_ERR", "TRANSAC_INC", "EMMET_INC", "CONTRAT_TERM", "DOUBLE_FACT", "CMD_ERR", "ADR_ERR", "SIRET_ERR", "CODE_ROUTAGE_ERR", "REF_CT_ABSENT", "REF_ERR", "PU_ERR", "REM_ERR", "QTE_ERR", "ART_ERR", "MODPAI_ERR", "QUALITE_ERR", "LIVR_INCOMP", "REJ_SEMAN", "REJ_UNI", "REJ_COH", "REJ_ADR", "REJ_CONT_B2G", "REJ_REF_PJ", "REJ_ASS_PJ", "IRR_VIDE_F", "IRR_TYPE_F", "IRR_SYNTAX", "IRR_TAILLE_PJ", "IRR_NOM_PJ", "IRR_VID_PJ", "IRR_EXT_DOC", "IRR_TAILLE_F", "IRR_ANTIVIRUS".
+ Veuillez corriger cette valeur si nécessaire.
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-09_MDT-113_200
+ warning
+
+
+
+
+ [BR-FR-CDV-CL-09/MDT-113_200] : Le code motif de statut (MDT-113) : "
+
+ ", n'est pas dans la liste des codes autorisés pour le statut DÉPOSÉE (200) :
+ "NON_TRANSMISE". Veuillez corriger cette valeur si nécessaire.
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-09_MDT-113_213
+ warning
+
+
+
+
+ [BR-FR-CDV-CL-09/MDT-113_213] : Le code motif de statut (MDT-113) : "
+
+ ", n'est pas dans la liste des codes autorisés pour le statut REJETÉE (213) :
+ "MONTANTTOTAL_ERR", "CALCUL_ERR", "DOUBLON", "DEST_INC", "ADR_ERR", "REJ_SEMAN", "REJ_UNI", "REJ_COH", "REJ_ADR", "REJ_CONT_B2G", "REJ_REF_PJ", "REJ_ASS_PJ".
+ Veuillez corriger cette valeur si nécessaire.
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-09_MDT-113_210
+ warning
+
+
+
+
+ [BR-FR-CDV-CL-09/MDT-113_210] : Le code motif de statut (MDT-113) : "
+
+ ", n'est pas dans la liste des codes autorisés pour le statut REFUSÉE (210) :
+ "TX_TVA_ERR", "MONTANTTOTAL_ERR", "CALCUL_ERR", "NON_CONFORME", "DOUBLON", "DEST_ERR", "TRANSAC_INC", "EMMET_INC", "CONTRAT_TERM", "DOUBLE_FACT", "CMD_ERR", "ADR_ERR", "REF_CT_ABSENT".
+ Veuillez corriger cette valeur si nécessaire.
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-09_MDT-113_207
+ warning
+
+
+
+
+ [BR-FR-CDV-CL-09/MDT-113_207] : Le code motif de statut (MDT-113) : "
+
+ ", n'est pas dans la liste des codes autorisés pour le statut LITIGE (207) :
+ "AUTRE", "COORD_BANC_ERR", "TX_TVA_ERR", "MONTANTTOTAL_ERR", "CALCUL_ERR", "NON_CONFORME", "DOUBLON", "DEST_INC", "DEST_ERR", "TRANSAC_INC", "EMMET_INC", "CONTRAT_TERM", "DOUBLE_FACT",
+ "CMD_ERR", "ADR_ERR", "SIRET_ERR", "CODE_ROUTAGE_ERR", "REF_CT_ABSENT", "REF_ERR", "PU_ERR", "REM_ERR", "QTE_ERR", "ART_ERR", "MODPAI_ERR", "QUALITE_ERR", "LIVR_INCOMP".
+ Veuillez corriger cette valeur si nécessaire.
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-09_MDT-113_206
+ warning
+
+
+
+
+ [BR-FR-CDV-CL-09/MDT-113_206] : Le code motif de statut (MDT-113) : "
+
+ ", n'est pas dans la liste des codes autorisés pour le statut APPROUVÉE PARTIELLEMENT (206) :
+ "AUTRE", "CMD_ERR", "SIRET_ERR", "CODE_ROUTAGE_ERR", "REF_CT_ABSENT", "REF_ERR", "PU_ERR", "REM_ERR", "QTE_ERR", "ART_ERR", "MODPAI_ERR", "QUALITE_ERR", "LIVR_INCOMP".
+ Veuillez corriger cette valeur si nécessaire.
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-09_MDT-113_208
+ warning
+
+
+
+
+ [BR-FR-CDV-CL-09/MDT-113_208] : Le code motif de statut (MDT-113) : "
+
+ ", n'est pas dans la liste des codes autorisés pour le statut SUSPENDUE (208) :
+ "JUSTIF_ABS", "COORD_BANC_ERR", "CMD_ERR", "SIRET_ERR", "CODE_ROUTAGE_ERR", "REF_CT_ABSENT", "REF_ERR".
+ Veuillez corriger cette valeur si nécessaire.
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-09_MDT-113_221
+ warning
+
+
+
+
+ [BR-FR-CDV-CL-09/MDT-113_221] : Le code motif de statut (MDT-113) : "
+
+ ", n'est pas dans la liste des codes autorisés pour le statut ERREUR_ROUTAGE (221) :
+ "ROUTAGE_ERR". Veuillez corriger cette valeur si nécessaire.
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-09_MDT-113_501
+ warning
+
+
+
+
+ [BR-FR-CDV-CL-09/MDT-113_501] : Le code motif de statut (MDT-113) : "
+
+ ", n'est pas dans la liste des codes autorisés pour le statut IRRECEVABLE (501) :
+ "IRR_VIDE_F", "IRR_TYPE_F", "IRR_SYNTAX", "IRR_TAILLE_PJ", "IRR_NOM_PJ", "IRR_VID_PJ", "IRR_EXT_DOC, "IRR_TAILLE_F", "IRR_ANTIVIRUS". Veuillez corriger cette valeur si nécessaire.
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-10 — Liste fermée de codes actions de facture
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-10_MDT-121
+ warning
+
+
+
+
+ [BR-FR-CDV-CL-10/MDT-121] : Le code d'action de facture (MDT-121) doit être dans la liste des codes autorisés :
+ "NOA", "PIN", "NIN", "CNF", "CNP", "CNA", "OTH".
+ Valeur actuelle : "
+
+ ". Veuillez corriger cette valeur si nécessaire.
+
+
+
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-11 — Liste fermée de codes pour MDT-207
+
+
+
+
+
+
+
+
+ BR-FR-CDV-CL-11_MDT-207
+ warning
+
+
+
+
+ [BR-FR-CDV-CL-11/MDT-207] : La valeur du TypeCode (MDT-207) doit appartenir à la liste fermée des codes autorisés :
+ MEN, MPA, RAP, ESC, RAB, REM, MAP, MAPTTC, MNA, MNATTC, CBB, DIV, DVA, MAJ.
+ Valeur actuelle : "
+
+ ". Veuillez corriger cette valeur si elle ne correspond pas à un code valide.
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/data/UC1_F202500003_01-CDV-200_Deposee.xml b/tests/data/UC1_F202500003_01-CDV-200_Deposee.xml
index 168227e..c1a0d14 100644
--- a/tests/data/UC1_F202500003_01-CDV-200_Deposee.xml
+++ b/tests/data/UC1_F202500003_01-CDV-200_Deposee.xml
@@ -1,63 +1,67 @@
-
-
- REGULATED
-
-
- urn.cpro.gouv.fr:1p0:CDV:invoice
-
-
-
- UC1_F202500003_01-CDV-200_Déposée
-
- 20250701151500
-
-
- WK
-
-
- WK
-
-
- 100000009
- VENDEUR
- SE
-
-
- 9998
- PPF
- DFH
-
-
-
-
- false
-
- 305
-
- 20250701151000
-
-
- F202500003
- 10
- 380
-
- 20250701151000
-
-
- 20250701
-
- 200
- Déposée
-
- 100000009
-
-
-
+xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100"
+ xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"
+ xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
+ xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossDomainAcknowledgementAndResponse:100"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+
+
+ REGULATED
+
+
+ urn.cpro.gouv.fr:1p0:CDV:invoice
+
+
+
+ F202500003_200_20250701151000#380_20250701
+ UC1_F202500003_01-CDV-200_Deposee
+
+ 20250701151500
+
+
+ WK
+
+
+ WK
+
+
+ 100000009
+ VENDEUR
+ SE
+
+ 100000009_STATUTS
+
+
+
+ 9998
+ PPF
+ DFH
+
+
+
+
+ false
+
+ 305
+
+ 20250701151000
+
+
+ F202500003
+ 10
+ 380
+
+ 20250701151000
+
+
+ 20250701
+
+ 200
+ Déposée
+
+ 100000009
+
+
+
\ No newline at end of file