windowadempiere

How can I make automatic generated column in Adempiere ?


I have two columns called Quantity and Issued Quantity. I want that when I put value in Quantity column, for instance 3, the Issued Quantity will automatically generate 3. Also I want it to happen the other way around.

The example is on Purchase Order window, PO Line tab. in Quantity section. When I put 4 in Quantity field, the PO Quantity field automatically generate 4.

I try to imitate the column and field but it doesn't work.


Solution

  • This is accomplished in Adempiere by a Callout which is configured in what Adempiere calls the Application Dictionary

    From the example you gave; updating the qty on the Purchase Order. If you login to Adempiere using the System user, you can view and modify the Application Dictionary.

    From the main menu select Application Dictionary->Table & Column.

    In the Search box that opens enter C_OrderLine as the DB Table name.

    Now Column tab and scroll down the list to locate the QtyEntered column. Switch to the Form view and near the end you will see were you can enter the field Callout.

    You should see that the C_OrderLine.QtyEntered field already has a value "org.compiere.model.CalloutOrder.qty; org.compiere.model.CalloutOrder.amt" which indicates it should run the method qty in the class org.compiere.model.CalloutOrder followed by the method amt in the org.compiere.model.CalloutOrder class.

    If you open those classes you can see how easily you can evaluate and modify values. Breaking some of of it down for you... if you open the CalloutOrder.java class you cab scroll down until you find the qty method.

    public String qty (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
    {
    

    You need use the signature as above for any new callout method you create. Follow that approach and Adempiere will look after passing the correct values for you

        if (isCalloutActive() || value == null)
            return "";
    

    It's good practice to start the method with the above ensure you do not open a Callout from within a Callout - which would break the Adempiere rules.

    int M_Product_ID = Env.getContextAsInt(ctx, WindowNo, "M_Product_ID"); 
    

    Is an example of how you could extract values from the existing window... the syntax would remain the same regardless of Column/Field the you just need to enter the "M_Product_ID" which is the Field name you wish to extract to use.

    Now this Callout is called by more than one Column/Field so it is littered with a big if...then...else to executed the logic needed for the relevant field. It's not pretty, but this is aimed at business developers who will concentrate more on business logic than coding principals.

    The code you are interested in is

        else if (mField.getColumnName().equals("QtyEntered"))
        {
            int C_UOM_To_ID = Env.getContextAsInt(ctx, WindowNo, "C_UOM_ID");
            QtyEntered = (BigDecimal)value;
            BigDecimal QtyEntered1 = QtyEntered.setScale(MUOM.getPrecision(ctx, C_UOM_To_ID), BigDecimal.ROUND_HALF_UP);
            if (QtyEntered.compareTo(QtyEntered1) != 0)
            {
                log.fine("Corrected QtyEntered Scale UOM=" + C_UOM_To_ID 
                    + "; QtyEntered=" + QtyEntered + "->" + QtyEntered1);  
                QtyEntered = QtyEntered1;
                mTab.setValue("QtyEntered", QtyEntered);
            }
            QtyOrdered = MUOMConversion.convertProductFrom (ctx, M_Product_ID, 
                C_UOM_To_ID, QtyEntered);
            if (QtyOrdered == null)
                QtyOrdered = QtyEntered;
            boolean conversion = QtyEntered.compareTo(QtyOrdered) != 0;
            log.fine("UOM=" + C_UOM_To_ID 
                + ", QtyEntered=" + QtyEntered
                + " -> " + conversion 
                + " QtyOrdered=" + QtyOrdered);
            Env.setContext(ctx, WindowNo, "UOMConversion", conversion ? "Y" : "N");
            mTab.setValue("QtyOrdered", QtyOrdered);
        }
    

    The code

    mTab.setValue("QtyOrdered", QtyOrdered);
    

    Is where it sets the value of the other quantity field Qty Ordered.

    Also, the call must not be Java. It is possible to link any [JSR223 script][3]. I never actually tried this approach myself, but it is even possible to implement Callouts using the Drools Rules Engine!