Questions fréquentes
Comment exécuter OfbizNeogia avec une configuration alternative pour éviter d'avoir à modifier les fichiers de configuration par défaut ?
- Créer un dossier ofbizNeogia/conf/site (il ne peut pas être commité par erreur car il est référencé dans .cvsignore)
- Placer les fichiers de configuration modifiés et les fichiers jars dans ce dossier
- 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 :
- ofbiz.neogia.site.conf=conf/portplus1 : configure tous les ports d'écoute à leur valeur par défaut + 1
- ofbiz.neogia.site.conf=conf/postgresql-8.0 : configuration d'ofbizNeogia pour utiliser la base de données postgresql-8.0
Comment faire fonctionner OfbizNeogia sous Eclipse ?
- Sélectionner le projet ofbizNeogia, effectuer un clic-droit dessus -> Run As (Exécuter comme)-> Run (Exécuter)...
- Sélectionner Application Java et cliquer sur New (Nouvelle)
- !! 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
- Onglet principal :
- 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.
- Window menu
- Preferences...
- Web and XML -> XML Catalog
- Click on Advanced...
- Click on Import...
- Select ofbizNeogia/.xmlcatalog
- Preferences...
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;
java
Résoudre Type safety: Unchecked cast from Object to List
Il faut utiliser la method UtilGenerics.checkList(xxx
nettoyer le cache manuellement
- delegator.clearCacheLine(GenericValue) <= pour une GénéricValue
- delegator.clearCacheLine(NomDentité) <= pour tous les caches d'une entité
Généralités sur les screens et les forms
Dans un form "single", comment ajouter un champs de saisie de donnée ?
- Selon le type de variable à saisir, on dispose de plusieurs balises : <text>, <text-find> <date-find> avec des options sur la taille de la zone de saisie et la taille maximale de la variable. Le <text-find> et le <date-find> permettent de disposer d'opérateurs sur cette variable. Cela sert pour des zones de recherches (les dates entre hier et aujourdh'ui, un nom commençant par Ar, ...).
Dans un form "single", comment positionner le focus dans un des champs ?
- On utilise l'attribut focus-field-name de la balise <form>.
Dans un form "single", comment définir la taille maximale du champs à renseigner ?
- On utilise la balise <text> et son attribut "maxlength".
- Ex:
<field name="productId" title="${uiLabelMap.ProductProductId}"><text maxlength="20" size="20"/></field>
- Pour les champs à renseigner on peut aussi utiliser la balise <text-find> qui permet de disposer d'opérateur sur le champs.
- Ex:
<field name="productId" title="${uiLabelMap.ProductProductId}"><text-find /></field>
Dans un form "single", comment choisir la position des champs ?
- L'attribut "position" permet de répartir les champs dans la zone. On fixe une position au niveau des colonnes par un numéro de 1 au nombre de colonnes désirées. Ainsi, s'il apparait le nombre 3, alors les champs seront répartis sur trois colonnes.
- Ex:
<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>
- Ainsi les éléments ayant une position à "1" seront alignés verticalement sur la première colonne.
Dans un form "single", comment mettre un champs caché ?
- On utilise la balise <hidden> au niveau du champs.
- Ex:
<field name="orderId"><hidden/></field>
Dans un form list, quels sont les opérateurs disponibles dans le service performFind utilisé pour constituer la liste ?
- and, between, equals, greaterThan, greaterThanEqualTo, in, lessThan, lessThanEqualTo, like, not, notEqual, or.
- not-in ex :
<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 ?
- Il suffit de mettre le champs noConditionFind à "Y".
- Ex:
<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 ?
- L'option <display-entity> permet de récupérer un autre champs de la base.
- Ex:
<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 ?
- Il suffit d'utiliser un <row-actions> dans la form.
- Ex:
<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 ?
- On utilise la balise <hyperlink> en renseignant sa target. La target correponds à une request du controller. On peut également passer des paramètres.
- Ex:
<field name="stickerLink" widget-style="buttontext" title="${uiLabelMap.ButtonSticker}">
<hyperlink target="stickerPDF.pdf?orderId=${orderId}&shipmentId=${shipmentId}" description="${uiLabelMap.ButtonSticker}"/>
</field>
Dans un form "list", comment charger les éléments d'un drop-down à partir d'une table ? Comment trier ces éléments ?
- On utilise la balise <entity-options> pour récupérer les données dans la base. On peut aussi appliquer une sélection avec opérateur ou ordonner.
- Ex:
<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 ?
- Les list multi permettent d'appeler un service pour traiter les informations de la liste, ligne par ligne. Ce service n'est pas appelé directement mais par le controller, grace à la notion de service-multi. On va donc définir la "target" du form, elle correspondra à une request du controller, qui lui appelera le service.
- Ex:
<form name="ListPickListItem" target="SendPicklistMulti" paginate-target="PickListItem" ....>
- La "target" correspond à une request du controller (elle permet de déclencher le service-multi), il n'y a rien de particulier à faire au niveau du service. Il sera appelé pour chaque ligne de la liste (coché) comme si c'était en provenance d'un form single.
<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 ?
- L'attribut also-hidden="false" de <display> permet cela.
- Ex:
<field name="orderDate" title="${uiLabelMap.OrderDate}"><display also-hidden="false" /></field>
Dans un form "multi", comment ajouter des cases à cocher ?
- On ajoute l'attribut use-row-submit="true" dans la balise form. On ajoute ensuite dans les champs un champs "_rowSubmit" avec une balise <check/>.
- Ex:
<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 ?
- L'attribut all-checked de la balise <check> doit être mis à "true".
- Ex:
<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 ?
- Il faut pour cela ajouter un champs "_rowSubmit" avec une condition exprimée par un "use-when". Cette solution pose souci car elle provoque un 'trou' dans le tableau. Il faut donc ajouter un deuxième champs "_rowSubmit" avec une condition inverse. Si cette condition porte sur un attribut d'une entité, ce champs doit se trouver dans la liste.
- Ex:
<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 ?
- On utilise les balises <entity-one>, <entity-and> et <entity-condition>.
Ex:
- Ex: Dans le cas où on dispose de la clé primaire on utilise <entity-one>
<entity-one entity-name="Product" value-name="product"> <field-map field-name="productId"/> </entity-one>
- Ex: Lorsqu'on récupère plusieurs enregistrement, on utilise <entity-and>. La liste peut être utilisé directement dans un form en renseignant l'attribut "list-name" avec le nom de la liste.
<entity-and list-name="lOrderItem" entity-name="OrderItem"> <field-map field-name="orderId"/> </entity-and>
- Ex: On peut aussi exprimer des contraintes avec <entity-condition>.
<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 ?
- On utilise la balise <condition> avec plusieurs autres balises servant d'opérateur : <not>, <if-empty>, <if-compare>, <if-has-permission>, ...
<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 ?
- Afficher le contenu complet de ma map
${entryMaps["entryMap${i}"]}
- Prendre un élément d'une liste contenue dans la map
${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
- Avec un itérateur
<#list 1..30 as i >
<fo:block>${i}</fo:block>
</#list>
- Sur une liste
<#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
Les balises du language XSL-FO
RenderX - XSL FO Features Test: Demo Code
Extensible Stylesheet Language (XSL) Version 1.1
Tuteur XSL-FO -- XSL-FO tutorial
Using XSL-FO to create printable documents
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


