API-Engine · Quellcode ZUGFeRD / Factur-X · Invoice Processing 187 Zeilen · CII-XML
/*
 * ZUGFeRD / Factur-X invoice processing example
 *
 * Scans a Domino database for unprocessed invoice documents,
 * reads the attached PDF into memory, extracts the embedded invoice XML
 * and stores selected invoice data back into the Domino document.
 */

/* Database and processing settings */

ZUGFeRD_DB_Path:="TEST\\TestDBMstr.NSF";
ZUGFeRD_DB_Search_Formula:="SELECT Form=\"ZUGFeRDDoc\" & @IsUnavailable(Status);";

XMLDoAttachFile:=0;
XMLAttachmentName:="Invoice.XML";

/* Find and process unprocessed invoice documents */

ZUGFeRD_DB_h:=@OpenDB(ZUGFeRD_DB_Path);

ZUGFeRD_DB_IDL:=@ScanDB(ZUGFeRD_DB_h;ZUGFeRD_DB_Search_Formula;@AnyAllDay;1;1);

ZUGFeRD_DB_IDL_Index:=1;
ZUGFeRD_DB_IDL_IndexEnd:=@Elements(ZUGFeRD_DB_IDL);
WHILE(ZUGFeRD_DB_IDL_Index <= ZUGFeRD_DB_IDL_IndexEnd){
    ZUGFeRD_ThisDoc_ID:=@GetListElement(ZUGFeRD_DB_IDL;ZUGFeRD_DB_IDL_Index);

    CALL:DoInvoiceDoc[GLOBAL](ZUGFeRD_DB_h;ZUGFeRD_ThisDoc_ID;XMLDoAttachFile;XMLAttachmentName);

    @Increment(ZUGFeRD_DB_IDL_Index);
}

ZUGFeRD_DB_h:=@CloseDB(ZUGFeRD_DB_h);


/*
 * Process a single invoice document
 */
DELFN:DoInvoiceDoc[GLOBAL]();
DEFFN:DoInvoiceDoc[GLOBAL](ZUGFeRD_DB_h;ZUGFeRD_ThisDoc_ID;XMLDoAttachFile;XMLAttachmentName)
{
    ZUGFeRD_ThisDoc_Update:=0;

    ZUGFeRD_ThisDoc_h:=@OpenNoteByID(ZUGFeRD_DB_h;ZUGFeRD_ThisDoc_ID;ZUGFeRD_ThisDoc_h);

    /* Get the PDF attachment */
    ZUGFeRD_ThisDoc_AttachmentNames:=@AttachmentNames(ZUGFeRD_ThisDoc_h);
    ZUGFeRD_ThisDoc_AttachmentLengths:=@AttachmentLength(ZUGFeRD_ThisDoc_h);

    IF(@Elements(ZUGFeRD_ThisDoc_AttachmentNames) > 0){

        ZUGFeRD_ThisDoc_AttachmentName:=@GetListElement(ZUGFeRD_ThisDoc_AttachmentNames;1);
        ZUGFeRD_ThisDoc_AttachmentLength:=@GetListElement(ZUGFeRD_ThisDoc_AttachmentLengths;1);

        /* Extract the embedded invoice XML from the PDF */
        CALL:GetInvoiceXML[GLOBAL](&ZUGFeRD_ThisDoc_h;&ZUGFeRD_ThisDoc_XML_BinBuffer;ZUGFeRD_ThisDoc_AttachmentName;ZUGFeRD_ThisDoc_AttachmentLength);

        IF(@IsError(ZUGFeRD_ThisDoc_XML_BinBuffer)){
            @LogReport("Unable to extract invoice XML";3);
            @LogReport(ZUGFeRD_ThisDoc_XML_BinBuffer;3);
        }ELSE{

            /* Read selected invoice data from the XML */
            CALL:InvoiceXMLGetInfo[GLOBAL](&ZUGFeRD_ThisDoc_XML_BinBuffer;&ZUGFeRD_ThisDoc_Update;
                &InvoiceNumber[ZUGFeRD_ThisDoc_h];&InvoiceDateRaw[ZUGFeRD_ThisDoc_h];&Seller[ZUGFeRD_ThisDoc_h];&Buyer[ZUGFeRD_ThisDoc_h];
                &Currency[ZUGFeRD_ThisDoc_h];&GrandTotal[ZUGFeRD_ThisDoc_h];&DueAmount[ZUGFeRD_ThisDoc_h]);

            /* Optionally attach the extracted XML to the document */
            IF(XMLDoAttachFile & ZUGFeRD_ThisDoc_Update){
                @DetachOSFileFromNote(ZUGFeRD_ThisDoc_h;@AnyAllDay;XMLAttachmentName);
                @CreateAttachmentFromBuffer(ZUGFeRD_ThisDoc_h;ZUGFeRD_ThisDoc_XML_BinBuffer;1;XMLAttachmentName);
            }
        }

        ZUGFeRD_ThisDoc_XML_BinBuffer:=@DestroyBuffer(ZUGFeRD_ThisDoc_XML_BinBuffer);
    }

    /* Finalize and save successfully processed documents */
    IF(ZUGFeRD_ThisDoc_Update){
        InvoiceDate[ZUGFeRD_ThisDoc_h]:=@Time(
            @TextToNumber(@Middle(InvoiceDateRaw[ZUGFeRD_ThisDoc_h];0;4));
            @TextToNumber(@Middle(InvoiceDateRaw[ZUGFeRD_ThisDoc_h];4;2));
            @TextToNumber(@Middle(InvoiceDateRaw[ZUGFeRD_ThisDoc_h];6;2));
            0;0;0);
        Status[ZUGFeRD_ThisDoc_h]:="Done";
    }

    ZUGFeRD_ThisDoc_h:=@CloseNote(ZUGFeRD_ThisDoc_h;ZUGFeRD_ThisDoc_Update);
}


/*
 * Read the PDF attachment into a BINBUFFER and extract
 * the embedded ZUGFeRD / Factur-X invoice XML
 */
DELFN:GetInvoiceXML[GLOBAL]();
DEFFN:GetInvoiceXML[GLOBAL](*ZUGFeRD_ThisDoc_h;*ZUGFeRD_ThisDoc_XML_BinBuffer;ZUGFeRD_ThisDoc_AttachmentName;ZUGFeRD_ThisDoc_AttachmentLength)
{
    Read_Part_Max_Read:=30000;

    ZUGFeRD_ThisDoc_Att_BinBuffer:=@CreateBuffer(ZUGFeRD_ThisDoc_AttachmentLength);
    ZUGFeRD_ThisDoc_Att_h:=@OpenAttachedFile(ZUGFeRD_ThisDoc_h;ZUGFeRD_ThisDoc_AttachmentName;"RBN");

    /* Read the PDF attachment in blocks */
    ZUGFeRD_ThisDoc_Att_RemainRead:=ZUGFeRD_ThisDoc_AttachmentLength;
    WHILE(ZUGFeRD_ThisDoc_Att_RemainRead > 0){
        IF(ZUGFeRD_ThisDoc_Att_RemainRead > Read_Part_Max_Read){
            ReadPartData:=@ReadAttachedFile(ZUGFeRD_ThisDoc_Att_h;"B";Read_Part_Max_Read);
            @WriteBuffer(ZUGFeRD_ThisDoc_Att_BinBuffer;ReadPartData);
            ZUGFeRD_ThisDoc_Att_RemainRead:=ZUGFeRD_ThisDoc_Att_RemainRead-Read_Part_Max_Read;
        }ELSE{
            ReadPartData:=@ReadAttachedFile(ZUGFeRD_ThisDoc_Att_h;"B";ZUGFeRD_ThisDoc_Att_RemainRead);
            @WriteBuffer(ZUGFeRD_ThisDoc_Att_BinBuffer;ReadPartData);
            ZUGFeRD_ThisDoc_Att_RemainRead:=ZUGFeRD_ThisDoc_Att_RemainRead-ZUGFeRD_ThisDoc_Att_RemainRead;
        }
    }

    ZUGFeRD_ThisDoc_Att_h:=@CloseAttachedFile(ZUGFeRD_ThisDoc_Att_h);

    /* Extract the embedded invoice XML directly from memory */
    ZUGFeRD_ThisDoc_XML_BinBuffer:=@PDFExtractInvoiceXML(ZUGFeRD_ThisDoc_Att_BinBuffer);
    ZUGFeRD_ThisDoc_Att_BinBuffer:=@DestroyBuffer(ZUGFeRD_ThisDoc_Att_BinBuffer);
}


