ERP 2.50:Developers Guide/How To Create a Manual Window
Languages: |
Contents |
Objective
The objective of this howto is to give you a well documented example of how a manual window is developed and the individual elements of the MVC framework it consists of.
To reach the objective a specific example will be used. The requirement we have is a window with a list of products where we can select multiple ones and then change their Product Category to a new one using a button. In other words, we need to batch set the product category of several products at once.
What the Result Should Be
No window like this exists within the core Openbravo ERP and the automatically generated windows do not support custom processing of multiply selected items. Hence, a manual window needs to be developed to support this process.
Let us start with a screenshot of the final window we will develop:
The specs of this window are:
- When this screen is called from the menu, all products should be shown that are shared among all Organizations (Organization = *)
- The filter on the top needs to include the following:
- Business Partner (supplier)
- Organization (that the product belongs to or * if it is shared among all)
- Product Category
- Product Type
- Purchased/Sold/Any
- Once filter parameters are entered, the Search button should be pressed
- Resulting products need to appear in the middle of the window
- Each product needs a check box next to it so that the user can select multiple products that he or she wants to change the product category of
- Once products are selected, the bottom of the screen should offer the list of Product Categories and a Process button
- The final Product Category to set should be selected and the Process button pressed
- Resulting message should be shown to the user
- The usual look and feel of Openbravo screens should be used
Pros
Advantages of manual windows (and generally of manually developed code) are:
- any custom functionality can be developed, there are no limitations
- more advanced user interface can be implemented as opposed to standard windows defined within the application dictionary
Cons
With power and control comes responsibility. Therefore, there are many downsides to manual code that suggest us to avoid manual code at all cost unless really necessary:
- more complex and time consuming to develop
- security must be implemented (which is frequently forgotten) by the developer
- harder to maintain - developer must take full ownership of code which means all bugfixing and upgrading needs to be done manually. Manual code generally does not benefit from Openbravo ERP patches.
Theory of Manual Code
Openbravo ERP framework is based on the MVC (Model-View-Controller) architecture approach. This decouples the three areas of development:
- User Interface - View
- Data Management - Model
- User Actions - Controller
When developing Openbravo ERP code, we should follow this approach which reflects in development of the following files:
- HTML that represents the user interface (part of the View)
- XML that maps dynamic parts of the HTML to the data elements and various runtime parameters (part of the view)
- XSQL that describes all data operations (SELECT, INSERT, UPDATE, DELETE) required by the process (model)
- JAVA controller that ties the data operations with the actions performed on top of the user interface (controller).
Normally, the development is done iteratively in the following sequence:
- Model - describe basic data operations
- View - design the user interface
- Controller - write the java servlet that will pull the two together correctly.
We suggest you develop the code incrementally, i.e. start with very basic UI (no parameters or processing features yet) and only some of the data operations (usually select) and then incrementally add functionality.
As with any new developments starting with version 2.50 and later, these must be part of a module.
More information on manual code can be found here http://wiki.openbravo.com/wiki/ERP/2.50/Developers_Guide/Concepts/UI_Fundamentals .
Implementing the Solution
Since this is one of the most complex topics, the solution files are provided to you here. the following files are included:
- BatchSetProductCategory.html - view
- BatchSetProductCategory.xml - view mapping
- BatchSetProductCategory.java - controller
- BatchSetProductCategory_data.xsql - model
Module
Before we can deploy the solution given, you probably know by now that any new development starting with version 2.50 and later must be part of a module. Please follow the How to create and package a module section to create a new module.
Placing the Code
Before the four solution source files can be saved within Openbravo ERP, the module's structure needs to be created. Create the following structure $OPENBRAVO_HOME/modules/org.openbravo.howtos/src/org/openbravo/howtos/ad_forms/.
This structure derives from:
- the fact that the module's package is org.openbravo.howtos, hence .../modules/org.openbravo.howtos
- the fact that we are developing manual code, hence .../src/...
- the fact the solution's Java file is located inside the org.openbravo.howtos.ad_forms package, hence .../org/openbravo/howtos/ad_forms
Now, put the four source files inside the $OPENBRAVO_HOME/modules/org.openbravo.howtos/src/org/openbravo/howtos/ad_forms/ folder.
Creating a Form inside the Application Dictionary
Now you need to tell Openbravo ERP about the new form (manual window) so use the Application Dictionary || Form window to enter it:
The Form Class and Mapping tabs get entered automatically as soon as you save the header definition of a Form. However, in order to make sure they follow modularity rules, you MUST doublecheck them and correct them accordingly:
Finaly, do not forget to create a new menu item that points to the newly defined Form.
Creating the Custom Messages
Since hardcoding messages into the Java Servlet is a bad practice which also does not allow for translations on top of it, we use Utility.messageBD() method to retrieve the actual messages (or their translation depending on the user language) from the database.
Of course, they need to be entered there first. Use the Application Dictionary || Messages window to enter the following messages:
- HT_NoProductsSelected - shown when the user clicks the SET button but no products are selected
- HT_NoNewProductCategorySelected - shown when the user clicks the SET button but no new product category to be set is selected
- HT_NewProductCategorySetError - shown when the user clicks the SET button and an unexpected error occurs
- HT_NewProductCategorySuccessfullySet - shown when the user clicks the SET and the new product category is successfully set for the selected products
You can use the following texts:
- HT_NoProductsSelected: "You have selected no products!"
- HT_NoNewProductCategorySelected: "No new product category to set has been selected!"
- HT_NewProductCategorySetError: "An unexpected error has occurred during setting the new category to selected products: "
- HT_NewProductCategorySuccessfullySet - " new products were successfully updated with the new product category."
For example, entering a message would be:
Now, enter all the other ones too.
Compiling the application
If using Eclipse, recompilation is not necessary if you have the "Build Automatically" option enabled. One only needs to make sure that the modules/org.openbravo.howtos/src folder is added to the Java Build Path of the main openbravo project.
If using the command line compilation, use the ant smartbuild or ant compile.development -Dtab=xxx to compile the application's manual code.
Restart Tomcat.
Solution Explained
Since all source files are too long to be listed here, we have included lots of comments inside the sample code.
Still, here's a quick overview on what to pay special attention to with individual elements.
Model - BatchSetProductCategory_data.xsql
This file is used to describe all data operations required by the controller (select, update, delete or insert). At compile time, this file is read and a BatchSetProductCategoryData.java class is automatically generated with the static methods that correspond to the ones defined here. By having it in the same package as the controller (see first line , the methods can be directly called from the servlet.
In the future, the DAL (Data Access Layer) should replace the need for this method of performing database operations since it makes the code database dependant (Postgres/Oracle).
See inside of the file for comments on what each individual method does.
View - BatchSetProductCategory.html and BatchSetProductCategory.xml
Openbravo main UI window is structured in the following way:
- two framesets with four frames
- left - loading menu (frameMenuLoading)
- left - menu (frameMenu)
- right - editing (appFrame)
- below - hidden and used for callouts (hiddenFrame)
The editing window (appFrame) is usually divided into 4 main columns in order for the elements such as separators and toolbar to be aligned and another sublevel of 6 for the labels and input boxes to be aligned.
- 1: tdleftTabs – vertical green separator with the button to hide the menu
- 2: tdleftSeparator – separator that makes a nice green round area
- 3: main column that contains the navigation bar, toolbar and all the content and consists of another 4
- 3.1: first column of labels
- 3.2: first column of input boxes
- 3.3: empty spacing column
- 3.4: second column of labels
- 3.5: second column of input boxes
- 3.6: empty spacing column
- 4: tdrightSeparator – right separator
The top of the editing window (3) contains the:
- Navigation bar
- Tool bar (in case of a manual window, this is often an empty one)
See the following article for more details on the UI Fundamentals:
http://wiki.openbravo.com/wiki/ERP/2.50/Developers_Guide/Concepts/UI_Fundamentals
Controller - BatchSetProductCategory.java
- Tree.getMembers() - get the currently selected organization and all its children
- Utility.messageBD() - return the message with the specified key in the language specified. These messages should be part of your module and defined within the Application Dictionary || Messages window.
ComboTableData Class
When dropdowns are required on a manual window, ComboTableData class should be used. Here's a quick syntax overview of the constrctor:
public ComboTableData(VariablesSecureApp _vars, ConnectionProvider _conn, String _referenceType, String _name, String _objectReference, String _validation, String _orgList, String _clientList, int _index) throws Exception
- _vars: usually the vars parsed from the HttpRequest object
- _conn: connection, usually the object itself (this) is passed that also contains the connection
- _referenceType: TABLE, TABLEDIR or LIST
- _name: Mandatory for the TABLEDIR listboxes since the whole logic is built around the field name. Recommended for the TABLE and LIST ones since it makes it easier to understand.
- _objectReference: name or ID of the specific reference used by the TABLE and LIST types. Use “” in case of the TABLEDIR. It is highly recommendable to use ID rather than name. When using name it only looks for references within core, so it will not work if the references is defined in a module. Furthermore, IDs are stable in the time, whether names might change.
- _validation: name or ID of the specific validation that should be applied to the listbox
- _orgList: comma separated list of granted organizations for the user
- _clientList: comma separated list of granted clients for the user
- _index: deprecated, set it to 0
To set _orgList and _clientList, we normally use the getContext() methods of the Utility class.
Utility.getContext(this, vars, "#User_Org", "--WINDOW NAME--");
This method lists all organizations the current user has access to
Utility.getContext(this, vars, "#User_Client", "--WINDOW NAME--");
Lists all clients current user has access to.
Because certain extra parameters might need to be taken from the session (such as field values stored for a validation, eg.C_REGION.C_COUNTRY = @TO_COUNTRY@) and the default selected value needs to be set, we need to use the fillSQLParameters method of the Utility class to set these. The constructor of this class looks like this:
public static void fillSQLParameters(ConnectionProvider conn, VariablesSecureApp vars, FieldProvider data, ComboTableData cmb, String window, String actual_value) throws ServletException {
- conn: connection, usually the object itself (this) is passed that also contains the connection
- vars: usually the vars parsed from the HttpRequest object
- data: a FieldProvider can be passed that would be used to set data for certain parameters; this is usually null for manual use.
- cmb: the ComboTableData object you would like to fill parameters for
- window: the name of the window; this is used mostly by WAD because sometimes the validations use values of other fields and they can be retrieved through the window_name|field_name syntax from the session
- actual_value: the default value that the combo box should take (can even be an item that is not active anymore)
Finally, using the select(false) method of the ComboTableData class, the corresponding HTML is generated that contains all <OPTION /> elements for each item of the listbox and the result is set as the data of the listbox's subreport. For example:
The Result
To test the new manual window, select a few products, the destination product category and hit the Set button:
Completing the Module
Even though the majority of work for a manual window is done by coding the source files, there are a few definitions inside the application dictionary that tell Openbravo ERP exactly of the existence of the sources. These definitions need to be exported from the database to be included with the module.
To export them, use the following command:
ant export.database
Now, the OpenbravoERP/modules/org.openbravo.howtos contains all code required for someone else to install this module and use the new manual window alongside with other developments you might have done as part of that module.