View source | Discuss this page | Page history | Printable version   

ERP 2.50:Upgrading From 2.40 and 2.3x


General concepts

Before starting with the definition of the upgrade process to r2.50 let's define some important concepts that will be used during the rest of the document.

Bulbgraph.png   As this document explains the upgrade process, it is very important to clearly understand the difference between upgrade and migration.
Openbravo component
Components are the logical objects that, all together, build the Openbravo ERP application. A component is a complete object. Examples of components are windows, reports, selectors, etc. Depending on the kind of object it can be completely defined in application dictionary (for example a window) or it can also include some code files (a selector is defined in application dictionary and implemented by some Java classes and other files).
A customization is a modification (or a complete new creation) on an Openbravo ERP component to adapt it to the customer requirements. When customized components are moved to modules the responsible for their migration is their owner, this means that there is not an automatic migration process.
It is the process that, maintaining the customizations and the customer data, moves an Openbravo ERP instance from an old version to a newer one. During this process the customized components are maintained as they were in the old version performing just the required modifications to make them work in the new one. Note that when upgrading customized core components, these components do not belong to core anymore but to the customization, thus those pieces of code will not be benefited with the possible bug fixed in the new version. The goal of this document is to explain how to do this upgrade.
This process incorporates the new version's developments to the customized elements including all the bug fixes. This is only required for manual code because application dictionary components automatically benefit from new developments. For manual code, depending on the component type, it might be required to compare the differences between the standard component in the old and in the new version to manually merge in the customized component those differences. Anyway this process in most of the cases is not necessary since the old component should work in the new version. The definition of this process is out of the scope of this document.

Steps to upgrade to 2.50

The upgrade from an existent 2.40 Openbravo ERP instance to an 2.50 consists in an automatic upgrade process and because of some of the new developments in 2.50 it also requires of some manual changes.

The steps to perform this upgrade are:

  1. Upgrade database and find file customizations: After this step, the database will have been upgraded to version 2.50, and the existing customizations in source files will have been moved to a specific folder inside Openbravo.
  2. Do the required changes in custom code to adapt it to r2.50: It is necessary to manually do some changes in the code in order to make it compatible with r2.50.
  3. Changes for modularity, basically the changes to be done will depend on the decision of maintaining customizations in srcClient as in older Openbravo ERP revisions which will be lower effort or to move the customizations to modules, which is more recommendable but will also increase the effort depending on what the customizations are.
  4. Preserve user interfaces translations in case there are different languages in use and exist manual code to be translated.

Upgrade database and find file customizations

This step involves upgrading the database, and finding customizations in source files. It is possible to update from any 2.40 version to any 2.50 version, to do so it is necessary to have the following Openbravo ERP instances and files (bellow, in this section it is explained how to get them):

The process will create a customization module, and a customization industry template, it will move the modularity-supported database customizations to them, and will move all customized source files to a specific folder inside the new 2.50 instance.

During this process, a customization module and industry template are automatically created, and all the customized database objects are moved to them. The upgrade process will ask for a Java package for both the module and the template. Make sure you enter a meaningful one, as you will have to take them into account when migrating your custom code.

Note: as all our previous upgraders do, the Openbravo ERP owned PL code (both functions and triggers) will be replaced during the upgrade process. We encourage not to change existing Openbravo ERP functions and triggers, but in case for some reason it is necessary to do so, the changes will need to be done again after the update process, so it's important to remember to save them before running the upgrader.

To upgrade an existing Openbravo 2.40 instance to version 2.50 from sources, first the code for both version 2.50, your specific version of 2.40, and the upgrader files need to be obtained.

To first obtain the 2.50 code, execute the following commands:

hg clone fresh_250_path_in_your_computer

This command clones the main repository to your system.

cd fresh_250_path_in_your_computer
hg tags

Now you will get a list of all the available tags in the repository, you should get a list like:

tip                             4830:1d27588e7bea
2.50MP5                         4828:600c52248c85
2.50MP4                         4824:2b559105f553
2.50MP3                         4400:5fa2eabb2b37
2.50MP2                         4185:b7d447cb0d2d
2.50MP1                         3917:2697b580d266
2.50                            3558:2eb7a3d19386
2.50beta                        3270:bcc34be9b9cd

You can now update your repository to the revision you want to update your instance to using the hg update command. For example:

hg update 2.50MP5

If you need to update to a version higher than 2.50mp20, you will need to update to 2.50mp20 and after that update to the last release. This is because the upgrade process is only compatible to releases lower than 2.50mp20.

You also need to obtain the code of a clean Openbravo ERP version 2.40, in the same revision or maintenance pack than your current instance. For example, if your instance is a standard 2.40, you need to do:

svn checkout fresh_240_path_in_your_computer

And finally, you need to get the files that are used to build and execute the upgrader:

hg clone upgrader_path_in_your_computer

Once you've downloaded these three groups of files, you need to configure the file inside the upgrader path (that can be found at upgrader_path_in_your_computer/config/ You must edit it so it looks like this:


Once you've done this. you need to build the upgrader. To do this, execute the following commands:

cd upgrader_path_in_your_computer
ant build.upgrader

This task will do two things:

Finally, you need to execute the database upgrader. To do this, execute the following commands:

cd upgrader_path_in_your_computer/database-upgrader
ant update.customized.database.modularity -DmodulePackage=org.openbravo.mycustomization.module -DtemplatePackage=org.openbravo.mycustomization.template

You can set the customization module package and the customization industry template package as you want. These properties will be used to set the Java package of both modules, which will contain all the database customizations your Openbravo ERP database contains, and that are automatically created by the upgrade task.

Known issue: When upgrading from Openbravo r2.40 mp3, and working with PostgreSQL, there is a known issue that consists in the upgrader incorrectly identifying a check constraint as customized, when in reality it wasn't. Therefore, you must manually removed the entry in the AD_EXCEPTIONS table which was added during the upgrade process to prevent an error. To do this, execute the following command in the database: DELETE FROM AD_EXCEPTIONS WHERE NAME1='AD_WINDOW_NAME_CHECK';

The last step is to configure the file of your new 2.50 instance, and do a full compilation. To do this, execute the following commands:

cd fresh_250_path_in_your_computer
ant setup
cd config

(Replace yourplatform with the name of your operating system, such as linux, linux-x64, windows, ...).

Fill in all the information the setup utility requests, and once you do it, you will have a configured file.

Note: Our new export mechanism has a validation process built-in to ensure that when any model is exported, it is consistent and valid. However, most of the models that were developed before Openbravo 2.50 will fail this validation. It is recommended, for users coming from older versions of Openbravo, to change the property validate.model in the new from value "true" to "false".

The next step is to compile the application:

cd fresh_250_path_in_your_computer
ant core.lib wad.lib trl.lib compile.complete.deploy

And once you've compiled the application, you need to export the database to export the module files:

ant export.database export.config.script -Dforce=true

Finally, you need to restart tomcat so that you can use your upgraded application.

Final note: as all our previous upgrade processes do, the Openbravo ERP owned PL code (both functions and triggers) will be replaced during the update process. We encourage not to change existing Openbravo ERP functions and triggers, but in case for some reason it is necessary to do so, the changes will need to be done again after the update process, so it's important to remember to save them before running the upgrade task.

File distribution

After upgrading to 2.50 the file system will look like:

Removal of tables and columns

The upgrader, by default, deletes tables and columns that have been deleted in the new version of Openbravo. However, if for some reason you don't want the upgrader to remove some particular columns or tables, or want to know at least which columns and tables will be removed, there is a way to do it. You first need to follow the process until the database upgrade step (that is, until just before the call to ant update.customized.database.modularity). Once you reach that point, you need to call the following commands:

cd upgrader_path_in_your_computer/database-upgrader
ant export.removed.objects.file

This task will generate a text file that contains the tables and columns that the upgrader will remove, contained in src-db/database/removedObjects.txt. This is an example of its content:

#AD_DEVELOPER# There are 100 rows in this table
#TEST# There are 2 rows in this table
#AD_SYSTEM.TAD_PARENT_VERSION# There are 1 rows with a non default value in this column.

You can see that this file contains all tables and columns that the upgrader will remove, with a comment symbol ("#"). To force the upgrader to preserve a table or column, just remove that symbol.

Once you've removed all the symbols corresponding to the tables and columns you want to preserve, the next step is to start the database upgrade process (the call to ant update.customized.database), and then proceed with the normal upgrade steps described below.

Changes in custom code to adapt it to r2.50

Changes for UUID

One of the major changes in r2.50 is the usage of UUIDs as primary key for database tables. This implies some modifications in the database structure. For more information about the purpose and scope of this project look at UUID usage.

Column types

Type for primary and foreign key columns, which in previous versions was declared as numeric(10), from r2.50 is a varchar(32) type. The upgrade process takes care of this following this logic:

This means that even if columns are not properly defined as foreign keys, they should be converted automatically by the upgrader. However, it is encouraged that foreign keys are used to maintain referential integrity.

If, for some reason, the upgrader has not changed a column that should be changed, it can be changed in the database, and then an ant export.database task should be executed to make sure the customization modules are in sync with the changes done in the database.

Rest of modifications

The rest of modifications to be performed to adapt customized code to the UUIDs are explained in the UUIDs usage article. Now customized code can easily be found in the directories described in the first chapter of this document: modules/org.openbravo.customization.module for PL code and codeCustomization for the rest of code, so the modifications are only needed for these files.

Just a couple of considerations about this:

Changes for reference list

In order to prevent naming clashes with modules allowing a name space for values in reference lists the size of the columns containing these values has been modified. These columns usually were of type char with a sort length (1 or 2). The new type is varchar with 60 character length. The type modification for the affected columns is automatically done by the upgrade process but some changes are required to be manually done in custom code.

PL code

Variables defined in PL code must fit the new size, so for variables used to contain data for references lists values they type should be VARCHAR2(60) instead of the previous one (typically CHAR(1)). This modification must be manually done. In case it is not done the PL code will still compile and will not crash unless the size of the values is bigger than the previously defined, that is: it will typically fail when using modules that add values to reference lists or in case the customization is transformed in a shareable module.

This modification is applicable to all PL code: functions, procedures and triggers. It only affects to variable definitions, so the way to apply it is as follows:

JavaScript renaming - Part 1: MessagesJS

The 2.40 release used in the head a call to the Javascript file MessagesJS.js (which is provided by a servlet):

<script language="JavaScript" src="../utility/MessagesJS.js" type="text/javascript"></script>

Due that this dynamic javascript servlet is used for more things that just messages, it has been renamed to DynamicJS.js, so in 2.50 the correct js call remains as:

<script language="JavaScript" src="../utility/DynamicJS.js" type="text/javascript"></script>

Old file name will be removed in 2.60 and it is recommended you update the manual windows now.

JavaScript renaming - Part 2: Spanish to English

The 2.40 release used Spanish names for some/most of the JavaScript functions and for the names of the HTML frames used in the application. These have been translated to English names for the 2.50 release.

Renamed HTML frames

Openbravo uses two frames for the main window which are defined in the Login_FS.html file. Both of these frames have been renamed. All references to the frame names must be changed in custom manual windows.

Renamed JavaScript functions

The following table summarizes the changes made to JavaScript function names. For the 2.50 release both the old (Spanish) and new (English) names will work, as wrapper functions have been created. These wrappers will be removed in the 2.60 release, so while it is still technically possible to leave function names unchanged in 2.50, it is recommended you make the necessary changes now.

File Name Old Name New Name
searchs.js insertarElementosList AddElementsToList
messages.js mensaje showJSMessage
utils.js limpiar clearform
confirmar confirmAction
esNumero validateNumber
campoNumerico validateNumberField
abrirNuevoBrowser openNewBrowser
abrirExcel openExcel
abrirPDF openPDF
abrirPDFFiltered openPDFFiltered
abrirPopup openPopUpDefaultSize
abrirPDFSession openPDFSession
abrirBusqueda openSearchWindow
rellenarCombo fillCombo
valorArray searchArray
marcarTodos markAll
estaEnCombo comboContains
tamanoMaximo handleFieldMaxLength
cambiarListaCombo changeComboData
eliminarElementosList clearSelectedElements
limpiarLista clearList
seleccionarListCompleto markCheckedAllElements