/*
 * Parse the invoice XML and extract selected header data
 */
DELFN:InvoiceXMLGetInfo[GLOBAL]();
DEFFN:InvoiceXMLGetInfo[GLOBAL](*ZUGFeRD_XML_BinBuffer;*ZUGFeRD_ThisDoc_Update;*InvoiceNumber;*InvoiceDateRaw;*Seller;*Buyer;*Currency;*GrandTotal;*DueAmount)
{
    ZUGFeRD_ThisDoc_Update:=1;
    InvoiceNumber:=InvoiceDateRaw:=Seller:=Buyer:=Currency:=GrandTotal:=DueAmount:=@Unavailable;

    /* XML namespaces used by the CII invoice */
    Prefixes:="rsm":"ram":"udt";
    Namespaces:=
        "urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100":
        "urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100":
        "urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100";

    /* Parse the XML document */
    Doc:=@XMLParse(ZUGFeRD_XML_BinBuffer;1);
    Root:=@XMLGetRoot(Doc);
    IF(@IsError(Doc;Root)){
        @LogReport("Doc:";3);
        @LogReport(Doc;3);
        @LogReport("Root:";3);
        @LogReport(Root;3);
        ZUGFeRD_ThisDoc_Update:=0;
    }ELSE{

        /* Invoice header fields to extract */
        XPaths:="./rsm:ExchangedDocument/ram:ID":
            "./rsm:ExchangedDocument/ram:IssueDateTime/udt:DateTimeString":
            "./rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:SellerTradeParty/ram:Name":
            "./rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeAgreement/ram:BuyerTradeParty/ram:Name":
            "./rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:InvoiceCurrencyCode":
            "./rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementHeaderMonetarySummation/ram:GrandTotalAmount":
            "./rsm:SupplyChainTradeTransaction/ram:ApplicableHeaderTradeSettlement/ram:SpecifiedTradeSettlementHeaderMonetarySummation/ram:DuePayableAmount";

        FieldNames:=@Explode("InvoiceNumber;InvoiceDateRaw;Seller;Buyer;Currency;GrandTotal;DueAmount";";");

        /* Map each XPath result to the corresponding document field */
        XPaths_Index:=1;
        XPaths_IndexEnd:=@Elements(XPaths);
        WHILE(XPaths_Index <= XPaths_IndexEnd){
            ThisXPath:=@GetListElement(XPaths;XPaths_Index);
            ThisFieldName:=@GetListElement(FieldNames;XPaths_Index);

            Node:=@XMLSelectSingleNode(Root;ThisXPath;Prefixes;Namespaces);
            Value:=@XMLGetContent(Node);
            IF(@IsError(Node;Value)){
                ZUGFeRD_ThisDoc_Update:=0;
                @LogReport("Node:";3);
                @LogReport(Node;3);
                @LogReport("Value:";3);
                @LogReport(Value;3);
            }

            @SetVar(ThisFieldName;Value);
            @Increment(XPaths_Index);
        }
    }

    @XMLRelease(Doc);
}
Originales, kommentiertes API-Engine-Beispielskript Auf Smartphones und Tablets horizontal scrollen, um lange Zeilen zu lesen.