In Compiere, you use a Java Callout for "data entry consequences" - example - you select a business partner, which then populates business partner location and user as well as other specific default values like payment terms. Without a Callout, the system would just set the dependent values (location, user) to null. Consequently, Callouts are essential when you want to provide easy-to-use, interactive windows.
Callouts are available for Compiere for a long time and one of the reason for Compiere's success. The ultimate objective is to have a single controller for Swing and the WebUI with one Callout API. At this momemnt, you need to use platform specific code to create a callout.
As a example, I will use the situation to automatocally select a revenue recognition method after you selected a product - i.e. after you enter the product, the system checks if revenue recognition applies and selects the appropriate mathod, which you the could overwrite. Revenue Recognition e.g. distributes the revenue you cannot recognize immediate, but over time.
After logging in as System Administrator, open window "Table and Column" - navigate to the table and column you want to enable - here you find the Callout flag and the Callout code.
Callout for Swing UI
The steps to create a Callout for the Swing UI are:
- Create a class which
- Create a method with the following signature:
public String justAnExample (Ctx ctx, int WindowNo, GridTab mTab, GridField mField, Object value, Object oldValue)
- Enter the fully qualified class.method name in the Data Dictionary Callout code for the column
The business logic you provide here should be repeated on the model level to have the same experience/behavior if you were to enter/modify a record manually via UI or via API.
There are many examples for callouts in Swing - check classes like CalloutInvoice for a bit more complex logic or the class CalloutUser for basic information.
Callout for WebUI
The objective was to have all functionality in the model class, so you would just add a special setter method - example from MConversionRate:
@UICallout public void setMultiplyRate (String multiplyRateOld, String multiplyRateNew, int windowNo) throws Exception
You would then just convert the String to the correct data type using a static method and call a standard method. This way, there is no need to replicate functionality on the model level as this is executed on the model level.
To enable the callout, you just select the Callout flag for the Column in the dictionary.
This approach is easy, if you are the owner of the object. If you want to extend an existing class, you have two options:
- If you create a component, you just enter your model package in your entity type and create in there your extension in your package - example:
public class MOrder extends org.compiere.model.MOrder
- Use an external class (details below). You may want to select this option, if you don't want to create your own extension, e.g. because another component is alreay doing that - or becuase the change is simple
To create an external [external to the model class] WebUI callout, you just create a method in a class with a parameter-less constructor and add the fully qualified class.method name in the Data Dictionary Callout code for the column - example:
public void justAnExample (PO po, UIField field, String oldValue, String newValue)
Note that you can use the same class.method name for SwingUI and WebUI - here
compiere.model.CalloutUser.justAnExample - as the parameters are different, it is easy to differentiate and allows to have the code in the same class. Note that you should use the ModelValidator to replicate the logic for the model level to achieve the same behavior via API.