The following Javascript functions have been also changed and marked as deprecated for the 2.50 release. They will be removed for the 2.60 release. Search in your code and if you are using some of these functions just rename them with the new name:

Old Name New Name
auto_complete_number autoCompleteNumber
auto_complete_date autoCompleteDate
auto_complete_time autoCompleteTime

In addition, the following functions have been deprecated for the 2.50 release and will be removed for the 2.60 release:

File Name Function
utils.js rellenarComboHijo

Renamed objects inside HTML templates

Some objects defined in each HTML template have been renamed. This includes the following two JavaScript variables which have to be defined as placeholders and replaced by XmlEngine:

For custom manual windows, these definitions must be renamed to the new names, so that standard code (i.e. the calculator pop up) can read and be displayed in the language the user has selected.

For these two objects the renaming has to be done in all three affected object types. The following snippet show how the definitions should look like to work with the 2.50 release for the defaultLang changes:

    <script language="JavaScript" type="text/javascript" id="paramLanguage">defaultLang = "en_US";</script>
    <PARAMETER id="paramLanguage" name="language" default=""></PARAMETER>
    xmlDocument.setParameter("language", "defaultLang=\"" + vars.getLanguage() + "\";");

Similar to the last case, each window can define a 'callback' function which is used to check if all needed values have been entered. It is defined on a per window basis, but called from a central place. The name of this function is different for normal windows and selectors, and both have been renamed in 2.50:

Again, backwards compatibility code has been implemented so it is possible to use both names in this 2.50 release, but as mentioned previously, old names will be removed in 2.60 and it is recommended you update the manual windows now.

New CSS distribution

In Openbravo ERP 2.40 the way of setting the CSS of each html is the following:

<LINK rel="stylesheet" type="text/css" href="../web/skins/Default/Main/XYZ.css" id="paramCSS"></LINK>

where XYZ could be

depending of the window type.

Various CSS also could be needed in some particular situations (manual window with a grid, ...). These CSS internally also make calls to others CSS.

To reduce the http traffic and in order to simplify style containers, since Openbravo ERP 2.40 MP1 and Openbravo ERP 2.50 there is only one single CSS file containing all the needed styles for Openbravo ERP.

The CSS call remain as:

<link rel="stylesheet" type="text/css" href="../../../../../web/skins/Default/XYZ.css" id="paramCSS"></link>

where XYZ could be

New button pattern

In order to avoid problems while pressing buttons in slow network environments, a new button pattern is defined (this works since Openbravo ERP 2.40 MP3).

You should convert your old buttons with the following structure:

<a class="ButtonLink" href="#"
  onfocus="setWindowElementFocus(this); window.status='AAAAAAAA'; return true;"
  onblur="window.status=''; return true;"
  onkeypress="this.className='ButtonLink_active'; return true;"
  onkeyup="this.className='ButtonLink_focus'; return true;"
  <table class="Button"
    onmousedown="this.className='Button_active'; return true;"
    onmouseup="this.className='Button'; return true;"
    onmouseover="this.className='Button_hover'; window.status='AAAAAAAA'; return true;"
    onmouseout="this.className='Button'; window.status=''; return true;"
      <td class="Button_left"><img class="Button_Icon YYYYYYYY" alt="EEEEEEEE" title="FFFFFFFFF" src="../../../../../web/images/blank.gif" border=0 id="GGGGGGGG"/></td>
      <td class="Button_text ZZZZZZZZ" id="HHHHHHHH">XXXXXXXX</td>
      <td class="Button_right"></td>

Into this one:

<button type="button" 
  onfocus="buttonEvent('onfocus', this); window.status='AAAAAAAA'; return true;" 
  onblur="buttonEvent('onblur', this);" 
  onkeyup="buttonEvent('onkeyup', this);" 
  onkeydown="buttonEvent('onkeydown', this);" 
  onkeypress="buttonEvent('onkeypress', this);" 
  onmouseup="buttonEvent('onmouseup', this);" 
  onmousedown="buttonEvent('onmousedown', this);" 
  onmouseover="buttonEvent('onmouseover', this); window.status='AAAAAAAA'; return true;" 
  onmouseout="buttonEvent('onmouseout', this);">
  <table class="Button" id="DDDDDDDD">
      <td class="Button_left"><img class="Button_Icon YYYYYYYY" alt="EEEEEEEE" title="FFFFFFFFF" src="../../../../../web/images/blank.gif" border="0" id="GGGGGGGG"/></td>
      <td class="Button_text ZZZZZZZZ" id="HHHHHHHH">XXXXXXXX</td>
      <td class="Button_right"></td>

Where AAAAAAAA, BBBBBBBB, CCCCCCCC, DDDDDDDD, EEEEEEEE, FFFFFFFF, GGGGGGGG, HHHHHHHH, XXXXXXXX, YYYYYYYY and ZZZZZZZZ are particular values of each button parameter. If any button parameter is missing and it is unique, just remove this parameter while converting.

Java & Autosave

Some processes (Java Servlets) requires the Id of the current record to be able to proceed, with Autosave enabled you cannot expect that the Id of the record must be in the parameters in the request. The solution to this issue is to use getGlobalVariable() method.

 String strWindowId = vars.getStringParameter("inpwindowId");
 String strKeyColumnId = vars.getStringParameter("inpkeyColumnId");
 String strRecordId = vars.getGlobalVariable("inpYourKeyId", strWindowId + "|" + strKeyColumnId);

The getGlobalVariable() method try to get the value of the request parameter (e.g. inpYourKeyId) if is null or empty string, tries to get the value from the session. In this case the save method always save the current id in the windowId|keyColumn (e.g. 180|C_Order_ID)

Changes for modularity

One of the biggest features in r2.50 is the inclusion of modules. From r2.50 it is possible to define all customizations as modules making much easier later upgrades.

For more information on modularity look at Modularity concept.

In order to develop modules a number of new rules have been created, thus some (optional) modifications will be required to adapt old customizations to modules.


The upgrade process maintains as customizations all the new PL/SQL objects (functions, procedures and triggers) but not the customized core ones, so after executing this process all the customized core PL/SQL objects will be replaced with the core 2.50 ones. To take into account these customizations, maintain them as part of the module and preserve them for future updates following these steps:

