Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error in calculating quantity ordered or reserved for manufacturing order and distribution order #3472

Merged
merged 3 commits into from
Jun 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions base/src/org/compiere/model/MInOut.java
Original file line number Diff line number Diff line change
Expand Up @@ -1459,9 +1459,9 @@ quantity, reservedDiff, orderedDiff, get_TrxName()))
} // stock movement

// Correct Order Line
if (product != null && orderLine != null && isSOTrx() && !orderLine.getParent().isReturnOrder()) // other in VMatch.createMatchRecord
if (product != null && product.isStocked() && orderLine != null && isSOTrx() && !orderLine.getParent().isReturnOrder()) // other in VMatch.createMatchRecord
orderLine.setQtyReserved(orderLine.getQtyReserved().add(QtySO));
else if (product != null && orderLine != null && !isSOTrx() && !orderLine.getParent().isReturnOrder())
else if (product != null && product.isStocked() && orderLine != null && !isSOTrx() && !orderLine.getParent().isReturnOrder())
orderLine.setQtyReserved(orderLine.getQtyReserved().add(QtyPO));

// Update Sales Order Line
Expand Down
170 changes: 76 additions & 94 deletions base/src/org/compiere/model/MOrder.java
Original file line number Diff line number Diff line change
Expand Up @@ -1313,6 +1313,9 @@ public String prepareIt()
m_processMsg = "@Error@ @Qty@ @QtyNotReserved@";
return DocAction.STATUS_Invalid;
}
//Calculate Sizes (Weight & Volume)
calculateOrderSizes(Arrays.asList(lines));

if (!calculateTaxTotal())
{
m_processMsg = "Error calculating tax";
Expand Down Expand Up @@ -1367,14 +1370,6 @@ public String prepareIt()
return DocAction.STATUS_Invalid;

m_justPrepared = true;
// if (!DOCACTION_Complete.equals(getDocAction())) don't set for just prepare
// setDocAction(DOCACTION_Complete);

/*for(final MOrderLine ol:getLines())
{
Util.assume(ol.getQtyReserved().compareTo(ol.getQtyOrdered()) == 0 || ol.getM_Product_ID() == 0 || dt.isProposal(),
"After prepareIt, reservations do not equal quantities ordered.");
}*/
return DocAction.STATUS_InProgress;
} // prepareIt

Expand Down Expand Up @@ -1434,30 +1429,7 @@ private boolean explodeBOM()
newLine.setPrice ();
newLine.save (get_TrxName());
}
}

/*MProductBOM[] boms = MProductBOM.getBOMLines (product);
for (int j = 0; j < boms.length; j++)
{
//MProductBOM bom = boms[j];
MPPProductBOMLine bom = boms[j];
MOrderLine newLine = new MOrderLine (this);
newLine.setLine (++lineNo);
//newLine.setM_Product_ID (bom.getProduct ()
// .getM_Product_ID ());
newLine.setM_Product_ID (bom.getM_Product_ID ());
//newLine.setC_UOM_ID (bom.getProduct ().getC_UOM_ID ());
newLine.setC_UOM_ID (bom.getC_UOM_ID ());
//newLine.setQty (line.getQtyOrdered ().multiply (
// bom.getBOMQty ()));
newLine.setQty (line.getQtyOrdered ().multiply (
bom.getQtyBOM()));
if (bom.getDescription () != null)
newLine.setDescription (bom.getDescription ());
//
newLine.setPrice ();
newLine.save (get_TrxName());
}*/
}

// Convert into Comment Line
line.setM_Product_ID (0);
Expand Down Expand Up @@ -1501,6 +1473,38 @@ public boolean isBinding() {
return binding;
}

/**
* Force same Warehouse for Line but SO/PO
* @param orderLine Order Line
*/
private void forceSameWarehouseToLine(int headerWarehouseId, MOrderLine orderLine) {
// enforce WH
if (headerWarehouseId != 0) {
if (headerWarehouseId != orderLine.getM_Warehouse_ID()) {
orderLine.setM_Warehouse_ID(headerWarehouseId);
orderLine.saveEx();
}
if (getAD_Org_ID() != orderLine.getAD_Org_ID()) {
orderLine.setAD_Org_ID(getAD_Org_ID());
orderLine.saveEx();
}
}
}

/**
* Calculate Sizes
*
* @param orderLines Order Lines
*/
private void calculateOrderSizes(List<MOrderLine> orderLines) {
setVolume(orderLines.stream().filter(orderLine -> orderLine.getM_Product_ID() > 0)
.map(orderLine -> Optional.ofNullable(orderLine.getProduct().getVolume()).orElse(BigDecimal.ZERO)
.multiply(orderLine.getQtyOrdered())).reduce(BigDecimal.ZERO, BigDecimal::add));
setWeight(orderLines.stream().filter(orderLine -> orderLine.getM_Product_ID() > 0)
.map(orderLine -> Optional.ofNullable(orderLine.getProduct().getWeight()).orElse(BigDecimal.ZERO)
.multiply(orderLine.getQtyOrdered())).reduce(BigDecimal.ZERO, BigDecimal::add));
}

/**
* Reserve Inventory.
* Counterpart: MInOut.completeIt()
Expand All @@ -1509,61 +1513,37 @@ public boolean isBinding() {
*/
private boolean reserveStock (MOrderLine[] lines)
{
List<MOrderLine> orderLines = Arrays.asList(lines);
boolean binding = isBinding();
boolean isSOTrx = isSOTrx();
// Force same Warehouse for all but SO/PO
final int headerWarehouseId = MDocType.DOCSUBTYPESO_StandardOrder.equals(getDocumentType().getDocSubTypeSO()) ||
MDocType.DOCBASETYPE_PurchaseOrder.equals(getDocumentType().getDocBaseType())
? 0 : getM_Warehouse_ID();
log.fine("Binding=" + binding + " - IsSOTrx=" + isSOTrx);
// Force same WH for all but SO/PO
int header_M_Warehouse_ID = getM_Warehouse_ID();
if (MDocType.DOCSUBTYPESO_StandardOrder.equals(getDocumentType().getDocSubTypeSO())
|| MDocType.DOCBASETYPE_PurchaseOrder.equals(getDocumentType().getDocBaseType()))
header_M_Warehouse_ID = 0; // don't enforce

BigDecimal volume = Env.ZERO;
BigDecimal weight = Env.ZERO;

// Always check and (un) Reserve Inventory
for (int i = 0; i < lines.length; i++)
{
MOrderLine line = lines[i];
MProduct product = line.getProduct();
// Always check and (un) Reserve Inventory
// Calculate Reserve Stock
orderLines.forEach(orderLine ->{
// Force same WH for all but SO/PO
// Check/set WH/Org
if (header_M_Warehouse_ID != 0) // enforce WH
{
if (header_M_Warehouse_ID != line.getM_Warehouse_ID())
line.setM_Warehouse_ID(header_M_Warehouse_ID);
if (getAD_Org_ID() != line.getAD_Org_ID())
line.setAD_Org_ID(getAD_Org_ID());
}
forceSameWarehouseToLine(headerWarehouseId, orderLine);
// Binding
BigDecimal target = binding ? line.getQtyOrdered() : Env.ZERO;
BigDecimal difference = target.subtract(line.getQtyReserved()).subtract(line.getQtyDelivered());
if (difference.signum() == 0)
{

if (product != null)
{
volume = volume.add(product.getVolume().multiply(line.getQtyOrdered()));
weight = weight.add(product.getWeight().multiply(line.getQtyOrdered()));
}
continue;
}

log.fine("Line=" + line.getLine()
+ " - Target=" + target + ",Difference=" + difference
+ " - Ordered=" + line.getQtyOrdered()
+ ",Reserved=" + line.getQtyReserved() + ",Delivered=" + line.getQtyDelivered());

line.reserveStock();
line.saveEx();
// Validate if exist a product
if (product != null) {
volume = volume.add(product.getVolume().multiply(line.getQtyOrdered()));
weight = weight.add(product.getWeight().multiply(line.getQtyOrdered()));
BigDecimal target = binding ? orderLine.getQtyOrdered() : Env.ZERO;
BigDecimal difference = target.subtract(orderLine.getQtyReserved()).subtract(orderLine.getQtyDelivered());
if (difference.signum() != 0) {
Optional<MProduct> maybeProduct = Optional.ofNullable(orderLine.getProduct());
maybeProduct.ifPresent(product -> {
if (product.isStocked()) {
orderLine.reserveStock();
orderLine.saveEx();
log.fine("Line=" + orderLine.getLine()
+ " - Target=" + target + ",Difference=" + difference
+ " - Ordered=" + orderLine.getQtyOrdered()
+ ",Reserved=" + orderLine.getQtyReserved() + ",Delivered=" + orderLine.getQtyDelivered());
}
});
}
} // reserve inventory

setVolume(volume);
setWeight(weight);
});
return true;
} // reserveStock

Expand Down Expand Up @@ -1626,8 +1606,7 @@ public boolean calculateTaxTotal() {
setGrandTotal(grandTotal.get());
return true;
} // calculateTaxTotal



/**
* Approve Document
* @return true if success
Expand Down Expand Up @@ -1671,8 +1650,12 @@ public String completeIt()
|| MDocType.DOCSUBTYPESO_Quotation.equals(DocSubTypeSO))
{
// Binding
if (MDocType.DOCSUBTYPESO_Quotation.equals(DocSubTypeSO))
reserveStock(getLines(true, MOrderLine.COLUMNNAME_M_Product_ID));
if (MDocType.DOCSUBTYPESO_Quotation.equals(DocSubTypeSO)) {
MOrderLine[] orderLines = getLines(true, MOrderLine.COLUMNNAME_M_Product_ID);
reserveStock(orderLines);
//Calculate Sizes (Weight & Volume)
calculateOrderSizes(Arrays.asList(orderLines));
}
m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_BEFORE_COMPLETE);
if (m_processMsg != null)
return DocAction.STATUS_Invalid;
Expand Down Expand Up @@ -2065,7 +2048,8 @@ public boolean voidIt()
m_processMsg = "@Error@ @Undo@ @QtyReserved@ @From@ (@Voided@)";
return false;
}

//Calculate Sizes (Weight & Volume)
calculateOrderSizes(Arrays.asList(lines));
// UnLink All Requisitions
MRequisitionLine.unlinkC_Order_ID(getCtx(), get_ID(), get_TrxName());

Expand Down Expand Up @@ -2204,6 +2188,9 @@ public boolean closeIt()
m_processMsg = "@Error@ @Undo@ @QtyReserved@ @From@ (@closed@)";
return false;
}

//Calculate Sizes (Weight & Volume)
calculateOrderSizes(Arrays.asList(lines));

setProcessed(true);
setDocAction(DOCACTION_None);
Expand Down Expand Up @@ -2259,6 +2246,9 @@ public String reopenIt() {
return "Failed to update reservations";
}

//Calculate Sizes (Weight & Volume)
calculateOrderSizes(Arrays.asList(lines));

setDocStatus(MOrder.DOCSTATUS_Completed);
setDocAction(DOCACTION_Close);
if (!this.save(get_TrxName()))
Expand Down Expand Up @@ -2370,14 +2360,6 @@ else if (MDocType.DOCSUBTYPESO_OnCreditOrder.equals(DocSubTypeSO) // (W)illCall(

setDocAction(DOCACTION_Complete);
setProcessed(false);

/*for(final MOrderLine ol: getLines())
{
Util.assume(ol.getQtyInvoiced().signum() == 0,
"After reactivateIt, QtyInvoiced is zero");
Util.assume(ol.getQtyReserved().compareTo(ol.getQtyOrdered()) == 0,
"After reactivateIt, reservations are still in place");
}*/
return true;
} // reActivateIt

Expand Down
9 changes: 4 additions & 5 deletions base/src/org/compiere/model/MOrderLine.java
Original file line number Diff line number Diff line change
Expand Up @@ -1129,6 +1129,8 @@ public void reserveStock() {
MAttributeSet.validateAttributeSetInstanceMandatory(product, Table_ID, isSOTrx(), getM_AttributeSetInstance_ID());
BigDecimal ordered = isSOTrx() ? Env.ZERO : difference;
BigDecimal reserved = isSOTrx() ? difference : Env.ZERO;
// update line
setQtyReserved(getQtyReserved().add(difference));
int locatorId = 0;
// Get Locator to reserve
if (getM_AttributeSetInstance_ID() != 0) // Get existing Location
Expand All @@ -1152,14 +1154,11 @@ public void reserveStock() {
}
}
// Update Storage
if (!MStorage.add(getCtx(), getM_Warehouse_ID(), locatorId,
MStorage.add(getCtx(), getM_Warehouse_ID(), locatorId,
getM_Product_ID(),
getM_AttributeSetInstance_ID(), getM_AttributeSetInstance_ID(),
Env.ZERO, reserved, ordered, get_TrxName()))
return;
Env.ZERO, reserved, ordered, get_TrxName());
} // stocked
// update line
setQtyReserved(getQtyReserved().add(difference));
}
}

Expand Down