Creating Charts in Openbravo Reports

Reporting is a decisive factor that determines the reach of an ERP among the Users. OpenbravoERP in particular have laid a lot of emphasis on the reporting structures. iReport is the tool officially supported by Openbravo for generating reports within Openbravo.

iReport is an opensource java based reporting tool. iReport provides lots of features like sub-reports,crosstab references, and various presentation gadgets like charts, bar graph, plotted line, etc. I have provided the steps for creating charts in reports in Openbravo.For basic on developing reports in iReport, refer here. You can download iReport here.

Lets see an example. I have 10 product categories and 500 products. I want to see which products fall under which category and how much is the stock available. Lets see how this could look.

 If you have not worked in iReports before, you can take a look at this. You can download iReport here. To add a chart to a window, use the chart tool icon in the interface. A screen shot of where it is located is provided below:

Once you have added the chart, you can access the chart properties as provided in the below screen shot.

In the chart properties, go to chart data -> details. Here you can add the categories based upon which you want the data. Here I have added the category as product Category and the series values in terms of the products in that particular category. Here the following key points to be noted are:

1. Series Expression:

This represents the bars that appears on the chart. Here we want all the products with the count. so we choose the products here

2. Category Expression:

This represents the  x-axis. Here the product category is our base and we provide that here.

3. Value Expression:

Value is nothing but the quantity that determines the height of the bars in the report. Here we are providing the count of each product.

4. Label Expression (optional) :

This provides the additional information about the bars in the chart that is provided under the chart. If its left empty, the name from the value expression will be pulled up.

Once all this is done, refer to the steps to import the same in the Openbravo Application and if you run the report, you will get the following output.

Having presented all this, generating reports in this format is really helpful. However Openbravo has now become the agile, tamed ERP…:). There is a new and powerful feature widgets.

Understanding OBDal in Openbravo

OBDal is an extensively used class in Openbravo. If offers lots of useful functions to enable external access to the Data Access Layer. OBDal provides the basic functions like insert,save,remove, etc. OBDal forms the base for the Data Access Layer(DAL) in Openbravo.

DAL Architecture

Though there are lots of useful functions in OBDal, we often use only few basic functions like save, remove, etc. Lets see the use of  the methods in OBDal and its usage.

1. void commitAndClose():

This function commits the transaction and closes the transaction. It will not only commit the current transaction but all the pending transactions. However, having more than one open transactions at a time is not advisable. There are few reasons why we should not have more than one open transactions. One of the reason is, if one of the open transactions failed to commit, all the pending transactions will be rolled back. This can be used in the code as follows.

OBDal.getInstance().commitAndClose();

There may be situations where we still need the transaction but just commit it. But when we use this method, it will not only commit but also closes the transaction. In this scenario, we can make use of the class SessionHandler( This class is exclusively for maintaining hibernate session for transactions). This class has a method commitAndStart(). This method will commit the transaction and starts a new session. This can be used in the code as follows.

SessionHandler.getInstance().commitAndStart();

2. void rollbackAndClose()

This method is used to rollback the transaction. Similar to commitAndClose() Method, this method will rollback all the open transactions.

OBDal.getInstance().rollbackAndClose();

The SessionHandler has a method rollback() which can be used when we don’t want to close the session but rollback the transaction.

SessionHandler.getInstance().rollback();

The SessionHandler class has two other methods that enables us to mark the transactions that needs to be rolled back. This can be done using the method, void setDoRollback(boolean). If the argument is true, then the transaction will be marked for rollback and if it is false, the transaction will not be marked for rollback. The other method is boolean getDoRollback() which will return whether the transaction is marked for rollback or not.

 SessionHandler.getInstance().setDoRollback(true);
 SessionHandler.getInstance().getDoRollback();

3. void disableActiveFilter() and void enableActiveFilter()

By default, the active filters will be enabled. Consider the line below.

Client clientList = OBDal.getInstance().get(Client.class,null); //Client is the class which we are referring and null denotes there is no filter

This will return all the records in ad_client  table that are active. We can disable this by using the method disableActiveFilter(). After disabling, the above line will return all the records irrespective of either the record is active or not. enableActiveFilter() is used to enable the filter. This methods can be used as follows.

OBDal.getInstance().disableActiveFilter();
 OBQuery<Client> clientList = OBDal.getInstance().createQuery(Client.class,null);
 for(Client client : clientList.list()) {
 //Processing
 }
 OBDal.getIstance().enableActiveFilter();

4. boolean isActiveFilterEnabled()

This method is used to verify whether the active filter is enabled or not. At any point of time, the active filter can be enabled and disabled and this method is useful to verify the status.

if(OBDal.getInstance().isActiveFilterEnabled()) {
 OBDal.getInstance().disableActiveFilter();
 }

5. boolean exists(String entityName, Object id)

This method is used to check whether a particular record exists in the database.

 OBDal.getInstance().exists(ADClient.ENTITY_NAME,"0");//ADClient is the entity name for Client Class and "0" refers to ad_client_id

To understand the use of this method, consider the code below.

Client clientList = OBDal.getInstance().get(Client.class,"45");
 try {
 String name = clientList.getName();
 } catch(Exception e) {
 log.info(e.getMessage());
 }

In the above code, if the record with ad_client_id = “45” doesn’t exists, it will throw java.lang.NullPointerException since we are trying to access the value(clientList.getName()). To avoid this, we can use exists() method as follows.

Client clientList = OBDal.getInstance().get(Client.class,"45");
 if(clientList.getInstance().exists(ADClient,"45"))  {
 try {
 String name = clientList.getName();
 } catch(Exception e) {
 log.info(e.getMessage());
 }

The above code will be executed only if the record is present in the database.

6. String getReadableClientsInClause() & String getReadableOrganizationsInClause()

This method returns an in-clause string of the clients that are readable by the current user. The In-Clause String looks like (“0″,”1000000″). This method is useful in many scenarios. Below is one such scenario.

While retrieving the records using OBDal, it will automatically take care of the security. However, when we use HQL Queries, we need to take care of the security. In order to retrieve the client and organization readable by the user, we can use this method.

For example,

String hql = "SELECT name  "
 +"FROM ADRole r"
 +"WHERE r.organization IN "+OBDal.getInstance().getReadableOrganizationsInClause()
 +" AND r.client IN "+OBDal.getInstance().getReadableClientsInClause()
 +" AND r.active=true ";
 Query query = OBDal.getInstance().getSession().createQuery(hql);

This query will return the name of the roles that are readable for the current user.

These are few methods that I felt important in OBDal that would ease development using DAL. For details on how to write DAL code, refer ([1] and  [2]).

Resolving runtime model error in Openbravo

Whenever we refer columns in Openbravo using foreign key  references, the Application reference for the same will be  mapped as TableDir by default. This will be set when we provide create columns from DB. This is a small but effective value-add provided by Openbravo for developers. It reduces our work by a fair share. But as with all systems, there is a small downside to it. First let us see how they map the reference ‘TableDir’ to the column. When we run the Create Columns from DB process, the process checks for the column name, if the column name ends with ‘id’, it will map that as ‘TableDir’. For more information on references, refer here.  For eg, if a column name is ad_client_id, it would be mapped to TableDir by default. But the downside is, even if my column is ‘paid’, it sets it as TableDir.

We will not realize this, until we compile. When we compile, we get the following error, “Reference column for paid not found in runtime model“.  To resolve this issue, we have to change the reference type of the Column from TableDir to the corresponding reference (String or Number) and recompile.

One more issue that we face commonly while compiling is, “Referenced property is null for tablename.field“, where tablename is the name of the particular table and the field is the name of the field. The problem with this columns is, in Tables and Columns in Application Dictionary, for this particular column ‘Link to Parent Column’ will be checked. But as in our example, the column paid is a String field and not linked to any table or column that is already present, that is the reason why the error shows, referenced property is null. To resolve this, deselect the ‘Link to parent Column’ check box in the Column Window. I have attached a screen shot below to show where to deselect ‘Link to parent column’ property and also how reference are mapped.

Tree Structure for Custom Windows in Openbravo

Generating Tree Structure is a great innovative feature that is present in OpenbravoERP. If you are wondering what it looks like, refer to Organization window in the Client Mode or the Menu Window in System Admin mode. There will be an icon called Tree in the Toolbar. Click on that and you will see something similar to the screen shot below.For more information, refer here.

This functionality will find its use in most places where there is a hierarchy to be shown and segregations are to be visualized. One more appreciable feature is that you can drag and drop the items and rearrange it. Doesn’t it sound really cool to you? I was really excited to test this out for the custom windows and with the help of Wiki, Forge and of course my colleague, I was able to create a tree similar to the one shown above for a custom window called ‘Department’. I have attached a screen shot of my tree below.

This feature is really helpful in lot of cases. I have shared the sequence of steps that I followed that enabled me to create such a structure. We have categorized the steps that we performed into 3 sections:

1. Database changes

2. Changes to be done in the Application

3. Changes to be done in code

1. Database Changes

  • Create a new table for the department. Eg: XYZ_department.

The following are the key fields in the table.

        "value" character varying(40) NOT NULL,
        "name" character varying(60) NOT NULL,
        description character varying(255),
        issummary character(1) NOT NULL DEFAULT 'N'::bpchar,
  •  Create a new table for storing the tree nodes. Eg: XYZ_treenodedp (Structure similar to ad_treenode table)
  • Add logic in the Department Table Trigger to insert values in XYZ_treenodedp and the corresponding delete logic also. Refer Organisation table trigger for more information.
  • Add a new column in ad_clientinfo. Eg: em_XYZ_tree_department

2. Changes to be done in the Application

  • Create Window for the Department. Set the field ‘Tree Included’ to Yes in Fields Tab. Eg: In Department window
  • Import the  corresponding column created in ad_clientinfo table into the Application.
  • Add a new entry in the list reference ad_treetype. Eg: Search key: XYZ_DP Name: Department
  • Create a new entry in Tree and Node Image window both in System administrator and desired client admin. Eg. Name: Primary Department Tree type: Department in System Administrator and Name: F&B International Admin Department Tree Type: Department in F&B International Admin.

  • Update and set the value for the em_XYZ_tree_department field as the client’s tree entry. Eg: In F&B International Admin, Set the value as ‘F&B International Admin Department.

PrimaryDepartment

3. Changes to be done in code

  • In WindowTreeUtility.java, add the following lines in checkSpecificChanges() Method.
else if (TreeType.equals("XYZ_DP")) { //Department
 result = "";
 }

  • In WindowTreeUtility.java, add the following lines in getTreeType() Method.

else if (keyColumnName.equals("XYZ_Department_ID"))
 TreeType = "XYZ_DP";

  •  In WindowTreeUtility.java, add the following lines in getTree() Method.

else if (TreeType.equals("XYZ_DP"))
 data = WindowTreeData.selectDepartment(conn, vars.getUser(), strEditable, strParentID,  strNodeId, TreeID);

1

else if (TreeType.equals("XYZ_DP"))
 WindowTreeData.updateDP(conn, vars.getUser(), strParentID, strSeqNo, TreeID, strLink);

  •  In WindowTree_data.xsql, add two new sql methods to select and update the tree nodes.

<SqlMethod name="updateDP" type="preparedStatement" return="rowCount">
 <SqlMethodComment></SqlMethodComment>
 <Sql>
 UPDATE XYZ_TREENODEDP SET UPDATED=now(), UPDATEDBY = ?,                 PARENT_id = ?, SEQNO=TO_NUMBER(?)   WHERE AD_TREE_ID = ?
 AND NODE_ID = ?
 </Sql>
 <Parameter name="updatedby"/>
 <Parameter name="parentId"/>
 <Parameter name="seqno"/>
 <Parameter name="adTreeId"/>
 <Parameter name="nodeId"/>
 </SqlMethod>

<SqlMethod name="selectDepartment" type="preparedStatement" return="multiple">
 <SqlMethodComment></SqlMethodComment>
 <Sql>
 SELECT tn.Node_ID,tn.Parent_ID,tn.SeqNo,                             m.XYZ_Department_ID AS ID, m.Name,m.Description,m.IsSummary
 FROM XYZ_TreeNodedp tn,
 XYZ_Department m
 WHERE tn.Node_ID = m.XYZ_Department_ID
 AND tn.AD_Tree_ID = ?
 ORDER BY COALESCE(tn.Parent_ID, '-1'), tn.SeqNo
 </Sql>
 <Parameter name="editable" optional="true" type="none" after="WHERE "                 text="tn.IsActive='Y' AND m.isActive='Y' AND "/>
 <Parameter name="parentId" optional="true" after="WHERE " text="tn.Parent_ID = ?             AND "/>
 <Parameter name="nodeId" optional="true" after="WHERE " text="tn.Node_ID = ?             AND "/>
 <Parameter name="adTreeId"/>
 </SqlMethod>

Import Loader Process For Custom Modules

Hi All,

The import loader process is used to load data into the openbravo windows from input files. Openbravo has provided the options to load product, business partner, etc., Now we have the option of creating import process for our own modules with a simple java file (Refer here). Right now this process reads data from csv file(The Input format is parsed using the file IdlServiceJava.java file). This can also be extended to read input from other formats by creating a service file similar to IdlServiceJava. The only catch here is that to try this out you need the Professional Subscription, after all not everything comes free in life…:).  I installed the modules, Initial Data Load and Initial Data Load Extension for Java. I used the sample import process that comes along with initial data load extension module and created a new import process for the window frequency.

