IDEMPIERE-4575 Cannot complete Material Receipt from negative PO (#419)
This commit is contained in:
parent
71a2ee3fe7
commit
0eb4986513
|
@ -1117,16 +1117,24 @@ public class MMatchPO extends X_M_MatchPO
|
||||||
if (validateOrderedQty)
|
if (validateOrderedQty)
|
||||||
{
|
{
|
||||||
MOrderLine line = new MOrderLine(getCtx(), getC_OrderLine_ID(), get_TrxName());
|
MOrderLine line = new MOrderLine(getCtx(), getC_OrderLine_ID(), get_TrxName());
|
||||||
|
BigDecimal qtyOrdered = line.getQtyOrdered();
|
||||||
BigDecimal invoicedQty = DB.getSQLValueBD(get_TrxName(), "SELECT Coalesce(SUM(Qty),0) FROM M_MatchPO WHERE C_InvoiceLine_ID > 0 and C_OrderLine_ID=? AND Reversal_ID IS NULL" , getC_OrderLine_ID());
|
BigDecimal invoicedQty = DB.getSQLValueBD(get_TrxName(), "SELECT Coalesce(SUM(Qty),0) FROM M_MatchPO WHERE C_InvoiceLine_ID > 0 and C_OrderLine_ID=? AND Reversal_ID IS NULL" , getC_OrderLine_ID());
|
||||||
if (invoicedQty != null && invoicedQty.compareTo(line.getQtyOrdered()) > 0)
|
if ( invoicedQty != null
|
||||||
|
&& ( (qtyOrdered.signum() > 0 && invoicedQty.compareTo(qtyOrdered) > 0)
|
||||||
|
|| (qtyOrdered.signum() < 0 && invoicedQty.compareTo(qtyOrdered) < 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
throw new IllegalStateException("Total matched invoiced qty > ordered qty. MatchedInvoicedQty="+invoicedQty+", OrderedQty="+line.getQtyOrdered()+", Line="+line);
|
throw new IllegalStateException("Total matched invoiced qty > ordered qty. MatchedInvoicedQty="+invoicedQty+", OrderedQty="+qtyOrdered+", Line="+line);
|
||||||
}
|
}
|
||||||
|
|
||||||
BigDecimal deliveredQty = DB.getSQLValueBD(get_TrxName(), "SELECT Coalesce(SUM(Qty),0) FROM M_MatchPO WHERE M_InOutLine_ID > 0 and C_OrderLine_ID=? AND Reversal_ID IS NULL" , getC_OrderLine_ID());
|
BigDecimal deliveredQty = DB.getSQLValueBD(get_TrxName(), "SELECT Coalesce(SUM(Qty),0) FROM M_MatchPO WHERE M_InOutLine_ID > 0 and C_OrderLine_ID=? AND Reversal_ID IS NULL" , getC_OrderLine_ID());
|
||||||
if (deliveredQty != null && deliveredQty.compareTo(line.getQtyOrdered()) > 0)
|
if ( deliveredQty != null
|
||||||
|
&& ( (qtyOrdered.signum() > 0 && deliveredQty.compareTo(qtyOrdered) > 0)
|
||||||
|
|| (qtyOrdered.signum() < 0 && deliveredQty.compareTo(qtyOrdered) < 0)
|
||||||
|
)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
throw new IllegalStateException("Total matched delivered qty > ordered qty. MatchedDeliveredQty="+deliveredQty+", OrderedQty="+line.getQtyOrdered()+", Line="+line);
|
throw new IllegalStateException("Total matched delivered qty > ordered qty. MatchedDeliveredQty="+deliveredQty+", OrderedQty="+qtyOrdered+", Line="+line);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
/***********************************************************************
|
||||||
|
* This file is part of iDempiere ERP Open Source *
|
||||||
|
* http://www.idempiere.org *
|
||||||
|
* *
|
||||||
|
* Copyright (C) Contributors *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or *
|
||||||
|
* modify it under the terms of the GNU General Public License *
|
||||||
|
* as published by the Free Software Foundation; either version 2 *
|
||||||
|
* of the License, or (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
|
||||||
|
* MA 02110-1301, USA. *
|
||||||
|
* *
|
||||||
|
* Contributors: *
|
||||||
|
* - Carlos Ruiz - globalqss *
|
||||||
|
**********************************************************************/
|
||||||
|
package org.idempiere.test.model;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import org.compiere.model.MBPartner;
|
||||||
|
import org.compiere.model.MInOut;
|
||||||
|
import org.compiere.model.MInOutLine;
|
||||||
|
import org.compiere.model.MOrder;
|
||||||
|
import org.compiere.model.MOrderLine;
|
||||||
|
import org.compiere.model.MProduct;
|
||||||
|
import org.compiere.process.DocAction;
|
||||||
|
import org.compiere.process.ProcessInfo;
|
||||||
|
import org.compiere.util.Env;
|
||||||
|
import org.compiere.util.TimeUtil;
|
||||||
|
import org.compiere.wf.MWorkflow;
|
||||||
|
import org.idempiere.test.AbstractTestCase;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Carlos Ruiz - globalqss
|
||||||
|
*/
|
||||||
|
public class PurchaseOrderTest extends AbstractTestCase {
|
||||||
|
|
||||||
|
public PurchaseOrderTest() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final int BP_PATIO = 121;
|
||||||
|
private static final int DOCTYPE_PO = 126;
|
||||||
|
private static final int DOCTYPE_RECEIPT = 122;
|
||||||
|
private static final int PRODUCT_SEEDER = 143;
|
||||||
|
private static final int USER_GARDENADMIN = 101;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* https://idempiere.atlassian.net/browse/IDEMPIERE-4575
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testQtyReservedForNegativeOrderAndReceipt() {
|
||||||
|
Properties ctx = Env.getCtx();
|
||||||
|
String trxName = getTrxName();
|
||||||
|
|
||||||
|
MOrder order = new MOrder(ctx, 0, trxName);
|
||||||
|
order.setBPartner(MBPartner.get(ctx, BP_PATIO));
|
||||||
|
order.setC_DocTypeTarget_ID(DOCTYPE_PO);
|
||||||
|
order.setIsSOTrx(false);
|
||||||
|
order.setSalesRep_ID(USER_GARDENADMIN);
|
||||||
|
order.setDocStatus(DocAction.STATUS_Drafted);
|
||||||
|
order.setDocAction(DocAction.ACTION_Complete);
|
||||||
|
Timestamp today = TimeUtil.getDay(System.currentTimeMillis());
|
||||||
|
order.setDateOrdered(today);
|
||||||
|
order.setDatePromised(today);
|
||||||
|
order.saveEx();
|
||||||
|
|
||||||
|
MOrderLine line1 = new MOrderLine(order);
|
||||||
|
line1.setLine(10);
|
||||||
|
line1.setProduct(MProduct.get(ctx, PRODUCT_SEEDER));
|
||||||
|
line1.setQty(new BigDecimal("-1"));
|
||||||
|
line1.setDatePromised(today);
|
||||||
|
line1.saveEx();
|
||||||
|
|
||||||
|
ProcessInfo info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_Complete);
|
||||||
|
assertFalse(info.isError());
|
||||||
|
order.load(trxName);
|
||||||
|
assertEquals(DocAction.STATUS_Completed, order.getDocStatus());
|
||||||
|
line1.load(trxName);
|
||||||
|
assertEquals(0, line1.getQtyReserved().intValue());
|
||||||
|
|
||||||
|
MInOut receipt = new MInOut(order, DOCTYPE_RECEIPT, order.getDateOrdered());
|
||||||
|
receipt.setDocStatus(DocAction.STATUS_Drafted);
|
||||||
|
receipt.setDocAction(DocAction.ACTION_Complete);
|
||||||
|
receipt.saveEx();
|
||||||
|
|
||||||
|
// negative receipt
|
||||||
|
MInOutLine receiptLine = new MInOutLine(receipt);
|
||||||
|
receiptLine.setOrderLine(line1, 0, new BigDecimal("-1"));
|
||||||
|
receiptLine.setQty(new BigDecimal("-1"));
|
||||||
|
receiptLine.saveEx();
|
||||||
|
|
||||||
|
info = MWorkflow.runDocumentActionWorkflow(receipt, DocAction.ACTION_Complete);
|
||||||
|
assertFalse(info.isError());
|
||||||
|
receipt.load(trxName);
|
||||||
|
assertEquals(DocAction.STATUS_Completed, receipt.getDocStatus());
|
||||||
|
|
||||||
|
line1.load(trxName);
|
||||||
|
assertEquals(0, line1.getQtyReserved().intValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue