9

carbone.io als Druckeditor in NINOX integrieren

Das Thema Drucklayouteditor ist ja schon seit Jahren leidiges Thema hier im Forum. Zu Recht, da man aus der Ninox heraus leider nur rudimentär Daten zu "Papier" bzw. PDF  bringen kann. Formatierungen werden nicht unterstützt, HTML genauso wenig. Diverse Workarounds sind die Folge oder gar Abwanderungen auf andere Softwarelösungen. 

Auch nach dem Update sind wieder nicht alle User glücklich, da die Nutzung von Word-Templates wohl nur Private Cloud bzw. On-Premise Usern vorbehalten ist.

Die dort verwendete Engine lässt sich aber klassisch über RestAPI in die NINOX integrieren. Benötigt wird ein carbone-Account, welcher in der Free Version mit 100 credits (100 erzeugte Dokumente) kostenfrei ist...

Hat man einen Account erstellt, kann man unter account.carbone.io seinen Test- bzw. Production-API-Key erzeugen:

In der NINOX brauchen wir dann ein Bildfeld in das unser erzeugtes PDF geladen wird, ein mehrzeiliges Textfeld "API", ein Feld für die spätere RenderID, einen Button für das Script und ein Word- oder OpenOffice-Template. Ich benutze OpenOffice und habe hier mal das Sample-Template von carbone geöffnet:

Wie man sieht, sind alle zu ersetzenden Felder durch {d.xxxxxxxxx} gekennzeichnet. Wir legen uns also unser Dokument in dieser Form an und laden es anschließend in das carbone Studio (studio.carbone.io)

Hier kann man schon mit den Daten spielen und testen, ob alles soweit funktioniert. Wenn alles passt, brauchen wir zum ansteuern aus NINOX heraus die ID des Templates. Diese findet man oben rechts unter dem Info-Button (i)...

Zurück zur NINOX. Wir haben also unser Bildfeld namens "Ausdruck", unser Textfeld "API" und "renderID" zur Kontrolle und unseren Button. In den Button schreiben wir nun folgendes Script:

let testKey := "Bearer DER_TESTKEY_AUS_CARBONE";
let liveKey := "Bearer DER_PRODUCTION_KEY_AUS_CARBONE";
let myKey := testKey;
let auth := {
        Authorization: myKey,
        'Content-Type': "application/json",
        'carbone-version': "3"
    };
let myTemplate := "DIE_TEMPLATE_ID_AUS_CARBONE_STUDIO";
do as server
    let response := http("POST", "https://render.carbone.io/render/" + myTemplate, auth, {
        data: {
            id: 12345,
            name: "Max Muster",
            adresse: KUNDENADRESSE
        },
        convertTo: "pdf",
        reportName: Produkt + "_EinlegerFront.pdf"
    });
    API := text(response.result);
    renderID := text(response.result.data.renderId)
end;
let myBild := "https://render.carbone.io/render/" + renderID;
importFile(this, myBild, "carbone.pdf");
Ausdruck := file(this, "carbone.pdf");

Fertig. Das sollte es gewesen sein... Wir schicken also über die NINOX Rest API unsere Daten an das carbone Template, erhalten eine renderID zurück und holen uns das gerenderte Dokument über die importFile-Funktion der NINOX in unser Bildfeld. Die übermittelten Daten im obigen Script können dabei feste Werte (wie 12345 und "Max Muster") sein, oder Feldnamen der Ninox (KUNDENADRESSE).

Den Dateinamen können wir in der importFile-Funktion festlegen. Hier ist es jetzt "carbone.pdf" - er könnte aber auch aus NINOX Feldnamen zusammengesetzt werden: KUNDENNR + "_Rechnung_" + RGNUMMER + ".pdf".  Die gleiche Formel muss dann aber auch in file() stehen

importFile(this, myBild, KUNDENNR + "_Rechnung_" + RGNUMMER + ".pdf");
Ausdruck := file(this, KUNDENNR + "_Rechnung_" + RGNUMMER + ".pdf");