Here are the steps which I followed.

1. Creating the Java Process file

 package com.fugoconsulting.xyzz.module.template.erpCommon.ad_process;

import org.openbravo.idl.proc.Parameter;
 import org.openbravo.idl.proc.Validator;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 import java.text.ParseException;
 import java.math.BigDecimal;
 import java.util.Date;
 import org.apache.log4j.*;

import org.openbravo.base.exception.OBException;
 import org.openbravo.base.provider.OBProvider;
 import org.openbravo.base.structure.BaseOBObject;
 import org.openbravo.dal.service.OBDal;
 import org.openbravo.erpCommon.utility.Utility;
 import org.openbravo.idl.proc.Value;
 import org.openbravo.module.idljava.proc.IdlServiceJava;
 import com.fugoconsulting.xyzz.module.template.XYZZFrequency;

/**
 *
 * @author Pandeeswari
 */
 public class ImportFrequency extends IdlServiceJava {

private static Logger log=Logger.getLogger(ImportFrequency.class);
 DateFormat df = new SimpleDateFormat("dd-MM-yyyy");

@Override
 public String getEntityName() {
 return "Simple Frequency";
 }

@Override
 public Parameter[] getParameters() {
 return new Parameter[] {
 new Parameter("Organization", Parameter.STRING),
 new Parameter("SearchKey", Parameter.STRING),
 new Parameter("Name", Parameter.STRING),
 new Parameter("Description", Parameter.STRING),
 new Parameter("Factor", Parameter.STRING),
 new Parameter("Date", Parameter.STRING) };
 }

@Override
 protected Object[] validateProcess(Validator validator, String... values) throws Exception {
 validator.checkOrganization(values[0]);
 validator.checkNotNull(validator.checkString(values[1], 40), "SearchKey");
 validator.checkNotNull(validator.checkString(values[2], 60), "Name");
 validator.checkString(values[3], 255);
 validator.checkBigDecimal(values[4]);
 validator.checkDate(values[5]);
 return values;
 }

@Override
 public BaseOBObject internalProcess(Object... values) throws Exception {

return createFrequency((String) values[0], (String) values[1], (String) values[2],
 (String) values[3], (String) values[4], (String) values[5]);
 }

public BaseOBObject createFrequency(final String Organization, final String searchkey,
 final String name, final String description, final String factor,
 final String aDate)
 throws Exception {

// Frequency
 XYZZFrequency frequencyExist = findDALInstance(false, XYZZFrequency.class, new Value("searchKey", searchkey));
 if (frequencyExist != null) {
 throw new OBException(Utility.messageBD(conn, "XYZZ_FREQ_EXISTS", vars.getLanguage())
 + searchkey);
 }
 XYZZFrequency frequency = OBProvider.getInstance().get(XYZZFrequency.class);

try {
 frequency.setActive(true);
 frequency.setOrganization(rowOrganization);
 frequency.setSearchKey(searchkey);
 frequency.setName(name);
 frequency.setDescription(description);
 frequency.setFactor(new BigDecimal(factor));
 // Date date = df.parse(aDate);
 Date  date = new Date();
 frequency.setDate(date);

OBDal.getInstance().save(frequency);
 OBDal.getInstance().flush();
 } catch (Exception e) {
 e.printStackTrace();
 }

// End process
 OBDal.getInstance().commitAndClose();

return frequency;
 }
 }

