updating status of entity based on some other entity value

I have following entities:

. PurchaseRequisition

. PurchaseRequisitionLine -Composite

. PurchaseOrder

. PurchaseOrderPr -Composite

. Purchase OrderLine -Composite

In my Purchase OrderPr a List of PurchaseRequisition is used to create a PurchaseOrder. When I issue a PO, the PoQuantity field in PurchaseRequisitionLine is updated through it’s listener as follows:


   EntityManager em = persistence.getEntityManager();

        TypedQuery<PurchaseRequisitionLine> query = em.createQuery("select e from erp$PurchaseRequisitionLine e " +
                "where e.purchaseRequisition.id = ?1 AND e.material.id = ?2", PurchaseRequisitionLine.class);
        query.setParameter(1, operation.getPurchaseRequisition().getId());
        query.setParameter(2, operation.getMaterial().getId());
        List<PurchaseRequisitionLine> lists = query.getResultList();

        if(!lists.isEmpty()){
            BigDecimal poQty=new BigDecimal(0);
            for (PurchaseRequisitionLine line : lists) {
                if(line.getPoQuantity() !=null){
                    poQty=line.getPoQuantity();
                }
                line.setPoQuantity(poQty.add(operation.getQuantity()));
            }
        }

It is working well. Now I want to update the status (= Status.CLOSED) of the respective PurchaseRequisition when all the records of the PR has 0 balance of PR i.e. Quantity - PoQuantity = 0.

Here is my code to do that in procurementService


   public void updatePurchaseRequisitionHeaderTotalQuantityAndClose(PurchaseRequisition purchaseRequisition){
        EntityManager em = persistence.getEntityManager();

        //Update Purchase Requisition
        //-------------------------------
        TypedQuery<PurchaseRequisitionLine> query = em.createQuery("select e from erp$PurchaseRequisitionLine e " +
                "where e.purchaseRequisition.id = ?1", PurchaseRequisitionLine.class);
        query.setParameter(1, purchaseRequisition.getId());

        List<PurchaseRequisitionLine> lists = query.getResultList();

        if(!lists.isEmpty()){
            BigDecimal balQty=BigDecimal.ZERO;
            for (PurchaseRequisitionLine balance : lists) {
                balQty=balQty.add(balance.getQuantity().subtract(balance.getPoQuantity()));

            }
            if(balQty.equals(0)){
                closePurchaseRequisition(purchaseRequisition);
            }
        }

    }

    public void closePurchaseRequisition(PurchaseRequisition purchaseRequisition){
        try (Transaction tx = persistence.createTransaction()) {

            //Update Purchase Requisition
            //-------------------------------
            TypedQuery<PurchaseRequisition> query = persistence.getEntityManager().createQuery("select e from erp$PurchaseRequisition e " +
                    "where e.id = ?1", PurchaseRequisition.class);
            query.setParameter(1, purchaseRequisition.getId());

            PurchaseRequisition pr = query.getFirstResult();
            if (!pr.equals(null)) {
                pr.setStatus(Status.CLOSED);
            }

            tx.commit();
        }
    }

What will be the best approach to calculate and change the Status of Purchase Requisition to be efficient and clean?

Where do you get the PurchaseRequisition instance from? If it is from the client, the it is detached and you can merge it and then just set its attribute value, which will be saved on the transaction commit. So there is no need to query for it in the second method. Something like this:


public void updatePurchaseRequisitionHeaderTotalQuantityAndClose(PurchaseRequisition purchaseRequisition){
    EntityManager em = persistence.getEntityManager();

    purchaseRequisition = em.merge(purchaseRequisition);

    //Update Purchase Requisition
    //-------------------------------
    TypedQuery<PurchaseRequisitionLine> query = em.createQuery("select e from erp$PurchaseRequisitionLine e " +
            "where e.purchaseRequisition.id = ?1", PurchaseRequisitionLine.class);
    query.setParameter(1, purchaseRequisition.getId());

    List<PurchaseRequisitionLine> lists = query.getResultList();

    if(!lists.isEmpty()){
        BigDecimal balQty=BigDecimal.ZERO;
        for (PurchaseRequisitionLine balance : lists) {
            balQty=balQty.add(balance.getQuantity().subtract(balance.getPoQuantity()));

        }
        if(balQty.equals(0)){
            purchaseRequisition.setStatus(Status.CLOSED);
        }
    }
}

I presume that the method is annotated with @Transactional. Otherwise you need to create a transaction inside.

Hi Konstantin
Yes it will be coming from client. So I call this procedure beforeCommit? Note that Entity listener will update before this update.

Mortoza

If you mean DsContext.BeforeCommitListener#beforeCommit than it is invoked from the client before sending entities to the middleware and thus before entity listeners.

ok, i see. And that’s why the status is not updated correctly.
In that case, this is not the right place to call it as this calculation should be done after Entity Listener. So what would be the right place to call it from? Is the transaction Listener would be good place? if so, where do I call the transaction listener?

I think you can place your code right in the BeforeUpdateEntityListener of PurchaseRequisition. In this case you don’t need to merge the instance - its already in the managed state.