Serveur d'impression

APEX Office Print – Serveur d’impression

Le 3 mai 2019 - 148 minutes de lecture

Version 19.1.5 avril 2019

Fourni par:

Logo APEX R & D

Sommaire

1.1 but

APEX Office Print facilite l'impression et l'exportation (docx, xlsx, pptx, pdf, html, md, txt, csv, ics) dans Oracle Application Express (APEX) ou tout simplement dans PL / SQL.

Créez un modèle dans Office, HTML ou Markdown, choisissez des données dans votre base de données et fusionnez-les en un seul. Vous pouvez facilement imprimer des PDF, des documents Office, HTML ou Markdown en un rien de temps. Cela vous fait économiser du temps et des efforts en créant des modèles dans lesquels vous pouvez facilement intégrer vos données.

APEX Office Print (AOP) est un produit d'APEX R & D, situé à Louvain, en Belgique.

Nous sommes un partenaire expérimenté qui vous aide à faciliter, améliorer et accélérer votre entreprise grâce à des solutions nouvelles et innovantes. S'appuyant sur une expertise technique approfondie, notre société fournit des services informatiques sur mesure pour la gestion de données et de processus d'entreprise.

1.2 Caractéristiques principales de l'AOP

APEX Office Print se concentre sur les points suivants:

  1. Impression simple
    C'est rapide, facile et vous permet d'économiser de l'argent. C'est la seule solution du marché entièrement intégrée à APEX. Par exemple, vous pouvez imprimer ou exporter vos données de rapports interactifs et de grilles en une seconde.

  2. Configuration rapide et facile
    Importez simplement le plug-in APEX dans votre application

  3. Tout type de données pris en charge
    Texte, images, codes à barres, formules…. il est facile de fusionner vos données avec n'importe quel modèle que vous créez

  4. Evolutif et sécurisé
    APEX Office Print est un produit évolutif et sécurisé qui répond à tous vos besoins d’impression.

  5. Prise en charge des API PL / SQL
    Il vous permet d'exécuter et de récupérer des rapports du serveur AOP directement à partir de votre code PL / SQL.

  6. Optimisé pour la performance
    Un excellent design avec les détails les plus fins pour améliorer la productivité de votre entreprise.

  7. Flexible
    APEX Office Print est un serveur d'impression vous permettant de créer des modèles dans Word, Excel et PowerPoint pour tout type de données.

1.3 Architecture AOP

Architecture AOP

C'est la base de données (plug-in APEX, API PL / SQL, service Web REST) ​​qui envoie une demande au serveur AOP (sur site ou dans notre cloud). Le modèle avec les données est envoyé au format JSON au serveur AOP.
Le navigateur n'a pas besoin d'avoir accès au serveur AOP.

1.4 Comment ça marche (aperçu)

Comment ça marcheComment ça marche

1.5 Comment ça marche (technique)

Le package APEX Office Print comprend un composant serveur, un plug-in Oracle APEX et une API PL / SQL.

La partie serveur renvoie les documents générés à la réception des demandes HTTP POST. Ces demandes nécessitent un fichier JSON structuré pouvant par exemple être déduit d'une base de données SQL. Les données de la base de données associées à un modèle génèrent des fichiers de sortie pertinents.

Le plug-in Oracle Application Express (APEX) générera les demandes HTTP POST comprises par la partie serveur. Le plug-in facilite la sélection d'un modèle, de votre source de données et du format de sortie directement à partir de votre application APEX.

L'API PL / SQL permet d'imprimer directement à partir de la base de données Oracle. L'API PL / SQL convient parfaitement si vous devez configurer l'impression automatique via un travail ou effectuer un publipostage.

Un exemple d’application est fourni avec le téléchargement, ce qui vous permet de voir de nombreux cas d’utilisation.

1.6 Cloud vs sur site

Il existe deux types de versions à acheter:

  • une version en nuage, qui enverra les demandes à APEX Office Print dans le nuage
  • une version sur site, qui comprend le composant serveur de APEX Office Print. C'est un exécutable que vous exécutez sur votre propre serveur et dans le plug-in APEX, vous référencez votre propre version locale de APEX Office Print. Dans ce cas, rien n'est envoyé au cloud AOP.

1.7 Licence

Ceci est un logiciel commercial; vous devez obtenir une licence valide pour utiliser ce logiciel et ce plug-in dans votre application. Pour la version sur site, une licence est requise par serveur (MID, ID d'ordinateur), vous exécutez APEX Office Print of ou vous pouvez choisir une licence d'entreprise qui n'est pas liée à MID.

S'il vous plaît visitez notre site Web https://www.apexofficeprint.com/ pour les différents forfaits.

Vous pouvez même vous inscrire pour un compte Cloud GRATUIT.

1.8 Inscription et téléchargement

  1. Ouvrez https://www.apexofficeprint.com/

  2. Cliquez sur le bouton "S'inscrire"

  3. Entrez vos coordonnées

  4. Vous recevrez un email avec un lien de confirmation, veuillez cliquer dessus

  5. En même temps, vous serez connecté à votre tableau de bord AOP. Sélectionner Téléchargements

  6. Choisissez le paquet que vous voulez et cliquez pour le télécharger

Important – Activation du numéro de clé API

Dans votre tableau de bord AOP, votre unique Numéro de clé API se trouve sous la zone Informations sur le compte de la page d'accueil. Ce numéro devra être ajouté à vos paramètres de plug-in pour que cela fonctionne. Pour plus d'informations sur la procédure à suivre, consultez la section Plugin APEX.

1.9 Guide d'installation rapide

  1. Décompressez le fichier que vous avez téléchargé à partir de https://www.apexofficeprint.com

  2. Exécutez aop_db_pkg.sql (dans le répertoire "db") dans votre schéma Oracle (Atelier SQL -> Scripts SQL -> Télécharger -> Sélectionnez un fichier et cliquez sur Télécharger)

  3. Importer dynamic_action_plugin_be_apexrnd_aop_da.sql et process_type_plugin_be_apexrnd_aop.sql (dans le répertoire "apex / apex release") dans Composants partagés> Plug-ins

  4. Sur la page que vous souhaitez utiliser AOP, ajoutez l'action ou le processus dynamique "APEX Office Print".

1.10 Guide de mise à niveau rapide

Si vous avez déjà une ancienne version de AOP installée.

  1. Décompressez le fichier que vous avez téléchargé à partir de https://www.apexofficeprint.com

  2. Exécutez aop_db_pkg.sql (dans le répertoire "db") dans votre schéma Oracle (Atelier SQL -> Scripts SQL -> Télécharger -> Sélectionnez un fichier et cliquez sur Télécharger)

  3. Importation dynamic_action_plugin_be_apexrnd_aop_da.sql et process_type_plugin_be_apexrnd_aop.sql (dans le répertoire "apex / apx release") dans Composants partagés> Plug-ins

  4. Facultatif: exécutez aop_db_sample_pkg.sql (dans le répertoire "db") dans votre schéma Oracle (Atelier SQL -> Scripts SQL -> Upload -> Sélectionnez un fichier et cliquez sur Upload) pour créer des exemples de scripts PL / SQL. Nous vous recommandons également d'installer la dernière version de AOP Sample App.

  5. Pour les versions sur site d'AOP, sur le serveur, arrêtez AOP, copiez le répertoire du serveur et redémarrez AOP avec le nouvel exécutable.

2.1 Conditions préalables

APEX Office Print requiert Oracle APEX 5.0.4 ou version ultérieure.
La prise en charge du réseau interactif est incluse dans Oracle APEX 5.1 et versions ultérieures.
Les bases de données distantes et les sources Web sont prises en charge dans Oracle APEX 18.1 et versions ultérieures.

Notez que plus la version APEX est élevée, plus le modèle d'application AOP contenant d'échantillons est important. Nous vous recommandons de consulter la dernière version de l'application exemple AOP, même si vous ne possédez pas encore la dernière version de APEX. De nombreux exemples fonctionneront également dans les versions précédentes d'APEX, mais ils n'existent pas nécessairement dans cette version de l'AOP Sample App.

Pour exécuter l'application exemple AOP, une application Oracle APEX Packaged appelée Exemple d'application de base de données doit d'abord être installée. La raison en est que la source et les modèles utilisent les données des tables (demo_orders, demo_order_items, demo_product_info,….) Qui sont installées par l'application packagée.

Suivez ces étapes pour installer l'application packagée dans votre espace de travail:

  1. Accédez à votre espace de travail cible
  2. Sélectionnez le générateur d'applications
  3. Sélectionnez Créer

  4. Sélectionnez une application packagée

  5. Sélectionnez Sample Database Application et cliquez sur le bouton Install Application.

  6. Sélectionner pour utiliser un identifiant d'application existant
    Remarque: Lorsque vous avez sélectionné Réaffecter automatiquement l'ID de l'application, vous devez vous assurer de modifier les valeurs de aop_api_pkg qui utilise APP_ID et AOP_URL en tant que variables globales.

  7. Sélectionnez pour installer des objets de support
  8. Suivez l'assistant pour terminer l'installation.

2.2 Importer l'exemple d'application AOP

  1. Accédez à votre espace de travail cible
  2. Sélectionnez le générateur d'applications
  3. Sélectionnez Importer et sélectionnez le fichier dans apex / version / aop_sample_apex_app.sql.
  4. Suivez l'assistant pour terminer l'importation
  5. L'application exemple AOP installera également tous les objets de support. Vous pourrez donc tout simplement commencer à utiliser l'application après l'importation.

2.3 Essai de l'exemple d'application AOP

L’application APEX fournie avec AOP montre différents exemples d’utilisation de APEX Office Print dans une application.

En inspectant des éléments de ces pages, vous pouvez apprendre rapidement à utiliser le plug-in AOP.

Notez que l'exemple d'application AOP pour APEX 5.0, 5.1 et 18.1 est différent. Plus la version APEX est élevée, plus vous trouverez de fonctionnalités dans l'application exemple AOP.

2.3.1 Exemple d'application AOP pour APEX 5.0

AOP Sample Application est composé de 19 parties:

  1. Échantillon d'impression

    Cette page contient différents boutons, tous liés à différents processus AOP et actions dynamiques qui présentent différents cas d'utilisation du plug-in AOP.

  2. Caractéristiques principales

    Cette section présente certains des principaux différenciateurs d’APEX Office Print par rapport à d’autres solutions d’impression.

  3. Impression dynamique

    De manière dynamique, vous pouvez sélectionner votre modèle dans Word, Excel ou PowerPoint et générer le résultat en fonction du client sélectionné.

  4. Rapports Imprimer

    Cette section présente des exemples d'utilisation d'un rapport et d'une grille classiques et interactifs en tant que source des données. Il y a aussi un exemple d'impression d'étiquettes.
    Vous pouvez même utiliser une combinaison de plusieurs rapports classiques et interactifs comme source de données. Cette fonctionnalité est l'une des plus impressionnantes d'AOP et ne figure dans aucun autre outil.

  5. Impression graphique

    Cette section montre des exemples d’impression de graphiques: Ligne, Barre, Colonne, Camembert, Radar, Zone, … Les graphiques sont des graphiques Office natifs. Ils peuvent même être adaptés après leur création dans Word, Excel et PowerPoint.

  6. Éditeur de texte enrichi

    Vous pouvez également écrire votre balisage dans un éditeur de texte enrichi et AOP comprendra et traduira le balisage (gras, couleur, etc.) en balisage Word natif. Dans votre modèle, vous devez mettre un trait de soulignement devant le nom de la balise, par exemple. _htmlcontent

  7. Images

    APEX Office Print est capable d’imprimer des images dans différents formats. Cet écran montre un exemple de configuration. Pour afficher des images, vous devez les encoder en base64 et mettre un% dans votre tag, par exemple. %image

  8. QR et codes à barres

    APEX Office Print peut imprimer différents codes à barres et QR. Cet écran montre un exemple de configuration.

  9. PDF en ligne

    Si vous souhaitez afficher le PDF en ligne dans une boîte de dialogue modale ou dans une certaine région (région), cette page indique exactement comment procéder. La valeur de la balise data-aop-inline-pdf doit être le nom de l'action dynamique qui appelle AOP.

  10. Impression complexe

    La section Impression complexe présente différents cas d'utilisation pour Word, Excel et PowerPoint. Il existe différents modèles qui montrent comment créer des mises en page plus complexes. Il existe également des exemples illustrant des fonctionnalités spécifiques, telles que l’utilisation des sauts de ligne dans vos données ou le téléchargement simultané de deux documents.

  11. Mailings Imprimer

    Word a une fonctionnalité pour créer des étiquettes via l'option mailings. Cet écran montre un exemple avec des étiquettes de taille Avery spécifiques.

  12. Email Imprimer

    Cet exemple montre comment appeler une procédure et envoyer un courrier électronique en pièce jointe. Il existe également une option pour envoyer le courrier électronique mais également télécharger le fichier.

  13. Exemple d'API PL / SQL

    Ici, vous pouvez voir l'API PL / SQL AOP en action. Il montre comment récupérer un document du serveur AOP et le stocker dans un tableau personnalisé. Ceci est extrêmement utile lorsque vous souhaitez planifier vos travaux d'impression et envoyer des courriels automatisés.

  14. Impression planifiée

    Vous pouvez planifier un travail pour imprimer chaque jour, semaine, mois, etc. un rapport spécifique à l'aide de dbms_scheduler et de l'API PL / SQL AOP.

  15. Impression par lots

    Si vous souhaitez imprimer des documents par lot, cette page vous indique trois façons de le faire.

    Le premier générera un document avec les pages ici.
    La seconde générera plusieurs documents.
    Et la dernière option générera plusieurs documents mais le présentera sous forme de fichier zip.

  16. Modèle et types de données

    Cette page donne un aperçu et un exemple des différents types de modèles et de données possibles dans le plug-in et l'API APEX Office Print (AOP).
    Le type de modèle définit où votre modèle est défini (table, système de fichiers, URL, APEX, …). Le type de données définit l'endroit où les données peuvent être trouvées pour être fusionnées avec le modèle (SQL, PL / SQL, JSON, REST, …).

  17. Utilisation de l'AOP

    Cette page donne un aperçu des pages où et comment le plug-in APEX Office Print (AOP) est utilisé.

  18. Test automatisé

    Vous pouvez tester automatiquement tous vos documents dans cet écran et voir si tous vos modèles et sources de données définis ont été fusionnés correctement. Cette option est particulièrement utile après une mise à niveau d'AOP ou d'Office.

  19. Modèles

    Ici, vous pouvez télécharger vos modèles dans une table personnalisée.

    L'idée ici est que, dans votre propre application, vous permettez aux utilisateurs de créer ou de mettre à jour leurs propres modèles et de les télécharger vers l'application sans que le développeur ait besoin de coder d'autres documents.

2.3.2 Exemple d'application AOP pour APEX 5.1

Pour Oracle Application Express (APEX) 5.1, nous voulions amener l’application exemple AOP à un autre niveau et inclure plus de détails sur son fonctionnement. Nous savons que lire de la documentation n’est pas très amusant. Nous avons donc mis beaucoup d’informations dans l’exemple d’application. Ainsi, en naviguant dans ce document, vous en apprendrez sur AOP.

Les différentes parties de l'exemple d'application:

  1. Début vous explique étape par étape comment vous pouvez obtenir le fonctionnement de l'AOP dans votre propre application.

  2. Tour montre les différentes techniques que vous pouvez utiliser et explique plus en détail quand utiliser quel plug-in, l'API PL / SQL ou faire une demande REST manuelle.

  3. Exemples montre différents cas d'utilisation d'AOP, afin que vous puissiez voir exactement en arrière-plan comment l'AOP est utilisé.

  4. Doc est un lien vers la dernière version de notre documentation en ligne.

  5. Plus est un lien vers notre site Web où vous trouverez l'historique des versions, les FAQ, les tutoriels, etc.

  6. Soutien ouvrira votre client de messagerie par défaut afin que vous puissiez nous écrire.

2.3.3 Exemple d'application AOP pour APEX 18.x

Pour Oracle Application Express (APEX) 18.1 et les versions ultérieures, nous avons recréé l'application exemple AOP à partir de zéro. Nous vous recommandons vraiment de passer par cet exemple d'application. Cette application présente les différentes fonctionnalités d'AOP, à la fois spécifiques à APEX et à ce que beaucoup de personnes recherchent dans une solution de reporting. Dans la mesure du possible, nous avons ajouté des informations supplémentaires afin que vous compreniez parfaitement le fonctionnement de l'AOP et la manière de créer votre rêve.

Les différentes parties de l'exemple d'application:

  1. Installation vous explique étape par étape comment vous pouvez obtenir le fonctionnement de l'AOP dans votre propre application.

  2. Architecture montre le flux des différents composants et techniques que vous pouvez utiliser et explique plus en détail quand utiliser quel plug-in, l'API PL / SQL ou effectuer une demande REST manuelle.

  3. Caractéristiques APEX montre l'intégration d'AOP avec des fonctionnalités APEX spécifiques telles que les rapports interactifs, le réseau interactif et le calendrier.

  4. Exemples montre différentes possibilités d’AOP afin que vous puissiez voir exactement dans les coulisses comment l’AOP est utilisé.

  5. Cas d'utilisation montrer différents cas d'utilisation demandés ou rencontrés par des personnes (à venir).

  6. Débogage comprend comment déboguer et tester AOP.

  7. Manuel utilisateur est un lien vers la dernière version de notre documentation en ligne.

  8. Soutien ouvrira votre client de messagerie par défaut afin que vous puissiez nous écrire.

  9. Administration de l'application telle que générée par APEX.

3.1 Pré-requis

Le plug-in APEX Office Print APEX nécessite Oracle APEX 5.0.4 ou version ultérieure.

Les plug-ins AOP reposent sur un package PL / SQL (aop_api_pkg, synonyme de aop_api19_pkg) qui doit être compilé en premier.

Pour rendre le package disponible, accédez à SQL Plus, SQLcl, SQL Developer ou SQL Workshop et exécutez le script SQL aop_db_pkg.sql que vous trouverez dans le répertoire db du fichier zip que vous avez téléchargé.

Vous pouvez également exécuter le fichier install.sql, qui installera des packages supplémentaires qui montreront comment utiliser AOP à partir de PL / SQL.

Si vous avez importé l'application exemple AOP et exécuté les objets de support, les packages sont automatiquement installés.

3.2 Attributs d'importation et de plug-in

Suivez ces étapes pour importer le plug-in dans votre application:

  1. Accédez à votre espace de travail cible
  2. Sélectionnez le générateur d'applications
  3. Sélectionnez l'application dans laquelle vous souhaitez importer le plug-in> (les plug-ins appartiennent à une application et non à un espace de travail)
  4. Accès Composants partagés> Plug-Ins
  5. Cliquez sur Importer>
  6. Parcourez et localisez les fichiers du programme d’installation dans apex / version / process_type_plugin_be_apexrnd_aop.sql)
  7. Terminez l'assistant.
  8. Faites de même pour le plug-in d'action dynamique dans apex / version / dynamic_action_plugin_be_apexrnd_aop.sql)

Suivez ces étapes pour terminer votre installation de plug-in en ajout de votre clé API de plug-in:

  1. Connectez-vous à https://www.apexofficeprint.com
  2. Copiez votre clé API à partir du tableau de bord
  3. Accédez à votre espace de travail APEX cible
  4. Sélectionnez le générateur d'applications
  5. Sélectionnez l'application dans laquelle vous souhaitez importer le plug-in (les plug-ins appartiennent à une application et non à un espace de travail).
  6. Accès Composants partagés> Paramètres du composant
  7. Ici, sélectionnez APEX Office Print (AOP) [Plug-in]
  8. Ajoutez votre clé API que vous avez copiée à l'étape 2

  9. Cliquez sur Appliquer

  10. L'installation est maintenant terminée

Note d'installation:
Pour utiliser l'API PL / SQL d'AOP, vous devrez peut-être configurer vos paramètres ACL (liste de contrôle d'accès) pour autoriser l'accès à:

http (s): //api.apexofficeprint.com

Pour plus de détails, veuillez vous reporter au guide d'installation Oracle APEX:
pour APEX 5.0 ou pour APEX 5.1
ou pour APEX 18.1

Si vous souhaitez mettre à jour certains paramètres de plug-in, vous les trouverez dans Composants partagés> Paramètres du composant> APEX Office Print (AOP). [Plug-in]

Vous pouvez modifier l'URL AOP, l'URL de basculement AOP (et la procédure appelée en cas de basculement), la clé d'API, le débogage et spécifier un package dans lequel ces paramètres sont spécifiés.
Depuis AOP 3.5, vous pouvez également spécifier un package de journal qui sera appelé à chaque demande. Vous pourrez ainsi contrôler directement à partir de votre base de données Oracle si les impressions ont réussi.
Si vous utilisez la version sur site de AOP, vous pouvez également modifier le convertisseur.

Depuis l'AOP 19.1, il est possible de changer le mode AOP en développement, ce qui signifie que vous n'utilisez pas de crédits dans notre AOP Cloud et que vous avez un nombre illimité d'impressions / de rapports (ignorés par la version de AOP On-Premises).
En mode de développement AOP, une zone de texte (filigrane) sera incluse en haut du document.

Pour générer un fichier PDF, APEX Office Print utilise un convertisseur externe. Par défaut, LibreOffice est utilisé (disponible sur toutes les plateformes), mais vous pouvez le remplacer par MS Office (Windows uniquement). Il est également possible d'utiliser un convertisseur personnalisé. La convergence personnalisée doit être définie dans le fichier aop_config.json. Voir la section 8.1 pour plus d'informations.

3.3 Comment utiliser le plug-in AOP

Ajoutez simplement un nouveau processus appelé AOP (plug-in) sur votre page APEX une fois que vous avez terminé les étapes de la section 3.2.

3.4 Démo de démarrage rapide

Une fois le plug-in importé dans votre application APEX 5, accédez à l'application Exemple de base de données – Page 4.

1) Créez un nouveau bouton appelé IMPRIMER et placez-le à droite du bouton RESET.

2) Créez un nouveau processus (APEX 5.0) ou une action dynamique (APEX 5.1) appelé AOP et sélectionnez le type AOP. [Plug-in]

3) Définissez l’option Type de données du plug-in sur SQL et collez la sélection suivante dans la source de données. S'il vous plaît noter l'utilisation du curseur Les données. Les balises que vous utilisez dans le modèle doivent être à l'intérieur de cette Les données le curseur.

`` `sql
sélectionner
'fichier1' comme "nom de fichier",
le curseur(
    sélectionner
    c.cust_first_name en tant que "cust_first_name",
    c.cust_last_name comme "cust_last_name",
    c.cust_city en tant que "cust_city",
    le curseur(
        sélectionner
        o.order_total en tant que "order_total",
        'Commande' || rownum comme "nom_de_commande",
        le curseur(
            sélectionner
            nom_produit comme "nom_produit",
            i.quantité en tant que "quantité",
            i.unit_price en tant que "unit_price",
            APEX_WEB_SERVICE.BLOB2CLOBBASE64 (p.product_image) en tant qu '"image"
            de
            demo_order_items i, demo_product_info p
            où
            o.order_id = i.order_id
            et i.product_id = p.product_id
                ) "produit"
        de
        demo_orders o
        où
        c.customer_id = o.customer_id
            ) "ordres"
    de
    demo_customers c
    où
    customer_id = 1
        ) en tant que "données"
du double
`` `

4) En tant que type de sortie, sélectionnez docx.

5) Ajouter comme condition pour que le processus ne soit exécuté que lorsque le bouton est cliqué sur IMPRIMER.

6) Cliquez sur Enregistrer et exécuter la page.

Lorsque vous cliquez sur le bouton Imprimer, vous devriez maintenant obtenir votre premier document Word.
   Ce document représente un modèle de départ basé sur vos données. Vous verrez toutes les balises que vous pouvez utiliser et quelques explications supplémentaires sur l'utilisation des expressions et de certaines fonctionnalités de AOP.
   Vous pouvez maintenant créer votre modèle dans MS Word (ou Excel ou PowerPoint) et utiliser les balises de votre modèle. Suivez les étapes suivantes pour le faire.

7) Créez votre modèle dans Word et utilisez les balises fournies dans le premier document que vous avez obtenu.

8) Allez à Composants partagés> Fichiers d’application statiques et téléchargez votre modèle.

9) Retournez à votre page et sélectionnez le processus AOP

10) Modifier le type de modèle en "Fichiers d’application statiques"

11) Dans Source du modèle, entrez le document que vous avez chargé à l’étape 8, par exemple. my_template.docx

12) Rouvrez votre page

Lorsque vous cliquez sur le bouton Imprimer, vous devriez maintenant obtenir votre document Word basé sur votre modèle avec les balises remplacées par les données provenant de la base de données.

3.5 Options de plug-in

Depuis AOP v2.3, deux plug-ins sont inclus: un plug-in de type processus et un plug-in d'action dynamique. Si vous utilisez APEX 5.1, le plug-in Dynamic Action fonctionnera toujours, tandis que le plug-in Process ne fonctionne que si l'attribut «Reload on Submit» (de la page) est défini sur «Always» (notez que cet attribut est nouveau). en 5.1). Cela est dû à un changement dans la manière dont APEX 5.1 gère le traitement de page. Si vous souhaitez importer une application APEX 5.0 dans 5.1 par défaut, elle est définie sur Toujours recharger lors de l'envoi, mais si vous créez une nouvelle application dans 5.1, elle est définie sur «Uniquement pour le succès», ce qui entraîne l'échec du plug-in de type de processus.

Il existe différentes options de configuration pouvant être utilisées dans AOP.

Dans les sous-sections suivantes, vous trouverez plus de détails pour chacune d’elles.

3.5.1 Type de modèle

Il représente quelle sera la source de vos modèles.

Le plug-in AOP vous permet de:

  • Utiliser les modèles par défaut AOP

  • Utiliser des fichiers statiques conservés sur un serveur ou en tant que fichiers d'application / d'espace de travail
    (agissant en tant que modèles globaux)

  • Définissez dynamiquement vos modèles

Modèle AOP

Générera un document Word avec un modèle de départ basé sur les données
(JSON) qui est soumis.

Fichiers d'application statiques

Fera référence aux fichiers que vous trouverez dans Composants partagés> Statique
Fichiers d'application

Fichiers statiques d'espace de travail

Référencez les fichiers que vous trouverez dans Composants partagés> Espace de travail statique
Des dossiers

SQL

Requête qui renvoie deux colonnes: template_type et file (dans cet ordre)

  • template_type peut être: docx, xlsx, pptx, html, md, txt, csv
  • Alors que la colonne de fichier prend en charge: clob base64 du blob (indice: utilisez apex_web_service.blob2clobbase64 pour convertir le blob en clob).

Fonction PL / SQL (retour du code SQL)

Renvoie une instruction select comme avec SQL.

Fonction PL / SQL (retour JSON)

Renvoie un objet JSON au format suivant:


"fichier": "clob base64 data",
"template_type": "docx, xlsx, pptx, html, md, txt, csv, ics"

Nom de fichier (avec le chemin relatif au serveur AOP)

Entrez le chemin et le nom du modèle qui est stocké sur le même
serveur AOP est en cours d'exécution à.

URL (appel de la base de données)

Entrez l'URL de votre modèle dans docx, xlsx, pptx, html, md, txt, ics ou csv.
par exemple. https://www.apexofficeprint.com/templates/aop_template_d01.docx
Assurez-vous toujours que votre URL se termine par le nom du fichier. Par exemple. pour Google Drive, ajoutez à la fin de l'URL & aop = .docx
Cet appel est effectué à partir de la base de données. Le serveur de base de données doit donc avoir accès à l'URL.

URL (appel de l'AOP)

Entrez l'URL de votre modèle dans docx, xlsx, pptx, html, md, txt, ics ou csv.
par exemple. https://www.apexofficeprint.com/templates/aop_template_d01.docx
Assurez-vous toujours que votre URL se termine par le nom du fichier. Par exemple. pour Google Drive, ajoutez à la fin de l'URL & aop = .docx
Cet appel est effectué à partir d'AOP. Le serveur AOP doit donc avoir accès à l'URL.

3.5.2 Source du modèle

Tous les types, à l'exception du type de modèle AOP par défaut, vous permettront de configurer ce paramètre. Il peut représenter un nom de votre fichier ou contenir du code pour votre SQL et PL / SQL.

Quelques exemples de sources de modèles peuvent être trouvés ici:

Fichiers d'application statiques

aop_simple_letter.docx

Fichiers statiques d'espace de travail

aop_simple_letter.docx

SQL

sélectionner
  a.TEMPLATE_TYPE en tant que template_type,
  apex_web_service.blob2clobbase64 (a.TEMPLATE_BLOB) en tant que fichier
 de aop_template a
où id = 1

Fonction PL / SQL (retour du code SQL)

déclarer
  l_return clob;
commencer
  l_retour: = q '[
    select
      a.TEMPLATE_TYPE as template_type,
      apex_web_service.blob2clobbase64(a.TEMPLATE_BLOB) as file
     from aop_template a
    where id = 1
  ]';
  return l_return;
fin;

Fonction PL / SQL (retour JSON)

déclarer
  l_return clob;

commencer
  l_return: = '"fichier": "", "modèle_type": "docx"';
  return l_return;
fin;

déclarer
  l_return clob;
  l_template clob;
  l_template_type aop_template.template_type% type;

commencer
  sélectionnez template_type, apex_web_service.blob2clobbase64 (template_blob) template
    dans l_template_type, l_template
    de aop_template
   où id =: p4_template;

  l_return: = '';
  return l_return;
fin;

Vous pouvez utiliser cette technique pour charger du HTML en tant que modèle. Veuillez consulter la page 114 de l'exemple d'application.

Nom de fichier (avec le chemin relatif au serveur AOP)

aop_template.docx

Remarque: le nom de fichier prend en charge les substitutions telles que les éléments d'application, les éléments de page et les variables système.

URL (fichier de retour)

http://apexofficeprint.com/templates/aop_template_d01.docx

3.5.3 Type de données

Type de données indique le type de source de données que vous utiliserez.

Les options disponibles incluent:

SQL

Sélectionnez une instruction dans laquelle vous pouvez utiliser le curseur pour créer des enregistrements imbriqués. Utilisez "" comme nom de colonne alias pour forcer les noms de colonne en minuscule.
Les données que vous sélectionnez doivent être à l'intérieur du curseur de données. Le plug-in AOP attend deux colonnes: nom de fichier et données.

sélectionner
    'fichier1' comme "nom de fichier",
    le curseur
    (
        *** Votre déclaration choisie ***
    ) en tant que "données"
du double

Fonction PL / SQL (retour du code SQL)

Renvoie une instruction select comme avec SQL.

Fonction PL / SQL (retour JSON)

Renvoie le code JSON défini dans l'exemple d'URL ci-dessus.

URL (retour JSON)

La source doit pointer sur l'URL qui renvoie l'objet JSON au format suivant: "nom_fichier": "fichier1", "données":[…] Si l'URL utilise un appel APEX ORDS REST, elle sera automatiquement encapsulée avec des JSON supplémentaires: "items":[…] Tout cela sera géré pour vous par le plug-in AOP.

Région (s): Rapport (s) classique et / ou interactif et / ou grille (s) et / ou graphique (s) interactive (s)

Un ou plusieurs rapports classiques et / ou interactifs et / ou des grilles interactives seront utilisés comme source pour vos données. Le plug-in Action dynamique a également la possibilité de prendre une capture d'écran, par exemple d'un graphique JET ou de tout autre div (svg / canvas).

Notez que vous pouvez utiliser des variables de liaison telles que: PX_ITEM dans votre instruction SQL. Vous trouvez des exemples lorsque vous cliquez sur Aide dans le plug-in APEX lorsque vous vous trouvez dans le champ Source de données.

3.5.4 Source de données

Dépend du type de données sélectionné et peut être:

SQL

sélectionner
  'fichier1' comme "nom de fichier",
  le curseur(
    sélectionner
      c.cust_first_name en tant que "cust_first_name",
      c.cust_last_name comme "cust_last_name",
      c.cust_city en tant que "cust_city",
      le curseur(
        sélectionner
          o.order_total en tant que "order_total",
          'Commande' || rownum comme "nom_de_commande",
          le curseur(
            sélectionner
              nom_produit comme "nom_produit",
              i.quantité en tant que "quantité",
              i.unit_price en tant que "unit_price",
              APEX_WEB_SERVICE.BLOB2CLOBBASE64 (p.product_image) en tant qu '"image"
            de
              demo_order_items i, demo_product_info p
            où
              o.order_id = i.order_id
              et i.product_id = p.product_id
                ) "produit"
        de
          demo_orders o
        où
          c.customer_id = o.customer_id
            ) "ordres"
    de
      demo_customers c
    où
      customer_id =: P4_CUSTOMER_ID
        ) en tant que "données"
du double

Assurez-vous de mettre les données retournées à l'intérieur du Les données le curseur.

sélectionner
  'fichier1' comme "nom de fichier",
  le curseur(
      *** Votre déclaration choisie ***
  )
   comme "données"
du double

Fonction PL / SQL (retour du code SQL)

Le SQL renvoyé doit contenir les données à l'intérieur du curseur de données, comme ci-dessus.

déclarer
  l_return clob;
commencer
  l_retour: = q '[
    select
      'file1' as "filename",
      cursor(
        select
          c.cust_first_name as "cust_first_name",
          c.cust_last_name as "cust_last_name",
          c.cust_city as "cust_city",
          cursor(
            select
              o.order_total as "order_total",
              'Order ' || rownum as "order_name",
              cursor(
                select
                  p.product_name as "product_name",
                  i.quantity as "quantity",
                  i.unit_price as "unit_price",
                  APEX_WEB_SERVICE.BLOB2CLOBBASE64(p.product_image) as "image"
                from
                  demo_order_items i, demo_product_info p
                where
                  o.order_id = i.order_id
                  and i.product_id = p.product_id
                    ) "product"
            from
              demo_orders o
            where
              c.customer_id = o.customer_id
                ) "orders"
        from
          demo_customers c
        where
          customer_id = :P4_CUSTOMER_ID
            ) as "data"
    from dual
  ]';
  return l_return;
fin;

Fonction PL / SQL (retour JSON)

Notez comment le fichier JSON contient l'objet de données avec les données réelles qu'il contient.

déclarer
  l_cursor sys_refcursor;
  l_return clob;
commencer
  apex_json.initialize_clob_output (dbms_lob.call, true, 2);
  ouvrir l_cursor pour
    sélectionnez 'fichier1' comme "nom de fichier",
      le curseur
        (sélectionner
         c.cust_first_name en tant que "cust_first_name",
         c.cust_last_name comme "cust_last_name",
         c.cust_city en tant que "cust_city",
         le curseur
           (sélectionner
              o.order_total en tant que "order_total",
              'Commande' || rownum comme "nom_de_commande",
              le curseur
              (sélectionner
                 nom_produit comme "nom_produit",
                 i.quantité en tant que "quantité",
                 i.unit_price en tant que "unit_price",
                 apex_web_service.blob2clobbase64 (p.product_image) en tant que "image"
               de
                 demo_order_items i,
                 demo_product_info p
               où
                 o.order_id = i.order_id
                 et i.product_id = p.product_id
               ) "produit"
            de
              demo_orders o
            où
              c.customer_id = o.customer_id
                et rownum <2
           )"ordres"
         de
           demo_customers c
         où
           customer_id =: P4_CUSTOMER_ID
        ) en tant que "données"
    du double;
  apex_json.write (l_cursor);
  l_return: = apex_json.get_clob_output;
  return l_return;
 fin;

URL avec le service Web ORDS RESTful

Pour cela, vous devez créer un nouveau Webservice en procédant comme suit:

  1. Open SQL Workshop -> Services RESTful.

    Cliquez sur le bouton Créer et suivez l'assistant. Pour le module de services RESTful

    Le nom peut être de votre préférence.

  2. Pour le modèle de ressource, entrez:

  3. Pour Resource Handler, entrez:

    L'instruction que nous avons utilisée dans cet exemple est:

sélectionner
  fichier1 'en tant que "nom de fichier",
  le curseur(
    sélectionner
      c.cust_first_name,
      c.cust_last_name,
      c.cust_city,
      le curseur(
        sélectionner
          o.order_total,
          'Commande' || rownum comme nom_ordre,
          le curseur(
            sélectionner
              p.nom_produit,
              i.quantité,
              i.unit_price,
              APEX_WEB_SERVICE.BLOB2CLOBBASE64 (p.product_image) en tant qu'image
            de
              demo_order_items i,
              demo_product_info p
            où
              o.order_id = i.order_id
              et i.product_id = p.product_id
                ) produit
        de
          demo_orders o
        où
          c.customer_id = o.customer_id
          et rownum <2
            ) ordres
    de
      demo_customers c
    où
      customer_id =: id
        ) en tant que "données"
du double

4. Enfin, cliquez sur le bouton Créer un module.

Remarque: Pour le paramètre Gestionnaire de ressources: GET après la création de votre service RESTful, vous devrez peut-être modifier le paramètre Requiert l'accès sécurisé de Oui à Non par défaut.

Rapport (s) classique et / ou interactif et / ou grille (s) interactive (s)

non défini dans la source de données mais dans la ou les identificateurs statiques de région (voir 3.5.5)

3.5.5 ID (s) statique (s) de région

Définissez un ou plusieurs identificateurs statiques de la région du rapport (rapport classique ou interactif ou grille interactive). Les identifiants statiques doivent être séparés par une virgule. par exemple. classic1, ir1, ir2
Vous pouvez définir l'ID statique de la région dans les attributs de région.
Vous pouvez appeler un rapport interactif spécifique en ajoutant un canal à côté, p. Ex. ir1 | my_saved_report.

3.5.6 Spécial

Fonctionnalités spécifiques de APEX Office Print qui deviennent disponibles lorsque le type de données est SQL ou Classic et / ou un rapport interactif

Les options disponibles incluent:

Traiter tous les nombres comme des chaînes
Il y a une limite dans APEX avec l'instruction cursor () dans SQL, qui ne se souvient pas du type de données dans lequel se trouve la colonne. Ainsi, lorsque to_char (0.9, '990D00'), il renverra 0.9 sous forme de nombre au lieu de chaîne '0.90' . Pour résoudre ce problème, cochez cette case et concaténez votre numéro avec "! FMT!" par exemple. '! FMT!' || to_char (35, '990D00') -! FMT! signifie format.

Sinon, si vous formatez votre numéro avec le symbole monétaire to_char (35, 'FML990D00'), Oracle le reconnaîtra comme une chaîne et vous n'avez pas besoin d'utiliser cette case.

Signaler en tant qu'étiquettes
Cochez cette case si vous souhaitez utiliser la source de données Classic Report ou Interactive Report, mais les imprimer en tant qu'étiquettes (à l'aide de la fonctionnalité Mailings de Word). * cette option est obsolète depuis AOP 3.0 car AOP comprend les étiquettes en fonction du modèle.

IR / IG: Afficher les filtres en haut
Lorsque des filtres sont appliqués au rapport / grille interactif, cette case à cocher les imprimera au-dessus du rapport.

IR / IG: Afficher les temps forts en haut
Lorsque des points forts sont appliqués au rapport / grille interactif, cette case à cocher les imprimera au-dessus du rapport.

IR / IG: Afficher l'en-tête avec filtre (Excel)
Lorsque coché, AOP transformera l'en-tête du rapport / grille interactif dans Excel en filtre.

IR / IG: Utiliser le rapport enregistré à la place du rapport en session
Si vous voulez vous assurer que vous appelez toujours un rapport / grille interactif spécifique, sans prendre en compte ce que la personne en fait, vous pouvez cocher cette case pour que le rapport interactif nommé (enregistré) soit pris. par exemple. ir1 | my_saved_report serait dans votre source.

IR / IG: Répétez l'en-tête sur chaque page
Lorsque la table couvre plusieurs pages, la ligne d'en-tête sera répétée sur chaque page.

3.5.7 Nom du fichier de sortie (uniquement dans le plug-in de processus)

Le nom de fichier peut être une chaîne codée en dur ou faire référence à un élément APEX. Il n'est pas nécessaire d'inclure l'extension de fichier. Si une extension de fichier définie est différente du type de sortie sélectionné, une nouvelle extension de fichier sera ajoutée au nom de fichier.
Découvrez également comment spécifier le nom de fichier de sortie dans le plug-in Dynamic Action (Init Code PL / SQL).

Exemples de noms de fichiers

Static: mon_fichier

Poste APEX: & P1_FILENAME.