I have created the Java File inside modules/mymodule/erpCommon/ad_process. You can place it where ever you want but just be careful to provide the proper Java package name.

Inside the getParameters() method, we provide the columns in the same order as it is in the input file. But the parameter names used in the method need not be the same.

The createFrequency() just inserts the value into the table using OBProvider.  The internalProcess(Object… values) Method which is inherited from IdlServiceJava class is used to call the appropriate method with appropriate parameters.

2. Register the file in entity default value

Register the Entity in Master Data Management -> Initial Data Load  -> Setup  -> Entity Default Value

Make Special note on the class name while adding the entity default value.

3. Import the data using import window

  • Go to Master Data Management -> Initial Data Load -> Process -> Import
  • Choose the input file
  • Choose the entity as Frequency

  • Give Validate
  • Once the input values are validated, the data can be loaded into the actual table by giving process.

  • If there occurs any problem with the input data, it will be logged in the boxes provided in the import screen.

Database Development Perspective in Eclipse for Openbravo,Postgres

Eclipse IDE is a great tool for Development and specially for development for an ERP like Openbravo. For setting up Openbravo in Eclipse refer here. Also Eclipse Provides many plug ins that could make the development even easier. There are many perspectives provided in Eclipse. (Refer Screen shot below)

Lets see about the Database Development Perspective in this Blog. Database Development Perspective allows us to connect to database directly, export data as files, import data, query, etc…