For example if the C_INVOICE_CREATE function is customized in r2.40, it would be necessary to insert it in database copying the one in r2.40. Then adapt it to r2.50 changing variables to support new UUIDs. Add it to the exceptions tab, and finally export database to check there is a C_INVOICE_CREATE.xml file within modules/org.openbravo.customization.module/src-db/database/model/functions directory.

Note that objects added to exceptions are out of maintenance. This means that they are inserted in database as they are in the module, not taking into account possible modifications on them in future core revisions.

Source code

Customizations in source code are saved in a separate directory (codeCustomizations) by the upgrade process. Note that although these customizations are preserved separately, they will not be visible when the application is compiled until one of the two possible actions is performed with them: convert to modules or merge in src.

There are two kinds of customizations and depending on this the process to make standard modules is slightly different. The two kind of customizations are:

Although converting customizations in standard modules has a number of advantages, specially when upgrading to future releases, it is always possible not to do so and still working in the same way as in previous versions: merge the customizations with Openbravo ERP core sources. Additionally there are some kind of customizations that is better to maintain in this manner. So it is necessary to decide whether the customizations will be maintained in this way moved to modules. Additionally it is possible to move part of the customizations to modules and to preserve the rest merged in core, for more information read the merge section in this document.

Move customizations to modules

This is the most recommendable way to maintain customizations as it is the new standard in r2.50 making possible a better integration with other modules and, virtually, to share own customizations with the rest of the community (note that in order to be able to share an existent customization further modifications will be required).

Some considerations

The way to move customizations to modules is to move their complete components (though it is possible to do it partially). For example in case there is a customization on a report that consists on a modification in the xsql file to calculate data in a different way, the recommended action is to move to a module the whole report. Thus this report will be treated as a complete object and will ease future upgrades without having to migrate it.

Before start moving the customizations to modules just take into account that modules are completely persisted within modules directory including all database information that is part of the module. To be able to export all database module's information to modules follow these steps:

Customer owned components to modules

These objects can be added to the module by repackaging them. Note that this new packaging affects only to source files, because the database elements that represent these objects already belong to the new module because the upgrade process set it. This repackaging basically consists on moving from the codeCustomizations/newCustomization directory to one directory inside modules/ During this chapter we'll use as example the Java package module org.openbravo.customization.module, thus the move would be from codeCustomizations/newCustomization to modules/org.openbravo.customization.module/src/org/openbravo/customization/module, obviously when moving Java classes it is also needed to modify their Java package.

Below is the step by step list to accomplish this, as example we are going to repackage a customized search reference called SalesOrder2:

mkdir -p modules/org.openbravo.customization.module/src/org/openbravo/customization/module 
cd modules/org.openbravo.customization.module/src/org/openbravo/customization/module 
mkdir info 
package; -> package; 

Look for org/openbravo/erpCommon/info/SalesOrder2 and replace it for org/openbravo/customization/module/info/SalesOrder2

look at the beginning of the xsql file for a line like:

<SqlClass name="SalesOrder2Data" package=""> and change it for <SqlClass name="SalesOrder2Data" package="">

Customized Core Components

Customizations for core components are not allowed in modularity. The standard way to work with customizations for these kind of objects is to create a new customer component within a module. For example to modify the standard Report General Ledger report it would be necessary to create a new report in the application dictionary (in this step pay special attention to UI Pattern field in the Report and process window, for manual code it must be manual, for further information read this document) inside the module and assign it a Java class properly named in the proper package. After this, the customization is no longer a core object but a custom owned one and the steps to follow are the same as explained in the previous section.

Finally, the references that were to the old object must be changed to the new one, note that currently they point to the core object, without any customization. For example if this report is called from the menu, that menu entry should point to the custom report instead to the core one, this entry will be exported to the custom template.

Merge customizations with Openbravo ERP core sources

Although it is recommendable to add customized objects to modules it is also possible to postpone it, partially do, or eventually, do not do it at all, maintaining these customizations as part of Openbravo ERP core sources.

To do this merge all the source files that the upgrade process left in codeCustomizations/newCustomizations/src with their correspondent ones in src and copy the ones in codeCustomizations/coreCustomizations/src to src directory. Note that this copy must be done preserving the directory hierarchy in both sides.

Bulbgraph.png   Note that if an instance contains customizations merged with core sources, it will be necessary to upgrade to future releases using a merge mechanism, this means that core will not be updatable using the "Module management console" since these customizations will be lost.

There are some exceptions where it is very difficult, or almost impossible to maintain customizations as packages and the only "clean" way do it is merging with core. These exceptions should be avoided if possible. They consist on customizations in very deep core elements, and to modularize them it would be required to move to modules a big amount of standard stuff. Other cases where it makes sense to merge customizations is in case the customization consists in a very reduced amount of changes of a core piece, in this case it could be meaningless to create a complete new object to move it to modules.

For example let's suppose there's a customization in a query for an xsql file that it is used in the accounting process, in this case it would make sense to maintain this xsql file merged in src (only if this customization is strictly required and that functionality cannot be developed in another way) because it is modifying a piece of code which is very deep in core (extracting it to a module would require extracting the whole accounting engine), and it is a very light customization of a single file.


The upgrade process is able to automatically manage database customizations as modules. It creates a new module called MyCustomizationModule and a new industry template called MyCustomizationTemplate. All customizations that can be expressed as part of a module or template are saved there.

Naming rules

A set of naming rules was defined for modules (Naming and packaging rules) which is necessary to follow in order to create a standard module, but in order to be possible to treat current customizations as modules the upgrade process generates the customization module without taking into account those rules and it populates the AD_Exception table with all the objects that were included in the module but didn't fulfill the naming rules. It works as a module for any purpose except that as it is not a standard module. It will not be shareable with the community in order to avoid naming clashes.

If the customization module is wanted to be standard to be shared it will be necessary to standardize all the object marked as exceptions. To do so they must be renamed following the naming rules, note that renaming database objects is not a trivial task: it also requires to adapt all the code (PL/SQL, XSQL...) to the new names.

Preserve user interfaces translations

This section explains how to preserve the existent translations for manual code, so in case in your instance you do not have translations (you don't use a second language) or you do not have manual code to be translated, you can skip it.

How translations work

Openbravo ERP distinguishes between translations for application dictionary elements (for example a field in a tab) and translations for text interfaces in manual code (for example a label in a manual report). The first case does not have any problem when upgrading to 2.50, the translations are automatically maintained. The problem is in the second case.

Whenever Openbravo ERP is compiled one of the processes that is run is the translate process. This process parses all manual files that can contain elements to be translated (html, srpt, fo and jrxml files) looking for translatable elements (for example a label in an html file). When one of these elements is found it looks in the database if already exists that element and in case it does not exist it inserts a new entry for that element as well as a translation entry for that element in each of the languages set as system. The text inserted in the translation in the same as the original one and the user must change it to translate to the different languages. To decide if an element already exists in the database is done by checking if exists the pair text-file, this means if there is any occurrence in the database that matches exactly the element to translate and it is in the same file (including the full path) where it was found.

As to move existent customizations to modules the files have been moved to different paths when executing the translate process for first time it will identify all the translatable entries in modules as new ones and it will insert new entries, this mean it will not use the old translations but it will generate new ones with the same text as the original one. To preserve the existent translations it is necessary to run an additional process described in the next section.

Steps to preserve translations

The process to recover the old translations includes the following steps:

  1. Do all the code migrations described in the sections above.
  2. Execute ant compile.complete. This task will add new entries in the manual text interfaces making the old ones out of use.
  3. Execute ant -f build-trl.xml. It will recover the old translations.
  4. Run again ant compile.complete. It will re-generate the entries that could not have been recovered (if any).

There are two different options when moving files to modules. The first one is to move the file to the new path preserving the file name, for example the customized file src/org/openbravo/erpCommon/ad_Reports/MyReport1.html is moved to modules/org.openbravo.mycustomization/src/org/openbravo/mycustomization/ad_reports/MyReport1.html. The second option is that the file is not only moved but also renamed, in the previous example the final file could be modules/org.openbravo.mycustomization/src/org/openbravo/mycustomization/ad_reports/MySalesOrderReport.html.

The recovering process tries to match the new entries (which were re-created with the ant compile.complete) with the old translations to point these translations to the new entries. In case the file was moved preserving the name the match is easier because it just compares the text entries for the old file and the new one and reuses the one that has the same text. In the second case the process does not have any way to identify which was the original file's name, so it tries to match the old entry looking the existent ones with the same text regardless the file they are in. The problem with this last approach is that multiple entries with the same text (and eventually different translations) can be in different files, in this case the process is not able to decide which one should use and it leaves it empty, so in this case the entry will not be translated.


Changes for background processes

Another significant feature of r2.50 is the integration of the Quartz process scheduling framework, which replaces background processing in r2.40 and earlier. The Quartz framework is a proven, robust inclusion in the Openbravo ERP stack that greatly increases the flexibility developers have not only running background processes, but also with process scheduling and responding to application/process events. You can find more details about Quartz integration r2.50 here.

In releases prior to r2.50 background processes and resources were placed in the org.openbravo.erpCommon.ad_background package, and any processes that were intended to be run periodically in the background had to implement the org.openbravo.erpCommon.ad_background.BackgroundProcess interface:

public interface BackgroundProcess {
  public void processPL(PeriodicBackground perioricBG, boolean directProcess) throws Exception;

Information pertaining to the given process or process instance, such as client or process id, or VariablesSecureApp instance, could be retrieved through the PeriodicBackground parameter instance. For example, the PeriodicAcctServer background process (r2.40) requires the VariablesSecureApp instance, client id and process id:

public void processPL(PeriodicBackground periodicBG, boolean directProcess) throws Exception {
  if (periodicBG.vars == null || periodicBG.adClientId.equals("")) {
    try {
      PeriodicAcctServerData[] dataOrg = PeriodicAcctServerData.selectUserOrg(periodicBG.conn, periodicBG.adProcessId);

In r2.50, PeriodicBackground, BackgroundProcess and the context listener org.openbravo.base.PeriodicBackgroundContextListener have been replaced by classes that integrate with the Quartz framework:

Modifying BackgroundProcess implementations

As a result of BackgroundProcess being removed, any custom implementations of this interface will have to be migrated to implement the new org.openbravo.scheduling.Process interface (although a default implementation of this interface is provided in org.openbravo.service.db.DalBaseProcess). The new interface contains a single method, much the same as the BackgroundProcess interface, so the migration should be just a matter of:

Old Periodic Accounting Background Process

package org.openbravo.erpCommon.ad_background;
public class PeriodicAcctServer implements BackgroundProcess {
 public void processPL(PeriodicBackground periodicBG, boolean directProcess) throws Exception {
   VariablesSecureApp vars = periodicBG.vars;

Periodic Accounting Background Process in r2.50

package org.openbravo.erpCommon.ad_process;
import org.openbravo.service.db.DalBaseProcess;
public class AcctServerProcess extends DalBaseProcess {
 public void doExecute(ProcessBundle bundle) throws Exception {
   VariablesSecureApp vars = bundle.getContext().toVars();

Changes related to numeric formatting


2.50MP5 introduces several changes in the way Openbravo ERP handles numeric formatting. In this section you'll get a detail explanation about this changes.

Include order of javascript files (utils.js before dojo.js)

The support for different enhances the dojo RealNumberTextbox widget to support different numeric format. This changes use some common code in the utils.js function which is executed on inclusion time of the dojo.js file. This means that the utils.js file must be included before the dojo.js file (if the dojo.js file is used in some html page). If the dojo.js file is included before the utils.js file then default values for the grouping separator and decimal separator will be used to allow custom non-updated code to still function as before.

Updating UI components

The User interface files needs to be updated to support proper formatting of displayed number (output formatting) and for parsing of number (input parsing). The input parsing changes are different depending on which input widgets are used (dojo-RealNumberTextbo or normal standard html input tag).

Output formatting of numeric fields (xmlEngine)

All numeric fields should be properly formatted using a numeric format specified in the Format.xml file. This should be done independent of the project to properly display the values in the correct format. But is now a requirement to allow the js-code to properly parse the number.

This can be done by using the xmlEngine 'format=<value>' attribute where value is one of the format names defined in the Format.xml file. If specified the format attribute will cause the value to be formatted on output for both the 'Field' and the 'Parameter' tags in a xmlEngine control file.

An example are these changes done to the xmlEngine control file of the 'Report General Ledger'.

Note: Which format name should be used depends on which type of value is displayed in the field, like prices, quantities... The right format should be chosen on a per-field basis.

Changes for dojo-RealNumberTextbox widgets

The dojo RealNumberTextbox widgets need a new attribute defining which format should be applied to a field. The attribute name must be 'outputformat'. The values are again the format names defined in the Format.xml file.

An example are these changes done to the html part of the 'Report General Ledger'.

The format used for the same field in the xml and html part should be obviously the same per field.

If a dojo RealNumberTextbox widget should contain a call to one of these javasscript methods:

then these javascript calls must be removed.

Changes for normal html-input widgets

These non dojo numeric input fields need the following attributes added:

In addition any call to one of these javascript methods needs to be removed:

Possible cleanup of js includes

After converting all numeric fields the following js imports are not longer needed and can be removed from the changed html files.

Changes for backend code reading numeric values

All java code which reads numeric parameters from a HTTP request needs to use special getNumeric* function defined in VariablesBase.

The mapping from the normal get* function to the special one for numeric values is:

This special getNumeric* functions need to be used both for reading values from the changed numeric fields as well as reading of numeric parameters sent to callouts.

An example for using the special GetNumeric* getter functions for reading numeric values can be found in this change done to the 'Report General Ledger'.

Changes to callouts

To types of changes need to be done to custom callouts.

The first one is get usage of the getNumeric* functions for reading of numeric paramters as outlined in the previous paragraph.

The second change concerns the quoting of numeric values in callout responses. All numeric values are not allowed to have quotes around them.

An example for the use of the getNumeric* functions to read the parameters can be found here.

An example for the removal of the quotes around numeric values in the reponse can be found here.


Upgrading a new window

Creating a table in Database

Let's create a new table called C_EMPLOYEE. The new C_EMPLOYEE table must include the AD_Client_ID, AD_Org_ID, IsActive, Created, CreatedBy, Updated and UpdatedBy fields that are mandatory and required for security and auditory purposes of the application. These fields are created in an Openbravo ERP 2.40 application located in home/user/OpenbravoERP2.40 folder.

PostgreSQL code

 CREATE TABLE c_employee( 
  c_employee_id numeric(10) NOT NULL, 
  ad_client_id numeric(10) NOT NULL, 
  ad_org_id numeric(10) NOT NULL, 
  isactive character(1) NOT NULL DEFAULT 'Y'::bpchar, 
  created timestamp without time zone NOT NULL DEFAULT now(), 
  createdby numeric(10) NOT NULL, 
  updated timestamp without time zone NOT NULL DEFAULT now(), 
  updatedby numeric(10) NOT NULL, 
  "name" character varying(60) NOT NULL, -- --OBTG:NVARCHAR-- 
  gender character(1), 
  CONSTRAINT c_employee_key PRIMARY KEY (c_employee_id), 
  CONSTRAINT c_employee_name UNIQUE (name), 
  CONSTRAINT c_employee_isactive_check CHECK (isactive = ANY (ARRAY['Y'::bpchar, 'N'::bpchar])))WITH (OIDS=FALSE);
 ALTER TABLE c_employee OWNER TO tad;COMMENT ON COLUMN c_employee."name" IS '--OBTG:NVARCHAR--';
Creating a new window
ant compile.development -Dtab='Employee'

New window.jpg

New window error message.jpg

Now that the new Employee window is finished in 2.40 version let's upgrade it to a 2.50 version.

Running the 2.40 upgrade Ant task
cd /home/user/
hg clone upgrader-2.40_2.50
svn checkout fresh_2.40
hg clone fresh_2.50
cd /home/user/upgrader-2.40_2.50
ant build.upgrader
cd /home/user/upgrader-2.40_2.50/database-upgrader
ant  update.customized.database.modularity -DmodulePackage=org.openbravo.employee.module -DtemplatePackage=org.openbravo.employee.template

At this point out OpenbravoERP2.40 database has being converted in a 2.50 ready database and our functionality is modularized.

Running the functionality in 2.50
ant core.lib wad.lib trl.lib compile.complete
ant export.database -Dforce=true 
ant package.module -Dmodule='org.openbravo.employee.module'


Upgrading a new Field, a new Constraint and a modified Core Column

These are the functionality changes in this example.

These changes are done in Openbravo ERP 2.40 application located in home/user/OpenbravoERP2.40 folder.

Adding a new column to the existing table in 2.40 database

PostgreSQL code

ALTER TABLE c_bpartner
 ADD COLUMN OFF_HOURS varchar(50);
Adding a Constraint

PostgreSQL code

  (ISEMPLOYEE = 'N' OR off_hours IS NULL) ;
Modifying the Existing Field
Displayed Length=30.

And also change the size of the column Taxid in the database


Run the Ant task

ant compile.development -Dtab='Business Partner'

Now the changes can be seen in the Business Partner (Master Data Management || Business Partner ||Business Partner) tab.


If the user try to select Employee check box and enter Office hour,an error message should be shown "Employees do not have office hours".


Now the functionalities Upgrading a new Field,Constraint,modifying the existing column is finished in 2.40 version.let's upgrade it to a 2.50 version.

Running the 2.40 upgrade Ant task
cd /home/user/
hg clone upgrader-2.40_2.50
svn checkout fresh_2.40
hg clone fresh_2.50
cd /home/user/upgrader-2.40_2.50
ant build.upgrader
cd /home/user/upgrader-2.40_2.50/database-upgrader
ant  update.customized.database.modularity -DmodulePackage=org.openbravo.samplefield.module -DtemplatePackage=org.openbravo.samplefield.template

At this point out OpenbravoERP2.40 database has being converted in a 2.50 ready database and our functionality is modularized.

Running the functionality in 2.50
ant core.lib wad.lib trl.lib compile.complete
ant export.database export.config.script -Dforce=true 
ant package.module -Dmodule='org.openbravo.samplefield.module'
ant package.module -Dmodule='org.openbravo.samplefield.template'


Upgrading a new Callout

This example explains how a Callout mechanism is upgraded from 2.40 to 2.50.

Create a new customized callout in 2.40 workspace

The functionality of our customized callout is explained below.

The output of our customized callout will look like as shown below,

Result callout 1.jpg

The code for new customized callout( ) is given below. And this callout is created in openbravoERP 2.40 application which is located in home/user/OpenbravoERP2.40 directory.

package org.openbravo.erpCommon.ad_callouts;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.openbravo.base.secureApp.HttpSecureAppServlet;
import org.openbravo.base.secureApp.VariablesSecureApp;
import org.openbravo.erpCommon.utility.Utility;
import org.openbravo.xmlEngine.XmlDocument;
public class Product_Discount_Callout extends HttpSecureAppServlet {
  private static final long serialVersionUID = 1L;
  public void init(ServletConfig config) {
    boolHist = false;
  public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException,
      ServletException {
    VariablesSecureApp vars = new VariablesSecureApp(request);
    if (vars.commandIn("DEFAULT")) {
      String strProductName = vars.getStringParameter("inpname");
      String strProductCategoryId = vars.getStringParameter("inpmProductCategoryId");
      try {
        if (strProductName != null && strProductCategoryId != null)
          printPage(response, vars, strProductName, strProductCategoryId);
      } catch (ServletException ex) {
    } else
  private void printPage(HttpServletResponse response, VariablesSecureApp vars,
      String strProductName, String strProductCategoryId) throws IOException, ServletException {
    log4j.debug("Output: dataSheet");
    XmlDocument xmlDocument = xmlEngine.readXmlTemplate(
    StringBuffer result = new StringBuffer();
    result.append("var calloutName='Product_Discount_Callout';\n\n");
    result.append("var respuesta = new Array(");
    result.append("new Array(\"inpdescription\", \"" + strProductName + "\")");
    if ("Discounts".equalsIgnoreCase(strProductName) || "Discount".equalsIgnoreCase(strProductName)) {
      result.append(", new Array(\"inpmProductCategoryId\", \"" + "1000005" + "\")");
      result.append(", new Array('MESSAGE', \""
          + Utility.messageBD(this, "Product_Category_Discount", vars.getLanguage()) + "\")");
    if ("1000005".equalsIgnoreCase(strProductCategoryId)) {
      result.append(", new Array('MESSAGE', \""
          + Utility.messageBD(this, "Product_Category_Discount", vars.getLanguage()) + "\")");
    // inject the generated code
    xmlDocument.setParameter("array", result.toString());
    xmlDocument.setParameter("frameName", "frameAplicacion");
    response.setContentType("text/html; charset=UTF-8");
    PrintWriter out = response.getWriter();

Once our new callout functionality is done in 2.40 version, it can be upgraded to 2.50.

Running the 2.40 upgrade Ant task:

cd /home/user/
hg clone upgrader-2.40_2.50
svn checkout fresh_2.40
hg clone fresh_2.50
cd /home/user/upgrader-2.40_2.50
ant build.upgrader
cd /home/user/upgrader-2.40_2.50/database-upgrader
ant update.customized.database.modularity -DmodulePackage=org.openbravo.mycallout.module -DtemplatePackage=org.openbravo.mycallout.template

At this point our OpenbravoERP2.40 database has been converted in a 2.50 ready database and our functionality is modularized.

Running the functionality in 2.50
ant core.lib wad.lib trl.lib compile.complete
ant export.database -Dforce=true
ant export.config.script -Dforce=true

Refactoring the obtained module

After upgrading to 2.50 the file system will look like:

The steps for code refactoring are given below.

package org.openbravo.erpCommon.ad_callouts;  --> package org.openbravo.mycallout.module.ad_callouts;

Refactor code.jpg

After refactoring the code, run the following Ant task and restart the server.

ant compile.development -Dtab=xx

Now we can test the upgradation, by testing the Product Window. ( General Setup || Master Data Management || Product || Product )

After testing is done, the module can be packaged by running the following Ant task.

ant package.module -Dmodule='org.openbravo.mycallout.module'

And the template can be packaged by running the following Ant task.

ant package.module -Dmodule='org.openbravo.mycallout.template'

Finally, we will get two .obx files, which can be installed and tested in any other 2.50 workspace.

Upgrading a new Field to existing Report Filter Window and in Report

These are the functionality changes in this example.

Add a new Field to the existing Report Filter Window

Hence the report filter window will look like this.



Till now the changes in 2.40 is completed.Now we have to upgrade to 2.50 version.

Running the 2.40 upgrade Ant task
cd /home/user/
hg clone upgrader-2.40_2.50
svn checkout fresh_2.40
hg clone fresh_2.50
cd /home/user/upgrader-2.40_2.50
ant build.upgrader
cd /home/user/upgrader-2.40_2.50/database-upgrader
ant  update.customized.database.modularity -DmodulePackage=org.openbravo.samplereport.module -DtemplatePackage=org.openbravo.samplereport.template

At this point out OpenbravoERP2.40 database has being converted in a 2.50 ready database and our functionality is modularized.

Running the functionality in 2.50





xmlDocument.setParameter("language", "LNG_POR_DEFECTO=\""+vars.getLanguage()+"\";");
xmlDocument.setParameter("direction", "var baseDirection = \"" + strReplaceWith + "/\";\n");



 xmlDocument.setParameter("language", "defaultLang=\""+vars.getLanguage()+"\";");
 xmlDocument.setParameter("directory", "var baseDirectory = \ ""+strReplaceWith + "/\";\n");


xmlDocument.setData("reportCBPartnerId_IN", "liststructure", ReportProjectBuildingSiteData.selectBpartner(this, Utility.getContext(this, vars, "#AccessibleOrgTree", ""), Utility.getContext(this, vars, "#User_Client", ""), ""));
xmlDocument.setData("reportMProductId_IN", "liststructure", ReportProjectBuildingSiteData.selectMproduct(this, Utility.getContext(this, vars, "#AccessibleOrgTree", ""), Utility.getContext(this, vars, "#User_Client", ""),""));
xmlDocument.setData("reportC_PRODUCTCATREGORY","liststructure",, Utility.getContext(this, vars, "#AccessibleOrgTree", ""), Utility.getContext(this, vars, "#User_Client", "")));



xmlDocument.setData("reportCBPartnerId_IN", "liststructure", SelectorUtilityData
            .selectBpartner(this, Utility.getContext(this, vars, "#AccessibleOrgTree", ""), Utility
                    .getContext(this, vars, "#User_Client", ""), ""));
    xmlDocument.setData("reportMProductId_IN", "liststructure", SelectorUtilityData
            .selectMproduct(this, Utility.getContext(this, vars, "#AccessibleOrgTree", ""), Utility
                    .getContext(this, vars, "#User_Client", ""), ""));
    ComboTableData comboTableData = new ComboTableData(vars, this, "TABLEDIR",
            "M_PRODUCT_CATEGORY_ID", "", "", Utility.getContext(this, vars, "#AccessibleOrgTree",
                "ReportProjectBuildingSite"), Utility.getContext(this, vars, "#User_Client",
                "ReportProjectBuildingSite"), 0);
        comboTableData.fillParameters(null, "ReportProjectBuildingSite", "");
    }catch(Exception ex){
    	throw new ServletException(ex);


xmlDocument = xmlEngine.readXmlTemplate("org/openbravo/erpCommon/ad_reports/ReportSalesOrderFilterJR").createXmlDocument();
String strReportName = "@basedesign@/org/openbravo/erpCommon/ad_reports/ReportSalesOrderJR.jrxml";



xmlDocument = xmlEngine.readXmlTemplate("org/openbravo/salesorder/ad_reports/ReportSalesOrderFilterJR").createXmlDocument();
 String strReportName = "@basedesign@/org/openbravo/salesorder/ad_reports/ReportSalesOrderJR.jrxml";



      <script language="JavaScript" type="text/javascript" id="paramDirection">
      var baseDirection = "../../../../../web/";



<script language="JavaScript" type="text/javascript" id="paramDirectory">
      var baseDirectory = "../../../../../web/";


<script language="JavaScript" src="../utility/MessagesJS.js" type="text/javascript"></script>



<script language="JavaScript" src="../utility/DynamicJS.js" type="text/javascript"></script>


<script language="JavaScript" type="text/javascript" id="paramLanguage">
        var LNG_POR_DEFECTO = "en_US";



<script language="JavaScript" type="text/javascript" id="paramLanguage">
        var defaultLang = "en_US";
depurar to validate ,
mensaje to showJSMessage
seleccionarListCompleto to markCheckedAllElements
eliminarElementosList to clearSelectedElements
limpiarLista to clearList


         <a class="ButtonLink" href="#" onfocus="setWindowElementFocus(this);window.status='View Results in a New Window'; return true;" onblur="window.status=''; return true;" onkeypress="this.className='ButtonLink_active'; return true;" onkeyup="this.className='ButtonLink_focus'; return true;" onclick="openServletNewWindow('EDIT_HTML', true, 'ReportSalesOrderFilterJR.html', 'ReportSalesOrderFilterJR', null, false, '700', '1024', true);return false;" id="buttonHTML">
           <table class="Button" onmouseout="this.className='Button';window.status='';return true;" onmouseover="this.className='Button_hover';window.status='HTML_Report';return true;" onmousedown="this.className='Button_active';return true;" onmouseup="this.className='Button';return true;">
                  <TD class="Button_left"><IMG class="Button_Icon Button_Icon_html" alt="View Results in a New Window" title="View Results in a New Window" src="../../../../../web/images/blank.gif" border="0/"></IMG></TD>
                   <TD class="Button_text">HTML Format</TD>
                   <TD class="Button_right"></TD>



<button type="button" 
                       onclick="openServletNewWindow('EDIT_HTML', true, 'ReportSalesOrderFilterJR.html', 'ReportSalesOrderFilterJR', null, false, '700', '1024', true);return false;" 
                       onfocus="buttonEvent('onfocus', this); window.status='View Results in a New Window'; return true;" 
                       onblur="buttonEvent('onblur', this);" 
                       onkeyup="buttonEvent('onkeyup', this);" 
                       onkeydown="buttonEvent('onkeydown', this);" 
                       onkeypress="buttonEvent('onkeypress', this);" 
                       onmouseup="buttonEvent('onmouseup', this);" 
                       onmousedown="buttonEvent('onmousedown', this);" 
                       onmouseover="buttonEvent('onmouseover', this); window.status='View Results in a New Window'; return true;" 
                       onmouseout="buttonEvent('onmouseout', this);">
     <table class="Button">
         <td class="Button_left"><img class="Button_Icon Button_Icon_html" alt="View Results in a New Window" title="View Results in a New Window" src="../../../../../web/images/blank.gif" border="0" /></td>
         <td class="Button_text">HTML Format</td>
         <td class="Button_right"></td>



<PARAMETER id="paramDirection" name="direction" default=""/>



<PARAMETER id="paramDirectory" name="directory" default=""/>
ant core.lib wad.lib trl.lib compile.complete
ant compile.development -Dmodule='org.openbravo.samplereport.module'
ant export.database export.config.script -Dforce=true 
ant package.module -Dmodule='org.openbravo.samplereport.module'
ant package.module -Dmodule='org.openbravo.samplereport.template'


Upgrading directly from 2.3x

Those users who still are running version 2.3x under Oracle do not need to upgrade to 2.40 first. It is possible to go directly to 2.50 by following this same guide, and with some changes desribed as follows.

In the Steps to upgrade to 2.50 section, just after cloning the upgrader-2.40_2.50 repository, apply this patch that adjusts the library paths to the 2.3x style:

patch -p1 < upgrader-libs.patch

Also, do not clone a fresh copy of 2.40 becasue it is not useful in this case. Instead, get a copy of your 2.3x version:

svn checkout fresh_23x_path_in_your_computer

Retrieved from ""

This page has been accessed 34,099 times. This page was last modified on 5 July 2017, at 17:30. Content is available under Creative Commons Attribution-ShareAlike 2.5 Spain License.