3.5.8 Init Code PL / SQL (uniquement dans le plug-in d'action dynamique)

Vous pouvez définir des variables globales de aop_api_pkg dans cette zone.

Par exemple, vous pouvez définir le nom du fichier de sortie ou une police:

aop_api_pkg.g_output_filename: = 'sortie';
aop_api_pkg.g_output_filename: = v ('P1_FILENAME');
aop_api_pkg.g_rpt_header_font_size: = '12';

3.5.9 Type de sortie

Les options disponibles incluent:

  • Word (docx)
  • Excel (xlsx)
  • PowerPoint (pptx)
  • PDF (pdf)
  • HTML (HTML)
  • Markdown (md)
  • Comma/Column Separated Values (CSV)
  • Word (rtf)
  • Defined by APEX Item

3.5.10 Output To

Available options include:

Navigateur

The browser will download the file to your Downloads folder.

Procedure

This option will call a procedure in a specific format e.g. send_email_prc. This option is useful in case you do not need the file on your own hard drive, but for example you want to mail the document automatically. In that case you can create a procedure that adds the generated document as an attachment to your apex_mail.send.

In the database the procedure needs to have following parameters:

procedure send_email_prc(
    p_output_blob in blob,
    p_output_filename in varchar2,
    p_output_mime_type in varchar2)

Procedure and Browser

This option allows you to call a procedure first and next download the file to your hard drive. An example is when you first want to store the generated document in a table before letting the browser to download it.

Inline Region (pdf/html/md only)

If you want to output a PDF in a certain region or as a pop-up modal dialog, use this option. See section: 2.3.1.9 for more info. Please note that feature is not available on IE. You can use the modal page options instead.

Directory (on AOP Server)

Save the file to a directory specified with g_output_directory. The default directory on the AOP Server is outputfiles. If you point this to a directory on a shared server or to a directory known by Google Drive or Dropbox, you can easily generate and share documents. Note that the AOP server should enable this option by using the –enable_save argument. It goes without saying that this option is not available while using cloud subscription.

4.1 Pre-requisites

APEX 5.0.4 or higher needs to be installed in the database as the PL/SQL API uses some packages that come with APEX e.g. apex_json

4.2 Install in the Database

Go into SQL Plus, SQLcl, SQL Developer or SQL Workshop and make sure following packages exist aop_api19_pkg and aop_plsql19_pkg and the synonyms aop_api_pkg and aop_plsql_pkg. As part of the installation those packages should have been compiled.

4.3 How to use

You can call AOP straight from PL/SQL. APEX Office Print comes with two different ways of calling AOP; one package is aop_api_pkg which is also used behind the scenes in the APEX Plug-in and the other on is aop_plsql_pkg.
aop_plsql_pkg is especially useful when you just want to do the call to the AOP server component or cloud.

Next to the above two packages we also provide two additional packages that show how to do the pl/sql calls. See the packages aop_sample_pkg and aop_test_pkg.

4.4 Parameters

aop_api_pkg

Global variables which can be set

-- Logger
g_logger_enabled            boolean := true;        -- In case you use Logger (https://github.com/OraOpenSource/Logger), you can compile this package to enable Logger output:
                                                    -- SQL> ALTER PACKAGE aop_api19_pkg COMPILE PLSQL_CCFLAGS = 'logger_on:TRUE'; 
                                                    -- When compiled and this global variable is set to true, debug will be written to logger too
-- Call to AOP
g_aop_url                   varchar2(100) := null;  -- AOP Server URL
g_api_key                   varchar2(50)  := null;  -- AOP API Key; only needed when AOP Cloud is used (http(s)://www.apexofficeprint.com/api)
g_aop_mode                  varchar2(15)  := null;  -- AOP Mode can be development or production; when running in development no cloud credits are used but a watermark is printed                                                    
g_failover_aop_url          varchar2(100) := null;  -- AOP Server URL in case of failure of AOP URL
g_failover_procedure        varchar2(200) := null;  -- When the failover URL is used, the procedure specified in this variable will be called
g_output_converter          varchar2(50)  := null;  -- Set the converter to go to PDF (or other format different from template) e.g. officetopdf or libreoffice
g_proxy_override            varchar2(300) := null;  -- null=proxy defined in the application attributes
g_transfer_timeout          number(6)     := 1800;  -- default of APEX is 180
g_wallet_path               varchar2(300) := null;  -- null=defined in Manage Instance > Instance Settings
g_wallet_pwd                varchar2(300) := null;  -- null=defined in Manage Instance > Instance Settings
g_output_filename           varchar2(300) := null;  -- output
g_cloud_provider            varchar2(30)  := null;  -- dropbox, gdrive, onedrive, aws_s3
g_cloud_location            varchar2(300) := null;  -- directory in dropbox, gdrive, onedrive, aws_s3 (with bucket)
g_cloud_access_token        varchar2(500) := null;  -- access token for dropbox, gdrive, onedrive, aws_s3 (needs json)
g_language                  varchar2(2)   := c_en;  -- Language can be: en, fr, nl, de, used for the translation of filters applied etc. (translation build-in AOP)
g_app_language              varchar2(20)  := null;  -- Language specified in the APEX app (primary language, translated language), when left to null, apex_util.get_session_lang is being used
g_logging                   clob          := '';    -- ability to add your own logging: e.g. "request_id":"123", "request_app":"APEX", "request_user":"RND"
g_debug                     varchar2(10)  := null;  -- set to 'Local' when only the JSON needs to be generated, 'Remote' for remore debug
g_debug_procedure           varchar2(4000):= null;  -- when debug in APEX is turned on, next to the normal APEX debug, this procedure will be called
                                                    --   e.g. to write to your own debug table. The definition of the procedure needs to be the same as aop_debug
-- APEX Page Items
g_apex_items                varchar2(4000):= null;  -- colon separated list of APEX items e.g. P1_X:P1_Y, which can be referenced in a template using Pxx_ITEM                                                    
-- Layout for IR 
g_rpt_header_font_name      varchar2(50)  := '';    -- Arial - see https://www.microsoft.com/typography/Fonts/product.aspx?PID=163
g_rpt_header_font_size      varchar2(3)   := '';    -- 14
g_rpt_header_font_color     varchar2(50)  := '';    -- #071626
g_rpt_header_back_color     varchar2(50)  := '';    -- #FAFAFA
g_rpt_header_border_width   varchar2(50)  := '';    -- 1 ; '0' = no border
g_rpt_header_border_color   varchar2(50)  := '';    -- #000000
g_rpt_data_font_name        varchar2(50)  := '';    -- Arial - see https://www.microsoft.com/typography/Fonts/product.aspx?PID=163
g_rpt_data_font_size        varchar2(3)   := '';    -- 14
g_rpt_data_font_color       varchar2(50)  := '';    -- #000000
g_rpt_data_back_color       varchar2(50)  := '';    -- #FFFFFF
g_rpt_data_border_width     varchar2(50)  := '';    -- 1 ; '0' = no border
g_rpt_data_border_color     varchar2(50)  := '';    -- #000000
g_rpt_data_alt_row_color    varchar2(50)  := '';    -- #FFFFFF for no alt row color, use same color as g_rpt_data_back_color
/* see also Printing attributes in Interactive Report */
-- Settings for Calendar
g_cal_type                  varchar2(10)  := c_cal_month; -- can be month (default), week, day, list; constants can be used
g_start_date                date          := null;    -- start date of calendar
g_end_date                  date          := null;    -- end date of calendar
g_weekdays                  varchar2(300) := null;    -- translation for weekdays e.g. Monday:Tuesday:Wednesday etc.
g_months                    varchar2(300) := null;    -- translation for months   e.g. January:February etc.  
g_color_days_sql            varchar2(4000):= null;    -- color the background of certain days. 
                                                    --   e.g. select 1 as "id", sysdate as "date", 'FF8800' as "color" from dual
-- HTML template to Word/PDF
g_orientation               varchar2(50)  := '';      -- empty is portrait, other option is 'landscape'
-- Call to URL data source
g_url_username              varchar2(300) := null;
g_url_password              varchar2(300) := null;
g_url_proxy_override        varchar2(300) := null;
g_url_transfer_timeout      number        := 180;
g_url_body                  clob          := empty_clob();
g_url_body_blob             blob          := empty_blob();
g_url_parm_name             apex_application_global.vc_arr2; --:= empty_vc_arr;
g_url_parm_value            apex_application_global.vc_arr2; --:= empty_vc_arr;
g_url_wallet_path           varchar2(300) := null;
g_url_wallet_pwd            varchar2(300) := null;
g_url_https_host            varchar2(300) := null;    -- parameter for apex_web_service, not used, please apply APEX patch if issues
-- Web Source Module (APEX >= 18.1)
g_web_source_first_row      pls_integer   := null;    -- parameter for apex_exec.open_web_source_query
g_web_source_max_rows       pls_integer   := null;    -- parameter for apex_exec.open_web_source_query
g_web_source_total_row_cnt  boolean       := false;   -- parameter for apex_exec.open_web_source_query
-- REST Enabled SQL (APEX >= 18.1)
g_rest_sql_auto_bind_items  boolean       := true;    -- parameter for apex_exec.open_remote_sql_query
g_rest_sql_first_row        pls_integer   := null;    -- parameter for apex_exec.open_remote_sql_query
g_rest_sql_max_rows         pls_integer   := null;    -- parameter for apex_exec.open_remote_sql_query
g_rest_sql_total_row_cnt    boolean       := false;   -- parameter for apex_exec.open_remote_sql_query
g_rest_sql_total_row_limit  pls_integer   := null;    -- parameter for apex_exec.open_remote_sql_query
-- IP Printer support
g_ip_printer_location       varchar2(300) := null;
g_ip_printer_version        varchar2(300) := '1';
g_ip_printer_requester      varchar2(300) := nvl(apex_application.g_user, USER);
g_ip_printer_job_name       varchar2(300) := 'AOP';
g_ip_printer_return_output  varchar2(5)   := null;   -- null or 'Yes' or 'true'
-- Post Processing
g_post_process_command       varchar2(100) := null;  -- The command to execute. This command should be present on aop_config.json file. 
g_post_process_return_output boolean       := true;  -- Either to return the output or not. Note this output is AOP's output and not the post process command output. 
g_post_process_delete_delay  number(9)     := 1500;  -- AOP deletes the file provided to the command directly after executing it. This can be delayed with this option. Integer in milliseconds. 
-- Convert characterset
g_convert                   varchar2(1)   := c_n;    -- set to Y (c_y) if you want to convert the JSON that is send over; necessary for Arabic support
g_convert_source_charset    varchar2(20)  := null;   -- default of database 
g_convert_target_charset    varchar2(20)  := 'AL32UTF8';  
-- Output
g_output_directory          varchar2(200) := '.';    -- set output directory on AOP Server
                                                    -- if . is specified the files are saved in the default directory: outputfiles
g_output_split              varchar2(5)   := null;   -- split file: one file per page: true/false
g_output_even_page          varchar2(5)   := null;   -- PDF option to always print even pages (necessary for two-sided pages): true/false
g_output_merge_making_even  varchar2(5)   := null;   -- PDF option to merge making all documents even paged (necessary for two-sided pages): true/false

-- Files
g_prepend_files_sql         clob := null;    -- format: select filename, mime_type, [file_blob, file_base64, url_call_from_db, url_call_from_aop, file_on_aop_server]
g_append_files_sql          clob := null;    --           from my_table

-- Sub-Templates
g_sub_templates_sql         clob := null;    -- format: select filename, mime_type, [file_blob, file_base64, url_call_from_db, url_call_from_aop, file_on_aop_server] from my_table

-- Password protected PDF
g_output_read_password      varchar2(200) := null;  -- protect PDF to read
g_output_modify_password    varchar2(200) := null;  -- protect PDF to write (modify)
g_output_pwd_protection_flag number(4)    := null;  -- optional; default is 4. 
                                                    -- Number when bit calculation is done as specified in http://pdfhummus.com/post/147451287581/hummus-1058-and-pdf-writer-updates-encryption
g_output_watermark          varchar2(4000) := null;  -- Watermark in PDF

Function call

function plsql_call_to_aop(
    p_data_type                 in varchar2 default c_source_type_sql,
    p_data_source               in clob,
    p_template_type             in varchar2 default c_source_type_apex,
    p_template_source           in clob,
    p_output_type               in varchar2,
    p_output_filename           in out nocopy varchar2,
    p_output_type_item_name     in varchar2 default null,
    p_output_to                 in varchar2 default null,
    p_procedure                 in varchar2 default null,
    p_binds                     in wwv_flow_plugin_util.t_bind_list default c_binds,
    p_special                   in varchar2 default null,
    p_aop_remote_debug          in varchar2 default c_no,
    p_output_converter          in varchar2 default null,
    p_aop_url                   in varchar2,
    p_api_key                   in varchar2 default null,
    p_aop_mode                  in varchar2 default null,
    p_app_id                    in number   default null,
    p_page_id                   in number   default null,
    p_user_name                 in varchar2 default null,
    p_init_code                 in clob     default c_init_null,
    p_output_encoding           in varchar2 default c_output_encoding_raw,
    p_output_split              in varchar2 default c_false,
    p_output_even_page          in varchar2 default c_false,
    p_output_merge_making_even  in varchar2 default c_false,
    p_failover_aop_url          in varchar2 default null,
    p_failover_procedure        in varchar2 default null,
    p_log_procedure             in varchar2 default null,
    p_prepend_files_sql         in clob     default null,
    p_append_files_sql          in clob     default null,
    p_sub_templates_sql         in clob     default null)
  return blob;

Note that some other procedures and functions are available in the package which could be helpful.

aop_plsql_pkg

function make_aop_request(
  p_aop_url          in varchar2 default g_aop_url,
  p_api_key          in varchar2 default g_api_key,
  p_json             in clob,
  p_template         in blob,
  p_output_encoding  in varchar2 default 'raw', -- change to raw to have binary, change to base64 to have base64 encoded
  p_output_type      in varchar2 default null,
  p_output_filename  in varchar2 default 'output',
  p_aop_remote_debug in varchar2 default 'No')
  return blob;

4.5 Example

Example with aop_api_pkg

déclarer
  l_binds           wwv_flow_plugin_util.t_bind_list;
  l_return          blob;
  l_output_filename varchar2(100) := 'output';
commencer
  -- define bind variables
  l_binds(1).name := 'p_id';
  l_binds(1).value := '1';

  l_return := aop_api_pkg.plsql_call_to_aop (
                p_data_type       => 'SQL',
                p_data_source     => q'[
                  select
                    'file1' as "filename",
                    cursor(
                      select
                        c.cust_first_name as "cust_first_name",
                        c.cust_last_name as "cust_last_name",
                        c.cust_city as "cust_city",
                        cursor(select o.order_total as "order_total",
                                      'Order ' || rownum as "order_name",
                                  cursor(select p.product_name as "product_name",
                                                i.quantity as "quantity",
                                                i.unit_price as "unit_price", APEX_WEB_SERVICE.BLOB2CLOBBASE64(p.product_image) as "image"
                                           from demo_order_items i, demo_product_info p
                                          where o.order_id = i.order_id
                                            and i.product_id = p.product_id
                                        ) "product"
                                 from demo_orders o
                                where c.customer_id = o.customer_id
                              ) "orders"
                      from demo_customers c
                      where customer_id = :p_id
                    ) as "data"
                  from dual
                ]',
                p_template_type   => 'SQL',
                p_template_source => q'[
                   select template_type, template_blob
                    from aop_template
                   where id = 1
                ]',
                p_output_type     => 'docx',
                p_output_filename => l_output_filename,
                p_binds           => l_binds,
                p_aop_url         => 'http://api.apexofficeprint.com/',
                p_api_key         => 'your API key',
                p_app_id          => 232);
end;

Example with aop_plsql_pkg

déclarer
  l_template        blob;
  l_output_file     blob;
commencer
  select template_blob
    into l_template
    from aop_template
   where id = 1;

  l_output_file := aop_plsql_pkg.make_aop_request(
                     p_json        => '[ "filename": "file1", "data": [ "cust_first_name": "APEX Office Print" ] ]',
                     p_template    => l_template,
                     p_output_type => 'docx',
                     p_aop_remote_debug => 'Yes');
end;

Dans aop_sample_pkg you find the above examples and you can run them with following command:

commencer
    aop_sample_pkg.call_aop_plsql_pkg;
    aop_sample_pkg.call_aop_api_pkg;
end;

Note that there are more examples in the aop_sample_pkg, so it's worthwhile to check it out.

4.6 PL/SQL API Documentation

The complete reference can be found in the AOP PL/SQL API documentation.

5.1 Overview

Behind the scenes the APEX plug-in is creating a JSON file that will be sent to the AOP server. Below you find more details about the JSON structure that is used. By understanding this JSON structure you can manually interact with the AOP server in case you wanted to code in PL/SQL or other languages.

5.2 JSON File

The JSON file is a file that follows the standard JSON structure (http://json.org/).

This JSON file contains an JSON object meaning it starts with and ends with . This JSON object contains four compulsory JSON objects namely "template", "output", "files", "api_key" and a few optional object "version", "logging", "apex_version", "aop_remote_debug" and "ipp". The purpose of each object will now be explained.

5.2.1 "version" object

This object contains the version of AOP JSON format used. The current version is 18.2 and backwards compatible thus optional. This will be used for future upgrades and if the newer version is not backwards compatible.

5.2.2 "template" object

This object has the necessary information about the template. Il contient:

JSON Explication
"file" This contains the template to be used, encoded in base64.
"filename" This option is for on-premise users. The template defined by this object will be used for processing. Note that the filename either contains a relative path from where the server is running from (or the folder/directory containing application) or an absolute path.
"url" This option allows you to give the URL containing the template. The URL will also work with google drive (also with google docs/slides/powerpoint) and dropbox file sharing link. However this might not work in the future since the way links work might be changed by google or dropbox. Note this URL can also use ftp protocol.
"template_type" This states what kind of template is being used. It must be either "docx", "pptx", "xlsx", "html" or "md".
"html_template_content" Since AOP 3.4 it is possible to just pass html as template. This is equivalent as using _html tag in word to create the template which is then again passed to the AOP with the data for rendering.
"orientation" nothing or "landscape". If landscape is provided then the html template content will be rendered in a landscape A4 word template. Taken only into account when html_template_content is provided.

If "file","filename" or "url" objects are not present in the "template" object then the server will respond with a custom template file of "template_type" made from this given JSON file. Currently only Word, Excel and PowerPoint template generation is supported.

The sharing link made by dropbox and google drive will be modified to that the online editor will not be triggered, and are subject to change by google drive and dropbox. For this reason using share link for production is discouraged. The change happens in the following way:

Google Docs Share URL:
https://docs.google.com/document/d/ID/edit?usp=sharing
will be changed to:
https://docs.google.com/document/d/ID/export?format=docx&id=ID

Google Sheets Share URL: 
https://docs.google.com/spreadsheets/d/ID/edit?usp=sharing
will be changed to: 
https://docs.google.com/spreadsheets/d/ID/export?format=xlsx&id=ID

Google Slides Share URL:
https://docs.google.com/presentation/d/ID/edit?usp=sharing
will be changed to:
https://docs.google.com/presentation/d/ID/export/pptx?id=ID&pageid=p

Dropbox Share URL:
https://www.dropbox.com/s/ID/filename?dl=0
will be changed to:
https://www.dropbox.com/s/ID/filename?dl=1

Google Drive Share URL:
https://drive.google.com/file/d/ID/view?usp=sharing
will be changed to:
https://drive.google.com/uc?export=download&id=ID

URL Template Example

5.2.3 "output" object

This object has the necessary information for producing an output file from the given JSON file. Il contient:

JSON Explication
"output_type" This states what kind of output file type is required. It can be either the same as template_type ("docx", "pptx", "xlsx", "html", "md"), "pdf" or any other output file supported by libreoffice/openoffice. Special output type: "onepagepdf", this will cause the ouptut to be converted to pdf and all the pages will be merged into one single page. Default: the same as template_type.
"output_encoding" This states what kind of output encoding is wished for the output file. It must be either "raw" or "base64".
"output_converter" This states which software should be used to convert to pdf. The ApexOfficePrint server usages LibreOffice. On premise users may use MS Office but will need to do some configuration first. Available values: "officetopdf" (Windows only) or "libreoffice" (Windows, Linux, OSX) or any other custom defined converters in aop_config.json file (see setting up AOP) if you are using On Premise Version.
"output_directory" If save on disk is enabled, then the document will be saved on the path resulted by combining this given path with the specified directory.
"output_even_page" If you want your output to have even pages, for example printing on both sides after merging, you can set this to be true. This option is only available when the output is pdf. Optional.
"output_merge_making_even" Merge each given document making even paged. This option is only available when the output is pdf. Optional.
"output_modify_password" Requires output pdf, the password needed to modify the pdf. Optional. Read password, if given, will be used if this field is empty.
"output_read_password" Requires output pdf, the password needed to open the pdf. Optional.
"output_password_protection_flag" Requires output pdf, bit field explained in the PDF specs in table 3.20 in section 3.5.2, should be given in decimal more info. Optional. Default (4).
"output_watermark" Requires output pdf, generates a diagonal custom watermark on every page in the PDF file. Optional.
"lock_form" Requires output pdf, locks/flattens the forms in the pdf. Optional.

Watermark Example

5.2.4 "api_key"

The value of this key is the API key given by ApexOfficePrint. Only applicable for service users.

5.2.5 "file" array

This array contains the data that will be used for the given template.
If this array contains more than one object then the output files, which are generated using the same template for each item, will be returned in a zip file. This array contains JSON objects with following fields:

JSON Explication
"filename" This field contains the name of the output file.
"data" This array (containing one object) or object contains the data that will be replaced in the template.

Example showing a basic JSON file which should be populated with data:


    "template": 
           "filename"               :"template.docx",
           "template_type"          :"docx"
    ,
    "output": 
           "output_encoding"        :"raw",
           "output_type"            :"docx",
           "output_directory"       :"."
    ,
    "files":[
             "filename"             :"file1",
             "data"                 : [...]
    ]

5.2.6 "logging" object

When AOP is started with –enable_printlog, it will create a file on the server called server_printjob.log.
You can add additional logging information next to the one AOP is logging by default, by adding additional keys and values in the logging object.

Par exemple:

                "logging": 
        "template_filename": "AOP template",
        "output_filename": "output.docx"
    

5.2.7 "ipp" object

AOP supports to print directly to an IP Printer by using this setting. If your IPP printer supports pdf files, your documents will be converter to pdf and sent to IPP printer. If your printer does not support PDF and supports Postscript then the pdf generated is converter to pdf using pdftops. You need download xpdf tools from: https://www.xpdfreader.com/download.html. Make sure that the binary pdftops is on PATH variable. You can download executables from apexofficeprint.com to check whether or not your IPP printer supports PDF/postscript.
The structure is:

"ipp": 
        "location": "http://10.0.14.223:631/",
        "version": "1.1",
        "requester": "YOUR NAME",
        "job_name": "AOP"
    

5.2.8 "post_process" object

This option is available since AOP version 19.1. This option allows the request to run a command after post processing.
The structure is:

"post_process":
    "command":"echo",  //The command to execute. This command should be present on aop_config.json file. 
    "return_output":true, //Either to return the output or not. Note this output is AOP's output and not the post process command output. 
    "delete_delay": 1500 // AOP deletes the file provided to the command directly after executing it. This can be delayed with this option. Integer in milliseconds. 


The templates are standard office files in which tags will be replaced by structured data from the JSON file. These tags are quite standardized for either .docx, .pptx ou .xlsx, however there are some subtle differences. They are all able to handle JavaScript angular expressions, on which some of the basics will follow.

6.0 Tag Overview

In the table below is an overview of the available tags and their support in Word, Excel and PowerPoint respectively. For more information on each tag, see the sections that follow.

Étiquette Word Excel PowerPoint HTML Markdown Txt CSV
data_string Oui Oui Oui Oui Oui Oui Oui
data_string_with_cell_markup$ Oui Oui Non Non Non N.A N.A
-labels Oui N.A N.A N.A N.A N.A N.A
_htmlcontent Oui Non Non Yes (by default) Yes (by default) N.A N.A
!slide_loop N.A N.A Oui N.A N.A N.A N.A
!excelsheet_loop N.A Oui N.A N.A N.A N.A N.A
#data_loop … /data_loop Oui Oui Oui Oui Oui Oui Oui
:inline_data_loop … /inline_data_loop Non Non Non Non Non Non Oui
:data_loop_horizontal … /data_loop_horizontal Oui Oui Non Non Non Non Non
=table_row_loop … /table_row_loop N.A N.A Oui N.A N.A N.A N.A
%imageKey Oui Oui Oui Oui Oui N.A N.A
Oui Oui Oui Oui Oui N.A N.A
Oui Oui Oui Oui Oui N.A N.A
$chart Oui Oui Oui Non Non N.A N.A
&interactive_report Oui Oui Non Non Non N.A N.A
&interactive_grid& Oui Oui Non Non Non N.A N.A
<rightToLeft Oui Not Necessary Not Necessary Not Necessary Not Necessary N.A N.A
+footnote Oui Non Non Non Non N.A N.A
*hyperlink Oui Oui Oui Not Necessary Not Necessary N.A N.A
~ Oui N.A N.A N.A N.A N.A N.A

Note: tags can't start with a number and should start with an alphabetical character (a-z,A-Z)

Special Tags:

current_child_index: Will resolve to current index of the record array, starting from 0.

#object./object: Will iterate over the names of the keys from the given object. If it's array then we look into the unique keys of the first 5 element. . will be replaced by the name of the key. Can be used for horizontal looping with unknown number of columns and columns name.

#object.values: Will iterate over the values of the given object.

6.1 Word (docx) template

These templates can contain the following tags:

6.1.1 data_string tags

This tag, data_string, will be replaced by the value of the key "data_string" in the JSON file.

6.1.1.1 Data string example

Given the JSON file with following content:

                
        "template": 
               "filename"               :"template.docx",
               "template_type"          :"docx"
        ,
        "output": 
               "output_encoding"        :"raw",
               "output_type"            :"docx"
        ,
        "files": [
                 "filename"             :"output",
                 "data": [
                         "first_name"   :"DemoName",
                         "last_name"    :"DemoLastName",
                         "city"         :"DemoCity"
                  ]
        ]

and template.docx with following content:

                                                                                                                                                                                    last_name first_name
                                             city

will result in:

                                                                                                                                                                                        DemoLastName DemoName
                                              DemoCity

Since the template and the output objects from the json will not change, these will be omitted from the examples given below.

6.1.2 %imagekey tags

This tag is the same as data_string but instead getting replaced by a string this tag is replaced by an image that is placed in the value of key "imagekey" after base64 encoding. Note that imagekey is just a variable. An image tag is represented by "%" after curly bracket.
You can also specify a fixed width and the height by adding following values "imagekey_width" and "imagekey_height". If you want to scale your image proportionally you can use the "imagekey_max_width" and "imagekey_max_height" tags. An example is created in the AOP Sample Application which shows how it works. The imagekey is pic, so we can use pic_max_width for example.
The given data can be a base64 encoded image or a URL pointing to an image(the URL must have image extension) or a ftp server image.

6.1.2.1 Image tag example

Replace /…code…./ for the base64 encoded string of the image

                
        ...
        "files":[
                 "filename"        :"output",
            "data":[
                  "product_name"   :"Wallet",
                  "price"          :"$500.00",
                  "pic"            :"/...code..../",
                  "pic_max_width"  : 100,
                  "pic_max_height" : 100
            ]
        ]

with template:

Product Image Prix
product_name %pic price

will result in:

Tip: in case you want to make your images equal in size, you can use PL/SQL to resize your images. Here's an example to put the size of the image to a maximum of 200px.

déclarer
  l_img blob;
commencer
  sélectionner une image
    into l_img
    from my_table
   where id = 1 for update;
  ordsys.ordimage.process(l_img, 'maxscale=200 200');
  update my_table
     set image = l_img
   where id = 1;
end;

6.1.3 barcode / qrcode tags

This tag will be replaced by the barcode or QR code created using the data of the key named "barcode" ou "qrcode". Notice that these are also variable. Barcode or qrcode tags are represented by | après
curly bracket. If this tag is found in the document there must be additional supporting keys containing the options for these tags. These options are:

  1. key_type, e.g. "barcode_type" if the key used is "barcode".
       This field contains the type of barcode required.
       The options are:
    codabar
        code128
        code128a
        code128b
        code128c
        code39
        ean13
        ean2
        ean5
        ean8
        itf
        itf14
        msi
        msi10
        msi1010
        msi11
        msi1110
        pharmacode
        upc
        upce

  2. key_height, e.g. "barcode_height" if the key used is "barcode".
       This field contains the height for the generated image.
       Default is 200 for QR, 50 for the rest.

  3. key_width, e.g. "barcode_width" if they key used is "barcode".
       This field contains the width for the generated image.
       Default is 200.

  4. key_errorcorrectlevel (only for QR code), e.g. "qrcode_errorcorrectlevel" if the key used is "qrcode". This field contains the level of which the QR code should be recoverable.
       The options are:
       "L" (up to 7% damage)
       "M" (up to 15% damage)
       "Q" (up to 25% damage)
       "H" (up to 30% damage)
       Extra info: http://www.qrcode.com/en/about/error_correction.html

  5. key_cellsize (only for QR code), e.g. "qrcode_cellsize". This field contains the dot size of a module.
       Default is 4.
       Extra info: http://www.qrcode.com/en/howto/cell.html

6.1.3.1 Barcode tag example

Given the JSON file:

                
        ...
        "files":[
                 "filename"           :"output",
            "data":[
                  "product_name"      :"Wallet",
                  "product_code"      :"1896547832148",
                  "product_code_type" :"ean13",
                  "product_link"      :"https://www.google.be/search?q=wallet",
                  "product_link_type" :"qrcode"
            ]
        ]

and template as:

will result in:

For barcodes, instead of doing the above, you could also choose to install a barcode font, for example Free 3of9 or http://www.dafont.com/3of9-barcode.font. Barcode fonts are more performant than images. See the other section for more information about language and font support.

6.1.4 $chart tags

This tag will be replaced by chart created using the data of the key named "chart". Notice that this key is a variable. Charts are represented by $ after curly bracket. If this tag is found in the document the chart object in the json must follow certain structure. Firstly, an optional object with key "options" to determine the options for the chart. The default options are:

                defaultOptions = 
            width: 5486400 / 9525, // width of the chart
            height: 3200400 / 9525, // height of the chart
            grid: true, // if a grid should be shown
            border: true, // if a border should be shown
            title: false,
            legend: 
                showLegend: true, // if the legend should be shown
                position: 'r'  // 'l' for left, 'r' right, 'b' bottom, 't' top
            ,
            dataLabels:   //Available only after AOP 19.1
                showDataLabels: false, // can be true or false, default true for pie/pie3d and doughnut. 
                seperator: false, // can be either false or anything else for example n or t or ; or (, if false)
                showSeriesName: false, // include the series name in the data label, true or false
                showCategoryName: false, // include the series category name in the data label, true or false
                showLegendKey: false,    // include the legend key (i.e the color of the series) in the data label, true or false
                showValue: false, // include the actual value in the data label
                showPercentage: false, // include the percentage, default true for pie/pie3d and doughnut
                position: 'center' // position to show the data label, can be 'center', 'left', 'right', 'above', 'below', 'insideBase', 'bestFit', 'outsideEnd', 'insideEnd'. note that not all options might be available for specific charts. 
            ,
            axis: 
                x: 
                    orientation: 'minMax', // or "maxMin"
                    min: undefined, // a specific number
                    max: undefined, // a specific number
                    type: undefined, // or "date"
                    date:  //date options
                        format: 'unix',
                        code: 'mm/yy',
                        unit: 'months',
                        step: '1'
                    ,
                    title:'title for x axis', //From 19.1.1
                    showValues: true //options to disable showing the values in axis

                ,
                y: 
                    orientation: 'minMax',
                    mix: undefined,
                    max: undefined,
                    title: 'Title for y axis', //From 19.1.1
                    showValues: true // options to disable showing the values in axis
                 ,
                y2:  //If using multiple charts and axis on the right side
                    orientation: 'minMax',
                    mix: undefined,
                    max: undefined,
                    title: 'Title for y2 axis', //From 19.1.1 
                    showValues: true // options to disable showing the values in axis
                
            
        

Secondly the type of chart should be determined by "type" key. The generation of following types of charts is supported:

6.1.4.1 Line

This is a normal chart where the data's are connected with lines. Multiple lines can be generated. The chart key should contain lines array inside with the data of the lines that should be generated and the name of the line. E.g.:

                "chart": 
            "lines": [
                
                    "data": [
                        
                            "x": "day 1",
                            "y": "4.3"
                        ,
                        
                            "x": "day 2",
                            "y": "2.5"
                        ,
                        
                            "x": "day 3",
                            "y": "3.5"
                        
                    ],
                    "name": "line 1",
                    "smooth": true, //Can be false
                    "symbol": "square" // can be diamond triangle
                ,
                
                    "data": [
                        
                            "x": "day 1",
                            "y": "2.4"
                        ,
                        
                            "x": "day 2",
                            "y": "4.4"
                        ,
                        
                            "x": "day 3",
                            "y": "1.8"
                        
                    ],
                    "name": "line 2"
                
            ],
            "type": "line"
        

will result in :

6.1.4.2 bar

In order to generate the bar chart, the chart object should contain array named bars. This array contains the objects with data about the bar and the name of the bar. For example, given the following:

                ...
    "chart": 
        "bars": [
            
                "data": [
                    
                        "x": "day 1",
                        "y": "4.3"
                    ,
                    
                        "x": "day 2",
                        "y": "2.5"
                    ,
                    
                        "x": "day 3",
                        "y": "3.5"
                    
                ],
                "name": "bar 1"
            ,
            
                "data": [
                    
                        "x": "day 1",
                        "y": "2.4"
                    ,
                    
                        "x": "day 2",
                        "y": "4.4"
                    ,
                    
                        "x": "day 3",
                        "y": "1.8"
                    
                ],
                "name": "bar 2"
            
        ],
        "type": "bar"
    
    ...

will result in:

Single bar chart is generated as follows:

                ...
    "chart": 
        "bars": [
            
                "data": [
                    
                        "x": "day 1",
                        "y": "4.3"
                    ,
                    
                        "x": "day 2",
                        "y": "2.5"
                    ,
                    
                        "x": "day 3",
                        "y": "3.5"
                    
                ],
                "name": "bar 1"
            
        ],
        "type": "bar"
    
    ...

will result in:

6.1.4.3 barStacked

This is similar to bar chart but the bars from same category will be stacked. For example, given the following:

                ...
    "chart": 
        "bars": [
            
                "data": [
                    
                        "x": "day 1",
                        "y": "4.3"
                    ,
                    
                        "x": "day 2",
                        "y": "2.5"
                    ,
                    
                        "x": "day 3",
                        "y": "3.5"
                    
                ],
                "name": "bar 1"
            ,
            
                "data": [
                    
                        "x": "day 1",
                        "y": "2.4"
                    ,
                    
                        "x": "day 2",
                        "y": "4.4"
                    ,
                    
                        "x": "day 3",
                        "y": "1.8"
                    
                ],
                "name": "bar 2"
            
        ],
        "type": "barStacked"
    
    ...

will result in:

6.1.4.4 barStackedPercent

This is similar to bar stacked chart, but the x axis will be in expressed in percentage.
For example, given the following:

                ...
    "chart": 
        "bars": [
            
                "data": [
                    
                        "x": "day 1",
                        "y": "4.3"
                    ,
                    
                        "x": "day 2",
                        "y": "2.5"
                    ,
                    
                        "x": "day 3",
                        "y": "3.5"
                    
                ],
                "name": "bar 1"
            ,
            
                "data": [
                    
                        "x": "day 1",
                        "y": "2.4"
                    ,
                    
                        "x": "day 2",
                        "y": "4.4"
                    ,
                    
                        "x": "day 3",
                        "y": "1.8"
                    
                ],
                "name": "bar 2"
            
        ],
        "type": "barStacked"
    
    ...

will result in:

6.1.4.5 column

This will produce a normal column chart. The chart object should contain an array named columns with objects containing the data and name of the column. E.g.:

                                "chart": 
            "columns": [
                
                    "data": [
                        
                            "x": "day 1",
                            "y": "4.3"
                        ,
                        
                            "x": "day 2",
                            "y": "2.5"
                        ,
                        
                            "x": "day 3",
                            "y": "3.5"
                        
                    ],
                    "name": "column 1"
                ,
                
                    "data": [
                        
                            "x": "day 1",
                            "y": "2.4"
                        ,
                        
                            "x": "day 2",
                            "y": "4.4"
                        ,
                        
                            "x": "day 3",
                            "y": "1.8"
                        
                    ],
                    "name": "column 2"
                
            ],
            "type": "column"
        

will result in:

A single column chart can be generated by following json:

                                "chart": 
            "columns": [
                
                    "data": [
                        
                            "x": "day 1",
                            "y": "4.3"
                        ,
                        
                            "x": "day 2",
                            "y": "2.5"
                        ,
                        
                            "x": "day 3",
                            "y": "3.5"
                        
                    ],
                    "name": "column 1"
                
            ],
            "type": "column"
        

will result in:

6.1.4.6 columnStacked

This will produce a column stacked chart. The chart object should contain an array named columns with objects containing the data and the name of the column. Par exemple:

                                "chart": 
            "columns": [
                
                    "data": [
                        
                            "x": "day 1",
                            "y": "4.3"
                        ,
                        
                            "x": "day 2",
                            "y": "2.5"
                        ,
                        
                            "x": "day 3",
                            "y": "3.5"
                        
                    ],
                    "name": "column 1"
                ,
                
                    "data": [
                        
                            "x": "day 1",
                            "y": "2.4"
                        ,
                        
                            "x": "day 2",
                            "y": "4.4"
                        ,
                        
                            "x": "day 3",
                            "y": "1.8"
                        
                    ],
                    "name": "column 2"
                
            ],
            "type": "columnStacked"
        

will result in:

6.1.4.7 columnStackedPercent

This will produce a column stacked percent chart. The chart object should contain an array named columns with objects containing the data and the name of the column. Par exemple:

                                "chart": 
            "columns": [
                
                    "data": [
                        
                            "x": "day 1",
                            "y": "4.3"
                        ,
                        
                            "x": "day 2",
                            "y": "2.5"
                        ,
                        
                            "x": "day 3",
                            "y": "3.5"
                        
                    ],
                    "name": "column 1"
                ,
                
                    "data": [
                        
                            "x": "day 1",
                            "y": "2.4"
                        ,
                        
                            "x": "day 2",
                            "y": "4.4"
                        ,
                        
                            "x": "day 3",
                            "y": "1.8"
                        
                    ],
                    "name": "column 2"
                
            ],
            "type": "columnStackedPercent"
        

will result in:

6.1.4.8 pie

This will produce a pie chart. The chart object should contain an array named pies with one element containing the data and name of the pie chart. Par exemple:

                                "chart": 
            "pies": [
                
                    "data": [
                        
                            "x": "Order 1",
                            "y": 1890
                        ,
                        
                            "x": "Order 2",
                            "y": 2380
                        ,
                        
                            "x": "Order 3",
                            "y": 1640
                        ,
                        
                            "x": "Order 4",
                            "y": 1090
                        ,
                        
                            "x": "Order 5",
                            "y": 950
                        ,
                        
                            "x": "Order 6",
                            "y": 1515
                        ,
                        
                            "x": "Order 7",
                            "y": 905
                        ,
                        
                            "x": "Order 8",
                            "y": 1060
                        ,
                        
                            "x": "Order 9",
                            "y": 730
                        ,
                        
                            "x": "Order 10",
                            "y": 870
                        
                    ],
                    "name": "pie 1"
                
            ],
            "type": "pie"
        

will result in:

6.1.4.9 radar

This will produce a radar chart. The chart object should contain an array named radars with one element containing the data and name of the radar chart. Par exemple:

                                "chart": 
            "radars": [
                
                    "data": [
                        
                            "x": "Order 1",
                            "y": 1240
                        ,
                        
                            "x": "Order 2",
                            "y": 380
                        ,
                        
                            "x": "Order 3",
                            "y": 840
                        ,
                        
                            "x": "Order 4",
                            "y": 490
                        ,
                        
                            "x": "Order 5",
                            "y": 1230
                        
                    ],
                    "name": "radar 1"
                
            ],
            "type": "radar"
        

will result in:

6.1.4.10 area

This will produce an area chart. The chart object should contain an array named areas with one element containing the data and name of the area chart. Par exemple:

                "chart": 
        "areas": [
            
                "data": [
                    
                        "x": "day 1",
                        "y": "4.3"
                    ,
                    
                        "x": "day 2",
                        "y": "2.5"
                    ,
                    
                        "x": "day 3",
                        "y": "3.5"
                    
                ],
                "name": "area 1"
            ,
            
                "data": [
                    
                        "x": "day 1",
                        "y": "2.4"
                    ,
                    
                        "x": "day 2",
                        "y": "4.4"
                    ,
                    
                        "x": "day 3",
                        "y": "1.8"
                    
                ],
                "name": "area 2"
            
        ],
        "type": "area"
    

will result in:

6.1.4.11 scatter

This will produce a scatter chart. The chart object should contain an array named scatters with one element containing the data and name of the scatter chart. Similar to previous charts however the x axis should contain only numbers.

6.1.4.13 bubble

This will produce a bubble chart. The chart object should contain an array named bubbles with one element containing the data and name of the bubble chart. It is similar to previous charts however, the data should can now contain size value to determine the size of a bubble. Example JSON:


    "chart": 
        "bubbles": [
            
                "data": [
                    
                        "x": "day 1",
                        "y": "4.3",
                        "size":"1"
                    ,
                    
                        "x": "day 2",
                        "y": "2.5",
                        "size":"3"
                    ,
                    
                        "x": "day 3",
                        "y": "3.5",
                        "size":"2"
                    
                ],
                "name": "Bubble series 1"
            ,
            
                "data": [
                    
                        "x": "day 1",
                        "y": "2.4",
                        "size":"4"
                    ,
                    
                        "x": "day 2",
                        "y": "4.4",
                        "size":"5"
                    ,
                    
                        "x": "day 3",
                        "y": "1.8",
                        "size":"1"
                    
                ],
                "name": "Bubble series 2"
            
        ],
        "type": "bubble"
    

will result in:

6.1.4.14 stock

This will produce a stock chart. The chart object should contain an array named stocks with one element containing the data and name of the stock chart. Here instead of y value: volume, open, close, high and low value should be given. The format of the x axis can also be given.
The x axis contains the date starting using 1900 notation, i.e. 1 will represent January 1 1900 more info.

Exemple:

    {
          "chart": {
            "stocks": [
              
                "data": [
                  
                    "x": "1",
                    "volume": "70",
                    "open": "44",
                    "high": "55",
                    "low": "11",
                    "close": "25"
                  ,
                  
                    "x": "2",
                    "volume": "120",
                    "open": "25",
                    "high": "57",
                    "low": "12",
                    "close": "38"
                  ,
                  
                    "x": "3",
                    "volume": "150",
                    "open": "38",
                    "high": "57",
                    "low": "13",
                    "close": "50"
                  ,
                  
                    "x": "4",
                    "volume": "135",
                    "open": "50",
                    "high": "58",
                    "low": "11",
                    "close": "35"
                  ,
                  
                    "x": "5",
                    "volume": "148",
                    "open": "34",
                    "high": "58",
                    "low": "25",
                    "close": "43"
                  
                ],
                "name": "s"
              
            ],
            "type": "stock",
            "options":
              "axis":
                "x":
                  "date":
                    "unit":"days",
                    "step":1,
                    "code":"dd"
                  
                
              
            
          },
          "name": "Stocks"
        }

will result in:

6.1.4.11 Combining Charts

It is possible to combine multiple charts. For example, a column and a line chart. If a second value axis is wished on the right side, then the values should be given as y2 instead of y. The type should be "multiple" and the chart should contain a multiples array which contains the different charts defined previously. It is possible to combine more than 2 types of chart but there can only be two value axes. An example is given below:

                "chart": 
        "multiples": [
            
                "columns": [
                    
                        "data": [
                            
                                "x": "day 1",
                                "y": "4.3"
                            ,
                            
                                "x": "day 2",
                                "y": "2.5"
                            ,
                            
                                "x": "day 3",
                                "y": "3.5"
                            
                        ],
                        "name": "bar 1"
                    ,
                    
                        "data": [
                            
                                "x": "day 1",
                                "y": "2.4"
                            ,
                            
                                "x": "day 2",
                                "y": "4.4"
                            ,
                            
                                "x": "day 3",
                                "y": "1.8"
                            
                        ],
                        "name": "bar 2"
                    
                ],
                "type": "column"
            ,
            
                "lines": [
                    
                        "data": [
                            
                                "x": "day 1",
                                "y2": "43"
                            ,
                            
                                "x": "day 2",
                                "y2": "25"
                            ,
                            
                                "x": "day 3",
                                "y2": "35"
                            
                        ],
                        "name": "line 1"
                    ,
                    
                        "data": [
                            
                                "x": "day 1",
                                "y2": "24"
                            ,
                            
                                "x": "day 2",
                                "y2": "44"
                            ,
                            
                                "x": "day 3",
                                "y2": "18"
                            
                        ],
                        "name": "line 2"
                    
                ],
                "type": "line"
            
        ],
        "options": 
            "border": true,
            "grid": true,
            "height": 700,
            "legend": 
                "position": "r",
                "showLegend": true
            ,
            "title": false,
            "width": 500
        ,
        "type": "multiple"
    

will result in:

The following SQL can be used:

sélectionner
    'file1' as "filename",
    cursor(select  
             cursor(select
                      c.cust_first_name || ' ' || c.cust_last_name as "customer",
                      c.cust_city                                  as "city"    ,
                      o.order_total                                as "total"   ,
                      o.order_timestamp                            as "timestamp"
                      from demo_customers c, demo_orders o
                     where c.customer_id = o.customer_id
                     order by c.cust_first_name || ' ' || c.cust_last_name
             ) as "report",
             cursor(select
                      'multiple' as "type",
                      'My Combo: Column with Line Chart' as "name",   
                      cursor(select
                               576     as "width" ,
                               336     as "height",
                               'Title' as "title" ,
                               'true'  as "grid",
                               'true'  as "border",
                               cursor(select
                                 'true' as "showLegend",
                                 'r' as "position"
                                 from dual
                               ) as "legend"
                             from dual
                      ) as "options",
                      cursor(select
                               tp as "type",
                               cursor(select
                                 nm as "name",
                                 cursor(select to_char(o.order_timestamp, 'MON RRRR') "label", 
                                               to_char(o.order_timestamp, 'MON RRRR') "x",
                                               sum (decode(p.category,nm,oi.quantity * oi.unit_price,0)) "y"
                                          from demo_product_info p, demo_order_items oi, demo_orders o
                                         where oi.product_id = p.product_id
                                           and o.order_id = oi.order_id
                                         group by to_char(o.order_timestamp, 'MON RRRR'), to_char(o.order_timestamp, 'RRRR MM')
                                         order by to_char(o.order_timestamp, 'RRRR MM')
                                 ) as "data"
                                 from (select 'Mens' nm from dual union all select 'Womens' nm from dual )
                                 where tp = 'column'
                               ) as "columns",
                               cursor(select
                                 nm as "name",
                                 cursor(select to_char(o.order_timestamp, 'MON RRRR') "label", 
                                               to_char(o.order_timestamp, 'MON RRRR') "x",
                                               sum (decode(p.category,nm,oi.quantity * oi.unit_price,0)) "y"
                                          from demo_product_info p, demo_order_items oi, demo_orders o
                                         where oi.product_id = p.product_id
                                           and o.order_id = oi.order_id
                                         group by to_char(o.order_timestamp, 'MON RRRR'), to_char(o.order_timestamp, 'RRRR MM')
                                         order by to_char(o.order_timestamp, 'RRRR MM')
                                 ) as "data"
                                 from (select 'Accessories' nm from dual)
                                 where tp = 'line'
                               ) as "lines"
                             from (select 'column' tp from dual   union all   select 'line' tp from dual)
                       ) as "multiples"
                     from dual
             ) as "chart"
           from dual
    ) as "data"
  from dual
  `` `

### 6.1.5 D3 (Data Driven Documents) images

With Word/Excel/PowerPoint documents, it's possible to let AOP execute some JavaScript code to generate a D3 image.

Given the JSON file with following content:

```json

    ...
    "files": [
            "filename": "output",
            "data": 
                "test": "CODE"
            
    ]

With as (JSON-encoded) code:

// Based on https://bl.ocks.org/mbostock/7f5f22524bd1d824dd53c535eda0187f
const d3 = require('d3');
const D3Node = require('d3-node')
const d3n = new D3Node()

const svg = d3n.createSVG(512, 512);
const [width, height] = [512, 512];
const margin =  top: 20, right: 30, bottom: 30, left: 40 ;

var x = d3.scaleLog().domain([2e-1, 5e0])
  .rangeRound([margin.left, width - margin.right])
var y = d3.scaleLog().domain([3e2, 2e4])
  .rangeRound([height - margin.bottom, margin.top])
var color = d3.scaleSequential(d3.interpolateYlGnBu).domain([0, 1.8]) // Points per square pixel.

svg.append("g")
  .attr("transform", "translate(0," + (height - margin.bottom) + ")")
  .call(d3.axisBottom(x).ticks(null, ".1f"))
  .select(".tick:last-of-type text")
  .select(function ()  return this.parentNode.appendChild(this.cloneNode()); )
  .attr("y", -3).attr("dy", null)
  .attr("font-weight", "bold").text("Carats");

svg.append("g")
  .attr("transform", "translate(" + margin.left + ",0)")
  .call(d3.axisLeft(y).ticks(null, ".1s"))
  .select(".tick:last-of-type text")
  .select(function ()  return this.parentNode.appendChild(this.cloneNode()); )
  .attr("x", 3).attr("text-anchor", "start")
  .attr("font-weight", "bold").text("Price (USD)");

d3.tsv("https://bl.ocks.org/mbostock/raw/7f5f22524bd1d824dd53c535eda0187f/diamonds.tsv", d => ( carat: +d.carat, price: +d.price ), (error, diamonds) => 
  if (error) throw error;
  if (diamonds[0] instanceof Error) throw diamonds[0];
  svg.insert("g", "g").attr("fill", "none")
    .attr("stroke", "#000").attr("stroke-width", 0.5)
    .attr("stroke-linejoin", "round").selectAll("path")
    .data(d3.contourDensity()
      .x(d => x(d.carat)).y(d => y(d.price))
      .size([width, height]).bandwidth(10)
      (diamonds))
    .enter().append("path")
    .attr("fill", d => color(d.value))
    .attr("d", d3.geoPath());
  finish(d3n);
);

And a Word document containing ?d3 test would produce the following result:

Should a field "test_data": [1,2,3] be present in the JSON (at the same place as "test": "CODE"), then the code will have access to the global Les données ce qui serait [1,2,3], or whatever "test_data" est. String, booleans, nunbers and objects are also possible.

6.1.5.1 Code structure

This is how the code is supposed to be organized:

// Import D3
const d3 = require('d3');
// Import D3-Node
const D3Node = require('d3-node');
// Instantiate a new D3Node, which will provide the SVG and will be required to finish
const d3n = new D3Node();
// Create a SVG (instead of selecting one from the (here non-existing) document)
const svg = d3n.createSVG(512, 512); // Different sizes are possible
// Start working on the SVG
svg.append('g').text('Test');
//  etc
// We can access the _data field if it was given:
svg.append('g').text(data ? data.toString() : 'No data passed!');
// When the SVG is finished, call the global finish() with the used D3Node object
finish(d3n);
// We can also call the global fail() (or throw an error) should something fail:
fail(new Error('We are missing something!'));

6.1.5.2 Specifications and limitations

  • The d3 library is version 4.12.0
  • d3-contour and d3-scale-chromatic (along with all default 4.12.0 submodules) are preloaded, e.g. d3.contour() est disponible
  • The code is run in an async environment, meaning attendre est disponible
  • The code has to either have a return statement with a D3Node object, or call finish() with one
  • After the code has successfully finished, the SVG will be extracted from the D3Node, converted to PNG and pasted in the Word/Excel/…
  • ES2015, ES2016 and ES2017 are supported, run inside a Node environment
  • Only d3 libraries (including sub-libraries like d3-polygon) can be returned by require()
  • d3-request can only use http:// and https:// URLs
  • There are time limitations, e.g. the whole script will time out after 30s, even when it's still fetching data over HTTP(S)
  • All errors are caught and will cause the whole PrintJob to fail. The stack trace will be shown

6.1.6 #data_loop … /data_loop tags

Using the opening tag #data_loop and closing tag /data_loop, we can loop inside the JSON array named "data_loop", meaning the items that are inside the tags will be repeated for each array element. Again, like in image tag "data_loop" is a variable. A loop tag is represented by "#" after the curly bracket.

6.1.6.1 General Data loop example

Given the JSON file with following content:

                
        ...
        "files":[
               "filename"           :"output",
                "data":[
                       "people":[
                              "first_name" :"DemoName1",
                              "last_name"  :"DemoLastName1",
                              "city"       :"DemoCity1",
                       
                              "first_name" :"DemoName2",
                              "last_name"  :"DemoLastName2",
                              "city"       :"DemoCity2",
                       
                              "first_name" :"DemoName3",
                              "last_name"  :"DemoLastName3",
                              "city"       :"DemoCity3"
                       ]
                ]]

and template.docx with following content:

The name of the employees are:
#peoplefirst_namelast_name from city city.
/people

will result in:

The name of the employees are:
DemoName1 DemoLastName1 from City DemoCity1.
DemoName2 DemoLastName2 from City DemoCity2.
DemoName3 DemoLastName3 from City DemoCity3.

6.1.6.2 Loops in table example

Using the previous data, if the template is changed to:

the result will then be:

6.1.6.3 Loops with numbering example

Using the previous data, if the template is changed to:

the result will be:

6.1.6.4 Loops in bullets

The same can be done with bullets:

will result in:

6.1.6.5 Math operations during a loop

Numeric operations inside a loop are supported by using the | operator. The following operations are supported:
|sum, calculates the total sum of a numeric property during a loop.
|avg, calculates the total average of a numeric property during a loop.
|min, returns the minimum numeric value of a property during a loop.
|max, returns the maximum numeric value of a property during a loop.

The following template is given:

Results in:

6.1.7 Horizontal Tabular Looping

Since verion 18.1 AOP also supports horizontal tabular looping using the :horizontal_loop … /horizontal_loop tags. However, this tag can be used to repeat only one row (in Word, in Excel this works like normal loop tag and repeats the cells defined by the rectangular boundary of starting and closing tag). Following is an example on how this could be used:

6.1.8 Simple angular like expressions

Simple angular like expressions are also supported that can perform simple mathematical operations.

A full list of Angular expression can be found at https://docs.angularjs.org/guide/expression.

6.1.8.1 Simple Expressions

Expressions like num1 + num2 will print the sum of num1 and num2.
Division, multiplication, addition and subtraction are allowed.

If the given key has a boolean value then you can use #boolean key…/boolean key to print the content inside tags if the value of boolean key is vrai. For negation ^boolean key…/boolean key is used. The content inside these tags will be printed if the boolean key has faux as value or if boolean key does not exists or if boolean key is an empty array.

6.1.8.2 String/Number Comparison

You can also check the value of keys with #key=='value'…/key=='value'. The content inside the tags will be only printed if the value of the key is equal to "value". Note here in #key=='value', that straight single quotes are used!

The numbers can also be compared in the same way as strings #key>;50…/key>;50.The content inside the tags will be only printed if the value of the key is greater than 50. The following operators are supported: <, >, <=, >=, ==, !=

6.1.8.3 Conditional and Comparison operator

Another way to compare variables is as follows: key == 'value' ? key2 : key3. This way other keys/variables can also be inserted. This will print out value of key2 if the expression is true and key3 if the expression is false.

Possible conditional operators are:

  • Equal: == (equal to) or === (equal value and equal type)
  • Not Equal: != or !== (not equal value or not equal type)
  • And: &&
  • Or: ||
  • Greater than: >
  • Less than: <
  • Greater than or equal: >=
  • Less than or equal: <=

6.1.8.4 Conditional example

For the JSON given in example below currency == 'EUR' ? '€'+price : price+'$' prints €50 if true and 50$ if false and given price variable is 50.

Given the JSON file with following content:

                
        ...
                 "data":[
                       "product":[
                              "product_name" :"Business Shirt",
                              "quantity"     :3,
                              "unit_price"   :50,
                              "onstock"      :true,
                              "cur"          :"EUR"
                       ,
                       
                              "product_name" :"Trousers",
                              "quantity"     :3,
                              "unit_price"   :80,
                              "onstock"      :false,
                              "cur"          :"USD"
                       ,
                       
                              "product_name" :"Jacket",
                              "quantity"     :3,
                              "unit_price"   :15,
                              "onstock"      :true,
                              "cur"          :"USD"
                       ,
                       
                              "product_name" :"Blouse",
                              "quantity"     :3,
                              "unit_price"   :60,
                              "onstock"      :false,
                              "cur"          :"EUR"
                       ]
                ]

and template with following content:

will result in:

Angular expressions can also be used inside floating texts. Below an example where the images are put inside floating textbox and are shown under condition.

6.1.8.5 String operations

If you tag resolves to a string then you can also use string manipulation functions like: substr, length, substring, replace, split. see prototype methods https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String

6.1.8.5 Array Operations

If your tag resolves to array, i.e for using on #loop tag. You can access the length of the loop array by .length property for example loop.length. You can also access individual array element with array access notation of javascript, for example loop[0].loop_inisde_element.

6.1.9 Labels printing

AOP also provides a way to print the labels in word document. To do so you can create a document with labels from going to Mailings options and then to Labels. Fill in the tags in address field and choose the type of label by clicking in Label option. A document can then be generated by clicking New document.
Currently however if labels are getting printed then we expect the document only containing labels and no other information, and that the tag keys are not used more than once.
Given the JSON file:

                ...
        "data": 
            "labels": [
                
                    "city": "city1",
                    "first_name": "firstname1",
                    "last_name": "lastname1",
                    "title": "Mr.",
                    "tracking_number_text": "TN49775377172",
                    "tracking_number": "TN49775377172",
                    "tracking_number_type": "code128",
                    "zip_code": 6981
                ,
                ...
                
                    "city": "city12",
                    "first_name": "firstname12",
                    "last_name": "lastname12",
                    "title": "Mr.",
                    "tracking_number_text": "TN49709864775",
                    "tracking_number": "TN49709864775",
                    "tracking_number_type": "code128",
                    "zip_code": 9740
                
            ]
        
    ...

and template:

will produce:

Note that in the first cell you need to add the labels tag. See also the Sample app.

6.1.10 HTML tag

HTML tags can also be converted to Word. The tag that has to be used is _key, thus underscore followed by the key which has HTML content in JSON. The tags that are currently supported are:


: in order to introduce breaks (newline)

..

: represents a paragraph .. : bold text .. : bold text .. : strike through .. : underline .. : italics

..

: heading 1

..

: heading 2

..

: heading 3

..

: heading 4
..
: heading 5
..
: heading 6 .. : subscript .. : superscript
    ..
: ordered list
    ..
: unordered list
  • ..
  • : list item ..
    : table (including th, tr, td) .. : caption : image
     .. 

    : preformatted text

    .. : text between the span will have the style defined, background-color, color, font-size and font-family are supported.

    Eg:
    Given the following key inside data:

                    "htmlcontent": "

    This is text coming from the database / session in HTML format.
    It supports:

    1. Des listes
    2. Audacieux
    3. Italic
    4. Underline
    5. Strikethrough
    6. Sousscénario
    7. Superscénario
    8. Text Color
    9. Background Text Color

    Heading 1

    Heading 2

    Heading 3

    Heading 4

    Normalt text with Font Change

    Code font

    "

    and the template:

    will produce:

    6.1.11 Interactive Report (IR) tag

    &interactive will be replaced in the given template by the interactive report that has been selected in APEX.
    Other than the simple interactive report, there are three other options that can be selected: Control Break, Group By, Pivot. Those will be illustrated below.
    Keep in mind that the tag that gets replaced is &interactive, no matter which of the above options is selected in APEX.
    For a concrete example, see section 11.

    Control Break:
    By clicking on Actions and selecting Control Break, one or more columns can be selected on which the table should be broken. For the purpose of illustration, assume we select Quantity.

    This splits the table up into partitions based on the value of the selected column. Thus, rows sharing the same value for Quantity, will be grouped together into the same partition.
    The resulting table can be seen below:

    As a final note, this option also supports the application of aggregates on the table data.

    Group By:
    By clicking on Actions and selecting Group By, one or more columns can be selected on which the table data should be grouped by. For the purpose of illustration, assume we select Quantity. Furthermore, one or more functions can be applied on the table data. In this example, we request the sum of the unit price for every group.

    The result is a new table with one column for every selected column on which the data should be grouped by, and one column for every selected function to be applied on the group data.

    The resulting table can be seen below:

    Additionally, a custom label and format may be selected for each function column and a sum can be performed over the values of each function column.

    Pivot:
    By clicking on Actions and selecting Pivot, the user is prompted to select at least one pivot column, at least one row column and at least one function over a particular column.
    Important to note is that the row column, pivot column and function column need to be different.
    For the sake of the example, we select Quantity as a pivot column, Product Name as a row column and sum over Unit Price as a function.

    The resulting table can be seen below:

    The additional options supported in this case are the same as the ones in Group By.

    Chart:
    AOP can also print your Interactive Report Chart view directly in your template by using $interactive.

    The result in PowerPoint can be seen below:

    Note that this is a native PowerPoint chart, so you can adapt, make bigger, change colors, etc. directly in PowerPoint.

    Width Manipulation:
    Since 18.2.2 it is possible to manipulate the widths of the interactive columns. You can do so by specifying it on HTML_EXPRESSION. You can use the following in html expression.

    #COLUMN_NAME#
    

    The default weight for each column is 1. Let's say you have 4 columns and you provide this html expression in the first colum. This will double the size of the first column in comparison to the remaining 3.

    The following formula is used to calculate the percentage of width a column gets:

    (weight of column)/(total weight provided for all the columns) * 100. Please note that these widths are the desired widths. If the content does not fit, it could be that the minimum width that fits will be taken by Word/LibreOffice.

    6.1.12 Multiple Interactive Reports in one template

    In this case, the template needs to have tags of the form &interactive_1,&interactive_2 and these tags will be replaced by the corresponding interactive reports. Many interactive reports can be selected by giving in their static IDs in a particular order (ir1,ir2,…) and it is in that order that their data will be inserted in the template. Thus, &interactive_1 gets replaced by the data in the first interactive report (static Id: ir1) and similarly for &interactive_2 that will get replaced by the data in the second interactive report (static Id: ir2) and so on.

    The result can be seen below:

    6.1.13 Table cell background

    You can give a background to a cell in a table in Word by using the column followed by _cell_background_color. The tag in the template should end with a $.

        cursor(select p.product_name as "product_name",
                                  i.quantity as "quantity",
                                  Cas
                                  when i.quantity between 1 and 2 then '#00FF00'
                                  when i.quantity between 2 and 3 then '#00FF00'
                                  else '#0000FF'
                                  end as "quantity_cell_background_color",
                                  i.unit_price as "unit_price"
                             from demo_order_items i, demo_product_info p
                            where o.order_id = i.order_id
                              and i.product_id = p.product_id
                          ) "backcolor"
    

    6.1.14 Right to Left tag

    In word when substituting the content in language written in right to left like Arabic, the <rightToLeft tag can be used to properly format the language. If the substituting content does not contain any right to left language character, then it will behave as normal substitution tag.

    A footnote tag can be used to insert footnote. The tag should start with "+" symbol. For example, given the following template:

    and the data as follows:

    
        "quote":"Only I can change my life. No one can do it for me.",
        "person":"Carol Burnett"
    
    

    will result in:

    Since AOP3.3 hyperlink feature is added using a tag that start with a * like: *tag. Given the template:

    And the data:

    
      "name": "Support",
      "company_url": "https://www.apexofficeprint.com",
      "company_url_text": "APEX RND",
      "mail": "[email protected]"
    
    

    will result in:

    The mail hyperlinks are automatically detected and mailto: will be appended for the link to work. The hyperlink text can be given by giving extra data that ends with _text. e.g: *tag_text. (see json above).

    This hyperlink will also work when output pdf is wished.

    Please note that in Excel the hyperlink will be added but the style will remain normal. You can change the tag style in template if another styling is wished. In Word your default hyperlink styling will be taken. If you wish another styling, you can change the style of the tag and add tag_preserve_tag_style:true options in the data.

    6.1.17 Table Of Content

    AOP versions greater than 3.5, also support generation of table of content in Word. Placing the ~tockey tag will generate table of content at the place where this tag is used. Since AOP version 18.2.3, AOP allows you to customize table of content. The following options are available:

    "tockey_title":"Title of Table Of Content", //Default Contents
    "tockey_show_level": 3, //The depth of heading to be shown, default 3
    "tockey_tab_leader": "underscore", //How the space between title and page number should be filled. Can be "hyphen", "underscore", or "dot" (default).
    
    

    6.1.18 Word Subtemplating

    Inside Word documents, the tag ?include NAME est disponible.

    Given the following JSON:

    
        ...
        "template": 
            "filename": "Template",
            "file": "UEsDBBAQBgQ...",
            "template_type": "docx"
        ,
        "templates": [
            
                "name": "Subtemplate1",
                "mime_type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
                "file_source": "base64",
                "file_content": "UEsDBBAQBgAIAA..."
            
        ]
    
    

    with the template containing ?include Subtemplate1 would replace the tag with the contents of the subtemplate.

    This tag can be used inside loops, and tags inside the subtemplate will also be replaced.

    Par exemple:

    #products
    Product name
        ?include Subtemplate1
    /products
    

    Should the subtemplate just consist of the content Amount: amount, then this could be an example result:

    Product Product1
        Amount: 5
    Product Product2
        Amount: 36
    

    This tag is currently only available inside Word templates, and the subtemplates currently can only be Word documents (templates) too.

    6.2 PowerPoint (pptx) template

    For pptx template files same tags are supported as in docx template.
    Attention should be paid when using "#", "%", "$" et "^" tags, namely they should be on their own text field. The position of the text field will determine where the top left of the chart and image will start. Repeating a template slide is done by specifying which array should be looped with "!" tag after the curly bracket for example !products to repeat over product array. If none is declared the root object is taken as array. Plusieurs "!" tags are not allowed in one slide.

    Given the JSON file with following content:

                    
            "template": 
                "template_type": "pptx",
                "filename": "demo.pptx"
            ,
            "output": 
                "output_encoding": "raw",
                "output_type": "pptx"
            ,
            "files": [
                
                    "filename": "output",
                    "data": [
                        
                            "slide_title": "Slides Per Product",
                            "company_name": "Company A",
                            "product": [
                                
                                    "product_name": "Business Shirt",
                                    "quantity": 3,
                                    "unit_price": 50
                                ,
                                
                                    "product_name": "Trousers",
                                    "quantity": 3,
                                    "unit_price": 80
                                ,
                                
                                    "product_name": "Jacket",
                                    "quantity": 3,
                                    "unit_price": 15
                                ,
                                
                                    "product_name": "Blouse",
                                    "quantity": 3,
                                    "unit_price": 60
                                
                            ]
                        
                    ]
            ]
    

    and the pptx template as follows:

    will result the following for the first slide:

    Since there is only one item in root JSON object this is repeated only once. In template slide 2 we have specified product array as our loop array with !product tag. Since there are 4 objects in our product array this template will be repeated four times. The result is as follows:

    6.3 Excel (xlsx) template

    In the xslx templates, some of the same tags as the previous types of templates can be used, as shown in the overview table at the start of this section. The JSON format should contain the same meta information elements (e.g. template_type, filename, …) and the data information is stocked under files/data.

    Regular tags can be used with corresponding keyword in the JSON file between brackets, like in the docx and pptx templates. The xlsx templates can loop over elements in a list by using the same technique as in the docx template: #loop_element to enter the loop and /loop_element to close it. The cells that are in the rectangle bounded by these two tags will be looped over and filled in using the data available in the JSON file. Nested loops are possible (however keep in mind to remain within the rectangle formed by the "parent" loop – see note after example below). Style will be copied from the template to the generated file accordingly. As with the docx templates, simple angular expressions can be used to perform mathematical operations.

    Xlsx example:

    Given the JSON file with following content:

                    {
            "template": 
            "template_type": "xlsx",
            "filename": "simple.xlsx"
            ,
            "output": 
            "output_encoding": "raw",
            "output_type": "xlsx"
            ,
            "files": [
            
                "filename": "file1",
                "data": [
                    
                        "cust_first_name": "Albert",
                        "cust_last_name": "Lambert",
                        "cust_city": "St. Louis",
                        "orders": [
                            
                                "order_total": 310,
                                "order_name": "Casual Shop's Order",
                                "product": [
                                    
                                        "product_name": "Shirt",
                                        "quantity": 3,
                                        "unit_price": 50
                                    ,
                                    
                                        "product_name": "Trousers",
                                        "quantity": 2,
                                        "unit_price": 80
                                    ]
                            ,
                            
                                "order_total": 200,
                                "order_name": "Sport Shop's order",
                                "product": [
                                    
                                        "product_name": "Sport's shoes",
                                        "quantity": 2,
                                        "unit_price": 100
                                    ]
                            ]]]}
    

    and the xlsx template as follows:

    Note: in the example above the /orders closing tag must be in the last column. Otherwise the child loops inside #orders…/orders, in this case #product…/product, would not be able to generate inside the rectangle formed between the tags of its parent loop (#orders…/orders).

    Interactive Report in Excel:
    As of version 2.2, all of the functionalities supported in Word regarding the interactive report are also supported in Excel.
    For the purpose of illustration, let's take this template as input:

    The resulting output is then:

    6.3.1 data_string_with_cell_markup$

    AOP 3.0 and above also supports cell settings.
    With a $ sign at the end of a tag, it is possible to specify different styles in a cell. This allows user to change for example the background of the cell dynamically. An example of such tag is tag_with_style$. The different styles then can be specified by appending either of the following in the data:
    + cell_locked: [y/n]
    + cell_hidden: [y/n]
    + cell_background: hex color e.g: #ff0000
    + font_name: name of the font e.g: Arial
    + font_size: e.g 14,
    + font_color: hex color e.g: #00ff00
    + font_italic: [y/n]
    + font_bold: [y/n]
    + font_strike: [y/n]
    + font_underline: [y/n]
    + font_superscript:[y/n]
    + font_subscript:[y/n]
    + border_top: [dashed / dashDot / hair / dashDotDot / dotted / mediumDashDot / mediumDashed / mediumDashDotDot / slantDashDot / medium / double / thick ]
    + border_top_color: hex color e.g: #000000
    + border_bottom: [dashed / dashDot / hair / dashDotDot / dotted / mediumDashDot / mediumDashed / mediumDashDotDot / slantDashDot / medium / double / thick ]
    + border_bottom_color: hex color e.g: #000000
    + border_left: [dashed / dashDot / hair / dashDotDot / dotted / mediumDashDot / mediumDashed / mediumDashDotDot / slantDashDot / medium / double / thick ]
    + border_left_color: hex color e.g: #000000
    + border_right: [dashed / dashDot / hair / dashDotDot / dotted / mediumDashDot / mediumDashed / mediumDashDotDot / slantDashDot / medium / double / thick ]
    + border_right_color: hex color e.g: #000000
    + border_diagonal: [dashed / dashDot / hair / dashDotDot / dotted / mediumDashDot / mediumDashed / mediumDashDotDot / slantDashDot / medium / double / thick ]
    + border_diagonal_direction: [up-wards|down-wards| both]
    + border_diagonal_color: hex color e.g: #000000
    + text_h_alignment: [top|bottom|center|justify]
    + text_v_alignment: [top|bottom|center|justify]
    + text_rotation: rotation of text value from 0-90 degrees

    Please note that if the tag is example$ then the data provided should be inside example_cell_background, example_font_italic …e.t.c.

    6.3.2 !sheetgeneration

    With AOP 3.3 and above you can also generate sheets automatically by using !tag in any cell. This can be used for example to generate a sheet report per customer. The sheet name can also be dynamically changed and should be provided by the key "sheet_name".
    An example:

            
            "customers": [
              
                "sheet_name": "John Dulles", //sheet name!
                "cust_first_name": "John",
                "cust_last_name": "Dulles",
                "cust_city": "Sterling",
                "orders": [
                  
                    "order_total": 2380,
                    "order_name": "Order 1",
                    "product": [
                      
                        "product_name": "Business Shirt",
                        "quantity": 3,
                        "unit_price": 50
                      ,
                      
                        "product_name": "Trousers",
                        "quantity": 3,
                        "unit_price": 80
                      ,
                      
                        "product_name": "Jacket",
                        "quantity": 3,
                        "unit_price": 150
                      
                    ]
                  
                ],
              
                "sheet_name": "William Hartsfield",
                "cust_first_name": "William",
                "cust_last_name": "Hartsfield",
                "cust_city": "Atlanta",
                "orders": [
                  
                    "order_total": 1640,
                    "order_name": "Order 1",
                    "product": [
                      
                        "product_name": "Blouse",
                        "quantity": 4,
                        "unit_price": 60
                      ,
                      
                        "product_name": "Skirt",
                        "quantity": 4,
                        "unit_price": 80
                      
                    ]
                  ,
                  
                    "order_total": 730,
                    "order_name": "Order 2",
                    "product": [
                      
                        "product_name": "Blouse",
                        "quantity": 4,
                        "unit_price": 60
                      
                    ]
                  
                ]
            ]
    
    

    And the template:

    Sheet Generation Template

    will result in:

    Sheet Generation Output Sheet 1Sheet Generation Output Sheet 2

    This is similar to hyperlink tag mentioned in section 6.1.16.
    In Excel, it is possible to hyperlink to a specific sheet and cell inside the document itself.
    The URL then should be of structure: "SheetName!Cell".
    An example:

    
          "examplehyperlink": "HyperlinkTarget!B2",
          "examplehyperlink_text": "Go to HyperlinkTarget"
    
    

    with template

    Sheet Generation Template

    will result in:

    Sheet Generation Template

    6.4 QRCode Image Replacing

    AOP also allows you replace a QRcode image with another image. The qr code can contain the image tags and barcode tags, i.e %key or . This method can be used if you are inserting a floating image, or need to have certain border styles on the image. The tag replacing will work as look as there are no artistic effects used for the image themselves.

    Please note that the scope always starts at the default place, so the #loop tags have no effect.

    example of image replacing

    6.5 Converter

    This feature only works when the output_type is pdf

    AOP can convert several types of files and/or append/prepend them to the outputted files.

    6.5.1 Appending/prepending files

    All append/prepend files will first be converted to PDF, after which the pages (as a whole) will be prepended/appended to the outputted files. Par exemple. images will appear on their own page, ne pas "pasted" into the template file.

    6.5.1.1 General structure

    The JSON sent to AOP will have this structure:

    
        ...
        "template":  ... ,
        "output": 
            "output_encoding": "base64",
            "output_type": "pdf" // Converter functionality only works with PDF as output_type
        ,
        "files": [
            
                "data":  ... ,
                "filename": "File1"
            ,
            
                "data":  ... ,
                "filename": "File2"
            ,
            ...
        ],
        "prepend_files": [
            // Array of prepend files (see 6.5.1.2 File Structure)
             ... ,
             ... ,
            ...
        ],
        "append_files": [
            // Array of prepend files (see 6.5.1.2 File Structure)
             ... ,
             ... ,
            ...
        ]
    
    

    6.5.1.2 File structure

    
        "filename": "Filename",
        "mine_type": "MIME TYPE",
        // File source can be "plain", "base64", "url" or "file",
        "file_source": "FILE SOURCE",
        // Used by "file_source": "plain" and "base64",
        "file_content": "...",
        // Used by "file_source": "url",
        "file_url": "http://...",
    
    

    6.5.1.3 Multiple files

    Should the JSON contain multiple files, e.g. like this:

    
        ...
        "files": [
            
                "data":  ... ,
                "filename": "File1"
            ,
            
                "data":  ... ,
                "filename": "File2"
            ,
            ...
        ],
    
    

    Then, as might be expected, a zip archive will be returned containing File1.pdf and File2.pdf.
    The append/prepend files will be appended/prepended to chaque fichier.

    6.5.2 Converting without template

    AOP allows converting files without a template, resulting in the append/prepend files being converted and stitched together.

    6.5.2.1 General structure

    The JSON sent to AOP will have this structure:

    
        ...
        "template": 
            // This template_type is template-less
            "template_type": "converter"
        ,
        "output": 
            "output_encoding": "base64",
            "output_type": "pdf", // Converter functionality only works with PDF as output_type
            "icon_font": "Font Awesome 5" // Changes the rendering font used to generate icons when converting HTML to PDF. Supported fonts are: "Font Awesome 5", "Font-APEX".
        ,
        // If the files array is empty, it'll default to a file with filename "Converted"
        // Giving (multiple) files will just result in a zip archive with identical files, but with the given names
        "files": [],
        "prepend_files": [
            // Array of prepend files (see 6.5.1.2 File Structure)
             ... ,
             ... ,
            ...
        ],
        "append_files": [
            // Array of prepend files (see 6.5.1.2 File Structure)
             ... ,
             ... ,
            ...
        ]
    
    

    Devrait "files" be empty or only contain one file, and "append_files" ou "prepend_files" only contain one file, then the output file will just be that append/prepend file converted to PDF.

    6.5.3 Supported mime types for converting/appending/prepending

    • PDF application / pdf
    • Text text/plain
    • CSV text/csv
    • Markdown text/markdown
    • HTML texte / html
    • Word application/vnd.openxmlformats-officedocument.wordprocessingml.document
    • Excel application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
    • PowerPoint application/vnd.openxmlformats-officedocument.presentationml.presentation
    • JPEG image/jpeg
    • PNG image/png
    • GIF image/gif
    • BMP image/bmp
    • MS-BMP image/x-ms-bmp

    Mind that tags in append/prepend files will ne pas be parsed! Append/prepend files are only converted and appended/prepended to the output files.

    7.1 How to write SQL queries and map them to template documents

    Please refer to the image below containing SQL query and matching template.

    AOP Plug-in supports PL/SQL cursor expressions which can be used in your templates as "data loops".

    Left side corresponds to the SQL query that we used in our demo example. Right side is our Word template.

    In SQL query you will notice three inner cursors called data, orders and product.

    Idea is for each customer to find orders and products and display it as an invoice letter.

    Data cursor is a standard part of AOP JSON structure and it needs to be present in all SQL queries. At the same time you do not have to specify it as a loop in your template. For more details about this please reference Section 9 of this Manual.

    Other two cursor names can be of your preference as long as they are reflected in your template.

    Why do we have cursor syntax?

    This is the way AOP engine merges your data with your templates.

    In our template example you want to display customer details (Data cursor) and then display all their orders (Orders cursor) with products (Product cursor) so each represents a separate cursor.

    This means that we want to be able to create a loop for orders and a separate loop for products. This is exactly what we have done in this template.

    The way AOP template loop works is by using #loop element…. /loop element notation. In the template notice that we are using the following:

    "Thank you for shopping at. We have following products reserved for you:
    
    #orders#product
        - product_name/product
    The total amount of your order is €order_total.
    /orders"
    

    First open Orders loop then open Product loop then doing a bullet numbering for all products. Before closing the Product loop and then closing the Orders loop.

    Once you create your SQL query it is very easy to implement it in your template following few simple tagging rules depending on a template type you are creating.

    8.1 Installation

    APEX Office Print is using an external converter. By default LibreOffice is used (available on all platforms), but this can be changed to MS Office (Windows only). One of these products must be installed on the same server where you will also install APEX Office Print.

    You can register and then login at https://www.apexofficeprint.com. Go to Downloads and download On Premise package for your platform. Currently we support Linux, Windows and OSX.

    Unzip the downloaded file, you will see a directory with the version downloaded version number of AOP e.g v18.1/

    Go to the version directory/server directory and copy executable file on the server where you want AOP running in a directory of your choice

    Executable files:

    • OSX: APEXOfficePrintOSX64
    • Linux (Redhat): APEXOfficePrintLinux64
    • Windows: APEXOfficePrintWin64

    Decide on which port you want to let AOP run. By default it is using port 8010. You can change that later (for example APEXOfficePrintLinux64 -p 5555).

    If you want to run the On-Premise Trial version of AOP you can skip the activation step.
    The on-premise version of AOP in Trial mode will work with Word and PDF, but it contains a trial watermark.
    The cloud version of AOP (free 100 days) has no limitations.
    

    Following step is only necessary when you bought AOP, it's not necessary to run in Trial mode (Linux example):

    • run ./APEXOfficePrintLinux64 -a
    • this will activate the software
    • you have to enter the email you registered with and it will try to generate the license key. License key will be generated if you have an open connection to the internet. If there’s no internet connection, or something goes wrong with the activation, AOP will generate a license request file. You can upload this license request file on your dashboard at https://www.apexofficeprint.com/. You can also contact [email protected] and send this generated file as attachment. We’ll send you the license file per email.
    • exit AOP

    To start APEX Office Print:

    • run ./APEXOfficePrintLinux64 &
    • or if you want it on a different port ./APEXOfficePrintLinux64 -p 8012 & ( on Linux using & at the end of the command, will run this command in backround)

    PDF converter options:

    LibreOffice can be downloaded from https://www.libreoffice.org. Make sure you download LibreOffice 5 or higher and no older version of LibreOffice is installed. Once the installation of LibreOffice is complete check if you can run soffice –version in a terminal.

    You should see something like:

    LibreOffice 5.4.4.2 22b09f6418e8c2d508a9eaf86b2399209b0990f4

    If that fails, make sure your environment variable PATH contains the directory of LibreOffice (bin directory). You can also create a symbolic link to soffice e.g.

    ln -s /opt/libreoffice5.4/program/soffice /usr/sbin/soffice
    

    Note that if you choose to convert using libreoffice the conversion will be done in Parallel.

    If you're on Windows, you can choose for LibreOffice or MS Office. In case you want to use MS Office, make sure you have MS Office 2003 or higher installed and also install OfficetoPDF (direct download), which allows to run conversions from the command line. Note: Place the OfficetoPDF executable location in the system PATH variable.

    After installing LibreOffice or MS Office, restart AOP.

    From version 18.1 onwards, it is possible to specify other converters. On the first run of APEXOfficePrint a configuraion file, aop_config.json, is created. Below an example:

    
        "config": 
            "port": 8010,
            "startat": "./",
            "license": "./aop.license",
            "silent": false,
            "verbose": false,
            "enable_printlog": false,
            "idle_timeout": 120,
            "instances": 1,
            "https_key": "",
            "https_cert": "",
            "https_port": false,
            "ipwhitelist": "",
            "pdf_temp_folder": "",
            "max_parallel_conversions":0,
            "pdf_error_threshold": 3,
            "enable_save": false,
            "enable_local_resources": false,
            "enable_macro": false
        ,
        "converters": 
            "abiword":
                "command": "abiword --to=outputFormat --to-name=outputFile inputFile",
                "handlesParallel": false
            
        ,
        "post_process_commands": 
            "echo":"echo "inputFile with input format $inputFormat has been successfully processed.""
        
    
    
    
    

    This allows for the users to use the converter of their choice. In the command section the following tags will be replaced:

    outputFormat: will be replaced by the output format needed. e.g: pdf 
    outputFile: the location and filename of the expected output. (includes output extension and is absolute path, i.e contains outputDir),
    inputFile: the location where the file for the conversion is located. (includes inputformat extenstion and is absolute path, i.e contains inputDir)
    inputFormat: the intput format of the input file. par exemple. docx
    inputDir: the directory where the inputFile is located. //After version 19.1.2
    outputDir: the output dir where AOP expects the output PDF (will always be the same as inputDir) //After version 19.1.2
    

    The other option handlesParallel should be true if the specified custom converter is capable of handling multiple pdf conversions at the same time.
    If a custom converter is used and the specified converter cannot handle parallel conversion, then the conversions are placed in a queue and called on first come first serve basis (even when multiple instances of AOP are running).

    Barcode option:

    Before AOP 3.1 an external tool needed to be installed to be able to generate barcodes, but since AOP 3.1 and above that is not necessary anymore. All the necessary components are within AOP itself.

    Testing the connection to AOP:

    Make sure the database server can connect to the port where AOP is running. If not, open the port so the database server can connect to the webserver:port (note you don't need to open it up to everybody, just the database server is fine)

    For example by running curl webserver:port (curl can be downloaded for free for windows via https://curl.haxx.se/download.html#Win64)

    $ curl 127.0.0.1:8010

    The installation on the server part is now complete.

    In the downloaded zip file there is also a sample application (app directory) that can be imported or you can just import the AOP plug-in (plugin directory) into your application. The only configuration there is to define the webserver:port where AOP is running and which converter you are using (LibreOffice, MS Office). You can do that under Shared Components > Component Settings. Then select APEX Office Print (AOP) Plug-in, change AOP URL and select appropriate converter.

    8.2 Configuration

    Following parameters can be used:

    -p or –port can set a different port the server should be running at

    Example: to run AOP on port 8015 run:

    APEXOfficePrintLinux64 -p 8015 (or ./APEXOfficePrintLinux64 -p 8015)

    8.3 Unlock Trial version

    By default AOP will run in TRIAL version.

    Only Word, PowerPoint and Excel templates can be created/processed in the TRIAL version of AOP. Once you have decided on a license level, the product can be activated by running -a or –activate:

    $ APEXOfficePrintLinux64 -a

    It will prompt for an email. Please use the same email you used when you subscribed for a license on https://www.apexofficeprint.com/

    When running AOP again, it will show the new licensed templates you can use.

    If there’s no internet connection, or something goes wrong with the activation, AOP will generate a license file which you can upload on the dashboard at https://www.apexofficeprint.com/. Add the generated file in the same directory of AOP and restart AOP to get the full version.

    8.4 Server Options

    To view all available option, run ./APEXOfficePrintLinux64 -h

    Following parameters can be used:                                               
        -a or --activate           : Activate the software                                
        -h or --help               : Show this menu                                       
        -p or --port               : For giving in the running port default: 8010         
                                      Example: APEXOfficePrint -p 5555                     
        -s or --startat            : Directory to start at.                               
        --license                  : The location of license file.                        
                                      Default looks at the startup directory               
        --silent                   : Do everything quietly even start message             
        -v or --version            : Show the current version of AOP                      
        --verbose                  : Log what AOP is currently doing.                     
        --enable_printlog          : Log data about the printjobs to server_printjob.log. 
        --idle_timeout             : The maximum idle seconds for a request.              
                                   : Default: 2 (pdf conversion time is considered idle)  
        -i or --instances          : The number of instances of AOP to start              
                                      Giving 0 will start max instances available          
        --https_cert               : The location of the https certificate                
        --https_key                : The location of the https private key file           
        --https_port               : The port for the https server to run on.             
                                      Having a key/cert but no port will make the https    
                                      server use the port from -p/--port (or the default)  
                                      Example: .. -p 80 --https_port 443 -https_key ...    
                                              http runs on port 80, https on port 443     
                                      Example: .. -p 80 --https_key ...                    
                                              https runs on port 80, no regular http      
        --ipwhitelist              : The file to read the IP whitelist from               
                                      If this parameter is empty, but 'ipwhitelist.txt'    
                                              exists, ipwhitelist.txt will be used        
                                      File format: one IP (range) or subnetwork per line   
                                      Example: 127.0.0.1, abc::0-def::ffff                 
                                              10.0.0.0/8, 192.0..                       
        --pdf_error_threshold      : Set the maximum amount of retries for processing a pdf 
                                      fichier.
        --max_parallel_conversions : Set the maximum number of parallel conversions       
                                   (per converter). default: number of cores             
        --enable_save              : This enables the option write to disk                
                                      Default: outputfiles dir of AOP directory            
        --enable_local_resources   : This enables accessing local files (e.g. templates) 
        --check_configuration      : Checks the configurations needed for AOP to run
    

    Since version 18.2 AOP creates a config file. These options can be saved in this config file. If no config file is there, AOP generates the config file in the first run.
    This configuration file is of JSON format. The default configuration is as follows:

    
        "config": 
            "port": 8010, // The port where AOP should start. 
            "startat": "./", // The default location to start at. Handly if you are using local resources. 
            "license": "./aop.license", // The location of the license file.
            "silent": false,  // If true does not log anything.
            "verbose": false, // If true logs what it is currently doing. (Ignores silent)
            "enable_printlog": false, // If true logs the incoming printjobs into a log file. 
            "idle_timeout": 120, // The timeout for conversion in seconds. 
            "instances": 1, // The number of instace to start. Ideally is equal to number of cores (if 0 AOP detects number of cores).
            "https_key": "", // The location for the https key for AOP to use when starting in HTTPS mode. 
            "https_cert": "", // The locatio for the https certificate for AOP to use when startin in HTTPS mode. 
            "https_port": 433, // The port to use while starting as HTTPS. 
            "ipwhitelist": "", // The location of the ipwhitelist file.
            "pdf_temp_folder": "", // The temp folder to use when converting to PDF.
            "max_parallel_conversions": 0 // The number of maximum parallel conversions allowed. 0 -> number of cores.
            "pdf_error_threshold": 3, // The number of retries after pdf failure.
            "enable_save": false, // Enables saving output in local directories.
            "enable_local_resources": false // Enables reading out the templates and resources (for e.g images).
            "enable_macro": false, // This allows docm and pptm templates to run macro's on event while pdf conversion
        ,
        "converters":  //Placeholder for converters. You can specify your own converters here and pass the value. See section 8.1 for more info. 
            "abiword":
                "command": "abiword --to=outputFormat --to-name=outputFile inputFile",
                "handlesParallel": false //From version 19.1 this can be a number, meaning x number of parallel conversions. false -> 1, 0/true -> number of cores
            
        
        "post_process_commands": // Available since version 19.1, this allows you to execute custom command once AOP has finished processing. See also section 5.2.8 
            "echo":"echo "inputFile with input format $inputFormat has been successfully processed.""
        
    
    

    8.5 Running as Service in Windows

    Using Microsoft Office as PDF converter

    If you wish to use Microsoft office as PDF converter for your documents, some tweaks are necessary before ApexOfficePrint can be used or started as service.

    32-Bit Windows

    Directory Creation

    Create a directory "Desktop" if it does not already exist under 
    "C:Windowssystem32configsystemprofileDesktop"

    DCOM config
    1. From Run (Windows + R), type dcomcnfg

    2. Aller vers Component Services > Computers > My Computer > DCOM Config

    3. Locate "Microsoft Excel Application" and right click properties of it

    4. Aller vers Security Tab et Customize la Launch and Activation Permissions and Edit

    5. Check that no instances of excel.exe are running before changing the properties, either close the applications that are running the Excel or go to task manager and kill the excel.exe processes.

    6. Ajouter la utilisateur actuel (type the current user, click check names, and click ok) and grant autorisation pour Local Launch et Local Activation

    7. Aller à Identity Tab and change the radio button to "The User"

    8. Do the same for "Microsoft PowerPoint Slide".

    9. Do the same for "Microsoft Word 97-2003 Document".

    Setting directory permissions
    1. Navigate to: "C:WindowsSystem32configsystemprofileAppDataRoamingMicrosoft".

    2. Right click and go to Properties

    3. Under Security Tab add the current user and grant the Modify, Read & Execute, List Folder Content, Read, and Write permissions.

    4. Do the same for "C:WindowsTemp".

    64-Bit Windows

    Directory Creation

    Create a directory "Desktop" if it does not already exist under:

    "C:Windowssystem32configsystemprofileDesktop"
    et
    "C:WindowsSysWOW64configsystemprofileDesktop"

    DCOM config
    1. From Run (Windows + R), type dcomcnfg (if your Microsoft Office is 32 bit then open command line and change directory to "C:WindowsSysWOW64" and run "mmc comexp.msc /32" command)

    2. Aller vers Component Services > Computers > My Computer > DCOM Config

    3. Locate "Microsoft Excel Application" and right click properties of it

    4. Aller vers Security Tab et Customize la Launch and Activation Permissions and Edit

    5. Check that no instances of excel.exe are running before changing the properties, either close the applications that are running the Excel or go to task manager and kill the excel.exe processes.

    6. Ajouter la utilisateur actuel (type the current user, click check names, and click ok) and grant autorisation pour Local Launch et Local Activation

    7. Aller à Identity Tab and change the radio button to "The Interactive User" ou "The Launching User" (automatic start)

    8. Do the same for "Microsoft PowerPoint Slide".

    9. Do the same for "Microsoft 97-2003 Document".
    Setting directory permissions

    Navigate to:

    1. "C:WindowsSystem32configsystemprofileAppDataRoamingMicrosoft".

    2. Right click and go to Properties

    3. Under Security Tab add the current user and grant the Modify, Read & Execute, List Folder Content, Read, and Write permissions.

      Do the same for:

    4. "C:WindowsSystem32configsystemprofileAppDataLocalMicrosoft"

    5. Do the same for "C:WindowsTemp".

    Using LibreOffice as pdf converter

    No extra steps are necessary.

    Managing the service

    • Navigate to Windows Service folder situated in the APEXOfficePrint folder.

    • Edit 1_SetupAsService.bat to include the full path to the executable APEXOfficePrintWin64.exe

      Note that you can also add additional parameters for example for the port it should run on and the starting directory.

      Terminal
      nssm.exe install APEXOfficePrint %0....APEXOfficePrintWin64.exe --port 8090 -s D:apexofficeprint

    • Run 1_SetupAsService.bat.

    • The service should be installed and can be seen in Services (Control Panel > Administrative Tools > Services).

    • To change how the APEXOfficePrint services starts you can change it from Services or start it manually via 2_StartService.bat (should be run as Administrator).

    • To check if the service has started, navigate to http://localhost:8010/

    • To stop the service run 3_StopService.bat as Administrator or stop it from Services.

    • To remove the APEXOfficePrint as service run 4_RemoveService.bat.

    • The APEXOfficePrint service should now be removed from Services. If it says Disabled then it will be removed after the service has been stopped.

    8.6 Run APEX Office Print at startup or as service in Linux

    After reboot of the server where APEX Office print is installed, you have to make sure that you also run APEXOfficePrintLinux64 command. If you want to automate the startup of AOP you can create in init.d.
    For example: /etc/init.d/aop-server

    #! / bin / bash
    #
    # Apex Office Print (AOP) Server
    #
    # chkconfig: 345 70 30
    # description: AOP is a print server for Oracle Application Express and PL/SQL
    # processname: APEXOfficePrint
    
    # Source function library.
    . /etc/init.d/functions
    
    RETVAL=0
    AOP_HOME=/opt/aop/v18.1/server
    AOP_PROCESS_NAME=APEXOfficePrint
    AOP_EXECUTABLE_NAME=APEXOfficePrintLinux64
    AOP_PORT=8010
    LIBREOFFICE_HOME=/opt/libreoffice5.4
    
    PATH=$LIBREOFFICE_HOME/program:$PATH
    export PATH
    
    start() 
            echo -n "Starting $AOP_PROCESS_NAME "
            echo -n "Current path is $PATH"
            $AOP_HOME/$AOP_EXECUTABLE_NAME -p $AOP_PORT -s $AOP_HOME &
            RETVAL=$?
            écho
            return $RETVAL
    
    
    stop() 
            echo -n "Shutting down $AOP_PROCESS_NAME: "
            pkill $AOP_PROCESS_NAME
            RETVAL=$?
            écho
            return $RETVAL
    
    
    status() 
            echo -n "TODO: Print $AOP_PROCESS_NAME status here... "
            RETVAL=$?
            return $RETVAL
    
    
    case "$1" in
        start)
            début
            ;;
        stop)
            Arrêtez
            ;;
        status)
            statut
            ;;
        restart)
            Arrêtez
            début
            ;;
        *)
            echo "Usage: $prog status"
            exit 1
            ;;
    esac
    exit $RETVAL
    

    8.7 Start/Stop APEX Office Print on Linux 7 with systemctl

    On Linux 7 you can use systemd (systemctl) to start and stop services.
    For Red Hat and Oracle Enterprise Linux you can follow the below instructions.

    As user root or sudo privileged user

    • cd into /usr/lib/systemd/system
    • create a file aop.service

    Paste the following in and adjust for your installation as required (personally I install AOP in /opt/oracle)

    [Unit]
    
    
    
    Description=APEX Office Print
    After=network.target
    
    [Service]
    Type=simple
    User=aop
    Group=aop
    
    Environment=AOP_HOME=/opt/aop/latest/server  ### Please see comment below
    Environment=AOP_PROCESS_NAME=APEXOfficePrint
    Environment=AOP_EXECUTABLE_NAME=APEXOfficePrintLinux64
    Environment=AOP_PORT=8010
    
    Environment=PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/bin/
    SyslogIdentifier=apexofficeprint
    Restart=always
    RestartSec=30
    TimeoutStartSec=30
    TimeoutStopSec=30
    
    ExecStart=/usr/bin/env $AOP_HOME/$AOP_EXECUTABLE_NAME -p $AOP_PORT -s $AOP_HOME
    
    ExecStop=/usr/bin/env pkill $AOP_PROCESS_NAME
    
    [Install]
    WantedBy=multi-user.target
    
    systemctl daemon-reload
    
    • A simple setup is to install the version of aop in /opt/aop. When you install a new version just unzip in this directory. You will end up for example with the following directories v3.4, v3.5 and v18.1. Create in the directory /opt/aop a symbolic link to point to the latest version.
    ln -s /opt/aop/v18.1 /opt/aop/latest
    

    Suppose something is not working properly and you need to revert back to your previous version, all you need to do is to create the symbolic link to a previous version. Par exemple

    unlink latest
    ln -s /opt/aop/v3.3 /opt/aop/latest
    
    start aop :  systemctl start aop
    stop aop :  systemctl stop aop
    status aop: systemctl status aop
    

    Example output of systemctl status aop

    [[email protected] system]# systemctl status aop.service 
    ● aop.service - APEX Office Print 
       Loaded: loaded (/usr/lib/systemd/system/aop.service; disabled; vendor preset: disabled) 
       Active: active (running) since Sat 2018-03-10 20:39:47 AEDT; 6s ago 
    Main PID: 28273 (APEXOfficePrint) 
       CGroup: /system.slice/aop.service 
               ├─28273 /opt/aop/latest/server/APEXOfficePrintLinux64 -p 8010 -s /opt/oracle/aop/latest/server 
               ├─28283 /opt/aop/v3.4/server/APEXOfficePrintLinux64 --pkg-fallback --max_old_space_size=16384 /snapshot/apexofficeprint/aop_server/node_modules/apexrnd-startup-utils/sequentialConverter.js -d 0 --idleT... 
               └─28288 /opt/aop/v3.4/server/APEXOfficePrintLinux64 --pkg-fallback --max_old_space_size=16384 /snapshot/apexofficeprint/aop_server/apexofficeprint.js -p 8010 -s /opt/oracle/aop/latest/server 
    Mar 10 20:39:47 http://proddb-032.acme.com systemd[1]: Started APEX Office Print. 
    Mar 10 20:39:47 http://proddb-032.acme.com systemd[1]: Starting APEX Office Print... 
    Mar 10 20:39:48 http://proddb-032.acme.com apexofficeprint[28273]: Current license is activated to: [email protected] 
    Mar 10 20:39:48 http://proddb-032.acme.com apexofficeprint[28273]: The products activated are: 
    Mar 10 20:39:48 http://proddb-032.acme.com apexofficeprint[28273]: Word 
    Mar 10 20:39:49 http://proddb-032.acme.com apexofficeprint[28273]: Listening on port 8010 
    Mar 10 20:39:49 http://proddb-032.acme.com apexofficeprint[28273]: AOP 1 running
    

    8.8 Step-by-step how to install LibreOffice on Linux

    In case you need to install LibreOffice on Linux, here're the steps (see also other section):

    # download LibreOffice for the PDF converter
    cd /tmp
    wget  http://downloadarchive.documentfoundation.org/libreoffice/old/5.4.7.2/rpm/x86_64/LibreOffice_5.4.7.2_Linux_x86-64_rpm.tar.gz
    
    # make sure no old versions exist
    yum remove openoffice* libreoffice*
    
    # extract tar
    tar -xvf LibreOffice_5.4.7.2_Linux_x86-64_rpm.tar.gz
    
    # install
    cd /tmp/LibreOffice_5.4.7.2_Linux_x86-64_rpm/RPMS/
    
    yum localinstall *.rpm
    
    # install some missing dependencies (depending your linux version this is not necessary)
    yum install cairo.x86_64
    yum install cups.x86_64
    yum install mesa-libGL.x86_64
    
    # install Java dependency (not necessary if you already have Java)
    yum install java-1.8.0-openjdk.x86_64
    
    # create symbolic link
    ln -s /opt/libreoffice5.4/program/soffice /usr/sbin/soffice
    

    8.9 HTTPS Configuration

    AOP also has support for the usages of https protocol. It requires a crt file and its private key file.
    A self-signed certificate and key can also be used. The certificate can be generated by using openssl command:

    openssl req -x509 -newkey rsa:2048 -keyout keytmp.pem -out aop.crt -days 365
    openssl rsa -in keytmp.pem -out aop.key
    

    Given aop.crt certificate file and aop.key private key file AOP can be started with:

    APEXOfficePrint --https_cert aop.crt --https_key aop.key
    

    The port number can also be specified with the –https_port argument. If this is provided HTTP and HTTPS server will run.

    You should see the following when started successfully on the console.

    Starting HTTP and HTTPS on port 8010 and 443
    AOP 1 (HTTP) running
    AOP 1 (HTTPS) running
    

    Please note that the certificate validation is done by the client.
    If you are using a self-signed certificate and visit the https location with browser, you will get a security warning (see below).

    You can configure the browsers to trust the self-signed certificate by adding it to the security exception.
    You will also have to add this certificate in your oracle wallet to get rid of 'Certificate Validation Error'.

    8.10 Installation errors

    Linux installation port error

    If you encounter this error:

    -------------------------------------------------
    Error on Thu Feb 04 2016 19:33:35 GMT-0800 (PST)
    -------------------------------------------------
    listen EADDRINUSE
    

    It means that the port you tried running AOP server is already taken and you need to change it by running this command:

    ./APEXOfficePrintLinux64 -p xxxx (replace xxxx by a free port)

    8.11 Docker image

    Conditions préalables

    Define a Docker network, if you don't have one yet

    docker network create my_network
    

    Make sure your Oracle database container is in this network

    docker network connect my_network oracle
    

    Start your ORDS container on this network

    docker run -t -i 
    --name ords 
    --network=my_network 
    -e DATABASE_HOSTNAME="oracle" 
    -e DATABASE_PORT="1521" 
    -e DATABASE_SERVICENAME="ORCLPDB1" 
    -e DATABASE_PUBLIC_USER_PASS=oracle 
    -e APEX_LISTENER_PASS=oracle 
    -e APEX_REST_PASS=oracle 
    -e ORDS_PASS=oracle 
    --volume /docker/apex/images:/usr/local/tomcat/webapps/i 
    -p 8181:8080
    ords/ords_apex:3.0.9
    

    Download the AOP docker image

    docker pull apexrnd/apexofficeprint
    

    Activating APEX Office Print the first time (Gold license only – not necessary for Enterprise license). This step is only needed once.

    docker run -it 
    --name apexofficeprint 
    --network=my_network 
    -p 8010:8010 
    -v /docker/apexofficeprint/:/apexofficeprintstartup/ 
    apexrnd/apexofficeprint 
    -s /apexofficeprintstartup/
    -a
    

    In case you have an Enterprise License, add the aop.license file in the directory you specified, in the below example it's /docker/apexofficeprint/

    Start an AOP container on the network of your Oracle database container

    docker run -d 
    --name apexofficeprint 
    --network=my_network 
    -p 8010:8010 
    -v /docker/apexofficeprint/:/apexofficeprintstartup/ 
    apexrnd/apexofficeprint 
    -s /apexofficeprintstartup/
    

    You should now be able to connect to APEX Office Print server by going to http://apexofficeprint:8010/. You can view this video to see the above in action.

    Create an ACL for APEX_050100 to the AOP container

    commencer
     DBMS_NETWORK_ACL_ADMIN.append_host_ace (
        host       => 'apexofficeprint',
        lower_port => 8010,
        upper_port => 8010,
        ace        => xs€ace_type(privilege_list => xs€name_list('http'),
                                  principal_name => 'APEX_050100',
                                  principal_type => xs_acl.ptype_db));
    end;
    

    Configure the APEX plug-in

    Go to Shared Components > Component Settings > APEX Office Print and put in the AOP URL a reference to your docker container e.g. http://apexofficeprint:8010/

    You can check the APEX Office Print tutorial page to see tutorials and videos.

    10.1 Output generates invalid Office documents

    In case Office documents are not opening as expected, probably there was an issue with the JSON that was send to the AOP server. If you run in the AOP Cloud, you can enable Remote Debugging, which you can access when you login in your APEX Office Print dashboard at https://www.apexofficeprint.com.
    If you're running the on-premise version of AOP, on the server there is a server_error.log file that contains the errors it found during rendering. First step is to check that file for more information.
    Next make sure that your JSON is valid by validating the JSON in for example http://jsonlint.com or by doing Remote Debug (see further on in this document)

    10.2 Invalid JSON generated by apex_web_service.make_rest_request

    Make sure APEX 5.0.4 or higher is installed. To download it login to support.oracle.com.

    10.3 Invalid JSON generated by apex_json

    Make sure you install an additional patch for APEX 5.0.4 PSE 24341756 or for APEX 5.1.0 PSE 25650850 or for APEX 5.1.1 PSE 25853436 or for APEX 5.1.4 PSE 27963501 available at https://support.oracle.com. Those will fix issues with apex_json which is used behind the scenes in AOP.

    You also might hit Oracle database bug (in 12.1.0.2). A patch is made available on https://support.oracle.com; search for patch #21424376. You won't experience this issue in 11.2.0.4 or 12.2.

    When using PL/SQL Function returning JSON, you might hit a bug in apex_plugin_util, which can be fixed by applying patch 26048323.

    Finally if you still encounter issues, use ORDS (SQL Workshop > RESTful Services) as your datasource. ORDS will generate the JSON instead of apex_json and AOP will use that JSON instead (see 3.5.4 Data Source – URL with ORDS RESTful Web Service).

    10.4 Running on Oracle Cloud

    If you are running on Oracle Cloud you must use HTTPS in the AOP Plug-in Component setting and when you call the aop_api_pkg paquet. Use https://www.apexrnd.be/aop as the URL.

    10.5 Invalid PDF file

    If you're running the on-premise version of AOP, check a file on the server called server_error.log or server_uncaugt_exceptions.log and see which error you get.
    Try to run your example in the same format as your template. If this also fails, there's an issue with the JSON or the template. Check your template and data again. If you receive your document fine, but PDF is not working, there's an issue finding LibreOffice or MS Office. Make sure those programs are installed correctly. Try to do a manual conversion on the command line in those tools and see if that works. If not, check the error and try to reinstall.
    You can also do Remote Debugging (see further on in this document), which will help identifying the real issue. If everything fails, please contact [email protected]

    10.6 ORA-29273: HTTP request failed

    ORA-29273: HTTP request failed ORA-06512: at "SYS.UTL_HTTP", line 1130 ORA-24247: network access denied by access control list (ACL)

    Make sure APEX_050000 or APEX_050100 schema has the rights to connect to APEX Office Print (http(s)://www.apexofficeprint.com for the Cloud version or your local URL in case of the on-premise version). The script to correct the issue can be found here: APEX 5.0 or for APEX 5.1 (use the correct script for your database version – for XE use prior to 12c)

    10.7 ORA-29024: Certificate validation failure

    ORA-29273: HTTP request failed ORA-06512: at "SYS.UTL_HTTP", line 1130 ORA-29024: Certificate validation failure

    In case you run over HTTPS you need to take into account the certificates.
    There're two ways to get around this:

    • Option 1: You can load our certificates in your Oracle wallet (the Oracle DB is doing the call to our server).

    • Option 2: You can add an entry in your webserver so a local entry is called by the database (which doesn't need a certificate) and the webserver is doing the redirect to handle the https call.

    Here's an example when in the plug-in you would specify a local address: http://apexrnd.localdomain/aop/

    
    
    
    
    ServerName  apexrnd.localdomain
    ServerAlias apexrnd.localdomain
    RewriteEngine On
    ProxyVia On
    ProxyRequests Off
    SSLProxyEngine On
    ProxyPass        /aop/   https://api.apexofficeprint.com/
    ProxyPassReverse /aop/   https://api.apexofficeprint.com/
    
    

    10.8 How to read and convert documents (docx, xlsx, pptx, pdf) on Linux

    You need to install LibreOffice https://www.libreoffice.org/download/libreoffice-fresh/. The steps to do this are outlined below:

    Make a connection to your server with ssh or putty, but make sure you don't forward or tunnel your X Display.

    Install supporting packages:

    yum install wget
    

    Download LibreOffice

    cd /tmp
    wget http://download.documentfoundation.org/libreoffice/stable/5.4.2/rpm/x86_64/LibreOffice_5.4.2_Linux_x86-64_rpm.tar.gz
    

    Install LibreOffice

    tar xzvf LibreOffice_5.4.2_Linux_x86-64_rpm.tar.gz
    cd LibreOffice_5.4.2.2_Linux_x86-64_rpm/RPMS
    yum localinstall *.rpm
    - or you can do rpm -ivh *.rpm
    

    Add LibreOffice to the profile for your user (as it needs to be able to find soffice)

    vi /etc/profile
    export PATH=$PATH:/opt/libreoffice5.4/program
    source /etc/profile
    

    Or add a symbolic link to LibreOffice

    ln -s /opt/libreoffice5.4/program/soffice /usr/sbin/soffice
    

    Check the version of LibreOffice and try to run a conversion

    soffice --version
    soffice --headless --invisible --convert-to pdf --outdir /tmp aop_interactive.docx
    

    If you get: Fontconfig warning: ignoring UTF-8: not a valid region tag

    echo "$LC_CTYPE"
    |-> you probably have UTF-8 defined; unset it
    export LC_CTYPE=""
    

    Make sure you restart APEX Office Print after installing LibreOffice.

    Remarque: we sometimes see LibreOffice doesn't generate the same PDF as MS Office is generating, but we found LibreOffice becoming more and more inline, so we recommend using the latest version of LibreOffice.

    Remarque: Depending the version of LibreOffice converting to HTML from docx, xlsx, pptx might include the images as base64 or include a link.

    10.9 ORA-31011: XML parsing failed, ORA-19202: Error occurred in XML processing, LPX-00651: VM Stack overflow

    You need to install an additional patch for APEX 5.0.4 which will fix this issue. Search in https://support.oracle.com for PSE 24341756.

    10.10 Error occurred while acquiring license

    You receive: "Error occurred while acquiring license. Please make sure that your API key is correct and that you have enough printing credits. Contact AOP if the problem persists."

    This means you ran out of credits. Go to https://www.apexofficeprint.com and upgrade your package or send an email to [email protected] to see what we can do for your case.

    10.11 SyntaxError: unexpected token P in JSON at position 0

    If you are using APEX 5.1, the Dynamic Action plug-in will always work, whereas the Process plug-in might give this error. When you put the process in the Processing part, it will only work if the “Reload on Submit” attribute (of the page) is set to “Always” (note this attribute is new in 5.1).
    This is due to a change how APEX 5.1 is handling Page Processing. If you would import an APEX 5.0 app in 5.1 by default it’s set to Always reload on submit, but if you create a new app in 5.1 it’s set to “Only for Success” and then the process plug-in is not working. Alternatively, you can put the AOP Process to be After Header and make it conditional, it will then work regardless of the setting of "Reload on Submit".

    10.12 Issues with Oracle XE

    When using Oracle XE, make sure you have the execute grant on the UTL_HTTP package.

    GRANT EXECUTE ON SYS.UTL_HTTP TO my_user;
    GRANT EXECUTE ON SYS.UTL_FILE TO my_user;
    

    If you receive "ORA-20000: Issue returned by AOP Service (REST call). Please verify the logs on the server. Returned HTTP code: . (code: -29273)", see section 10.6.

    10.13 Chinese and other language and font support

    If you need special characters or language support, make sure the necessary fonts and languages are on your system. For example to add Chinese support on RHEL Linux do:

    yum install "@Chinese Support"
    

    Further more if you want to install additional fonts here's a good link. AOP Cloud API has Google Noto fonts installed.

    Installing a font is nothing more than installing the font on your system.
    For example on (RedHat) Linux, we copy the *.ttf files (or directory) to /usr/share/fonts/ and run "fc-cache -f -v"

    Depending if you have a GUI (Linux/Windows) you can just double click on the font and it will install it in your system. If your system recognises is, MS Office or LibreOffice should be able to use it for the PDF conversion.

    For barcodes, you could also choose to install a barcode font, for example Free 3of9 or http://www.dafont.com/3of9-barcode.font. Barcode fonts are more performant than images.

    If you are using font awesome and using html tag or interactive reports/grid in Word, you will have to install the font-awesome desktop fonts in order to render on the PDFs properly. (AOP cloud server has free versions installed.)

    10.14 Running AOP installed in a single schema but shared across multiple schemas

    It is possible to install AOP only once and call it from other places. In order to do this, after you install AOP – go to the package aop_api19_pkg and aop_plsql19_pkg and remove the AUTHID CURRENT_USER and recompile.

    10.15 Running on-premise AOP under HTTPS

    Since AOP version 3.1 AOP can be configured to use HTTPS server. The key and the certificate files can be provided to AOP using the –https_key and –https_cert arguments.

    For older versions however we recommend setting up an Apache Reverse Proxy which is doing the SSL in front of AOP.
    From Apache to AOP it would be unencrypted, but if it’s on the same machine as Apache and the port of AOP is not open and only accessible by localhost, we believe you're save.

    To prevent access to AOP other than the Apache Reverse Proxy, you can do (on Linux):

    iptables -A INPUT -p tcp --dport 8010 -s 127.0.0.0/8 -j ACCEPT
    iptables -A INPUT -p tcp --dport 8010 -j DROP
    

    (instead of DROP you can use REJECT too)

    So that would mean only a program on localhost (like Apache) can connect to port 8010, all others are rejected.

    10.16 The requested URL has been prohibited

    If in APEX you force all outgoing connections to be HTTPS by setting:
    Manage Instance -> Security -> HTTP Protocol -> Require Outbound HTTPS -> No.

    make sure you're calling AOP also with HTTPS. If you're calling the AOP cloud https://api.apexofficeprint.com make sure to load the certificate in your database or setup a proxy on your end.

    10.17 PDF output suddenly stopped working

    Probably LibreOffice or MS Office process is stuck. A way to solve this is running a script that checks for long running processes and that kills those. If you're using the AOP Cloud, please contact [email protected]

    10.18 Map or Gantt or Other div not in output

    In some occations divs are not screenshotted well enough, so they don't appear in the output. For example the JET Gauge might not be taken. We are looking for a workaround for a future release.

    10.19 ORA-29273: HTTP request failed ORA-12535: TNS:operation timed out

    Please check your firewall if it allows outgoing connection from the database to the AOP server.
    If you added the AOP port to the firewall rules, make sure to restart the daemon.

    If you're using a proxy, make sure to specify the proxy in Shared Components > Application Definition Attributes > Proxy Server or specify the global variable in the AOP_API_PKG.g_proxy_override.

    See also further in this doc at chapter 14 Debugging connections to AOP Server

    10.20 Font in PDF is different from the font in my Word template

    This is most likely due to the fact that the font you chose in Word, is available on your local computer, but not in the server. If you install that font also on the server where AOP is running, it should do the conversion well. See also 10.13 Chinese and other language and font support.

    10.21 The generation of my document is slow

    You would need to figure out where you lose time:

    • creation of JSON: your SQL statement or other source is taken to transform in JSON. You can trace what is going on by setting your page in debug mode (APEX) or running your SQL statement in a SQL window.

    • time needed on the server by AOP: you can trace that by enabling logging (only on-premise) Start the AOP server with –enable_printlog or –verbose, which will show the incoming requests.

    • network time: measure the time to travel from your database to our cloud or to your own on-premise install. If you would use the on-premise version and put AOP on the same machine as the database, it would be the fastest. Or if you could add it on another server where the network is fast, that should get rid of the transfer time.

    If the conclusion is that everything is as fast as possible, we advise the reports that take a long time, to run in the background with a job. You could also schedule the reports to run overnight and store the results in a table.

    10.22 Invalid multi-column chart or Unexpected Error

    With some versions of the Oracle Database there's an issue with the Cost Based Optimiser.
    Till you upgrade your database, you might want to try to use /+rule/ hint in your top level SQL statement.

    10.23 Safe button in Components Settings not available

    Most likely you subscribed the plug-in from another place. Go to Shared Components > Plug-ins
    – Click on References (number) and copy your logic where you used AOP. This is so you don't have to recreate your logic later. Next, remove all the processes or dynamic actions that use the plug-in.
    – Now you should be able to go to Shared Components > Plug-ins > AOP and hit the Delete button so the AOP plug-in is removed.
    – Import the AOP plug-in again, but make sure you don't reference it from another app, so Import from file.
    – Use the logic from step 1 to recreate your call(s) to AOP.

    10.24 sqlerrm: ORA-31011: XML parsing failed ORA-19202: Error occurred in XML processing LPX-00664: VM Node-Stack overflow

    The node stack of the XSL VM can be set with an event. It defaults to 300, the maximum is 4096. You can set it with:

    alter session set events='31153 trace name context forever, level 4096'; 
    

    The below steps describe how to export an Interactive Report to Excel (XLSX) with AOP via the native IR download dialog. The changes are done on the global page and works for all IR of the app without the need of creating a DA on each page for each report, so reducing a lot of manual work.

    Create a JS file with the following content and upload/reference it app-wide:

    function addAOPXLSXDownloadToIR(pStaticIdItem) 
      // hack into dialogopen event of jquery ui dialogs
      $('body').on('dialogopen', function(event, ui) 
        var dialogWindow$ = $(event.target);
        // only process if it´s an IR download dialog
        if (dialogWindow$.parents('div.ui-dialog').find('span.ui-dialog-title').text() === apex.lang.getMessage('APEXIR_DOWNLOAD')) 
          // get ID/static ID of IR
          var currentRegionId = dialogWindow$.attr('id').match(/(.+)_dialog_js/)[1];
          if (currentRegionId) 
            // build html markup for XLSX download button
            var html = apex.util.htmlBuilder();
            html.markup('')
              .markup('')
              .markup('')
              .markup('')
              .markup('')
              .markup('XLSX')
              .markup('')
              .markup('')
              .markup('');
            // append html
            $('.a-IRR-iconList').append(html.toString());
          
        
      );
    
    

    Create a page 0 item for holding the IR static ID:

    P0_AOP_IR_STATIC_ID
    

    Create a page load DA (Execute JavaScript Code) on page 0 to call above JS function

    addAOPXLSXDownloadToIR('P0_AOP_IR_STATIC_ID’);
    

    Create a page 0 DA (On Change of “P0_AOP_IR_STATIC_ID”) which calls the AOP plugin

    • 1 True Action (AOP plugin)

    • 2 True Action (Execute JavaScript – To close the IR download dialog after download)
    var staticId = $v('P0_AOP_IR_STATIC_ID');
    $('div#' + staticId + '_dialog_js').parent().find('button').click();
    

    Note: every IR should have a static ID.

    That´s it, the final result looks like this (on every IR in the app):

    10.26 ORA-06550: PLS-00201: identifier 'AOP_API_PKG.xxx' must be declared

    The APEX Plug-in can't find the AOP_API_PKG package. To fix the issue, run aop_db_pkg.sql (in the "db"-directory) in your Oracle Schema (SQL Workshop -> SQL Scripts -> Upload -> Select file and hit Upload)

    10.27 ORA-31186: Document contains too many nodes

    When there's a huge amount of data (>2 million rows) Oracle might give this error. If this amount is really necessary to export, as a workaround we recommend splitting the query so there's less data in one document and then merge the documents together with AOP.

    10.28 ORA-31061: XDB error: special char to escaped char conversion failed.

    The data in the tables contains non-unicode characters. Most likely this is due to copy/paste of documents. It's best to correct the data in the database, but if this can't be done, as a workaround in your query you can use regexp_replace( COLUMN , '[[:cntrl:]]', '').

    10.29 ORA-20001: Issue returned by AOP Service (REST call: 504): Unknown error. Check AOP server logs.

    This means that your request was too big and the processing took longer that the gateway timeout. AOP API will end the connection after 5 mins. Workaround would be to split the request into multiple files and merge them back later. You could also go with AOP On-premise version where you do not have this limitation.

    AOP is fully instrumented with APEX debug messages, so when you turn debugging on in your APEX application you will see many AOP: … calls.
    Depending the level of APEX debug mode, more detailed debug output will be available. See Dimitri Gielis's blog post how to put APEX Trace on, which will show the most debug messages.

    You can also specify a global variable g_debug_procedure if you want to call your own debug procedure which for examples logs the information in your own table.

    If you use Logger, you can also enable logger by compiling aop_api_pkg with a PL/SQL flag.

        ALTER PACKAGE aop_api19_pkg COMPILE PLSQL_CCFLAGS = 'logger_on:TRUE';
    

    If you're scheduling reports or calling the AOP packages with PL/SQL you can debug straight from PL/SQL. Here's an example:

    déclarer
      l_binds           wwv_flow_plugin_util.t_bind_list;
      l_return          blob;
      l_output_filename varchar2(100) := 'output';
    commencer
      -- remove previous debug
      apex_debug.remove_debug_by_age(
        p_application_id  => 232,
        p_older_than_days => -1);
    
      -- create an APEX session with the debug enabled
      aop_api_pkg.create_apex_session(
        p_app_id       => 232,
        p_enable_debug => 'Y');
    
      l_return := aop_api_pkg.plsql_call_to_aop (
                    p_data_type       => aop_api_pkg.c_source_type_rpt,
                    p_data_source     => 'ir1',
                    p_template_type   => aop_api_pkg.c_source_type_apex,
                    p_template_source => 'aop_interactive.docx',
                    p_output_type     => 'pdf',
                    p_output_filename => l_output_filename,
                    p_binds           => l_binds,
                    p_aop_url         => 'http://api.apexofficeprint.com/',
                    p_api_key         => 'your API key',
                    p_app_id          => 232,
                    p_page_id         => 5,
                    p_init_code       => 'aop_api_pkg.g_language := ''en'';');
    end;
    /
    

    If you receive an error and you need some help of us, do following steps:

    1) Go in your application to Shared Components > Component Settings > APEX Office Print (AOP) [Plug-in] and enable remote debugging (see parameters screenshot)

    ![ ](media/aop_component_settings.png)
    
    Note 1: you find your API key when you login in your dashboard on 
    
    Note 2: Make sure APEX_050000 or APEX_050100 schema has the rights to connect to http(s)://www.apexofficeprint.com
    

    2) Run your report again.

    3) Login on https://www.apexofficeprint.com and go to Remote Debug

    ![ ](media/aop_remote_debug.png)
    

    4) Click on the magnifying glass, and the JSON that was generated behind the scenes which is send to the AOP server component will be shown.

    5) Investigate the received JSON:

    -) JSON is valid, and valid output: this is how it should be.

    -) JSON is invalid: this is probably due to your version of APEX. If you are below APEX 5.1.2, you need a patch linked to apex_json.

    -) JSON is valid, but invalid Office file (Word, Excel, PowerPoint): this means that AOP couldn't merge your data with the template you provided. If the template and requested output is the same format (e.g. your template is in Word and you request a Word document); check your template again if all substitution strings are correct. If you believe everything is ok, click the button "Sent to Support" and contact [email protected]

    -) JSON is valid, but invalid PDF (or other output format): if the template and output format are different, a conversion is going on handled by LibreOffice or MS Office. Either the conversion goes wrong, or most likely the initial file before the conversion was already wrong. To debug further, set the output format to the same format as your template and run your report again. If the output is invalid, follow previous steps (see JSON is valid, but invalid Office file). If the output is ok, click the button "Sent to Support" and send an email to [email protected] as it means there's a bug in the conversion.

    If you receive an error and you need some help of us, do following steps:

    1. Go in your application to Shared Components > Component Settings > APEX Office Print (AOP) [Plug-in] and set Debug to Local.

    2. Run your report again. A JSON file will now be downloaded instead of the report. This JSON is what is sent to the AOP server component behind the scenes.

    3. Investigate the received JSON:

      -) JSON is valid, and valid output: this is how it should be.

      -) JSON is invalid: this is probably due to your version of APEX. If you are below APEX 5.1.2, you need a patch linked to apex_json.

      -) JSON is valid, but invalid Office file (Word, Excel, PowerPoint): this means that AOP couldn't merge your data with the template you provided. If the template and requested output is the same format (e.g. your template is in Word and you request a Word document); check your template again if all substitution strings are correct. If you believe everything is ok, contact [email protected]

      -) JSON is valid, but invalid PDF (or other output format): if the template and output format are different, a conversion is going on handled by LibreOffice or MS Office. Either the conversion goes wrong, or most likely the initial file before the conversion was already wrong. To debug further, set the output format to the same format as your template and run your report again. If the output is invalid, follow previous steps (see JSON is valid, but invalid Office file). If the output is ok, send an email to [email protected] as it means there's a bug in the conversion.

    4. If you didn't find a solution yourself, please send the JSON file to [email protected]

    Open a first command prompt or shell and run AOP in verbose mode:

    ./APEXOfficePrintLinux64 —-verbose
    

    Copy the test.json file to your server where AOP is running in /tmp folder

    In another command prompt or shell go to /tmp folder and run (If you are in windows environment you can download curl from https://curl.haxx.se/download.html#Win64):

    curl -X POST -H 'Content-Type: application/json' -d @test.json http://127.0.0.1:8010/ > output.docx
    

    This should show the below output and have created an output.docx file

            % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                     Dload  Upload   Total   Spent    Left  Speed
    100  164k  100 68310  100   97k   335k   492k --:--:-- --:--:-- --:--:--  494k
    

    Check the first shell, AOP should have printed:

    Prinjob received.
    Sending back response.
    Prinjob completed.
    

    Try to run the same curl command but with your server name

    curl -X POST -H 'Content-Type: application/json' -d @test.json http://:8010/ > output.docx
    

    Same as before for output.

    Go to the database server copy the test.json in the /tmp folder and run the curl command again

    curl -X POST -H 'Content-Type: application/json' -d @test.json http://:8010/ > output.docx
    

    This should do the same as before.

    Instead of using curl you can also use a RESTClient like Postman. You will have to add the header 'Content-Type: application/json' and give the data from the test.json into the body section.

    Go into APEX > SQL Workshop, and try to connect to the AOP server

    select apex_web_service.make_rest_request('http://:8010/', 'GET') from dual
    

    Try to generate a first document, adjust the below script to your settings and run

    déclarer
      l_return          blob;
      l_output_filename varchar2(100) := 'output';
    
    commencer
      aop_api_pkg.g_proxy_override := null; -- set the proxy if you use that
    
      l_return := aop_api_pkg.plsql_call_to_aop (
                    p_data_type       => 'SQL',
                    p_data_source     => q'[
                      select
                        'file1' as "filename",
                        cursor(
                          select 'hello world' as "string"
                            from dual
                        ) as "data"
                      from dual
                    ]',
                    p_template_type   => null,
                    p_template_source => null,
                    p_output_type     => 'docx',
                    p_output_filename => l_output_filename,
                    p_aop_url         => 'http://:8010/', -- change to the AOP server
                    p_api_key         => '',
                    p_app_id          => 232); -- change to the AOP sample app number
      sys.htp.p(dbms_lob.getlength(l_return));
    end;
    

    In the shell where AOP is running you should see the incoming connection.

    Hopefully the below steps give you more insight where your connection is failing so you can correct accordingly.

    -) Does AOP have to go on its own server, the database server or the application (ORDS) server?

    You can choose. Having AOP on the same server as the database machine is most performant and easiest as you don’t have network connections to other servers. If you install AOP on its own server you can size and monitor that server better. AOP on the Application server is another option, as long as the database can connect to the AOP server component, the AOP server doesn't need to be accessible from the outside (clients).
    So it’s whatever you are most comfortable with.

    -) Is there anything special we have to do with AOP to get it to work with SSL?

    You can add a reverse proxy for the SSL or you can specify the https certificate when starting the AOP server itself.
    Most people don’t do SSL as it’s only the database that needs to access the AOP server component, so typically you don’t even pass the network where others are. However AOP can start in SSL mode if the SSL certificate and its key are provided via –https_key and –https_cert argument.

    -) Where do I get the SSL certificate of API server?

    If you are using HTTPS (we always recommend you to do this) for connecting with the API server, you might get a SSL certification validation error:

    ORA-29273: HTTP request failed ORA-06512: at "SYS.UTL_HTTP", line 1130 ORA-29024: Certificate validation failure
    In this case you will have to load the SSL certificate of the root certification authority, in our case that of GoDaddy, into your oracle wallet. You can get this certificate by visiting https://apexofficeprint.com/ and looking at the certificate information. Example firefox:

    It could be that you will have to change the URL to https://www.apexrnd.be/aop/

    -) How resource intensive is it? Does it eat up a lot of CPU, RAM, or hard drive space?

    It depends how many prints you do… AOP initially consumes about 400MB RAM, but depending the prints it can go up to 4GB (a limit we put). In case you have larger documents, we recommend downloading the high memory version which can consume up to 16GB.
    CPU is not much compared to the specs these days and hard drive space is about 500MB.
    The executable is about 500MB and we might create some temporary files (during pdf conversion) and a log and error file.

    -) Do I have to install LibreOffice when we need Word and Excel output only?

    No – LibreOffice or MS Office is only used when you want to convert from one format to another.
    So Word-Word or Excel-Excel is working without. But if you want to do for example Word->PDF you need LibreOffice or MS Office or another converter you prefer.

    -) Can AOP print directly to a printer

    AOP 3.1 and above includes the ability to print directly to an IP Printer, as long as it's available from the server AOP is running on. If you want to print to a local printer, check the Sample app how to print to an inline region, by adding a little bit of JavaScript to the dynamic action you can let the browser come up with a print window automatically.

    -) Can you repeat the Table header in Word and Excel?

    Yes, this is a setting in Office.
    When you right click on your header row in Word, you can go to Table Properties – Row and check the "Repeat as header row at the top of every page". An example is given on page 113 of sample application.

    -) Does AOP support Pivots in Excel

    Yes, you can use the transpose function in Excel to pivot your data. AOP can also loop vertically by using the :tag.

    -) Why is there a difference between an output in Word and PDF

    When going from Word to PDF, we use an external converter: MS Office or LibreOffice. It might be that if your template was built on your desktop in MS Office (Word), but your server is using LibreOffice (Linux) a font is different or there are minimal changes. The easiest way to find out what the difference is, is to open the template in LibreOffice on your Desktop and see why LibreOffice is treating it different. In most use cases it works just fine going from one to the other, but sometimes it's in the details.

    -) Can I install the APEX Plug-in somewhere so all my apps have access to it?

    You can make the aop_api_pkg a public synonym for aop_api19_pkg PL/SQL package in case you only want the package in a global schema. The Oracle APEX plug-in itself you would still need to import in every APEX application you want to use it in, but the plug-in can point to the public package.

    -) Can I use dynamic page break in Word?

    Oui. In some cases, you might want to start a new page for every record for example for certificates. You can put the page break inside a conditional expression. You can use the rownum function to generate the id for every record and check if that is equals to the record length. An example is shown in page 119 of our sample application. Given the data:

    sélectionner
      'file1' as "filename",
      cursor(
        sélectionner
          cursor(
              sélectionner
              rownum as "customerIndex",
              c.cust_first_name as "cust_first_name",
              c.cust_last_name as "cust_last_name"
              from demo_customers c
          ) as "customers"
          from dual
    ) as "data"
    from dual
    

    You can use the following tag to insert page break for every record except for the last.

    #customerIndex!=customers.length
     -------------page break ------------
    /customerIndex!=customers.length
    

    Please note that if you wish to output to pdf, the same can be achieved by using the PowerPoint template and !slides_loop tag. In this case there is no need to use the rownum function.

    -) Can I adjust the width and height of interactive report/grid export in Word?

    If you are exporting interactive grid, you can adjust the columns width as you like (due to meta data issue you will also have to change the width a bit for all columns.). The ratio is then automatically taken into account.

    In interactive report, you can use the following in html expression.

    #COLUMN_NAME#
    

    The default weight for each column is 1. Let's say you have 4 columns and you provide this html expression in the first column. This will double the size of the first column in comparison to the remaining 3.

    The following formula is used to calculate the percentage of width a column gets:

    (weight of column)/(total weight provided for all the columns) * 100.
    

    Since version 19.1.4 AOP allows to specify the width in either px,in,cm,em or pt.
    Use the following HTML EXPRESSION:

    #COLUMN_NAME#
    

    If AOP detects this in one of the columns, the columns which do not have this expression will get the minimum width specified.

    -) How can I show custom success and error messages using AOP Dyncamic Action Plugin?

    You can defines another TRUE action before the AOP Plugin is triggered and overwrite the showSuccessMessage and showErrorMessage functions.

    Below we illustrate some example templates and the generated output.

    Example 1

    This is the input template:

    This is the result after AOP has processed the template and the given data:

    Example 2

    This is the input template:

    This is the result after AOP has processed the template and the given data:

    Exemple 3

    This is the input template:

    This is the result after AOP has processed the template and the given data:

    Exemple 4

    This is the input template:

    This is the result after AOP has processed the template and the given data:

    Copyright © 2015-2019, APEX R&D

    Tous les droits sont réservés.

    Authors: Dimitri Gielis, Sunil Tandan and Lino Schildenfeld

    This software and related documentation are provided under a license agreement containing restrictions on use and disclosure that are protected by intellectual property laws. Except as expressly permitted in your license agreement or allowed by law, you may not use, copy, reproduce, translate, broadcast, modify, license, transmit, distribute, exhibit, perform, publish, or display any part, in any form, or by any means. Reverse engineering, disassembly, or de-compilation of this software, unless required by law for interoperability, is prohibited. The information contained herein is subject to change without notice and is not warranted to be error-free. If you find any errors, please report them to us in writing.

    Commentaires

    Laisser un commentaire

    Votre commentaire sera révisé par les administrateurs si besoin.