To connect your Openbravo postgresql database, these are the steps to be performed.

1. Choose Database Development from the available list of perspectives.

2. Create a new Connection and connect the driver to database. Refer the following screen shots.

3. In the Driver definition, choose your host and database name, the database field can be anything (column1), it does not matter. Its just the name that will show in Eclipse.

4. Once this is done, your eclipse will be as below.

Under Schemas, you will have public that will have the tables and functions.

Now you are connected to your database and you can query, or use the other options as I have shown in the screen shot below.

Happy Working..:)

Radio Button Reference for Openbravo

Last month I happened to see this issue, https://forge.openbravo.com/plugins/espforum/view.php?group_id=100&forumid=549512&topicid=7022038 accidentally, and I was more inclined about the solution model. Radio buttons are very common and are quite useful, but its surprising to note that it has not found its place in Openbravo. I felt Radio Button can be used in many places and that it should be part of the standard Reference Types. I could not get more in to it at that time, but couple of days ago got some time out of work and got a chance to give it a shot. I took the Yes/No Reference type as the base and remodelled the html file (WADYesNo.html) alone and then I was able to create a radio buttons out of it. I thought to contribute it to the community as a small dedication to the great work that is being in progress.

Feel free to buzz me at shankar@fugoconsulting.com. I would be glad to help the community and contribute in a small way that I can. I have also been trying to write some blogs about the basic issues that we face in Openbravo ERP. You can look at those at http://fugoconsulting.wordpress.com/category/openbravo/.

Solution Model:

The following are the sequence of files that I changed for the solution. All these are not needed to bring out a basic Radio Button especially  the skin images. But I have provided it as reference to the sequence of files to be added for a new reference type.

In src-wad/src/org/openbravo/wad/controls add the following files:

  • WADRadioButton.java
/*
 @author: Shankar Balachandran
*/
package org.openbravo.wad.controls;

import java.util.Properties;

import org.openbravo.xmlEngine.XmlDocument;

public class WADRadioButton extends WADControl {

 public WADRadioButton() {
 }

 public WADRadioButton(Properties prop) {
 setInfo(prop);
 initialize();
 }

 public void initialize() {
 generateJSCode();
 }

 private void generateJSCode() {
 setValidation("");
 setCalloutJS();
 }

 public String getType() {
 return "Radio_Check";
 }

 public String editMode() {
 XmlDocument xmlDocument = getReportEngine().readXmlTemplate(
 "org/openbravo/wad/controls/WADRadioButton").createXmlDocument();

 xmlDocument.setParameter("columnName", getData("ColumnName"));
 xmlDocument.setParameter("columnNameInp", getData("ColumnNameInp"));

 if (getData("IsReadOnly").equals("Y") || getData("IsReadOnlyTab").equals("Y")
 || getData("IsUpdateable").equals("N")) {
 xmlDocument.setParameter("disabled", "Y");
 xmlDocument.setParameter("logChanges", "");
 xmlDocument.setParameter("disabledFalse", "return false;");
 } else {
 xmlDocument.setParameter("disabled", "N");
 xmlDocument.setParameter("callout", getOnChangeCode());
 }
 if (getData("IsMandatory").equals("Y"))
 xmlDocument.setParameter("required", "true");
 else
 xmlDocument.setParameter("required", "false");

 return replaceHTML(xmlDocument.print());
 }

 public String newMode() {
 XmlDocument xmlDocument = getReportEngine().readXmlTemplate(
 "org/openbravo/wad/controls/WADRadioButton").createXmlDocument();

 xmlDocument.setParameter("columnName", getData("ColumnName"));
 xmlDocument.setParameter("columnNameInp", getData("ColumnNameInp"));

 if (getData("IsReadOnly").equals("Y") || getData("IsReadOnlyTab").equals("Y")) {
 xmlDocument.setParameter("disabled", "Y");
 xmlDocument.setParameter("logChanges", "");
 xmlDocument.setParameter("disabledFalse", "return false;");
 } else {
 xmlDocument.setParameter("disabled", "N");
 xmlDocument.setParameter("callout", getOnChangeCode());
 }
 if (getData("IsMandatory").equals("Y"))
 xmlDocument.setParameter("required", "true");
 else
 xmlDocument.setParameter("required", "false");

 return replaceHTML(xmlDocument.print());
 }

 public String toXml() {
 StringBuffer text = new StringBuffer();
 if (getData("IsParameter").equals("Y")) {
 if (getData("IsDisplayed").equals("N")) {
 text.append("<PARAMETER id=\"").append(getData("ColumnName")).append("\" name=\"").append(
 getData("ColumnName")).append("\" attribute=\"value\"/>");
 } else {
 text.append("<PARAMETER id=\"").append(getData("ColumnName")).append("\" name=\"").append(
 getData("ColumnName")).append("\" boolean=\"checked\" withId=\"paramCheck\"/>");
 }
 } else {
 if (getData("IsDisplayed").equals("N")) {
 text.append("<FIELD id=\"").append(getData("ColumnName")).append("\" attribute=\"value\">");
 text.append(getData("ColumnName")).append("</FIELD>");
 } else {
 text.append("<FIELD id=\"").append(getData("ColumnName")).append(
 "\" boolean=\"checked\" withId=\"paramCheck\">");
 text.append(getData("ColumnName")).append("</FIELD>");
 }
 }
 return text.toString();
 }

 public String toJava() {
 return "";
 }

 public String getDefaultValue() {
 return "N";
 }

 public boolean isText() {
 return true;
 }
}
  • WADRadioButton.html

<?xml version="1.0" encoding="UTF-8" ?>

<FIELD_TMP>
 <div id="xx_inp">
 <span><input type="radio" name="inpxx" id="xx" value="Y" onchange="return true;" onclick="changeToEditingMode('force');logChanges(this);xx();return true;" required="false"/></span>
 </div>
</FIELD_TMP>

  • WADRadioButton.xml

<?xml version="1.0" encoding="UTF-8"?>

<REPORT>
 <template file="WADRadioButton.html"/>
 <PARAMETER id="paramChecked" name="checked" default="Y"/>

 <PARAMETER id="xx_inp" name="columnName" attribute="id" replace="xx"/>
 <PARAMETER id="xx" name="columnName" attribute="id" replace="xx"/>
 <PARAMETER id="xx" name="columnNameInp" attribute="name" replace="xx"/>
 <PARAMETER id="xx" name="callout" attribute="onclick" replace="xx();" default=""/>
 <PARAMETER id="xx" name="required" attribute="required"/>
 <PARAMETER id="xx" name="disabled" boolean=" onclick='return false;' readonly=true" withId="paramChecked"/>
 <PARAMETER id="xx" name="logChanges" attribute="onclick" replace="logChanges(this);" default="logChanges(this);"/>
 <PARAMETER id="xx" name="disabledFalse" attribute="onclick" replace="return true;" default="return true;"/>

 <DISCARD id="discard"/>
</REPORT>

In src/org/openbravo/reference/ui add the following files

  • UIRadioButton.java

/*
 @author: Shankar Balachandran
*/
package org.openbravo.reference.ui;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Vector;

import javax.servlet.ServletException;

import org.openbravo.base.secureApp.VariablesSecureApp;
import org.openbravo.erpCommon.businessUtility.BuscadorData;

public class UIRadioButton extends UIReference {
 public UIRadioButton(String reference, String subreference) {
 super(reference, subreference);
 }

 public void generateFilterHtml(StringBuffer strHtml, VariablesSecureApp vars,
 BuscadorData fields, String strTab, String strWindow, ArrayList<String> vecScript, Vector<Object> vecKeys) throws IOException, ServletException {
 UIList list = new UIList("17", "47209D76F3EE4B6D84222C5BDF170AA2");
 list.generateFilterHtml(strHtml, vars, fields, strTab, strWindow, vecScript, null);
 }

 public void generateFilterAcceptScript(BuscadorData field, StringBuffer params,
 StringBuffer paramsData) {
 UITableDir tableDir = new UITableDir(reference, subReference);
 tableDir.generateFilterAcceptScript(field, params, paramsData);
 }
}

In web/skins/Default/Common

  • Add the Radio Button Folder with images

In web/skins/Default, in Openbravo_ERP_250.css add the following Code.

 


