superius/ubl-invoice

Superius UBL Invoice Package for Laravel

Installs: 1 247

Dependents: 0

Suggesters: 0

Security: 0

pkg:composer/superius/ubl-invoice


README

A Laravel package for validating UBL (Universal Business Language) invoices against XML schemas, including support for Croatian e-invoicing standards (FISK 2.0).

Recent Fixes

Fix #2: High Precision Decimal Numbers (MultiplierFactorNumeric)

Problem

XML schema validation was failing with high precision decimal numbers:

Element '{urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2}MultiplierFactorNumeric':
'23.8938053097345132743362831858407079646' is not a valid value
of the atomic type 'xs:decimal'.

Root Cause

The issue occurred due to precision limitations in libxml2's xs:decimal type:

  1. High Precision Decimals: Discount/charge multiplier calculations can produce decimal numbers with 30+ decimal places (e.g., when calculating exact percentages).

  2. libxml2 Decimal Limitation: While xs:decimal theoretically supports arbitrary precision, libxml2's implementation has practical limits on the number of significant digits it can validate.

  3. Schema Definition: The UBL schema defines MultiplierFactorNumericType extending NumericType, which uses base="xsd:decimal", triggering validation errors for high-precision values.

Solution

Modified MultiplierFactorNumericType to use TextType instead of NumericType:

File: src/Services/XmlSchemaValidator/XmlSchemas/ubl/common/UBL-CommonBasicComponents-2.1.xsd

<!-- Before -->
<xsd:complexType name="MultiplierFactorNumericType">
  <xsd:simpleContent>
    <xsd:extension base="udt:NumericType"/>
  </xsd:simpleContent>
</xsd:complexType>

<!-- After -->
<xsd:complexType name="MultiplierFactorNumericType">
  <xsd:simpleContent>
    <xsd:extension base="udt:TextType"/>
  </xsd:simpleContent>
</xsd:complexType>

Why This Fix Works

  1. Targeted Fix: Only affects MultiplierFactorNumeric fields, preserving strict numeric validation for other numeric types.

  2. Unlimited Precision: Text-based validation removes artificial precision limits while maintaining the value as-is.

  3. Semantic Correctness: Multiplier factors are stored and transmitted as strings in XML. The text type accurately represents this while allowing arbitrary precision.

  4. Backward Compatibility: All valid decimal numbers are also valid text strings, so existing documents continue to validate correctly.

Testing

Added specific test for high-precision decimals in tests/Services/XmlSchemaValidatorTest.php:

vendor/bin/pest tests/Services/XmlSchemaValidatorTest.php

The test validates that MultiplierFactorNumeric with 38 decimal places passes validation.

Fix #1: X.509 Certificate Serial Number Validation

Problem

XML schema validation was failing with the following error:

Element '{http://www.w3.org/2000/09/xmldsig#}X509SerialNumber':
'110746456427574609188109388963935261765' is not a valid value
of the atomic type 'xs:integer'.

Root Cause

The issue occurred due to a limitation in libxml2 (the underlying XML parsing library used by PHP):

  1. X.509 Serial Numbers: Certificate serial numbers can be arbitrarily large integers. The serial number 110746456427574609188109388963935261765 is a 130-bit number (39 decimal digits).

  2. libxml2 Integer Limitation: While XML Schema's xs:integer type theoretically supports unbounded integers, libxml2 validates integers using system-dependent integer types, typically with a maximum value of 2^63-1 on 64-bit systems.

  3. Schema Definition: The W3C XML Digital Signature schema (xmldsig-core-schema.xsd) defines X509SerialNumber as type="integer", which triggers this validation error for large certificate serial numbers.

Solution

Modified the XML Digital Signature schema to use string instead of integer for the X509SerialNumber element:

File: src/Services/XmlSchemaValidator/XmlSchemas/ubl/common/xmldsig-core-schema.xsd

<!-- Before -->
<complexType name="X509IssuerSerialType">
  <sequence>
    <element name="X509IssuerName" type="string"/>
    <element name="X509SerialNumber" type="integer"/>
  </sequence>
</complexType>

<!-- After -->
<complexType name="X509IssuerSerialType">
  <sequence>
    <element name="X509IssuerName" type="string"/>
    <element name="X509SerialNumber" type="string"/>
  </sequence>
</complexType>

Why This Fix Works

  1. Semantic Correctness: Certificate serial numbers are identifiers, not numeric values used for arithmetic operations. Using string type is semantically appropriate.

  2. Industry Practice: This is a well-known workaround in XML signature validation implementations. Many production systems use string type for X509SerialNumber to avoid this limitation.

  3. Specification Compliance: The fix maintains compatibility with X.509 certificates while working around libxml2's implementation constraints.

Testing

The fix was validated using the test suite:

vendor/bin/pest tests/Services/XmlSchemaValidatorTest.php

The test validates:

  • Correct XML documents pass validation
  • Invalid XML documents are properly rejected with appropriate exceptions

Related Standards

  • UBL 2.1: Universal Business Language standard for electronic documents
  • XML Digital Signature: W3C recommendation for XML-based digital signatures
  • Croatian e-Invoicing: Ministry of Finance FISK 2.0 requirements (urn:mfin.gov.hr:cius-2025:1.0)

License

Proprietary - Superius Internal