Learn how easy it is to sync an existing GitHub or Google Code repo to a SourceForge project! See Demo

Close

Distribution Order: (How) does it work?

2011-11-07
2013-03-07
  • Angelo Dabalà
    Angelo Dabalà
    2011-11-07

    Hello everybody,

    I'm trying to figure out how the distribution order works, I spent  a few days now, digging into the code, and at the moment I'm persuaded that the functionality has many bugs, I wonder if there is a more up to date version somewhere; this is where I took the code:

    https://adempiere.svn.sourceforge.net/svnroot/adempiere/branches/libero

    this is the list of bugs (and/or doubts) I've currently found:

    1. Mandatory Transit Warehouse. I wonder why it's mandatory to have a transit warehouse, so there should always be two material movement one from the original locator to the transit warehouse, and one from the transit warehouse to the destination locator. What if there is no transit warehouse?

    2. How to generate the Material Movement? Currently there are two ways, using a process (org.eevolution.process.MovementGenerate) or a custom form (org.eevolution.form.OrderDistribution) which in turn call the same process. It seems from the code that the quantity for the movement is taken from the ConfirmedQty of the DD_OrderLine, now even if it's possible to input this qty into the DO window there is a callout which control that it's never greater than the QtyDelivered but the QtyDelivered shoul be updated by the completion of the Material Movement so we have a chicken-egg problem here.

    3. Wrong definition of m_movement.c_bpartner_location_id. The db constraint for this column is

    CONSTRAINT cbpartnerlocation_mmovement FOREIGN KEY (c_bpartner_location_id)
          REFERENCES c_location (c_location_id) MATCH SIMPLE
          ON UPDATE NO ACTION ON DELETE NO ACTION DEFERRABLE INITIALLY DEFERRED

    the definition inside the dictionary is also wrong, the reference is "Location (Address)".

    I found this error after changing the process and managing to create the movement using the QtyOrdered instead of the ConfirmedQty, I got an integrity check violation because the method org.eevolution.process.MovementGenerate.createMovement(MDDOrder, Timestamp) do the following

    MMovement move = new MMovement(order.getCtx(), 0, order.get_TrxName());
    move.setC_BPartner_ID (order.getC_BPartner_ID());
    move.setC_BPartner_Location_ID (order.getC_BPartner_Location_ID()); // shipment address

    which is right in my opinion, but the column reference another table so that's the problem.

    In the end I wonder how is the status of this functionality, the problems I got are so basic that they lead me to think that nobody is using it, or maybe it's just me missing something.

    I hope somebody will enlighten me

    Regards,
    Angelo Dabala'

     
  • Hello Angelo!

    I've been a little busy and so far I have a few minutes to help.

    The transit warehouse is needed to identify the product you are traveling and update the quantity on hand. so to know which are the products, quantities and value of inventory in transit we must have a different warehouse source or destination.

    The current Inventory Move does not allow  management material in transit, as you complete a "Inventory Move" the quantity on hand is updated even when the inventory is still in transit.

    The order of distribution are generated during the execution of MRP with DRP option is activated, MRP suggests a distribution orden  for products with a network code rather than a Manufacturing Order or Requisition.

    The Distribution Order also may be generated manually.

    The cycle of an order of distribution is:

    1 .-A Inventory Move is created from the source warehouse to warehouse in transit by the amount confirmed using the option Generate Movement Manual (the operation is similar to the shipments, the delivery rule is used to validate the inventory available).
    2 .- When the material reaches its destination it is necessary to receive the material of the  distribution order, so a Inventory Move is generated by receiving material from the warehouse in transit  to warehouse target (the operation is similar to the receipt of a purchase order).

    The confirmed quantity  can be set using distribution lists or manually

    The callout that validate that quantity confirmed must be greater than quantity to deliver, so the quantity to deliver = quantity ordered - quantity in transit  - quantity delivered.

    Note: please check that is not  the same quantity to deliver that the quantity delivered.

    about that location into the inventory move should be definite the same way that distribution order, so that you found a bug here, so as this column can be null and  is not mandatory may be that  not cause some issues, but you are in correct, I should fix this problem.

    kind regards
    Victor Perez
    www.e-evolution.com

     
  • Angelo Dabalà
    Angelo Dabalà
    2011-11-08

    Hello Victor,

    thank you very much for your reply, I'm still a bit confused about the use of the quantities, into MovementGenerate there is a first loop for every line with the following test:

    271                                         //BigDecimal toDeliver = line.getQtyOrdered()
    272                                         BigDecimal toDeliver = line.getConfirmedQty(); //.subtract(line.getQtyDelivered());
    273                                         MProduct product = line.getProduct();
    274                                         //      Nothing to Deliver
    275                                         if (product != null && toDeliver.signum() == 0)
    276                                                 continue;

    so it just look at ConfirmedQty, if it's zero it loops to the next line.

    Then if the delivery rule is CompleteOrder there is a second loop where quantity is calculated as

    400                                                 BigDecimal toDeliver = line.getQtyOrdered().subtract(line.getQtyDelivered());

    So I don't understand why it use two different method.

    About the Callout, you are right about QtyToDeliver it's equal to getQtyOrdered().subtract(getQtyInTransit()).subtract(getQtyDelivered());

    The problem is inside the callout:

    206         public String qtyConfirmed (Properties ctx, int WindowNo, GridTab mTab, GridField mField, Object value)
    207         {
    208                 I_DD_OrderLine line = GridTabWrapper.create(mTab, I_DD_OrderLine.class);               
    209                 MDDOrderLine orderLine = new MDDOrderLine(ctx, line.getDD_OrderLine_ID(), null);
    210                
    211                 if (line.getConfirmedQty().compareTo(orderLine.getQtyToDeliver()) > 0)

    If you are inserting a new record and still haven't save it, the line 209 return a new MDDOrderLine and so getQtyToDeliver() return zero. Even if you save the record the result is not reliable because you could change the QtyOrdered and then the ConfirmedQty without saving. I think we should replace the method getQtyToDeliver() with a local calculation, since we can't cast the interface to the M class.

    Best regards,
    Angelo Dabala'

     
  • Angelo Dabalà
    Angelo Dabalà
    2011-12-05

    Hello Victor,

    another question about the Distribution Order, this one is about the callout

    org.eevolution.model.CalloutDistributionOrder.qty(Properties, int, GridTab, GridField, Object)

    near the end there is a check for quantity availability which start with the following code

    // Storage
    if (M_Product_ID != 0
    && Env.isSOTrx(ctx, WindowNo)
    && QtyOrdered.signum() > 0) // no negative (returns)
    {

    it never fire, because Env.isSOTrx(ctx, WindowNo) is returning false. I saw that isSOTrx is not checked neither on the Window nor on the Menu. Is that intentional or it's just my DB which is wrong?

    Regards,
    Angelo