/*Custom Code Developed by Shankar 	Balachandran*/
/*
*************************
* Radio Button
*************************
*/
.dojoHtmlRadioButton {
border: 0px;
width: 16px;
height: 16px;
margin: 2px;
vertical-align: middle;
}
.dojoHtmlRadioButtonOn {
background-image: 	url(Common/RadioButton/Enabled.png) ;
}
.dojoHtmlRadioButtonOff {
background-image: 	url(Common/RadioButton/Simple.png) ;
}
.dojoHtmlRadioButtonDisabledOn {
background-image: 	url(Common/RadioButton/Disabled.png) ;
}
.dojoHtmlRadioButtonDisabledOff {
background-image: 	url(Common/RadioButton/Enabled.png) ;
}
.dojoHtmlRadioButtonOnHover {
background-image: 	url(Common/RadioButton/Simple.png) ;
}
.dojoHtmlRadioButtonOffHover {
background-image: 	url(Common/RadioButton/Simple.png) ;
}
.RadioButton_NOT_focused, 	.Radio_NOT_focused {
}
.RadioButton_container_NOT_focused, 	.Radio_container_NOT_focused {
padding: 0px;
margin: 0px;
width: 0px;
height: 0px;
border-style: solid;
border-width: 2px;
border-color: transparent;
}
.RadioButton_focused, 	.Radio_focused {
border: 2px solid #4D98CA;
outline-style: solid;
outline-width: 2px;
outline-color: #4D98CA;
}
.RadioButton_container_focused, 	.Radio_container_focused {
border-style: solid;
border-width: 2px;
border-color: transparent;
}

Then you have to create a base reference in the Application for the Radio Button. Below is a screen shot for reference.

You can assign the reference to any column that you want. I assigned it to the ”Default” field in the Module Window. Attached below is the screen shot of the field mapping.

Then you can “compile.complete.deploy” and then check the Module Window for the change. Attached below is the Screen shot with the Radio Button in Disabled and Enabled states.

Radio Button Disabled:

Radio Button Enabled:

Note:

 

  1. Option buttons are best utilised with the Button Group and they are least useful when used as individual items.
  2. I tried creating the same in RC4. And in the new UI, all I got was a text box with default value ‘False’. Not sure what piece I missed. But when I viewed it through the classic mode option, (URL/?mode=classic), I was able to view the Radio Button correctly.
For more external reference examples, refer here.

Retrieving Parameters for DAL Process and Callouts in OpenbravoERP

Process:

In OpenbravoERP, when we write DAL Process, the first thing that we would need are the input parameters with which we can operate on the Window. By default there are some key parameters passed to the process bundle. They are:

1. Record ID

2. Tab Id

3. Client ID

4. Org ID

These values are presented to the user as key-value pairs. They can be retrieved as provided below:


String id=(String) bundle.getParams().get("TDS_Process_Pay_ID");
String id=(String) bundle.getParams().get("tabId");

The Catch here is that the key-value pairs are Case Sensitive. So the case of your name matters. But more often than not we cannot guess the case of our element variables. Instead of playing the guessing game you can use a very useful method provided in the same process bundle class, which is bundle.getParamsDefalated().This method returns all the process parameters that can be used in the process as a single string delimited by {[key1,value1]}. One example string that was retrieved is provided here.

Bundle {“map”:{“entry”:[{“string”:["adOrgId",""]},{“string”:["tabId","9EB442F0BD9141319FAF085EF30D7CC9"]},{“string”:["TDS_Process_Pay_ID","FF8081812EB2DA4C012EB2DD8117001A"]},{“string”:["adClientId",""]}]}}

Using this you can make sure you provide the right name to retrieve the process parameters.
Callout:

Callouts are a cool feature in Openbravo that helps us in defaulting fields and validating them at runtime. There is a simplecallout class defined in Openbravo using which we can extend and write our own callouts easily and effectively.For basics about developing callouts refer here. Even in callouts you have to retrieve the field’s value that you want to operate upon and set in the same manner. More often I see people confusing themselves between the parameter for Callout and process. The input field is usually prefixed  by ‘inp’ and the variable names are camel cased.For eg if the database field name is ‘first_name’, the field can be retrieved using the following command,

</pre>
String firstName = info.getStringParameter("inpfirstName",null);

And in case of Numeric fields, this command can be used.

BigDecimal noofbed = info.getBigDecimalParameter("inpnoOfBed");

And its easily a best practice to include logger so that you can record the status of the Process/Callout. You have to import the org.apache.log4j.Logger for this purpose. The logger can be instantiated and used as follows:

private static Logger log = Logger.getLogger(TrialProgram.class);
log.info("Displaying Sample Information");

Changing User Interface modes in Openbravo 3.0

OpenbravoERP 3.0 has brought a radical change to its User interface in its latest release 3.0. But like ardent developers I felt the 2.50 User Interface to be more suited for rapid development and I like the 2.50-3.0 Compatibility User interface for regular working. The buttons and the overall setup was pretty cool in it. Just when I thought there was no way to switch back, I came across this wiki link http://wiki.openbravo.com/wiki/ERP/3.0/Developers_Guide/How_To_Switch_to_Classic_Mode.

