Rule snippets

From iDempiere en

Model Validator

Enforce current date

To enforce POS-orders to be completed only with the current date the following snippet was attached to c_order on before complete:

 import org.compiere.util.Env;
 today = Env.getContextAsDate(A_Ctx, "#Date");
 if (A_PO.getDateOrdered().before(today) && A_PO.getC_DocTypeTarget_ID() == 1000041)
   msg = "POS-Aufträge nicht für zurückliegende Daten";
   msg = "";
 return msg;

Of course the doctype ID must be adjusted to your installation. The usage of #Date instead of the systemtime allows to use an older date by setting it at login if required.

Tested with groovy


Remove unknown products from import

When importing products for example from price lists of a vendor it may be necessary only to import those products which are already present in the database. This script could be executed as process to remove all products from i_product which are not known by either upc/ean or the combination of vendor and vendorproductno.

 import org.compiere.model.MTable;
 import org.compiere.util.DB;
 import org.compiere.util.Msg;
 int no = DB.executeUpdate ("delete from I_Product where ad_client_id = " + A_AD_Client_ID + 
   " and I_Product_ID not in " + 
   "  (select ip.I_Product_ID from I_Product ip " +
   "     join c_bpartner cb on cb.value = ip.bpartner_value or cb.c_bpartner_id = ip.c_bpartner_id " +
   "     join M_Product_po mpo on mpo.vendorproductno = ip.vendorproductno and mpo.c_bpartner_id = cb.c_bpartner_id " +
   "     join M_Product mp on mp.M_Product_ID = mpo.M_Product_ID and mp.isactive = 'Y' " + 
   "  union select ip.I_Product_ID from I_Product ip " +
   "        join m_product mp on mp.upc = ip.upc and mp.isactive = 'Y')", A_TrxName);
 A_ProcessInfo.addLog(0,null,null, "" + no + " Datensätze gelöscht");
 result = "OK";

Tested with groovy

Create price list version with one shot scheduler

To be able to create long running price list versions after work hours a schedule schema was created, running daily at 18:00. This schedule than was disabled at the first run by the following script which also starts the price list generation.

 import org.compiere.util.Env;
 import org.compiere.model.MScheduler;
 import org.compiere.model.MPInstance;
 import org.compiere.model.MProcess;
 import org.compiere.process.ProcessInfo;
 import org.compiere.process.ProcessInfoParameter;
 import org.compiere.process.ProcessCall;
 import org.adempiere.base.Core;
 Scheduler = new MScheduler (Env.getCtx(), P_AD_Scheduler_ID, null);
 ProcessInfo pi = new ProcessInfo("Pricelistcreation",103);
 MPInstance mpi = new MPInstance(Env.getCtx(), 0, null);
 ProcessCall process = Core.getProcess("org.compiere.process.M_PriceList_Create");
 boolean success = process.startProcess(Env.getCtx(), pi, null);
 return success ? "OK" : "failed";

The process starting this script must have params AD_Scheduler_ID and Record_ID. The params than have to be filled manually with the correct IDs of the scheduler entry and the price list version entry. The user than has to activate the record, save it and activate the scheduler. If it is of no problem that scheduler will be restarted after server restart you can replace 'Scheduler' lines deactivating the entry by the following lines. Then only the scheduler has to be reactivated and started. Remark: it showed that reactivating in certain cases is not enough. If the time for the originally intended next run has gone the scheduler will start the process immediately. So before restarting the scheduler change schedule back and forth to get the intended 'Date next run'.

 import org.compiere.server.AdempiereServerMgr;
 SvrMgr = AdempiereServerMgr.get(false);
 SvrMgr.stop("Scheduler" + P_AD_Scheduler_ID);

tested with groovy

Ensure a replenish entry is present for stocked products

Because the replenish report will find missing products only if there is at least an entry with minimum level 0 after importing new products the corresponding replenish entries have to be created. This is done here.

 import org.compiere.util.Env;
 import org.compiere.model.MProduct;
 import org.compiere.model.MReplenish;
 ctx = Env.getCtx();
 count = 0;
 MProduct [] emptyproducts = MProduct.get (ctx, "isStocked = 'Y' and not exists (select 1 from m_replenish where m_replenish.m_product_id = m_product.m_product_id)", A_TrxName);
 for (MProduct prod: emptyproducts) {
    replenish = new MReplenish (ctx, 0, A_TrxName);
    replenish.setLevel_Max (Env.ZERO);
    replenish.setLevel_Min (Env.ZERO);
    replenish.setM_Product_ID (prod.getM_Product_ID());
    replenish.setM_Warehouse_ID (1000001);
    replenish.setReplenishType ("1");
 A_ProcessInfo.addLog(0,null,null, "" + count + " Nachbestellungssätze erzeugt");
 return "OK"

tested with groovy

Executing a shell script from a rule process

This example illustrates how to execute a shell script from a process rule.

For testing:

  • Add a process with
    • Search Key, Name =
    • Data Access Level = System
    • Classname =
  • Assign the process to the column Test.Processing
  • Create the rule with the text below and
    • Search Key, Name =
    • Event Type = Process
    • Rule Type = JSR 223 Scripting APIs
  • Create the shell script /tmp/ with the text below
  • Give execute permissions to the shell script with chmod +x /tmp/


System.out.println("debuggin beanshell script");
int exitValue = -1;
try {
  Runtime r = Runtime.getRuntime();
  String command = "/tmp/ " + A_Record_ID;
  A_ProcessInfo.addLog (0, null, null, "Executing script /tmp/");
  Process p = r.exec(command);
  BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
  String inputLine;
  while ((inputLine = in.readLine()) != null) {
    A_ProcessInfo.addLog (0, null, null, inputLine);
  exitValue = p.exitValue();
} catch (IOException e) {
  System.out.println("error in script -> " + e.getLocalizedMessage());
result = "OK - exit value = " + exitValue;

Shell Script example

echo "Record $1 processed successfully"
ls -l
exit 2

See Also