commit 0aa4b359577a44f953b5f80dddc4ac25a8d04a49
Author: david.miguelez <david.miguelez@openbravo.com>
Date:   Thu Aug 27 10:48:44 2020 +0200

    Fixes ISSUE-44804. Releases non allocated reservations
    
    When the reservations are created automatically for a Sales Order,
    this reservations are not allocated.
    
    When AWO then generates the Tasks, this reservations are not taken
    into account because they are not allocated, so AWO creates new
    allocated reservations.
    
    Afterwards, the system should check if there is more quantity reserved
    than necesary and, in this case, release the previously created
    not allocated reservation, as it is no longer necesary once
    the allocated one has been created.

diff --git a/src/org/openbravo/warehouse/advancedwarehouseoperations/utils/AWOReservationForTask.java b/src/org/openbravo/warehouse/advancedwarehouseoperations/utils/AWOReservationForTask.java
index 0cebe52f..31330c57 100644
--- a/src/org/openbravo/warehouse/advancedwarehouseoperations/utils/AWOReservationForTask.java
+++ b/src/org/openbravo/warehouse/advancedwarehouseoperations/utils/AWOReservationForTask.java
@@ -10,6 +10,7 @@
 package org.openbravo.warehouse.advancedwarehouseoperations.utils;
 
 import java.math.BigDecimal;
+import java.util.List;
 
 import javax.enterprise.context.Dependent;
 import javax.enterprise.inject.Any;
@@ -68,6 +69,15 @@ public class AWOReservationForTask {
       if (isPossibleToAddExpectedQtyToReservationQty(reservation)) {
         reservation.setQuantity(reservation.getQuantity().add(task.getExpectedQuantity()));
       }
+
+      // Flush changes and refresh. It is necessary in order to see changes done by Triggers in the
+      // DB such as changing the reservedQty due to the new Reservation Stock created
+      OBDal.getInstance().flush();
+      OBDal.getInstance().refresh(reservation);
+
+      if (isMoreQuantityReservedThanOrdered(reservation)) {
+        tryToReleaseNonAllocatedReservations(reservation);
+      }
       processReservationIfInDraftStatus(reservation);
       return reservation;
     } finally {
@@ -147,6 +157,42 @@ public class AWOReservationForTask {
     return reservation.getQuantity().add(task.getExpectedQuantity()).compareTo(orderLineQty) <= 0;
   }
 
+  private boolean isMoreQuantityReservedThanOrdered(final Reservation reservation) {
+    final BigDecimal orderLineQty = awoReservation.getOrderLineQty(task) == null ? BigDecimal.ZERO
+        : awoReservation.getOrderLineQty(task);
+    return reservation.getReservedQty().compareTo(orderLineQty) > 0;
+  }
+
+  private void tryToReleaseNonAllocatedReservations(final Reservation reservation) {
+    final BigDecimal orderLineQty = awoReservation.getOrderLineQty(task) == null ? BigDecimal.ZERO
+        : awoReservation.getOrderLineQty(task);
+    final BigDecimal reservedQty = reservation.getReservedQty();
+    BigDecimal overReservedQty = reservedQty.subtract(orderLineQty);
+
+    for (final ReservationStock reservationStock : getNonAllocatedReservations(reservation)) {
+      final BigDecimal qtyToRelease = overReservedQty
+          .min(reservationStock.getQuantity().subtract(reservationStock.getReleased()));
+      reservationStock.setReleased(reservationStock.getReleased().add(qtyToRelease));
+      overReservedQty = overReservedQty.subtract(qtyToRelease);
+    }
+
+  }
+
+  private List<ReservationStock> getNonAllocatedReservations(final Reservation reservation) {
+    //@formatter:off
+    final String hql = "" +
+       "   as rs " +
+       " where rs.reservation.id = :reservationId " +
+       "   and rs.allocated = false " +
+       "   and rs.quantity > 0 " +
+       "   and (rs.quantity - rs.released) > 0 ";
+    //@formatter:on
+    return OBDal.getInstance()
+        .createQuery(ReservationStock.class, hql)
+        .setNamedParameter("reservationId", reservation.getId())
+        .list();
+  }
+
   private void processReservationIfInDraftStatus(final Reservation reservation) {
     boolean isInDraft = OBAWO_Constants.STATUS_DRAFT.equals(reservation.getRESStatus());
     if (isInDraft) {