Though by default the users are provided with the 3.0 user interface, they have the option of reverting to the 2.50 User Interface mode or the 2.50-3.0 compatibility mode.I will present a simple screen shot of each mode and discuss its pro’s and con’s.

2.50 User Interface Mode:

2.50 User Interface Mode

2.50 User Interface Mode

Type the Url like this in your browser to switch to the Classic User interface.

http://localhost:8040/openbravo/security/Menu.html?noprefs=true

Pros:

  • Clean User Interface.
  • Classic left side menus

Cons:

  • Limited space for actual content
  • Design pretty old
  • Not much suitable for fast editing

2.50-3.0 Compatibility mode:

 

2.50-3.0 Compatibility Mode

2.50-3.0 Compatibility Mode

Pros:

  • Web based look
  • Clean UI, more space for actual content
  • Widgets for integrating other web services

Cons:

  • Not suitable for fast editing
  • Menu structures are difficult to fathom for 2.50 users.

3.0 latest User Interface:

 

3.0 RC4 latest User interface

3.0 RC4 latest User interface

Pros:

  • Edit in grid.
  • View child simultaneously.
  • Data operations like excel, formulae, adding runtime columns
  • User configurable widgets for Ob data.

Cons:

  • Buttons on top are little unclear at times when they have to be done in a sequence
  • The buttons errors out many times when tried in form mode. Works properly in grid mode.
  • The form alignment is still messy when there are more fields with display logics involved(compared to the other 2 versions)
  • Not Developer friendly  (I did not find the field sequence tab at all, at times edit in grid did not save, when i tried deleting multiple values it shows success, but records are not deleted)

Having said all this, I think the 3.0 is the future and I am sure they will clear the bugs and make it the preferred UI for many like me.And with more and more User Interface enhancements, I think working with Openbravo would be more like gaming than working..:)

Happy Working…

Email Validation using Callouts in Openbravo

Hi Folks,

I have a written a simple Java code that validates an email ID. This is not a completely validated one, but a basic validated one. This can also be also used as a template for creating Callouts in Openbravo. special mention to my colleague Pandi and one more thanks to Ivan from Openbravo in helping me accomplish this task…:)

package org.openbravo.erpCommon.ad_callouts;

import javax.servlet.ServletException;
import org.apache.log4j.Logger;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.openbravo.erpCommon.ad_callouts.SimpleCallout;
import org.openbravo.erpCommon.utility.SequenceIdData;
import org.openbravo.erpCommon.utility.OBError;
import org.openbravo.scheduling.ProcessBundle;

public class Email_CL extends SimpleCallout {

   private static final long serialVersionUID = 1L;
   private static Logger log = Logger.getLogger(Email_CL.class);

 @Override
 protected void execute(CalloutInfo info) throws ServletException {

   String mailid = info.getStringParameter("inpemail",null);
   // Set the email pattern string
    Pattern p = Pattern.compile(".+@.+\\.[a-z]+");
   
   // Match the given string with the pattern
   Matcher m = p.matcher(mailid.toString());

   // check whether match is found
   boolean matchFound = m.matches();

   StringTokenizer st = new StringTokenizer(mailid, ".");
   String lastToken = null;

    while (st.hasMoreTokens())
    {
       lastToken = st.nextToken();
    }

   //if (matchFound && lastToken.length() >= 2
   //     mailid.length() - 1 != lastToken.length())

   if(!matchFound)
       info.addResult("MESSAGE","InValid Email");
   
 }
}

Importing it into the Application :
Generally callouts are present in the folder ad_callouts in org/openbravo/erpCommon in the source folder of openbravo. You can put your callout file here and then we should define a callout in our application in Application Dictionary under setup folder callout is there. Now Give a name for the callout preferably the name of your java file because the mapping class file and a auto-generated html file will be generated. You check the existing callouts for path and adjust yours accordingly. Then this defined callout should be assigned to the field where the action has to be performed. for the above example it would be the string field where email will be entered. To assign callout to a column go to tables and columns and choose the corresponding column. There will be a field called callout. Choose your name there. Compile and deploy and check your callout.

Note:
To check whether your callout is called properly, u can use the empty frame at the end of each page. For that go to src/org/openbravo/erpCommon/security. There will be a file called Login_FS.Html. In line No.52 the frame ratio would be “100%,*”. Change that too “90%,20%”. This will create a empty text area at the end of every page and if that page has callout, the text “Callout response page” will be displayed. Or else if some error is displayed your path settings in callout definition has to be changed.

Happy Working..:)

Follow

Get every new post delivered to your Inbox.