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.
![]() | 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).
- Customization
- 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.
- Upgrade
- 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.
- Migration
- 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:
- 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.
- 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.
- 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.
- 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):
- A 2.40 customized instance to update: including both source files and database. Note that this database will be converted into a 2.50 maintaining the 2.40 customizations. Therefore is highly recommendable to do a backup before starting this process.
- A 2.40 fresh clone. This clone must be exactly the same 2.40 version the customizations were done in. It will be used to be compared with the customized one to detect all customizations. These customizations will be applied in the 2.50 fresh clone.
- A 2.50 fresh clone. This clone contains all the sources to be updated to. It can be any 2.50 version. Note that when the process finishes this directory will be the new updated instance.
- A upgrader clone. Additionally to the previously mentioned, a upgrader source clone it is necessary. It will be able to create the upgrader from the 2.40 version to the 2.50 one.
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 https://code.openbravo.com/erp/stable/2.50/ 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 https://dev.openbravo.com/svn/openbravo/tags/r2.40 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 https://code.openbravo.com/erp/devel/upgrader-2.40_2.50/ upgrader_path_in_your_computer
Once you've downloaded these three groups of files, you need to configure the upgrader.properties file inside the upgrader path (that can be found at upgrader_path_in_your_computer/config/upgrader.properties). You must edit it so it looks like this:
target.path=fresh_250_path_in_your_computer original.path=fresh_240_path_in_your_computer source.path=path_to_your_customized_240_instance checksum.file=checksum.file module.dir=mod
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:
- First, it will build the database upgrader. This upgrader will be located under upgrader_path_in_your_computer/database-upgrader. The next step will be to execute this upgrader.
- Second, it will find the source files you've customized in your customized 2.40 instance, and will copy them to a codeCustomizations folder inside your new 2.50 instance.
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 Openbravo.properties 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 ./setup-properties-yourplatform
(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 openbravo.properties 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 Openbravo.properties 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:
- Openbravo root directory: Contains the standard Openbravo ERP 2.50, without any customization.
- modules/org.openbravo.mycustomization.module: This directory contains all the database customizations that were possible to be extracted as a module.
- modules/org.openbravo.mycustomization.template: This directory contains all the database customizations that were possible to be extracted as a template.
- codeCustomizations: This directory contains all the customizations for source files (not including the database ones that are in the two previously defined directories). These contents is what in previous versions happened to be in srcClient folder, but upgrade process looks for all modified files, regardless they were or were not in srcClient. These contents are split in two sub-directories:
- newCustomization: contains the new objects added by the customer
- coreCustomization: contains all the customizations for the core objects.
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:
# REMOVED TABLES AND COLUMNS IN OPENBRAVO ERP #AD_DEPENDENCIES #AD_DEVELOPER# There are 100 rows in this table #AD_ID_TRANSLATION #AD_PINSTANCE_LOG #A_ASSET_ADDITION #A_ASSET_CHANGE #A_ASSET_CHANGE_AMT #A_ASSET_USE #C_NATION #TEST# There are 2 rows in this table #TIME_DIMENSION ... #AD_REGISTRATION_INFO.OB_DEVELOPMENT #AD_REGISTRATION_INFO.OB_DEVELOPMENT_ANNOUNCE #AD_REGISTRATION_INFO.OB_COMMITS #AD_SYSTEM.TAD_VERSION #AD_SYSTEM.TAD_LEVEL #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:
- Each column that is defined in db structure as primary key and which type is numeric is automatically converted to varchar2(32).
- Each column that is defined in db structure as foreign key and which type is numeric is automatically converted to varchar2(32).
- Also, each physical column that has a corresponding entry in AD_COLUMN table, and which has a reference of type table, tabledir, search, or PAttribute, and is numeric is automatically converted to varchar2(32).
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:
- In the wiki page many changes are proposed to be done using regular expressions. Although doing it in this way can save time, it is also dangerous because it can do modifications that should not do. This is so because regular expressions do not take into account code logic but only character strings, so depending on how objects are named they could not work. Because of this, if the customized number of files is not too big it is recommendable to modify them manually.
- Be specially careful when adapting PL code because the problems in it do not appear in compilation time but in execution. This means that a PL that apparently is correct could have errors that might crash in certain cases.
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:
- Find in PL code the blocks of variable definitions: variables are defined at the beginning of the code or within DECLARE clauses (between DECLARE and BEGIN key words).
- Look for the variables that are used to store values defined in reference values and change their type to VARCHAR2(60). For example a typical change would be
v_Type CHAR(1); to v_Type VARCHAR2(60); - Some tips:
- If the variable is used in a SELECT statement, you can check the type of the column from which the variable takes the data, because the column types are updated by the upgrader.
- In general, variables of type CHAR(1) used to stored boolean values ('Y', 'N') are not necessary to change.
- Some tips:
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.
- frameAplicacion -> appFrame
- frameOculto -> hiddenFrame
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 |
generarArrayChecks | |
menuContextual |
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:
- LNG_POR_DEFECTO -> defaultLang
- baseDirection -> baseDirectory
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:
- HTML template
<script language="JavaScript" type="text/javascript" id="paramLanguage">defaultLang = "en_US";</script>
- XML control file
<PARAMETER id="paramLanguage" name="language" default=""></PARAMETER>
- Java servlet
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:
- For normal windows:
- depurar -> validate
- For selectors:
- depurarSelector -> validateSelector
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
- Main_Edition.css
- Main_Manual.css
- Main_Popup.css
- Main_Relation.css
- Main_Report.css
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
- Openbravo_ERP.css <- It points to the latest version of the CSS. It is used in WAD windows because these windows always are being to be updated.
- Openbravo_ERP_240.css <- If you create a new manual window in 2.40 you have to use this css file. When you upgrade to a newer version you won't have to change this call because in 2.50 there is also a Openbravo_ERP_240.css to maintain backward compatibility.
- Openbravo_ERP_250.css <- If you create a new manual window in 2.50 you have to use this css file. When you upgrade to a newer version you won't have to change this call.
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;" onclick="BBBBBBBB" id="CCCCCCCC"> <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;" id="DDDDDDDD"> <tr> <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> </tr> </table> </a>
Into this one:
<button type="button" id="CCCCCCCC" class="ButtonLink" onclick="BBBBBBBB" 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"> <tr> <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> </tr> </table> </button>
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.
PL/SQL
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:
- Detect the customized core objects in r2.40. This can be done comparing the xml files in src-db/database/model directory from the r2.40 instance with the standard ones in the same version.
- Add these objects to database.
- Do the required modifications to these objects to make they work in r2.50, including UUIDs modifications, reference lists ones and possible adjustments.
- Include these objects in the new module's exceptions. This can be done adding new entries in Application Dictionary > Module > Module > Naming Exceptions. When there are elements in this tab they are exported to the module even if they do not follow the naming rules.
- Export database to ensure they are exported to the module.
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:
- Customer owned components customizations. This type of customization consists on creating new components in order to add new functionalities; for example, a new report that is not in core. This is the kind of customization which can be (more) easily converted into standard modules. They can be found on newCustomization directory.
- Core components customizations. Customizations for core components are modifications in core objects to change their behavior; for example, an standard Openbravo ERP report which is modified in order to show more information. These customizations require more effort to become standard modules. They can be found on coreCustomization directory.
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:
- Ensure your module and template are set as "in development". This can be checked in Application Dictionary > Module.
- Execute ant export.database. This process will export to XML files all database information in modules.
- Execute ant export.config.script. This task will export the configuration script which is used to perform modifications on elements that are outside our module.
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/your.module.java.package. 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:
- Make the directory tree to contain all the custom sources within the module:
mkdir -p modules/org.openbravo.customization.module/src/org/openbravo/customization/module
- Go into that directory
cd modules/org.openbravo.customization.module/src/org/openbravo/customization/module
- Make the directories inside this one, for example SalesOrder2 was in newCustomization/org/openbravo/erpCommon/info directory, although any desired directory is possible to be created it is a good practice to maintain the same structure for the new module, so let's create the info directory:
mkdir info
- Move from the newCustomization/org/openbravo/erpCommon/info the sources for SalesOrder2 to the newly created directory.
- Now edit the Java file (in this case SalesOrder2.java) to adapt it to the new package.
- Change package: at the beginning of the java file change the package declaration:
package org.openbravo.erpCommon.info; -> package org.openbravo.customization.module.info;
- Note that Java classes can make reference without any importation to the rest of classes in its own package, as the Java package for the custom class has changed it will be necessary to explicitly import any of the classes in the old package that is used. For example if our customized SalesOrder2 uses SalesOrderData in the org.openbravo.erpCommon.info package it is necessary to add a line like, in case in our package there's a SalesOrderData it will be necessary to fully qualify the naming for this one in case we want to access it:
import org.openbravo.erpCommon.info.SalesOrderData;
- Change the path to read xml engine templates as they are read in an absolute way:
Look for org/openbravo/erpCommon/info/SalesOrder2 and replace it for org/openbravo/customization/module/info/SalesOrder2
- Now edit xsql files to change their package. xsql files are translated into Java classes and the package they belong to is explicitly declared at the beginning of the file:
look at the beginning of the xsql file for a line like:
<SqlClass name="SalesOrder2Data" package="org.openbravo.erpCommon.info"> and change it for <SqlClass name="SalesOrder2Data" package="org.openbravo.customization.module.info">
- Change the class for that object in application dictionary. To do this open the application and locate your object (if it is a selector it will be in Reference window) and go to the class tab. There change the Java class name to the new one. In our example go to Application Dictionary > Reference > Reference and select Sales Order 2 selector then in Application Dictionary > Reference > Selector Class change Java Class Name field to org.openbravo.customization.module.info.SalesOrder2.
- Change the mapping for all the elements below the class for example: the mapping was /info/SalesOrder2_FS.html now should be /org.openbravo.customization.moduleinfo/SalesOrder2_FS.html. This is done to avoid naming clashes, note that the path should maintain the same directories depth to be possible to maintain the same relative calls.
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.
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.
Database
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:
- Do all the code migrations described in the sections above.
- Execute ant compile.complete. This task will add new entries in the manual text interfaces making the old ones out of use.
- Execute ant -f build-trl.xml. It will recover the old translations.
- 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:
- PeriodicBackground - The threaded/scheduling capabilities of the PeriodicBackground class have been replaced by org.openbravo.scheduling.OBScheduler and its reference to the underlying Quartz Scheduler.
- BackgroundProcess - The interface that background processes needed to implement prior to r2.50 has been replaced by the org.openbravo.scheduling.Process interface, which similarly defines a single method, execute(ProcessBundle bundle). This is main/only change you will need to implement if you have created custom background process which extend from BackgroundProcess.
- PeriodicBackgroundContextListener - this context listener has been replaced by org.openbravo.base.OBSchedulerInitializerListener, which performs similar functionality, but kick starts the Quartz scheduling framework and loads existing background processes that have been scheduled and have not yet finished.
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:
- change the import statement to import org.openbravo.service.db.DalBaseProcess
- change the implements declaration to extends DalBaseProcess
- change the method signature from processPL(PeriodicBackground periodicBG, boolean directProcess) to doExecute(ProcessBundle bundle)
- modify any references to PeriodicBackground variables so they are retrieved from the ProcessBundle parameter of the Process method.
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(); ...
Introduction
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:
- autoCompleteNumber (in 2.50)
- auto_complete_number (in 2.40)
- validateNumberBox
- validateIntegerBox
then these javascript calls must be removed.
Changes for normal html-input widgets
These non dojo numeric input fields need the following attributes added:
- outputformat="<formatName>"
- onfocus="numberInputEvent('onfocus', this);"
- onblur="numberInputEvent('onblur', this);"
- onkeydown="numberInputEvent('onkeydown', this, event);"
- onchange="numberInputEvent('onchange', this);"
In addition any call to one of these javascript methods needs to be removed:
- autoCompleteNumber (in 2.50)
- auto_complete_number (in 2.40)
- validateNumberBox
- validateIntegerBox
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.
- ValidationNumberBox.js
- ValidationIntegerBox.js
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:
- getStringParameter(String) -> getNumericParameter(String)
- getStringParameter(String,String) -> getNumericParameter(String,String)
- getRequiredStringParameter(String) -> getRequiredNumericParameter(String)
- getRequiredStringParameter(String,String) -> getRequiredNumericParameter(String,String)
- getGlobalVariable(String,String,String) -> getNumericRequiredGlobalVariable(String,String,String)
- getRequestGlobalVariable(String,String) -> getNumericRequestGlobalVariable(String,String)
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.
Examples
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
- Create a new list validation reference name Gender and assign it to the column gender.
- Register the table in the application dictionary (Application Dictionary||Tables and Columns|| Table ) and add the columns by clicking the button Create Column from DB.
- Create a new Window named Employee (Application Dictionary || Windows, Tabs,and Fields||Window ) and map the window to the created table.
- Sort the fields in the field sequence according to the field to be displayed in the UI.
- Create a new Menu (General Setup || Application ||Menu||Menu ) and assign the window created to this menu. Drag the menu into the Master Data management tree node.
- After these changes in the application dictionary, compile the Employee window:
ant compile.development -Dtab='Employee'
- And the Employee window looks like.
- Add a Message (Application Dictionary || Message||Message) to the constrain in the application dictionary.
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
- Download a fresh copy of upgrade script from the repository:
cd /home/user/ hg clone https://code.openbravo.com/erp/devel/upgrader-2.40_2.50/ upgrader-2.40_2.50
- Take a fresh copy of Openbravo ERP 2.40 and 2.50:
svn checkout https://dev.openbravo.com/svn/openbravo/tags/r2.40 fresh_2.40 hg clone https://code.openbravo.com/erp/stable/2.50/ fresh_2.50
- Edit the /home/user/upgrader-2.40_2.50/config/upgrader.properties file and point to your source codes:
target.path=/home/user/fresh_2.50 original.path=/home/user/fresh_2.40 source.path=/home/user/OpenbravoERP2.40 checksum.file=checksum.file module.dir=mod
- Launch the upgrader:
cd /home/user/upgrader-2.40_2.50 ant build.upgrader
- After upgrader finished, run the modularization task. The Java package name chosen for the module is org.openbravo.employee.module and the one chosen for the template is org.openbravo.employee.template:
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
- Edit the Openbravo.properties file in the fresh 2.50 and point to the OpenbravoERP2.40 database.
- Build the fresh 2.50 application by running the Ant task:
ant core.lib wad.lib trl.lib compile.complete
- After completing the compilation restart the tomcat and check the UI that newly created table is available in 2.50.
- Now we have to convert some of the code manually.
- Change the data type of column gender for table Employee to varchar(60) using PGAdmin client.
- Change the module name from MyModule to Employee.
- For getting the modules in the file structure run the Ant task:
ant export.database -Dforce=true
- After running the above Ant task we get two modules in the modules folder:
- One is the Employee module.
- The other one is the template module which our case is not used since we have not changed anything from Openbravo core.
- Create the .OBX file using the Ant task:
ant package.module -Dmodule='org.openbravo.employee.module'
- The .OBX file is available in this link
Upgrading a new Field, a new Constraint and a modified Core Column
These are the functionality changes in this example.
- Adding a new Column to the existing table in the database
- Adding Constraint.
- Changing the property of existing Field in the core.
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
- We are customizing in ERP2.40 located in /home/user/OpenbravoERP2.40.
- Add a new column OFF_Hours in 2.40 c_bpartner table.
PostgreSQL code
ALTER TABLE c_bpartner ADD COLUMN OFF_HOURS varchar(50);
- Adding a Constraint
- Add a constraint in c_bpartner,such that if Office Hours are entered then business partner should not be a Employee and vice versa.Hence run this Sql query
PostgreSQL code
ALTER TABLE C_BPARTNER ADD CONSTRAINT CBPARTNER_OFF_HOURS_CHECK CHECK (ISEMPLOYEE = 'N' OR off_hours IS NULL) ;
- Modifying the Existing Field
- Select the Business Partner window(Application Dictionary || Windows, Tabs,and Fields || Window ) and change the field Tax id in the table 'c_bpartner.
Displayed Length=30.
And also change the size of the column Taxid in the database
size=40
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
- Download a fresh copy of upgrade script from the repository:
cd /home/user/ hg clone https://code.openbravo.com/erp/devel/upgrader-2.40_2.50/ upgrader-2.40_2.50
- Take a fresh copy of Openbravo ERP 2.40 and 2.50:
svn checkout https://dev.openbravo.com/svn/openbravo/tags/r2.40 fresh_2.40 hg clone https://code.openbravo.com/erp/stable/2.50/ fresh_2.50
- Edit the /home/user/upgrader-2.40_2.50/config/upgrader.properties file and point to your source codes:
target.path=/home/user/fresh_2.50 original.path=/home/user/fresh_2.40 source.path=/home/user/OpenbravoERP2.40 checksum.file=checksum.file module.dir=mod
- Launch the upgrader:
cd /home/user/upgrader-2.40_2.50 ant build.upgrader
- After upgrader finished, run the modularization task. The Java package name chosen for the module is org.openbravo.samplefield.module and the one chosen for the template is org.openbravo.samplefield.template:
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
- Edit the Openbravo.properties file in the fresh 2.50 and point to the OpenbravoERP2.40 database.
- Build the fresh 2.50 application by running the Ant task:
ant core.lib wad.lib trl.lib compile.complete
- After completing the compilation restart the tomcat and check the UI that newly created table is available in 2.50.
- Now we have to convert some of the code manually.
- Change the module name from "MyModule" to "Sample Field".
- Change the template name from "MyTemplate" to "Sample Field Template"
- For getting the modules in the file structure run the Ant task:
ant export.database export.config.script -Dforce=true
- After running the above Ant task we get two modules in the modules folder:
- One is the Sample Field module.
- The other one is the Sample Field Template module which contains the Openbravo core changes.Thats the change in the size and display length of the column 'Taxid' will be noted in this file "configScript.xml".
- Create the .OBX file using the Ant task
ant package.module -Dmodule='org.openbravo.samplefield.module' ant package.module -Dmodule='org.openbravo.samplefield.template'
- The .OBX file is available in this link.Both the module and the 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.
- When we type "Discounts" in the Name field of Product window, the Product Category dropdown is set to "Discounts" and displays a message that "Product Category - Discounts is selected" on the top of the window.
- And also the text we entered in Name field is copied to Description field.
The output of our customized callout will look like as shown below,
The code for new customized callout( Product_Discount_Callout.java ) 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 java.io.IOException; import java.io.PrintWriter; 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) { super.init(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) { pageErrorCallOut(response); } } else pageError(response); } private void printPage(HttpServletResponse response, VariablesSecureApp vars, String strProductName, String strProductCategoryId) throws IOException, ServletException { log4j.debug("Output: dataSheet"); XmlDocument xmlDocument = xmlEngine.readXmlTemplate( "org/openbravo/erpCommon/ad_callouts/CallOut").createXmlDocument(); 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()) + "\")"); } result.append(");"); // inject the generated code xmlDocument.setParameter("array", result.toString()); xmlDocument.setParameter("frameName", "frameAplicacion"); response.setContentType("text/html; charset=UTF-8"); PrintWriter out = response.getWriter(); out.println(xmlDocument.print()); out.close(); } }
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:
- Download a fresh copy of upgrade script from the repository:
cd /home/user/ hg clone https://code.openbravo.com/erp/devel/upgrader-2.40_2.50/ upgrader-2.40_2.50
- Take a fresh copy of Openbravo ERP 2.40 and 2.50:
svn checkout https://dev.openbravo.com/svn/openbravo/tags/r2.40 fresh_2.40 hg clone https://code.openbravo.com/erp/stable/2.50/ fresh_2.50
- Edit the /home/user/upgrader-2.40_2.50/config/upgrader.properties file and point to your source codes:
target.path=/home/user/fresh_2.50 original.path=/home/user/fresh_2.40 source.path=/home/user/OpenbravoERP2.40 checksum.file=checksum.file module.dir=mod
- Launch the upgrader:
cd /home/user/upgrader-2.40_2.50 ant build.upgrader
- After upgrader finished, run the modularization task. The Java package name chosen for the module is org.openbravo.mycallout.module and the one chosen for the template is org.openbravo.mycallout.template:
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
- Edit the Openbravo.properties file in the fresh_2.50 such that the database points to the OpenbravoERP2.40 and set validate.model as false.
- Build the fresh_2.50 application by running the following Ant task.
ant core.lib wad.lib trl.lib compile.complete
- After completing the compilation restart the tomcat and start the application.
- Ensure your module and template are set as in development. This can be checked in Application Dictionary > Module.
- To export all database informations in modules into XML files run the following Ant task.
ant export.database -Dforce=true
- To export the configuration script which is used to perform modifications on elements that are outside our module, run the following Ant task.
ant export.config.script -Dforce=true
Refactoring the obtained module
After upgrading to 2.50 the file system will look like:
- Openbravo root directory: Contains the standard Openbravo ERP 2.50, without any customization.
- modules/org.openbravo.mycallout.module: This directory contains all the database customizations that were possible to be extracted as a module.
- modules/org.openbravo.mycallout.template: This directory contains all the database customizations that were possible to be extracted as a template.
- codeCustomizations: This directory contains all the customizations for source files (not including the database ones that are in the two previously defined directories). These contents is what in previous versions happened to be in srcClient folder, but upgrade process looks for all modified files, regardless they were or were not in srcClient. These contents are split in two sub-directories:
- newCustomization: contains the new objects added by the customer
- coreCustomization: contains all the customizations for the core objects.
The steps for code refactoring are given below.
- create a directory structure /src/org/openbravo/mycallout/module/ad_callouts in the /modules/org.openbravo.mycallout.module directory
- copy the callout java servlet file which is available in newCustomization directory into newly created directory( /src/org/openbravo/mycallout/module/ad_callouts ).
- change the package declaration at the beginning of java file ( Product_Discount_Callout.java ) such that
package org.openbravo.erpCommon.ad_callouts; --> package org.openbravo.mycallout.module.ad_callouts;
- configure project build path to include /modules/org.openbravo.mycallout.module/src directory.
- modify AD_MODEL_OBJECT.xml file such that the classname tag should have modified package declartion.
- modify Java Class Name field in Callout Class Tab ( Application Dictionary || Setup || Callout || Callout Class ) such that it reflects the modified package name.
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
- Add a new Field in the Jrxml.
- Add a new Field to the existing Report Filter Window
- We are customizing in ERP2.40 located in /home/user/OpenbravoERP2.40.
- The fields are added in the report 'Sales Order Report' (Sales Management || Analysis Tools || Sales Order Report || Sales Order Report)
- Add a Document No field to filter window ,such that the result will also be filter by Document No.Make this field as mandatory.
- Change the location of the Currency Field.
Hence the report filter window will look like this.
- In the Report window ,add a field Address(client contact address).The report 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
- Download a fresh copy of upgrade script from the repository:
cd /home/user/ hg clone https://code.openbravo.com/erp/devel/upgrader-2.40_2.50/ upgrader-2.40_2.50
- Take a fresh copy of Openbravo ERP 2.40 and 2.50:
svn checkout https://dev.openbravo.com/svn/openbravo/tags/r2.40 fresh_2.40 hg clone https://code.openbravo.com/erp/stable/2.50/ fresh_2.50
- Edit the /home/user/upgrader-2.40_2.50/config/upgrader.properties file and point to your source codes:
target.path=/home/user/fresh_2.50 original.path=/home/user/fresh_2.40 source.path=/home/user/OpenbravoERP2.40 checksum.file=checksum.file module.dir=mod
- Launch the upgrader:
cd /home/user/upgrader-2.40_2.50 ant build.upgrader
- The above task copies all the modified src file from 2.40 to 2.50 in to the folder codeCustomizations.
- Since the above modified files are in core it will copied under the folder struture (OpenbravoERP2.50/codeCustomizations/coreCustomization)
- After upgrader finished, run the modularization task. The Java package name chosen for the module is org.openbravo.samplereport.module and the one chosen for the template is org.openbravo.samplereport.template:
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
- Edit the Openbravo.properties file in the fresh 2.50 and point to the OpenbravoERP2.40 database.
- Create a module struture src/org/openbravo/salesorder/ad_reports inside the module folder 'org.openbravo.samplereport.module' and copy all the files from codeCustomizations (codeCustomizations/coreCustomization) folder in to module folder.
- Now we have to change some of the code manually.
- These are the changes to be in 2.50 source files.
XSQL
- There are some changes need to be done in OrderEdition_data.xsql
- Remove all TO_NUMBER.
- Change the currency symbol function
C_CURRENCY_SYMBOL(TO_NUMBER(?)) to C_CURRENCY_SYMBOL(?, '0','Y')
Java
- There are some changes need to be done in ReportSalesOrderJR.java
2.40
xmlDocument.setParameter("language", "LNG_POR_DEFECTO=\""+vars.getLanguage()+"\";"); xmlDocument.setParameter("direction", "var baseDirection = \"" + strReplaceWith + "/\";\n");
to
2.50
xmlDocument.setParameter("language", "defaultLang=\""+vars.getLanguage()+"\";"); xmlDocument.setParameter("directory", "var baseDirectory = \ ""+strReplaceWith + "/\";\n");
- Java Code may be pointing some methods which are out of your module (mainly xsql methods)
- Example Since their is no changes in ReportProjectBuildingSite_Data.xsql,this file is not included in the coreCustomization.But ReportProjectBuildingSiteData.java are included in ReportSalesOrderJR.java.Hence change this file according to 2.50 code base.
2.40
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",SubCategoryProductData.select(this, Utility.getContext(this, vars, "#AccessibleOrgTree", ""), Utility.getContext(this, vars, "#User_Client", "")));
to
2.50
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", ""), "")); try{ 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", ""); xmlDocument.setData("reportC_PRODUCTCATREGORY","liststructure",comboTableData .select(false)); }catch(Exception ex){ throw new ServletException(ex); }
- Change the path of the xml document ,jrxml file.
2.40
xmlDocument = xmlEngine.readXmlTemplate("org/openbravo/erpCommon/ad_reports/ReportSalesOrderFilterJR").createXmlDocument(); String strReportName = "@basedesign@/org/openbravo/erpCommon/ad_reports/ReportSalesOrderJR.jrxml";
to
2.50
xmlDocument = xmlEngine.readXmlTemplate("org/openbravo/salesorder/ad_reports/ReportSalesOrderFilterJR").createXmlDocument(); String strReportName = "@basedesign@/org/openbravo/salesorder/ad_reports/ReportSalesOrderJR.jrxml";
HTML
- There are some changes need to be done in ReportSalesOrderFilterJR.html
- Change the variable baseDirection to baseDirectory and also the ID of the script from paramDirection to ParamDirectory.
2.40
<script language="JavaScript" type="text/javascript" id="paramDirection"> var baseDirection = "../../../../../web/"; </script>
to
2.50
<script language="JavaScript" type="text/javascript" id="paramDirectory"> var baseDirectory = "../../../../../web/"; </script>
- Change the source directory of the javascript form MessagesJS.js to DynamicJS.js
2.40
<script language="JavaScript" src="../utility/MessagesJS.js" type="text/javascript"></script>
to
2.50
<script language="JavaScript" src="../utility/DynamicJS.js" type="text/javascript"></script>
- Change the variable LNG_POR_DEFECTO to defaultLang
2.40
<script language="JavaScript" type="text/javascript" id="paramLanguage"> var LNG_POR_DEFECTO = "en_US"; </script>
to
2.50
<script language="JavaScript" type="text/javascript" id="paramLanguage"> var defaultLang = "en_US"; </script>
- Change these Javascript functions
depurar to validate , mensaje to showJSMessage seleccionarListCompleto to markCheckedAllElements eliminarElementosList to clearSelectedElements limpiarLista to clearList
- Change the button pattern
2.40
<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;"> <TR> <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> </TR> </TABLE> </a>
to
2.50
<button type="button" id="buttonHTML" class="ButtonLink" 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"> <tr> <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> </tr> </table> </button>
XML
- There are some changes need to be done in ReportSalesOrderFilterJR.xml
- Change the id for the parameter paramDirection to paramDirectory.
2.40
<PARAMETER id="paramDirection" name="direction" default=""/>
to
2.50
<PARAMETER id="paramDirectory" name="directory" default=""/>
- Build the modified 2.50 application by running the Ant task:
ant core.lib wad.lib trl.lib compile.complete
- After completing the compilation restart the tomcat.
- Point the Sales Order Report (Sales Management || Analysis Tools || Sales Order Report || Sales Order Report) tree node towards the module.This can be done by following changes.
- Select Sales Order Report from Report and Process(Application Dictionary || Report and Process || Report & Process ) and change the java package name of the report to org.openbravo.salesorder.ad_reports.ReportSalesOrderJR.
- Change the module name from "MyModule" to "Sample Report".
- Change the template name from "MyTemplate" to "Sample Report Template"
- After the above changes run the Ant task,
ant compile.development -Dmodule='org.openbravo.samplereport.module'
- For getting the modules in the file structure run the Ant task.While running the task make sure core is not InDevelopment :
ant export.database export.config.script -Dforce=true
- After running the above Ant task we get two modules in the modules folder:
- One is the Sample Report module.
- The other one is the Sample Report Template module which contains the Openbravo core changes.Thats the changes in the java package name will be noted in this file "configScript.xml".
- Create the .OBX file using the Ant task
ant package.module -Dmodule='org.openbravo.samplereport.module' ant package.module -Dmodule='org.openbravo.samplereport.template'
- The .OBX file is available in this link.Both the module and the 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 https://dev.openbravo.com/svn/openbravo/tags/r2.35mpx fresh_23x_path_in_your_computer