Search code examples
invoicepdfa

Create a facturX with Mustang from XML String


I'm trying to build a facturx using Mustang library in an API. I have a (valid) XML string as entry

@PostMapping
public FxResponse createFacturX(@RequestBody XmlRequest request) throws IOException {
    if(request.getVersion() == null) {
        request.setVersion(2);
    }

    ByteArrayOutputStream output = new ByteArrayOutputStream();
    log.debug("Converting to PDF/A-3u");

    if ((request.getVersion() < 1) || (request.getVersion() > 2)) {
        throw new IllegalArgumentException("invalid version");
    }


    PDFAConformanceLevel pdfaConformanceLevel;
    switch (request.getConformanceLevel()) {
        case "BASIC":
            pdfaConformanceLevel = PDFAConformanceLevel.BASIC;
            break;
        case "ACCESSIBLE":
            pdfaConformanceLevel = PDFAConformanceLevel.ACCESSIBLE;
            break;
        case "UNICODE":
            pdfaConformanceLevel = PDFAConformanceLevel.UNICODE;
            break;
        default:
            throw new IllegalArgumentException("invalid level");
    }

    System.out.println(Arrays.toString(request.getPdf().getBytes(StandardCharsets.UTF_8)));
    byte[] xmlData = request.getXml().getBytes(StandardCharsets.UTF_8);
    byte[] pdfData = Base64.getDecoder().decode(request.getPdf().getBytes(StandardCharsets.UTF_8));


    ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1()
            .setProducer("Mustang API")
            .setCreator("Creator ME")
            .setZUGFeRDVersion(request.getVersion())
            .setConformanceLevel(pdfaConformanceLevel)
            .load(pdfData);
    ze.attachFile("factur-x.xml", xmlData, "text/xml", "Data");
    ze.setXML(xmlData);

    log.debug("Attaching ZUGFeRD-Data");
    ze.disableAutoClose(true);
    ze.export(output);
    byte[] bytes = output.toByteArray();
    InputStream inputStream = new ByteArrayInputStream(bytes);

    byte[] pdfBytes = IOUtils.toByteArray(inputStream);

    try {
        Utils.facturxValidator(request.getXml());
    } catch (Exception e) {
        e.printStackTrace();
    }

    String encoded = Base64.getEncoder().encodeToString(pdfBytes);
    return new FxResponse("OK", encoded);
}

I do retrieve a PDF as output but i have errors while validating the PDF.

enter image description here

On the other hand, my XML is fully valid

enter image description here

I tried to check if pdf was compliant or not to and I also tried mustang cli to check the ouput. I do have the following failures:

  <xml>
    <info>
      <version>2</version>
      <profile>urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:basic</profile>
      <validator version="2.4.0"/>
      <rules>
        <fired>466</fired>
        <failed>3</failed>
      </rules>
      <duration unit="ms">5242</duration>
    </info>
    <messages>
      <notice type="27" location="/*:CrossIndustryInvoice[namespace-uri()='urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100'][1]/*:ExchangedDocumentContext[namespace-uri()='urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100'][1]" criterion="ram:GuidelineSpecifiedDocumentContextParameter/ram:ID = $XR-CIUS-ID">[BR-DE-21] Das Element "Specification identifier" (BT-24) soll syntaktisch der Kennung des Standards XRechnung entsprechen. (From /xslt/XR_21/XRechnung-CII-validation.xslt)</notice>
      <notice type="27" location="/*:CrossIndustryInvoice[namespace-uri()='urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100'][1]/*:SupplyChainTradeTransaction[namespace-uri()='urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100'][1]/*:ApplicableHeaderTradeAgreement[namespace-uri()='urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100'][1]/*:SellerTradeParty[namespace-uri()='urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100'][1]" criterion="ram:DefinedTradeContact">[BR-DE-2] Die Gruppe "SELLER CONTACT" (BG-6) muss übermittelt werden. (From /xslt/XR_21/XRechnung-CII-validation.xslt)</notice>
      <notice type="27" location="/*:CrossIndustryInvoice[namespace-uri()='urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100'][1]/*:SupplyChainTradeTransaction[namespace-uri()='urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100'][1]/*:ApplicableHeaderTradeSettlement[namespace-uri()='urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100'][1]/*:SpecifiedTradeSettlementPaymentMeans[namespace-uri()='urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100'][1]" criterion="not(ram:ApplicableTradeSettlementFinancialCard) and not(/rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradePaymentTerms/ram:DirectDebitMandateID or /rsm:CrossIndustryInvoice/rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:CreditorReferenceID or ram:PayerPartyDebtorFinancialAccount/ram:IBANID)">[BR-DE-23-b] Wenn BT-81 "Payment means type code" einen Schlüssel für Überweisungen enthält (30, 58), dürfen BG-18 und BG-19 nicht übermittelt werden. (From /xslt/XR_21/XRechnung-CII-validation.xslt)</notice>
    </messages>
    <summary status="valid"/>
  </xml>

My questions are the following :

  1. How can I solve those failure
  2. Are those errors have impact on my facturX ? I do validated them on a test site, It's not on production

Solution

  • I noticed that i forgot to set facturx profile, for example, EXTENDED:

    ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1()
            .setProducer("Mustang API")
            .setCreator("Creator ME")
            .setProfile("EXTENDED");
            .setZUGFeRDVersion(request.getVersion())
            .setConformanceLevel(pdfaConformanceLevel)
            .load(pdfData);
    ze.attachFile("factur-x.xml", xmlData, "text/xml", "Data");
    ze.setXML(xmlData)
    

    Available values are the following:

    {"MINIMUM", new Profile("MINIMUM", "urn:factur-x.eu:1p0:minimum")},
    {"BASICWL", new Profile("BASICWL", "urn:factur-x.eu:1p0:basicwl")},
    {"BASIC", new Profile("BASIC", "urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:basic")},
    {"EN16931", new Profile("EN16931", "urn:cen.eu:en16931:2017")},
    {"EXTENDED", new Profile("EXTENDED", "urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended")},
    {"XRECHNUNG", new Profile("XRECHNUNG", "urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_2.1")}
    

    It works fine now !