Commit ad3772f4 authored by Atul Gaware's avatar Atul Gaware Committed by Víctor Martínez Romanos
Browse files

Fixed BUG-0050259: Issue DO automatically when DO imported by API

**Create Movement Line though product does not have enough stock,
if partial stock exists create lines with available stock, if
pendingqty exists or there is no stock then create movement lines
for the required quantity for product without attribute set, for
product with attribute set only create partial movements as per
stock available else do not create movements irrespective of the
overissue flag.
**Add pendingqty to the movementline created for partial stock
in case product has no attribute and bin has overissue inventory
status
parent bd167807
......@@ -21,6 +21,7 @@ package org.openbravo.distributionorder.actionHandler;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
......@@ -40,6 +41,7 @@ import org.openbravo.distributionorder.erpCommon.utility.DistributioOrderUtils;
import org.openbravo.erpCommon.utility.OBMessageUtils;
import org.openbravo.erpCommon.utility.SequenceIdData;
import org.openbravo.materialmgmt.StockUtils;
import org.openbravo.model.common.enterprise.Locator;
import org.openbravo.model.materialmgmt.onhandquantity.StockProposed;
import org.openbravo.model.materialmgmt.transaction.InternalMovement;
import org.openbravo.model.materialmgmt.transaction.InternalMovementLine;
......@@ -69,28 +71,50 @@ public class ProcessIssue extends BaseProcessActionHandler {
/**
* Creates and adds the Goods Movement lines from the Distribution Order into the Goods Movement
* that is being, Processes the Goods Movement
* that is being, Processes the Goods Movement. The process will try to deliver as many units as
* possible.
*
* @param movement
* - Goods Movement header to be processed.
* @return a JSONObject with the response actions.
*/
public static JSONObject processIssueDO(final InternalMovement movement) {
return processIssueDO(movement, Collections.emptyMap());
return processIssueDO(movement, Collections.emptyMap(), false);
}
/**
* Create Goods Movement Lines with quantities based on Issue Quantity Map, processes the Goods
* Movement
* Movement. The process will try to deliver the units in the issueQtyMap, and it will fail if not
* possible to deliver all of them
*
* @param movement
* - Goods Movement header to be processed.
* @param issueQtyMap
* - Map that holds pending issue quantity for DO Line
* - Map that holds pending issue quantity for DO Line. If empty, try to deliver as many
* units as possible. If not empty, fits to the provided units and fail if not possible
* to deliver all of them.
* @return a JSONObject with the response actions.
*/
public static JSONObject processIssueDO(final InternalMovement movement,
final Map<String, BigDecimal> issueQtyMap) {
return processIssueDO(movement, issueQtyMap, issueQtyMap != null && !issueQtyMap.isEmpty());
}
/**
* Create Goods Movement Lines with quantities based on Issue Quantity Map, processes the Goods
* Movement
*
* @param movement
* - Goods Movement header to be processed.
* @param issueQtyMap
* - Map that holds pending issue quantity for DO Line
* @param failIfNotFullyDelivered
* - Fail creation of Goods Movement when it is not fully delivered
* @return a JSONObject with the response actions.
*/
public static JSONObject processIssueDO(final InternalMovement movement,
final Map<String, BigDecimal> issueQtyMap, boolean failIfNotFullyDelivered) {
OBContext.setCrossOrgReferenceAdminMode();
try {
if (movement.getObdoIntransitLocator() == null) {
......@@ -100,7 +124,8 @@ public class ProcessIssue extends BaseProcessActionHandler {
.build();
}
StringBuilder errorsWhileAddingLines = createMovementlines(movement, issueQtyMap);
StringBuilder errorsWhileAddingLines = createMovementlines(movement, issueQtyMap,
failIfNotFullyDelivered);
if (errorsWhileAddingLines.length() != 0) {
return getResponseBuilder()
.showMsgInProcessView(MessageType.ERROR, OBMessageUtils.messageBD("Error"),
......@@ -136,19 +161,28 @@ public class ProcessIssue extends BaseProcessActionHandler {
* When creating the lines for the Goods Movement, it retrieves available Stock from all possible
* locations except from the Bin defined as In Transit in the Document
*
* When Stock is partially available or completely unavailable, product has no attribute set Goods
* Movement Lines are created for pending qty or complete quantity respectively when Issue
* warehouse has Storage Bin with over issue inventory status.
*
* @param movement
* a Goods Movement object that is going to contain the created Goods Movement Lines
* @param failIfNotFullyDelivered
* - Fail creation of Goods Movement & its lines when it is not fully delivered
* @param issueQtyMap
* a map with the issued qtys per DO line. If empty, the process will try to deliver the
* full line, otherwise it will fit to the qty in the map
*/
private static StringBuilder createMovementlines(final InternalMovement movement,
Map<String, BigDecimal> issueQtyMap) {
Map<String, BigDecimal> issueQtyMap, boolean failIfNotFullyDelivered) {
ScrollableResults linesDO = null;
final Map<String, String> existingProductIds = new HashMap<String, String>();
try {
final DistributionOrder distributionOrder = movement.getObdoDistorder();
// Get Locator with over issue inventory status for Issue Warehouse in DO
final Locator overIssueLocator = getOverissueBinForWarehouse(
distributionOrder.getWarehouseIssue().getId());
linesDO = DistributioOrderUtils.getDistOrderLinesScrollableResult(distributionOrder);
long lineno = (movement.getMaterialMgmtInternalMovementLineList().size() * 10) + 10;
......@@ -187,14 +221,33 @@ public class ProcessIssue extends BaseProcessActionHandler {
if (distOrdline.getQtyConfirmed().intValue() > 0
&& pendingQty.compareTo(BigDecimal.ZERO) > 0) {
final BigDecimal movementQty = qtyOnHand.min(pendingQty);
createAndSaveMovementLine(movement, distOrdline, stock, movementQty, lineno);
createAndSaveMovementLine(movement, distOrdline, stock, movementQty, lineno, null,
existingProductIds);
pendingQty = pendingQty.subtract(movementQty);
linesadd++;
lineno += 10;
}
}
if (pendingQty.compareTo(BigDecimal.ZERO) > 0 && overIssueLocator != null) {
// If Quantity is pending due to stock unavailability try
// to add lines when issue warehouse has over issue storage bin
int addedLinesadd = workWithNegativeStockIfPossible(distOrdline, movement,
overIssueLocator, pendingQty, lineno, existingProductIds);
if (addedLinesadd != -1) {
pendingQty = BigDecimal.ZERO;
linesadd += addedLinesadd;
}
}
// If Not fully Delivered and quantity is still pending, fail and revert
// Scenario: Partial Movement Lines for Product with Attribute set are created,
// and failIfNotDelivered flag is true.
if (pendingQty.compareTo(BigDecimal.ZERO) > 0 && failIfNotFullyDelivered) {
throw new OBException("createMovementLines Failed, not fully Delivered...");
}
// No lines added
if (linesadd == 0) {
if (resultMessage.length() == 0) {
resultMessage.append(OBMessageUtils.messageBD("OBDO_STOCK"));
......@@ -361,9 +414,7 @@ public class ProcessIssue extends BaseProcessActionHandler {
* @return The pinstanceid, from which you will get the result in StockProposed
*/
private static String callProcessGetStock(final String recordID, final String clientId, final String orgId,
final String productId, final String uomId, final String warehouseId, final String attributesetinstanceId,
final BigDecimal quantity, final String warehouseRuleId, final String reservationId) {
private static String callProcessGetStock(final String recordID, final String clientId, final String orgId, final String productId, final String uomId, final String warehouseId, final String attributesetinstanceId, final BigDecimal quantity, final String warehouseRuleId, final String reservationId) {
final String processId = SequenceIdData.getUUID();
OBContext.setAdminMode(false);
try {
......@@ -405,10 +456,12 @@ public class ProcessIssue extends BaseProcessActionHandler {
* The Movement Quantity of the Goods Movement Line
* @param lineno
* The Line No. of the created Movement Line
* @return
* @param locator
* The Distribution Order Issue Warehouse's OverIssue Locator
* @return movement line
* The Movement Line created
*/
private static InternalMovementLine createAndSaveMovementLine(final InternalMovement movement,
final DistributionOrderLine distOrdline, final StockProposed stock, final BigDecimal movementQty, final long lineno) {
private static InternalMovementLine createAndSaveMovementLine(final InternalMovement movement, final DistributionOrderLine distOrdline, final StockProposed stock, final BigDecimal movementQty, final long lineno, final Locator locator, final Map<String, String> existingProductIds) {
final InternalMovementLine movementline = OBProvider.getInstance().get(InternalMovementLine.class);
movementline.setOrganization(movement.getOrganization());
movementline.setClient(movement.getClient());
......@@ -416,17 +469,85 @@ public class ProcessIssue extends BaseProcessActionHandler {
movementline.setProduct(distOrdline.getProduct());
movementline.setLineNo(lineno);
movementline.setMovementQuantity(movementQty);
movementline.setAttributeSetValue(stock.getStorageDetail().getAttributeSetValue());
if (stock != null) {
movementline.setAttributeSetValue(stock.getStorageDetail().getAttributeSetValue());
movementline.setStorageBin(stock.getStorageDetail().getStorageBin());
} else {
movementline.setStorageBin(locator);
}
movementline.setUOM(distOrdline.getUOM());
movementline.setObdoDistorderline(distOrdline);
movementline.setStorageBin(stock.getStorageDetail().getStorageBin());
movementline.setNewStorageBin(movement.getObdoIntransitLocator());
movementline.setOperativeQuantity(distOrdline.getOperativeQuantity());
movementline.setAlternativeUOM(distOrdline.getAlternativeUOM());
OBDal.getInstance().save(movementline);
existingProductIds.put(distOrdline.getProduct().getId(), movementline.getId());
return movementline;
}
/**
* Creates or updates an existing line to work with negative stock if possible
*
* @param distOrdline
* - The Distribution Order Line
* @param movement
* - The Internal Movement
* @param locator
* - The Locator
* @param movementQty
* - The Movement Quantity for Movement Line
* @param lineno
* - The Line no to be set in case new Movement Line to be created
* @return line count
* - The No.of lines added, being -1 if no possible to work with negative stock, 0 if an existing line have been reused and 1 if a new line has been created
*/
private static int workWithNegativeStockIfPossible(DistributionOrderLine distOrdline, InternalMovement movement, Locator locator, BigDecimal movementQty, long lineno, final Map<String, String> existingProductIds) {
int lineCount = -1;
// Create Movement Lines only when product does not have attribute set
if (distOrdline.getProduct().getAttributeSet() == null) {
// Check whether movement line already exists for product in the movement, if so add
// the quantity to same line else create a new one
String productId = distOrdline.getProduct().getId();
InternalMovementLine movementline = null;
if (existingProductIds.containsKey(productId)) {
// get movementLine if it already exists for Product proposed in new line
movementline = OBDal.getInstance().get(InternalMovementLine.class, existingProductIds.get(productId));
}
if (movementline != null) {
movementline.setMovementQuantity(movementline.getMovementQuantity().add(movementQty));
OBDal.getInstance().save(movementline);
lineCount = 0;
} else {
createAndSaveMovementLine(movement, distOrdline, null, movementQty, lineno,
locator, existingProductIds);
lineCount = 1;
}
}
return lineCount;
}
/**
* Returns OverIssue Bin from the Issue Warehouse of Distribution Order
* @param warehouse - Issue Warehouse of Distribution Order
* @return Locator with over issue inventory status
*/
private static Locator getOverissueBinForWarehouse(String warehouseId) {
//@formatter:off
String hql =
"as sb" +
" where sb.warehouse.id = :warehouseId " +
" and sb.inventoryStatus.overissue = true " +
" order by sb.default desc, sb.relativePriority asc, sb.id ";
//@formatter:on
return OBDal.getInstance()
.createQuery(Locator.class, hql)
.setNamedParameter("warehouseId", warehouseId)
.setMaxResult(1)
.uniqueResult();
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment