ERP en LOGICIEL LIBRE dédié aux PME-PMI

           Devenez partenaire Principal ou Majeur de Neogia

Questions fréquentes

Contents

Comment exécuter OfbizNeogia avec une configuration alternative pour éviter d'avoir à modifier les fichiers de configuration par défaut ?

  1. Créer un dossier ofbizNeogia/conf/site (il ne peut pas être commité par erreur car il est référencé dans .cvsignore)
  2. Placer les fichiers de configuration modifiés et les fichiers jars dans ce dossier
  3. Créer un fichier ofbizNeogia/site.properties qui contient la ligne suivante :
ofbiz.neogia.site.conf=conf/site

Il y a des exemples de configurations alternatives dans le dossier ofbizNeogia/conf :


Comment faire fonctionner OfbizNeogia sous Eclipse ?

  1. Sélectionner le projet ofbizNeogia, effectuer un clic-droit dessus -> Run As (Exécuter comme)-> Run (Exécuter)...
  2. Sélectionner Application Java et cliquer sur New (Nouvelle)
  3.  !! Set Run configuration name to OfbizNeogia !!
    • Onglet principal :
      • Projet : ofbizNeogia
      • Classe principale : org.ofbiz.base.start.Start
    • Arguments :
      • Arguments VM : -Xms128M -Xmx256M (coller directement cette information dans la zone qui est éditable)
      • Répertoire de travail : utiliser par défaut le répertoire de travail
    • Cheminement de classe :
      • Entrées Amorce : JRE System Library (laisser par défaut)
      • Entrées utilisateurs : ofbiz.jar depuis le projet ofbizNeogia (il faut supprimer tous existant et ne mettre que le jar : ofbiz.jar du projet à debugger)
    • Environnement :
      • Ajouter une variable à l'environnement LC_ALL=C
  4. Cliquer sur appliquer et exécuter


Vous pouvez également consulter le guide établi en espagnol :

Comment voir quels sont les fichiers modifiés après un rafraîchissement ?

Après avoir rafraîchi un composant, tous ses fichiers générés apparaissent modifiés parce que leur "timbre à date" a changé. Néanmoins, seul un petit sous-ensemble a réellement été modifié. En effectuant une mise à jour cvs au niveau du composant, le "timbre à date" des fichiers inchangés sera réactualisé.

Why some xml files contains validation errors when displayed in Eclipse?

By default, Eclipse looks for xml schema definitions by using the namespaces declared in xml documents which points to www.ofbiz.org. Xml schemas presented on this site don't contain neogia extensions that's why validation errors appear. You can define an XML catalog to force eclipse to look for xml schema on the machine instead of on the net.


Change TCP Port

You can find some basic start configuration in the file: {ofbiz.neogia.home}/base/config/ofbiz-containers.xml. On this file you can change the line:

                <property name="port" value="8080"/>

You can use any port that you want (of course an unused port).

This works for windows also. Remember that you have to be careful with the port number, for example on linux any port below 1024 requires root priviledges to work.

Comptabilité

Saisie de facture impossible; Le rôle d'acteur n'existe pas

Vous venez de charger les données minimum (seed) vous avez paramétré le centre de profit, les périodes, les comptes comptables, .... et plein d'autres choses. Vous testez votre configuration et dans la comptabilité lors de la saisie d'une facture fournisseur le message d'erreur <<Le rôle d'acteur n'existe pas>> apparait:
Vous avez oublié de modifier dans le fichier AccountingProperties.properties l'ID de l'acteur représentant la société pour lequel vous faite la compta, cet acteur doit avoir le rôle INTERNAL_ORGANIZATION.


Généralités sur les Services

L'appel du service renvoie l'erreur :
" EventHandlerException: Service invocation error (null) "
ou
"org.ofbiz.service.GenericServiceException: Specified object is null (null)"

Cette erreur peut se produire lorsqu'un service n'est pas déclaré conformément à sa classe.
Par exemple s'il n'est pas déclaré en "static". Au lieu de

public Map nomService(DispatchContext ctx, Map context)


Il faut faire:

public static Map nomService(DispatchContext ctx, Map context)

groovy

appel d'un service, avec remplissage du context

   trainingActionContext = dctx.makeValidContext("updateTrainingAction", "IN", context);
   trainingActionContext.startDate = startDate;
   trainingActionContext.completionDate = completionDate;
   resultMap = dispatcher.runSync("updateTrainingAction", trainingActionContext);
   if ( ServiceUtil.isError(resultMap) ) return resultMap;

UEL

UEL = Unified Expression Language (pour plus d'info cf http://docs.oracle.com/javaee/5/tutorial/doc/bnahq.htm et https://cwiki.apache.org/confluence/display/OFBTECH/Unified+Expression+Language+%28JSR-245%29+in+OFBiz)

${} et UEL

l'UEL est utilisé dans les ${} et cela permet de permet de faire un certain nombre d'opération simple (calcul de base et condition de base ? :) Quand la syntaxe UEL ne suffit pas il est possible de mettre groovy: en début ( ${groovy: } ) pour disposer de toutes la syntaxe de groovy. En terme de performance groovy: nécessite une instanciation de l'interpréteur groovy, même si c'est très très très minime, quand il n'y en a pas besoin autant pas le faire.

L'inconvénient majeur de l'UEL c'est que contrairement à groovy: lorsqu'une variable est non défini il n'y a pas de message explicite, l'expression dans son ensemble retourne null

ex: ${toto=='Y'?uiLabelMap.bravo:uiLabelMap.perdu} retourne null si toto n'existe pas

alors que

${groovy: toto=='Y'?uiLabelMap.bravo:uiLabelMap.perdu} génère dans la console java.lang.IllegalArgumentException: Error running groovy script [ toto ]: javax.script.ScriptException: groovy.lang.MissingPropertyException: No such property: toto for class:

Dans une form / screen / menu (mais pas script), il est possible de tester si une variable existe via context ex: ${empty context.toto}

Quand on souhaite faire un test pour un use-when afin de le rendre lisible, il est fortement conseillé d'utiliser l'UEL de manière le plus simple

comme il est possible d'utiliser la simple quote c'est beaucoup plus lisible.

 ${'supplier'==roleType}

est mieux que

  &quot;supplier&quot;.equals(&quot;${roleType}&quot;)

toujours dans un soucis de simplification, si vous disposer d'une variable boolean autant l'utiliser en direct use-when="showToto" et pas use-when="${showToto}"

UEL et Mini-langue

dans la version 13.07 et trunk la xsd de référence est simple-methods-v2.xsd (simple-methods.xsd est deprecated) Donc il est important de bien vérifier ce qu'il y a (ou ce que vous mettez) en début des fichiers mini-lang

La syntaxe correct de <set est

 <set field="xxx" from="uel expression" />

le 1 et 2 sont les solutions conseillé.

concernant value, il est possible d'écrire

le 1 est conseillé pour la lisibilité et le 2 pour le puriste

UEL et use-when

Toutes les variables du context ne sont pas forcément disponible dans le use-when.

Le use-when n'utilise pas l'UEL en direct donc == ne fonctionne pas.

Si vous ne disposez pas d'une variable booléen, il est conseillé d'utiliser ${} et donc une UEL.

En cas de soucis, pour le debuggage, il faut se souvenir que les variables inexistantes (ou situé dans un context non visible) ne génère pas d'erreur mais un null globale donc un true

java

Résoudre Type safety: Unchecked cast from Object to List

Il faut utiliser la method UtilGenerics.checkList(xxx

nettoyer le cache manuellement

Convertir un String encodé d'un type vers un autre

Généralités sur les screens et les forms

Dans un form "single", comment ajouter un champs de saisie de donnée ?

Dans un form "single", comment positionner le focus dans un des champs ?

Dans un form "single", comment définir la taille maximale du champs à renseigner ?

 <field name="productId" title="${uiLabelMap.ProductProductId}"><text maxlength="20" size="20"/></field> 
 <field name="productId" title="${uiLabelMap.ProductProductId}"><text-find /></field> 

Dans un form "single", comment choisir la position des champs ?

 <form name="FindOrder" target="Orders" type="single">
   <field name="productId" position="1"><text/></field>
   <field name="goodValue" position="2"><text/></field>
   <field name="orderId" position="3"><text/></field>
   <field name="entryDate" position="1"><date-find/></field>
   <field name="submitButton" title="${uiLabelMap.CommonFind}" position="1" widget-style="buttontext">
     <submit button-type="text-link"/>
   </field>
 </form>

Dans un form "single", comment mettre un champs caché ?

 <field name="orderId"><hidden/></field>

Dans un form list, quels sont les opérateurs disponibles dans le service performFind utilisé pour constituer la liste ?

 <form name="ListExamples" type="list" list-name="listIt" paginate-target="FindExample" default-entity-name="Example" separate-columns="true"
       odd-row-style="alternate-row" header-row-style="header-row-2" default-table-style="basic-table hover-bar">
       <actions>
           <set field="notExamples[]" value="EX01" />
           <set field="notExamples[]" value="EX03"/>
           <set field="parameters.exampleId_fld0_op" value="not-in"/>
           <set field="parameters.exampleId_fld0_value" from-field="notExamples" type="List"/>
           <service service-name="performFind" result-map="result" result-map-list="listIt">
               <field-map field-name="inputFields" from-field="exampleCtx"/>
               <field-map field-name="entityName" value="Example"/>
               <field-map field-name="orderBy" from-field="parameters.sortField"/>
               <field-map field-name="viewIndex" from-field="viewIndex"/>
               <field-map field-name="viewSize" from-field="viewSize"/>
           </service>
       </actions>

Dans un form list, comment peut-on charger une liste sans que les critères du performFind aient été entrés ?

 <actions>
   <service service-name="performFind" result-map-name="result" result-map-list-name="listIt">
     <field-map field-name="inputFields" env-name="requestParameters"/>
     <field-map field-name="entityName" env-name="entityName"/>
     <set field="noConditionFind" value="Y"/>
     <field-map field-name="orderBy" value="shipmentId"/>
     <field-map field-name="orderBy" value="dateCreated"/>
   </service>
 </actions>

Dans un form "list", comment faire pour qu'un champs de la liste affiche non pas la clé mais un autre champs de la table ?

       <field name="statusId" title="Nom de statut">
            <display-entity entity-name="StatusItem" description="${description}" key-field-name="statusId"/>
       </field>

Dans un form "list", comment faire lorsqu'on veut utilisé un display-entity mais que la table a plusieurs clés ?

     <row-actions>
       <entity-one entity-name="FacilityLocation" use-cache="true">
         <field-map field-name="facilityId" env-name="facilityIdTo"/>
         <field-map field-name="locationSeqId" env-name="locationSeqIdTo"/>
       </entity-one>
     </row-actions>
     <field name="locationName" title="${uiLabelMap.WarehouseLocationName}"><display /></field>

Dans un form "list", comment créer un lien pour renvoyer vers une autre uri ?

 <field name="stickerLink" widget-style="buttontext" title="${uiLabelMap.ButtonSticker}">
   <hyperlink target="stickerPDF.pdf?orderId=${orderId}&shipmentId=${shipmentId}" description="${uiLabelMap.ButtonSticker}"/>
 </field>

Dans une form "list" comment avoir une colonne qui apparait selon un paramètre

Dans les listes pour avoir une colonne visible ou non, selon une variable, le plus simple est de

  1. créer une variable booléen
    • <set field="showTypeB" value="${showType$string!='Y'}" type="Boolean"/> dans le action de la form
    • ou <set field="widget.showTypeB" from="showType$string!='N'" /> dans le wactions
  2. mettre un use-when au niveau du champ ET du title
    • <field name="exampleTypeId" use-when="showTypeB" title="${showTypeB?uiLabelMap.CommonType:' '}" >

Dans un form "list", comment charger les éléments d'un drop-down à partir d'une table ? Comment trier ces éléments ?

 <field name="facilityId" position="1" title="${uiLabelMap.ProductFacility}:" >
   <drop-down allow-empty="true">
     <entity-options entity-name="Facility" description="${description}"  key-field-name="facilityId">
       <entity-constraint name="facilityTypeId" operator="equals"  value="PICK"/>
       <entity-constraint name="facilityId" operator="not-equals"  value="MONO"/>
       <entity-order-by field-name="description"/>
     </entity-options>
   </drop-down>
 </field>

Dans un form multi, comment utiliser un service dans les listes ?

 <form name="ListPickListItem" target="SendPicklistMulti" paginate-target="PickListItem" ....>
   <request-map uri="updateTrainingActionPartyAssMulti">
       <security https="true" auth="true"/>
       <event type="service-multi" invoke="updateTrainingActionPartyAss"/>
       <response name="success" type="request" value="json"/>
       <response name="error" type="request" value="json"/>
   </request-map>

, le "paginate-target" correspond à une view du controller (elle appele donc un screen pour afficher la liste dans celui-ci).

Dans un form multi, le retour OUT du service n'est pas pris en compte dans ma list ?

http://neogia.org/Multi_Service

Dans un form "multi", comment faire pour qu'un champs de la liste ne soit envoyé au service ?

 <field name="orderDate" title="${uiLabelMap.OrderDate}"><display also-hidden="false" /></field>

Dans un form "multi", comment ajouter des cases à cocher ?

 <form name="ListPickListItem" target="SendPicklistMulti" paginate-target="PickListItem"
   type="multi" list-name="listIt" paginate="true" use-row-submit="true">
   <actions>
     <service service-name="performFind" result-map-name="result" result-map-list-name="listIt" >
       <field-map field-name="inputFields" env-name="requestParameters" />
       <field-map field-name="entityName" env-name="entityName"/>
     </service>       
   </actions>
     <field name="_rowSubmit" title="${uiLabelMap.CommonSelect}"><check/></field>
     <field name="picklistBinId"><hidden/></field>
     <field name="picklistId" title="${uiLabelMap.PicklistId}"><display /></field>
     <field name="picklistDate" title="${uiLabelMap.PicklistDate}"><display type="date-hm"/></field>
     <field name="submitButton" title="${uiLabelMap.CommonSend}" position="1" widget-style="buttontext">
       <submit button-type="text-link"/>
     </field>
   </form>

Dans un form "multi", comment faire pour que tous les éléments de la liste soient cochés par défaut ?

 <form name="ListOrdersMulti" target="SendOrdersMulti" ... use-row-submit="true">
   <field name="_rowSubmit" title="${uiLabelMap.CommonSelect}"><check all-checked="true"/></field>
   <field name="orderStatusId" title="${uiLabelMap.CommonStatus}">
     <display-entity also-hidden="false" entity-name="StatusItem" description="${description}" key-field-name="statusId"/>
   </field>
      .....
   <field name="submitButton" title="${uiLabelMap.CommonSend}" position="1" widget-style="buttontext">
     <submit button-type="text-link"/>
   </field>
 </form>

Dans un form "multi" avec des cases à cocher, comment faire pour qu'une ligne ne soit pas cochable ?

 <form name="ListReceive" target="ReceiveIn" paginate-target="ReceiveSelection"
 type="multi" list-name="listIt" paginate="true" use-row-submit="true">
   <field name="facilityId"><hidden /></field>
   <field name="_rowSubmit" title="${uiLabelMap.CommonSelect}" use-when="! "PICK".equals( "${facilityId}" )"><check/></field>
   <field name="_rowSubmit" title="${uiLabelMap.CommonSelect}" 
     use-when=" "STOCK".equals( "${facilityId}" )"><display/></field>
   <field name="quantity" entry-name="qtyToReceive" title="${uiLabelMap.CommonQty}" 
     use-when="! "BIG_P".equals( "${facilityId}" )"><text size="2" /></field>
   <field name="orderId" title="${uiLabelMap.OrderOrderId}"><display /></field>
   <field name="productId" title="${uiLabelMap.ProductProductId}">
     <display description="<a onClick="showDetail('ShowProduct','productId', '${productId}')">${productId}</a>"/>
   </field>
   <field name="orderDate" title="${uiLabelMap.OrderDate}"><display type="date-hm"/></field>
   <field name="submitButton" title="${uiLabelMap.CommonSend}" widget-style="buttontext"><submit /></field>
 </form>

Dans un screen, comment récupérer des informations dans une table ?

Ex: 
 <entity-one entity-name="Product" value-name="product">
   <field-map field-name="productId"/>
 </entity-one>
 <entity-and list-name="lOrderItem" entity-name="OrderItem">
   <field-map field-name="orderId"/>
 </entity-and>
 <entity-condition list-name="lInvent" entity-name="InventoryItem" >
   <condition-list combine="and">
     <condition-expr field-name="productId" env-name="productId"/>
     <condition-expr field-name="quantityOnHandTotal" operator="greater-equals" value="1"/>
   </condition-list>
 </entity-condition>

Dans un screen, comment faire pour afficher un form ou un screen selon une variable récupérer dans les paramètres ?

<screen ...>
  <actions>
    ....
    <set field="productId" from-field="parameters.productId"/>
  </actions>
  <widgets>  
    <container>
      
    </container>
  </widget>
</screen>

A quoi sert le global="true" dans le set

Par défaut, les variables créer dans un screen, une form ou un menu sont visible uniquement au niveau où elles sont créé (le screen, la form ou le menu). Cela permet de garantir une indépendance d'usage, global=true permet de la définir au niveau du plus niveau (souvent le screen qui utilise le ou les decorator, les form, ...), attention elle n'est disponible que pour les instructions se trouvant après.
Dans les decorators il faut souvent utiliser le global="true" pour pouvoir les utiliser au niveau des forms

Dans un screen ou un form, comment comparer avec la valeur null ?

Dans le contexte, la variable "null" permet de réaliser ce genre de comparaison en utilisant la balise "env-name".

<entity-condition list-name="listIt"  entity-name="SiriusScreenProductWithStock">
 <select-field field-name="productId"/>
 <select-field field-name="facilityId"/>
 <select-field field-name="internalName"/>
 <select-field field-name="locationSeqId"/>
 <select-field field-name="quantity"/>
 <condition-list combine="and">
   <condition-expr field-name="productId" operator="equals" env-name="requestParameters.productId" ignore-if-empty="true"/>
   <condition-expr field-name="locationSeqId" operator="equals" env-name="requestParameters.locationSeqId" ignore-if-empty="true"/>
   <condition-expr field-name="facilityId" operator="in" env-name="facilitiesList"/>
   <condition-expr field-name="quantityOnHandTotal" operator="not-equals" value="0" ignore-if-empty="true"/>
   <condition-expr field-name="quantityOnHandTotal" operator="not-equals" env-name="null"/>
 </condition-list>
 <order-by field-name="productId"/>
 <order-by field-name="facilityId"/>
 <order-by field-name="locationSeqId"/>
</entity-condition>

Dans un screen ou un form, comment créer une liste d'éléments ?

Il y a plusieurs méthodes. Ceci permet de charger une liste :

 <set field="facilitiesList[]" value="BIG_P"/>
 <set field="facilitiesList[]" value="VERTICAL_P"/>
 <set field="facilitiesList[]" value="NOT_EXPECTED_B"/>

Mais on peut aussi utiliser le bsh pour créer et charger la liste :

 <set field="facilityTypeList" value="${bsh: import org.ofbiz.base.util.UtilMisc; UtilMisc.toList("WAREHOUSE","STOCK")}" type="List"/>

Dans un screen ou une form, comment récupérer une liste utilisable en provenance d'un submit de form ?

Il est possible d'utiliser les capacités du service handler du controller, pour cela il faut déclarer un service avec un ou des paramètres de type list avec un suffix

 <attribute name="statusList" type="List" mode="IN" optional="true" string-list-suffix="Status"/>

Dans la form de départ (celle qui sera submitté) tous les contenu des variables qui doivent se retrouver dans la liste, doivent avoir en nom de variable des noms avec le suffix donné dans le service.

Il y a la même chose pour les Map (prefix)

Dans l'addon TCM (et surement dans un addon dédié ou directement OFBiz, dans le futur) il y a un java qui peut être utilisé en tant que service qui transfert les paramètres d'entrés en paramètres de sortie. Donc dans le service créé on l'utilisera :

 <service name="createStatusList" engine="java" location="org.ofbiz.tcm.TcmUtil" invoke="convertParamType" auth="true">

Dans le controller, l'entrée renverra sur le screen souhaité où les variables souhaités seront disponible.

Freemarker (*.ftl)

Comment faire pour appeler un service dans un fichier .ftl ?

Exemple :

<#assign pageTotal = dispatcher.runSync("getTotalAmountForAdvancedGlEntry", Static["org.ofbiz.base.util.UtilMisc"].toMap("trItIdName",
 '${transaction.idName}' , "trTyIdName", '${transactionType.idName}', "userLogin", userLogin))/>

Comment lire une map ?

${entryMaps["entryMap${i}"]}
${entryMaps["entryMap${i}"]["bonDyns"][0].description?if_exists}

Afficher une valeur au format 0,00

Test si la variable contient une valeur, si oui, on applique le formatage. Il n'est pas possible de combiner ?if_exists et ?string...

<#if pageTotal["amounts"].ChargeAchatCol_Charge_Achat_1?has_content>${monthTotal["amounts"].ChargeAchatCol_Charge_Achat_1?string(",##0.00")}

Boucle finie

<#list 1..30 as i >
    <fo:block>${i}</fo:block>
</#list>
<#list nomDeListe as item >
    <fo:block>${item.champ}</fo:block>
</#list>

Affichage date au format jj/mm/aaaa

${dateEdition?string("dd/MM/yyyy")}

XSL-FO pour générer des fichiers au format pdf via FOP

Ecrire un texte vertical

On crée un block-container de la taille voulue et on indique via reference-orientation l'orientation du texte. Dans ce block-container, il ne reste plus qu'à mettre un block standard contenant le texte.

<fo:block-container width="30mm" height="4mm" reference-orientation="90">
   <fo:block text-align="center" font-size="8pt">Mon texte vertical</fo:block>
</fo:block-container>

Nettoyage des logs

Les tableaux

Si message de ce style :

INFO  [LayoutManager] table-layout="fixed" and width="auto", but auto-layout not supported => assuming width="100%"

Dans la déclaration du tableau, mettre :

<fo:table table-layout="fixed" width="100%">

Liste de liens

Tutoriel renderx

les paragraphes

XSL-FO généralités

[XSL-FO sur w3schools

Les balises du language XSL-FO

XSL-FO table-row Object

RenderX - XSL FO Features Test: Demo Code

XSL Formatting Objects

Extensible Stylesheet Language (XSL) Version 1.1

XSL-FO Tutorial and Samples

Tuteur XSL-FO -- XSL-FO tutorial

Using XSL-FO to create printable documents

Régions et marges

Messages d'erreurs dans les logs

Les polices

Pour ceux qui générent des PDF via FOP, vous avez dû vous apercevoir que peu de polices étaient disponibles. J'ai donc rajouté dans neogia un certain nombre de polices libres afin de pouvoir avoir un plus grand choix.

Les polices "Liberation" sont maintenant dispo et sont équivalentes à Liberation Sans = Arial, Albany, Helvetica, Nimbus Sans L et Bitstream Vera Sans Liberation Serif = Times New Roman, Thorndale, Nimbus Roman et Bitstream Vera Serif. Liberation Mono = Courier New, Cumberland, Courier, Nimbus Mono L et Bitstream Vera Sans Mono.

pour plus d'infos sur ces polices, voir : http://framablog.org/index.php/post/2007/05/12/Liberation-fonts-polices-libres-de-caractere

De plus, j'ai aussi ajouté la police jGara2, qui est un équivalent de Garamond http://www.janthor.com/jGaramond/index.html

Vous trouverez un aperçu des polices, et aussi de la manière de les appeler pour les utiliser dans vos documents. Media:NewFonts.pdf