Wenn dann alles im Layout passt, kann man auf den liveKey wechseln und erhält ein Wasserzeichen-freies PDF (welches aber dann Credits kostet)

Ich hoffe das Vorgehen ist einigermaßen verständlich, das Script habe ich aus einer laufenden Umgebung zusammenkopiert, dort ist es umfangreicher eingebettet mit dialog() und alert()-Funktionen, einem Schalter für Test-bzw.Livebetrieb usw.

Happy printing!

Gruß, Tobias

26 Antworten

null
    • ⭐ Ninox Partnerin - Kennes Digital
    • Stefanie_K
    • vor 1 Jahr
    • Gemeldet - anzeigen
    let myBild := "https://render.carbone.io/render/" + renderID;
    importFile(this, myBild, "carbone.pdf");
    Ausdruck := file(this, "carbone.pdf");
    

    Dies liefert leider einen Fehler zurück bzw. es wird keine Datei zu Ninox importiert. Ich habe es per Make auch getestet und dort funktioniert es. Der Report wird ordnungsgemäß erstellt, aber von Ninox nicht korrekt abgeholt. Irgendeine Idee, woran es liegen könnte?

    • UweG
    • vor 1 Jahr
    • Gemeldet - anzeigen

    Wie löst du das Script aus?
    Über einen Trigger wird es nicht funktionieren.
    Auch wenn das Script innerhalb 'do as server' ausgeführt werden soll wird es nicht funktionieren.
    importFile() funktioniert nur, wenn aktiv ausgelöst und ausserhalb von 'do as server'.

      • ⭐ Ninox Partnerin - Kennes Digital
      • Stefanie_K
      • vor 1 Jahr
      • Gemeldet - anzeigen

      UweG Es liegt mit hinter dem Button, der auch die Daten an Carbone sendet, so wie Tobias es angegeben hatte.

      • UweG
      • vor 1 Jahr
      • Gemeldet - anzeigen

      Stefanie Kennes Habe im Discord gesehen, dass die Datei sehr gross ist.
      Kannst du die Datei mal auf einen CloudSpeicher ablegen und dort einen ShareLink erstellen.
      Probiere mal ob du über den ShareLink des Bildes vom CloudSpeicher mit importFile() in Ninox laden kannst.
      Wenn es auch nicht funktioniert, spielt die Größe der Datei oder die Zeitdauer des Ladens wohl eine Rolle weshalb es nicht in Ninox funktioniert.

      • ⭐ Ninox Partnerin - Kennes Digital
      • Stefanie_K
      • vor 1 Jahr
      • Gemeldet - anzeigen

      UweG Ich habe jetzt etliche Tests laufen lassen und mit Carbone Rücksprache gehalten. Das Problem konnte nicht eindeutig identifiziert werden, aber ich vermute, wie du, die Dateigröße und Ladezeiten sind zu groß. Trotzdem als Tipp, falls es mal jemand benötigt. Man kann via Carbone auf die Bildqualität Einfluss nehmen:

      convertTo : {
      formatName : 'pdf',
      formatOptions: {
      MaxImageResolution : 75,
      Quality : 1,
      ReduceImageResolution : true
      }
      }
      
      • UweG
      • vor 1 Jahr
      • Gemeldet - anzeigen

      Stefanie Kennes Das funktionieert meines Wissens nur, wenn man Carbone direkt benutzt. Mit dem dyn. Druckeditor funktioniert es nicht, da man außer den Daten keine weitere Informationen mit übergeben kann.

    • T_Bartzsch
    • vor 1 Jahr
    • Gemeldet - anzeigen

    Hallo Stefanie,  kannst Du den link mit der renderID denn manuell im Browser öffnen? Also läuft carbone wie es soll...? Oder wird die renderID in Ninox gar nocht befüllt?

    Vielleicht müssten man ein sleep(1000) dazwischen setzen, damit carbone noch eine sekunde länger zum generieren hat...

    • Michi.1
    • vor 1 Jahr
    • Gemeldet - anzeigen

    Ich habe meine ersten Gehversuche unternommen, was ja auch so weit mit der Anleitung von Torsten und der DB aus dem api forum klappt. Ich hab noch das Problem was Stefanie hier gepostet hat mit dem bildfeld wo das pdf dann liegen soll.

    Wie schafft man es den Seitenumbruch bei tabellen, so zu gestalten, daß auf der 2. Seite wieder der Tabellenkopf erscheint? Also nicht nur die Tabelle weiter geführt wird. Fest darstellen kann man es ja nicht in der Vorlage. Man weiß ja nie wie groß das übergebenen array ist.

    let testKey := first(select Ninox).text(CarbonetestAPI);
    let liveKey := first(select Ninox).text(CarboneAPI);
    let myKey := testKey;
    let auth := {
            Authorization: myKey,
            'Content-Type': "application/json",
            'carbone-version': "3"
        };
    let myTemplate := "121003b89f7df5fxxxxxxxxxxxxxxx";
    let vArray := [];
    let vArrayObj := [];
    let vObj := {};
    for i in Untertabelle order by Nummer do
        vObj := {
                Position: text(i.Nummer),
    Name: i.Name,
                irgendwas: i.irgendwas
            };
        vArrayObj := [vObj];
        vArray := array(vArray, vArrayObj)
    end;
    let vBody := {
            data: {
                vVorname: Vorname,
                vName: Name,
                vDatum: format(Datum, "DD.MM.YYYY"),
                vTabelle: vArray
            },
            convertTo: "pdf",
            reportName: Name + ".pdf"
        };
    body_Daten := text(vBody);
    do as server
        let response := http("POST", "https://render.carbone.io/render/" + myTemplate, auth, vBody);
        'Response Carbone' := text(response.result);
        RenderID := text(response.result.data.renderId)
    end;
    sleep(1000);
    let myBild := "https://render.carbone.io/render/" + RenderID;
    importFile(this, myBild, "carbone.pdf");
    PDF := file(this, "carbone.pdf")

    • T_Bartzsch
    • vor 1 Jahr
    • Gemeldet - anzeigen

    ... ich habe mich jetzt eine Weile nicht beteiligt, da mir momentan die Arbeit über den Kopf wächst... Ich weiß nicht, ob das vielleicht relevant ist, aber in meinem (funktionierenden) Script heißt der reportName im Body der Anfrage genauso, wie später das PDF im importFile script. 

    Das sollte zwar eigentlich egal sein, da man beim import ja einen neuen/anderen Namen vergeben kann .... aber wer weiß :)

      • Michi.1
      • vor 1 Jahr
      • Gemeldet - anzeigen

       danke dir, werd ich mal schauen nächste woche. Bin ja gerade erst in der welt von API angekommen:) aber das viel größer problem beim testen ist, wie ich eine Tabelle vernünftig bei einem seitenumbruch darstellen kann. Also der tabellen Kopf wieder erscheint! Oder wie löst ihr das? 

      Das mit cnt (record) dann mach folgendes .... hab ich gesehen, aber eben nicht wie die Beschriftung wieder über die Einträge kommt. 

      Schönes WE

      Grüße Michi

      • Developer by Smartplanung
      • smartplanung
      • vor 1 Jahr
      • Gemeldet - anzeigen

       Hallo Michi,

      ich kann gerade nicht nachschauen. Aber man müsste das in Word in der Tabelle einstellen können, dass die Kopfzeile bei Seitenumbrüchen angezeigt/wiederholt wird.

      Dafür die Kopfzeile markieren, Rechtsklick und auf Tabelleneigenschaften die Option auswählen.

      VG

      • Michi.1
      • vor 1 Jahr
      • Gemeldet - anzeigen

       Danke dir, probiere ich gerne, dachte das wir über das script gesteuert

      • Michi.1
      • vor 1 Jahr
      • Gemeldet - anzeigen

      Also werden alle Einstellungen vom eingelesenen dockument übernommen wenn ich das richtig verstehe? Kenn mich da nicht aus, war auch froh von dem zeug weg zu kommen 

      • Developer by Smartplanung
      • smartplanung
      • vor 1 Jahr
      • Gemeldet - anzeigen

       eigentlich ja. Es wird erst etwas kniffelig, wenn man bestimmte Tabellen oder andere Objekte ausblenden möchte. Dann muss man entsprechende Skripte im Dokument hinterlegen.

      Grundsätzlich wird aber alles im Dokument/Template festgelegt, was die Formatierung betrifft. Mit Ninox wird nur der Inhalt (Texte, Bilder, usw) übergeben. Wenn man das externe Carbone nutzt, kann man nochmal ein paar separate Einstellungen vornehmen, wie z.B. die Bildqualität. Bei der Ninox Carbone Engine kann man bisher nur separat den Testdruck mit Carbone Wasserzeichen im Ninox Code einstellen - ich glaube das soll seitens Ninox noch erweitert werden.

      • Michi.1
      • vor 1 Jahr
      • Gemeldet - anzeigen

       Danke dir .... aber kommen bestimmt noch mehr Fragen. Ist direkt über API, soll ja aber besser weden als mir der druckengie von ninox. Aber jetzt weis ich schon mal mehr wo ich was suche. Bzw. Ändern muß 

    • Rafael_Sanchis
    • vor 1 Jahr
    • Gemeldet - anzeigen

    It would be a good idea to share a model for those of us who do not have experience in this.

    • Michi.1
    • vor 1 Jahr
    • Gemeldet - anzeigen

    Umbruch bei \n im Array 🤔

    Ich habe eine Printtabelle wo die Einträge von mehreren dmfa zusammengefasst werden.

    Schema: 1 Record mit den Feldern Gruppe (ist die Bezeichnung des DMFA) und ein Feld Bezeichnung (ist die Auswahl des DMFA) Bezeichnung ist dabei als Join() abgelegt.

    Kann mir einer helfen, wie ich den Umbruch hinbekommen??

    {d.vTabelle[i].Name:convCRLF:html\n<br> } Das geht nicht.

    So soll es wieder aussehen.... War mal mit Leo´s Hilfe entstanden:

    Das ist die Printtabelle:

    • Michi.1
    • vor 1 Jahr
    • Gemeldet - anzeigen

    {d.vTabelle[i].Name:convCRLF} passt

    • Michi.1
    • vor 1 Jahr
    • Gemeldet - anzeigen

     

    Wie bekommt man das Template hin ???  Es ist ja nur eine Tabelle vorhanden, diese wird aber nach jeder kompletten Kategorie über einen Seitenumbruch im neuen Absatz weiter geführt. Nur wie?????

    Was ist im Template der angesprochene Seitenumbruch, welchen man den Wert true übergibt ?? Oder wie muss ich das gestalten??

    So wie bei mir soll es eben nicht aussehen, jede Gruppe soll eigenständig abgebildet werden.

     

     

    Find einfach nichts in der Hilfe von Carbone. (ist aus dem API Team / Carbone Template Upload / 'Untertabelle/Untertabelle' )

        "/
    / Untertabelle2-Array mit JSON-Object für jeden einzelnen Record erstellen /
    /";
        function Modelle2(Untertabelle1ID : number) do
            let vArray1 := [];
            let vArrayObj1 := [];
            let vObj1 := {};
            for i in Untertabelle1.Untertabelle2[Untertabelle1 = Untertabelle1ID] do
                vObj1 := {
                        ModellType: i.Automodelle.Modell,
                        'vStückzahl': i.'Stückzahl',
                        vProduziertIn: i.'Produziert in'.'File Original'
                    };
                vArrayObj1 := [vObj1];
                vArray1 := array(vArray1, vArrayObj1)
            end;
            vArray1
    end;
        "/
    / Untertabelle1-Array mit JSON-Object für jeden einzelnen Record erstellen /
    /";
        let vArray := [];
        let vArrayObj := [];
        let vObj := {};
        for i in Untertabelle1 do
            vObj := {
                    vMarke: i.Automarke.Marke,
                    Modelle: Modelle2(number(i.Nr))
                };
            vArrayObj := [vObj];
            vArray := array(vArray, vArrayObj)
        end;
        "// HTTP-Call definieren //";
        let vBody := {
                data: {
                    vVorname: Vorname,
                    vName: Name,
                    vBild: "Bild",
                    vSeitenumbruch: true,
                    Marke: vArray
                },
    
      • ⭐ Ninox Partnerin - Kennes Digital
      • Stefanie_K
      • vor 1 Jahr
      • Gemeldet - anzeigen

       Versuch mal, in Word nach der 2. Zeile eine leere Zeile einzufügen, der du die Umrandung wegnimmst. Dann ist es eine Zeile, sieht aber aus wie ein Abstand. Über die Tabelleneigenschaften kannst du noch festlegen, welche Zeilen zusammengehalten werden sollen.
       

    • Michi.1
    • vor 1 Jahr
    • Gemeldet - anzeigen

    Danke dir Stefanie,  hab es so gelöst, das ich zwei Tabellen anlege, wo aber in der zweiten Tabelle dann [i+1]enthalten ist. Das bringt mir einzelne Tabellen.

    Hast du aber vielleicht eine Ahnung wie oder was der seitenumbruch im Skript auf dem Template bewirkt? Finde in der Doku nichts 

     vSeitenumbruch: true
      • ⭐ Ninox Partnerin - Kennes Digital
      • Stefanie_K
      • vor 1 Jahr
      • Gemeldet - anzeigen

       Ich kenne die Datenbank leider nicht, aber könnte mir vorstellen, dass es einmal angedacht war, es als Bedingung zu übergeben. Du kannst in Carbone in die Variablen Bedingungen einfügen und nur wenn eine Bedingung erfüllt ist, wird z.B. ein Wert angezeigt. 

      https://carbone.io/documentation.html#conditioned-output

      In deinem Fall könntest du z.B. einen Absatz machen, darin einen Seitenumbruch wie folgt einstellen:

      {d.vSeitenumbruch:ifEQ(true):showBegin}Hier käme dann in Word ein Seitenumbruch hin{d.vSeitenumbruch:showEnd}

      Nur wenn dann die Variable vSeitenumbruch mit dem Wert "true" übergeben wird, wird auf dem finalen Word-Dokument ein Seitenumbruch erzeugt.

      • Michi.1
      • vor 1 Jahr
      • Gemeldet - anzeigen

       🙃 das hätte mir auch einfallen können. Hatte das nur für Text oder Tabellen etc. auf dem Schirm. Ist schon ein bisschen Umdenken nötig, dass man das für alle im Dokument verfügbaren Formatierungen nehmen kann.

      • Michi.1
      • vor 1 Jahr
      • Gemeldet - anzeigen

      grüß dich,

      ich bekomme es einfach nicht hin, den "Abschnittswechsel nächste Seite" (befindet sich unter {d.vtext2:html} auszublenden. Bekomm zwar den Inhalt vom Angebot (ersten 2 Seiten) ausgeblendet, jedoch hab ich dann die 1. Seite bis auf den Kopf leer. Auf der 2. kommt dann die eigentliche Rechnung. Diese soll ja aber auf der 1. Seite sein. Hast du eine Ahnung? Den nicht benötigten Inhalt für die Rechnung bekomme ich wie gesagt mit {d.vRechnunganz:ifEQ(true):showBegin} / Ende ausgeblendet.

      Hab mal das Template angehangen.

      Schönes Wochenende

      • Michi.1
      • vor 1 Jahr
      • Gemeldet - anzeigen
       said:
      Bekomm zwar den Inhalt vom Angebot (ersten 2 Seiten)

       Ist natürlich auf dem Dokument nur die erste Seite, beim Druck sind es 2 Seiten für das Angebot und eine Seite für die Kostenaufstellung, welche auch für die Rechnung verwendet werden soll.