IDEMPIERE-493 Add validation for matching
This commit is contained in:
parent
7023ce3eea
commit
ba27cda7cf
|
@ -1552,16 +1552,18 @@ public class MInOut extends X_M_InOut implements DocAction
|
||||||
log.fine("PO Matching");
|
log.fine("PO Matching");
|
||||||
// Ship - PO
|
// Ship - PO
|
||||||
MMatchPO po = MMatchPO.create (null, sLine, getMovementDate(), matchQty);
|
MMatchPO po = MMatchPO.create (null, sLine, getMovementDate(), matchQty);
|
||||||
boolean isNewMatchPO = false;
|
if (po != null) {
|
||||||
if (po.get_ID() == 0)
|
boolean isNewMatchPO = false;
|
||||||
isNewMatchPO = true;
|
if (po.get_ID() == 0)
|
||||||
if (!po.save(get_TrxName()))
|
isNewMatchPO = true;
|
||||||
{
|
if (!po.save(get_TrxName()))
|
||||||
m_processMsg = "Could not create PO Matching";
|
{
|
||||||
return DocAction.STATUS_Invalid;
|
m_processMsg = "Could not create PO Matching";
|
||||||
|
return DocAction.STATUS_Invalid;
|
||||||
|
}
|
||||||
|
if (isNewMatchPO)
|
||||||
|
addDocsPostProcess(po);
|
||||||
}
|
}
|
||||||
if (isNewMatchPO)
|
|
||||||
addDocsPostProcess(po);
|
|
||||||
// Update PO with ASI
|
// Update PO with ASI
|
||||||
if ( oLine != null && oLine.getM_AttributeSetInstance_ID() == 0
|
if ( oLine != null && oLine.getM_AttributeSetInstance_ID() == 0
|
||||||
&& sLine.getMovementQty().compareTo(oLine.getQtyOrdered()) == 0) // just if full match [ 1876965 ]
|
&& sLine.getMovementQty().compareTo(oLine.getQtyOrdered()) == 0) // just if full match [ 1876965 ]
|
||||||
|
@ -1580,18 +1582,21 @@ public class MInOut extends X_M_InOut implements DocAction
|
||||||
// Ship - Invoice
|
// Ship - Invoice
|
||||||
MMatchPO po = MMatchPO.create (iLine, sLine,
|
MMatchPO po = MMatchPO.create (iLine, sLine,
|
||||||
getMovementDate(), matchQty);
|
getMovementDate(), matchQty);
|
||||||
boolean isNewMatchPO = false;
|
if (po != null) {
|
||||||
if (po.get_ID() == 0)
|
boolean isNewMatchPO = false;
|
||||||
isNewMatchPO = true;
|
if (po.get_ID() == 0)
|
||||||
if (!po.save(get_TrxName()))
|
isNewMatchPO = true;
|
||||||
{
|
if (!po.save(get_TrxName()))
|
||||||
m_processMsg = "Could not create PO(Inv) Matching";
|
{
|
||||||
return DocAction.STATUS_Invalid;
|
m_processMsg = "Could not create PO(Inv) Matching";
|
||||||
|
return DocAction.STATUS_Invalid;
|
||||||
|
}
|
||||||
|
if (isNewMatchPO)
|
||||||
|
addDocsPostProcess(po);
|
||||||
}
|
}
|
||||||
if (isNewMatchPO)
|
|
||||||
addDocsPostProcess(po);
|
|
||||||
// Update PO with ASI
|
// Update PO with ASI
|
||||||
oLine = new MOrderLine (getCtx(), po.getC_OrderLine_ID(), get_TrxName());
|
oLine = new MOrderLine (getCtx(), iLine.getC_OrderLine_ID(), get_TrxName());
|
||||||
if ( oLine != null && oLine.getM_AttributeSetInstance_ID() == 0
|
if ( oLine != null && oLine.getM_AttributeSetInstance_ID() == 0
|
||||||
&& sLine.getMovementQty().compareTo(oLine.getQtyOrdered()) == 0) // just if full match [ 1876965 ]
|
&& sLine.getMovementQty().compareTo(oLine.getQtyOrdered()) == 0) // just if full match [ 1876965 ]
|
||||||
{
|
{
|
||||||
|
|
|
@ -222,6 +222,33 @@ public class MMatchInv extends X_M_MatchInv
|
||||||
return true;
|
return true;
|
||||||
} // beforeSave
|
} // beforeSave
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean afterSave(boolean newRecord, boolean success) {
|
||||||
|
if (!success)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (getM_InOutLine_ID() > 0)
|
||||||
|
{
|
||||||
|
MInOutLine line = new MInOutLine(getCtx(), getM_InOutLine_ID(), get_TrxName());
|
||||||
|
BigDecimal matchedQty = DB.getSQLValueBD(get_TrxName(), "SELECT Coalesce(SUM(Qty),0) FROM M_MatchInv WHERE M_InOutLine_ID=?" , getM_InOutLine_ID());
|
||||||
|
if (matchedQty != null && matchedQty.compareTo(line.getMovementQty()) > 0)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("Total matched qty > movement qty. MatchedQty="+matchedQty+", MovementQty="+line.getMovementQty()+", Line="+line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getC_InvoiceLine_ID() > 0)
|
||||||
|
{
|
||||||
|
MInvoiceLine line = new MInvoiceLine(getCtx(), getC_InvoiceLine_ID(), get_TrxName());
|
||||||
|
BigDecimal matchedQty = DB.getSQLValueBD(get_TrxName(), "SELECT Coalesce(SUM(Qty),0) FROM M_MatchInv WHERE C_InvoiceLine_ID=?" , getC_InvoiceLine_ID());
|
||||||
|
if (matchedQty != null && matchedQty.compareTo(line.getQtyInvoiced()) > 0)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("Total matched qty > invoiced qty. MatchedQty="+matchedQty+", InvoicedQty="+line.getQtyInvoiced()+", Line="+line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the later Date Acct from invoice or shipment
|
* Get the later Date Acct from invoice or shipment
|
||||||
* @return date or null
|
* @return date or null
|
||||||
|
@ -279,7 +306,9 @@ public class MMatchInv extends X_M_MatchInv
|
||||||
deleteMatchInvCostDetail();
|
deleteMatchInvCostDetail();
|
||||||
// end AZ
|
// end AZ
|
||||||
|
|
||||||
|
// delete m_matchinv doesn't auto make m_matchpo invalid
|
||||||
// Get Order and decrease invoices
|
// Get Order and decrease invoices
|
||||||
|
/*
|
||||||
MInvoiceLine iLine = new MInvoiceLine (getCtx(), getC_InvoiceLine_ID(), get_TrxName());
|
MInvoiceLine iLine = new MInvoiceLine (getCtx(), getC_InvoiceLine_ID(), get_TrxName());
|
||||||
int C_OrderLine_ID = iLine.getC_OrderLine_ID();
|
int C_OrderLine_ID = iLine.getC_OrderLine_ID();
|
||||||
if (C_OrderLine_ID == 0)
|
if (C_OrderLine_ID == 0)
|
||||||
|
@ -303,6 +332,7 @@ public class MMatchInv extends X_M_MatchInv
|
||||||
mPO[i].saveEx();
|
mPO[i].saveEx();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
} // afterDelete
|
} // afterDelete
|
||||||
|
|
|
@ -19,6 +19,7 @@ package org.compiere.model;
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.sql.PreparedStatement;
|
import java.sql.PreparedStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.Savepoint;
|
||||||
import java.sql.Timestamp;
|
import java.sql.Timestamp;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
@ -27,6 +28,8 @@ import java.util.logging.Level;
|
||||||
import org.compiere.util.CLogger;
|
import org.compiere.util.CLogger;
|
||||||
import org.compiere.util.DB;
|
import org.compiere.util.DB;
|
||||||
import org.compiere.util.Env;
|
import org.compiere.util.Env;
|
||||||
|
import org.compiere.util.Trx;
|
||||||
|
import org.compiere.util.ValueNamePair;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Match PO Model.
|
* Match PO Model.
|
||||||
|
@ -100,6 +103,53 @@ public class MMatchPO extends X_M_MatchPO
|
||||||
return retValue;
|
return retValue;
|
||||||
} // get
|
} // get
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get PO Match of Receipt Line
|
||||||
|
* @param ctx context
|
||||||
|
* @param M_InOutLine_ID receipt
|
||||||
|
* @param trxName transaction
|
||||||
|
* @return array of matches
|
||||||
|
*/
|
||||||
|
public static MMatchPO[] get (Properties ctx,
|
||||||
|
int M_InOutLine_ID, String trxName)
|
||||||
|
{
|
||||||
|
if (M_InOutLine_ID == 0)
|
||||||
|
return new MMatchPO[]{};
|
||||||
|
//
|
||||||
|
String sql = "SELECT * FROM M_MatchPO WHERE M_InOutLine_ID=?";
|
||||||
|
ArrayList<MMatchPO> list = new ArrayList<MMatchPO>();
|
||||||
|
PreparedStatement pstmt = null;
|
||||||
|
ResultSet rs = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
pstmt = DB.prepareStatement (sql, trxName);
|
||||||
|
pstmt.setInt (1, M_InOutLine_ID);
|
||||||
|
rs = pstmt.executeQuery ();
|
||||||
|
while (rs.next ())
|
||||||
|
list.add (new MMatchPO (ctx, rs, trxName));
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
s_log.log(Level.SEVERE, sql, e);
|
||||||
|
if (e instanceof RuntimeException)
|
||||||
|
{
|
||||||
|
throw (RuntimeException)e;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
DB.close(rs, pstmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
MMatchPO[] retValue = new MMatchPO[list.size()];
|
||||||
|
list.toArray (retValue);
|
||||||
|
return retValue;
|
||||||
|
} // get
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get PO Matches of receipt
|
* Get PO Matches of receipt
|
||||||
* @param ctx context
|
* @param ctx context
|
||||||
|
@ -249,8 +299,54 @@ public class MMatchPO extends X_M_MatchPO
|
||||||
C_OrderLine_ID = sLine.getC_OrderLine_ID();
|
C_OrderLine_ID = sLine.getC_OrderLine_ID();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (C_OrderLine_ID > 0)
|
||||||
|
{
|
||||||
|
return create(ctx, iLine, sLine, C_OrderLine_ID, dateTrx, qty, trxName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (sLine != null && iLine != null)
|
||||||
|
{
|
||||||
|
MMatchPO[] matchpos = MMatchPO.get(ctx, sLine.getM_InOutLine_ID(), trxName);
|
||||||
|
for (MMatchPO matchpo : matchpos)
|
||||||
|
{
|
||||||
|
C_OrderLine_ID = matchpo.getC_OrderLine_ID();
|
||||||
|
MOrderLine orderLine = new MOrderLine(ctx, C_OrderLine_ID, trxName);
|
||||||
|
BigDecimal toInvoice = orderLine.getQtyOrdered().subtract(orderLine.getQtyInvoiced());
|
||||||
|
if (toInvoice.signum() <= 0)
|
||||||
|
continue;
|
||||||
|
BigDecimal matchQty = qty;
|
||||||
|
if (matchQty.compareTo(toInvoice) > 0)
|
||||||
|
matchQty = toInvoice;
|
||||||
|
|
||||||
|
if (matchQty.signum() <= 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
MMatchPO newMatchPO = create(ctx, iLine, sLine, C_OrderLine_ID, dateTrx, matchQty, trxName);
|
||||||
|
if (!newMatchPO.save())
|
||||||
|
{
|
||||||
|
String msg = "Failed to update match po.";
|
||||||
|
ValueNamePair error = CLogger.retrieveError();
|
||||||
|
if (error != null)
|
||||||
|
{
|
||||||
|
msg = msg + " " + error.getName();
|
||||||
|
}
|
||||||
|
throw new RuntimeException(msg);
|
||||||
|
}
|
||||||
|
qty = qty.subtract(matchQty);
|
||||||
|
if (qty.signum() <= 0)
|
||||||
|
return newMatchPO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MMatchPO create(Properties ctx, MInvoiceLine iLine,
|
||||||
|
MInOutLine sLine, int C_OrderLine_ID, Timestamp dateTrx,
|
||||||
|
BigDecimal qty, String trxName) {
|
||||||
MMatchPO retValue = null;
|
MMatchPO retValue = null;
|
||||||
String sql = "SELECT * FROM M_MatchPO WHERE C_OrderLine_ID=?";
|
String sql = "SELECT * FROM M_MatchPO WHERE C_OrderLine_ID=? ORDER BY M_MatchPO_ID";
|
||||||
PreparedStatement pstmt = null;
|
PreparedStatement pstmt = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try
|
try
|
||||||
|
@ -261,14 +357,17 @@ public class MMatchPO extends X_M_MatchPO
|
||||||
while (rs.next ())
|
while (rs.next ())
|
||||||
{
|
{
|
||||||
MMatchPO mpo = new MMatchPO (ctx, rs, trxName);
|
MMatchPO mpo = new MMatchPO (ctx, rs, trxName);
|
||||||
if (qty.compareTo(mpo.getQty()) == 0)
|
if (qty.compareTo(mpo.getQty()) >= 0)
|
||||||
{
|
{
|
||||||
|
BigDecimal toMatch = qty;
|
||||||
|
BigDecimal matchQty = mpo.getQty();
|
||||||
|
if (toMatch.compareTo(matchQty) > 0)
|
||||||
|
toMatch = matchQty;
|
||||||
if (iLine != null)
|
if (iLine != null)
|
||||||
{
|
{
|
||||||
if (mpo.getC_InvoiceLine_ID() == 0
|
if ((mpo.getC_InvoiceLine_ID() == 0)
|
||||||
|| mpo.getC_InvoiceLine_ID() == iLine.getC_InvoiceLine_ID())
|
|| (mpo.getC_InvoiceLine_ID() == iLine.getC_InvoiceLine_ID()))
|
||||||
{
|
{
|
||||||
mpo.setC_InvoiceLine_ID(iLine);
|
|
||||||
if (iLine.getM_AttributeSetInstance_ID() != 0)
|
if (iLine.getM_AttributeSetInstance_ID() != 0)
|
||||||
{
|
{
|
||||||
if (mpo.getM_AttributeSetInstance_ID() == 0)
|
if (mpo.getM_AttributeSetInstance_ID() == 0)
|
||||||
|
@ -282,10 +381,10 @@ public class MMatchPO extends X_M_MatchPO
|
||||||
}
|
}
|
||||||
if (sLine != null)
|
if (sLine != null)
|
||||||
{
|
{
|
||||||
if (mpo.getM_InOutLine_ID() == 0
|
if ((mpo.getM_InOutLine_ID() == 0)
|
||||||
|| mpo.getM_InOutLine_ID() == sLine.getM_InOutLine_ID())
|
|| (mpo.getM_InOutLine_ID() == sLine.getM_InOutLine_ID()))
|
||||||
{
|
{
|
||||||
mpo.setM_InOutLine_ID(sLine.getM_InOutLine_ID());
|
|
||||||
if (sLine.getM_AttributeSetInstance_ID() != 0)
|
if (sLine.getM_AttributeSetInstance_ID() != 0)
|
||||||
{
|
{
|
||||||
if (mpo.getM_AttributeSetInstance_ID() == 0)
|
if (mpo.getM_AttributeSetInstance_ID() == 0)
|
||||||
|
@ -297,33 +396,152 @@ public class MMatchPO extends X_M_MatchPO
|
||||||
else
|
else
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if ((iLine != null || mpo.getC_InvoiceLine_ID() > 0) && (sLine != null || mpo.getM_InOutLine_ID() > 0))
|
||||||
|
{
|
||||||
|
int M_InOutLine_ID = sLine != null ? sLine.getM_InOutLine_ID() : mpo.getM_InOutLine_ID();
|
||||||
|
int C_InvoiceLine_ID = iLine != null ? iLine.getC_InvoiceLine_ID() : mpo.getC_InvoiceLine_ID();
|
||||||
|
|
||||||
|
//verify invoiceline not already linked to another inoutline
|
||||||
|
int tmpInOutLineId = DB.getSQLValue(mpo.get_TrxName(), "SELECT M_InOutLine_ID FROM C_InvoiceLine WHERE C_InvoiceLine_ID="+C_InvoiceLine_ID);
|
||||||
|
if (tmpInOutLineId > 0 && tmpInOutLineId != M_InOutLine_ID)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//verify m_matchinv not created yet
|
||||||
|
int cnt = DB.getSQLValue(mpo.get_TrxName(), "SELECT Count(*) FROM M_MatchInv WHERE M_InOutLine_ID="+M_InOutLine_ID
|
||||||
|
+" AND C_InvoiceLine_ID="+C_InvoiceLine_ID);
|
||||||
|
if (cnt <= 0)
|
||||||
|
{
|
||||||
|
Trx trx = trxName != null ? Trx.get(trxName, false) : null;
|
||||||
|
Savepoint savepoint = trx != null ? trx.getConnection().setSavepoint() : null;
|
||||||
|
MMatchInv matchInv = new MMatchInv(mpo.getCtx(), 0, mpo.get_TrxName());
|
||||||
|
matchInv.setC_InvoiceLine_ID(C_InvoiceLine_ID);
|
||||||
|
matchInv.setM_Product_ID(mpo.getM_Product_ID());
|
||||||
|
matchInv.setM_InOutLine_ID(M_InOutLine_ID);
|
||||||
|
matchInv.setAD_Client_ID(mpo.getAD_Client_ID());
|
||||||
|
matchInv.setAD_Org_ID(mpo.getAD_Org_ID());
|
||||||
|
matchInv.setM_AttributeSetInstance_ID(mpo.getM_AttributeSetInstance_ID());
|
||||||
|
matchInv.setQty(mpo.getQty());
|
||||||
|
matchInv.setDateTrx(dateTrx);
|
||||||
|
if (!matchInv.save())
|
||||||
|
{
|
||||||
|
if (savepoint != null)
|
||||||
|
{
|
||||||
|
trx.getConnection().rollback(savepoint);
|
||||||
|
savepoint = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
matchInv.delete(true);
|
||||||
|
}
|
||||||
|
String msg = "Failed to auto match invoice.";
|
||||||
|
ValueNamePair error = CLogger.retrieveError();
|
||||||
|
if (error != null)
|
||||||
|
{
|
||||||
|
msg = msg + " " + error.getName();
|
||||||
|
}
|
||||||
|
//log as debug message and continue
|
||||||
|
s_log.fine(msg);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (savepoint != null)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
trx.getConnection().releaseSavepoint(savepoint);
|
||||||
|
} catch (Exception e) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (iLine != null)
|
||||||
|
mpo.setC_InvoiceLine_ID(iLine);
|
||||||
|
if (sLine != null)
|
||||||
|
mpo.setM_InOutLine_ID(sLine.getM_InOutLine_ID());
|
||||||
|
|
||||||
|
if (!mpo.save())
|
||||||
|
{
|
||||||
|
String msg = "Failed to update match po.";
|
||||||
|
ValueNamePair error = CLogger.retrieveError();
|
||||||
|
if (error != null)
|
||||||
|
{
|
||||||
|
msg = msg + " " + error.getName();
|
||||||
|
}
|
||||||
|
throw new RuntimeException(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
qty = qty.subtract(toMatch);
|
||||||
|
if (qty.signum() <= 0)
|
||||||
|
{
|
||||||
retValue = mpo;
|
retValue = mpo;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
s_log.log(Level.SEVERE, sql, e);
|
s_log.log(Level.SEVERE, sql, e);
|
||||||
|
if (e instanceof RuntimeException)
|
||||||
|
{
|
||||||
|
throw (RuntimeException)e;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new IllegalStateException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
DB.close(rs, pstmt);
|
DB.close(rs, pstmt);
|
||||||
rs = null; pstmt = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create New
|
// Create New
|
||||||
if (retValue == null)
|
if (retValue == null)
|
||||||
{
|
{
|
||||||
if (sLine != null)
|
BigDecimal sLineMatchedQty = null;
|
||||||
|
if (sLine != null && iLine != null)
|
||||||
{
|
{
|
||||||
retValue = new MMatchPO (sLine, dateTrx, qty);
|
sLineMatchedQty = DB.getSQLValueBD(sLine.get_TrxName(), "SELECT Sum(Qty) FROM M_MatchPO WHERE C_OrderLine_ID="+C_OrderLine_ID+" AND M_InOutLine_ID=?", sLine.getM_InOutLine_ID());
|
||||||
if (iLine != null)
|
}
|
||||||
retValue.setC_InvoiceLine_ID(iLine);
|
|
||||||
|
if (sLine != null && (sLine.getC_OrderLine_ID() == C_OrderLine_ID || iLine == null)
|
||||||
|
&& (sLineMatchedQty == null || sLineMatchedQty.signum() <= 0))
|
||||||
|
{
|
||||||
|
if (qty.signum() > 0)
|
||||||
|
{
|
||||||
|
retValue = new MMatchPO (sLine, dateTrx, qty);
|
||||||
|
retValue.setC_OrderLine_ID(C_OrderLine_ID);
|
||||||
|
if (iLine != null)
|
||||||
|
retValue.setC_InvoiceLine_ID(iLine);
|
||||||
|
if (!retValue.save())
|
||||||
|
{
|
||||||
|
String msg = "Failed to update match po.";
|
||||||
|
ValueNamePair error = CLogger.retrieveError();
|
||||||
|
if (error != null)
|
||||||
|
{
|
||||||
|
msg = msg + " " + error.getName();
|
||||||
|
}
|
||||||
|
throw new RuntimeException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (iLine != null)
|
else if (iLine != null)
|
||||||
{
|
{
|
||||||
retValue = new MMatchPO (iLine, dateTrx, qty);
|
if (qty.signum() > 0)
|
||||||
|
{
|
||||||
|
retValue = new MMatchPO (iLine, dateTrx, qty);
|
||||||
|
retValue.setC_OrderLine_ID(C_OrderLine_ID);
|
||||||
|
if (!retValue.save())
|
||||||
|
{
|
||||||
|
String msg = "Failed to update match po.";
|
||||||
|
ValueNamePair error = CLogger.retrieveError();
|
||||||
|
if (error != null)
|
||||||
|
{
|
||||||
|
msg = msg + " " + error.getName();
|
||||||
|
}
|
||||||
|
throw new RuntimeException(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -617,6 +835,20 @@ public class MMatchPO extends X_M_MatchPO
|
||||||
setPriceMatchDifference(difference);
|
setPriceMatchDifference(difference);
|
||||||
setIsApproved(true);
|
setIsApproved(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//validate against M_MatchInv
|
||||||
|
if (getM_InOutLine_ID() > 0 && getC_InvoiceLine_ID() > 0)
|
||||||
|
{
|
||||||
|
int cnt = DB.getSQLValue(get_TrxName(), "SELECT Count(*) FROM M_MatchInv WHERE M_InOutLine_ID="+getM_InOutLine_ID()
|
||||||
|
+" AND C_InvoiceLine_ID="+getC_InvoiceLine_ID());
|
||||||
|
if (cnt <= 0)
|
||||||
|
{
|
||||||
|
MInvoiceLine invoiceLine = new MInvoiceLine(getCtx(), getC_InvoiceLine_ID(), get_TrxName());
|
||||||
|
MInOutLine inoutLine = new MInOutLine(getCtx(), getM_InOutLine_ID(), get_TrxName());
|
||||||
|
throw new IllegalStateException("[MatchPO] Missing corresponding invoice matching record for invoice line "
|
||||||
|
+ invoiceLine + " and receipt line " + inoutLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -632,6 +864,46 @@ public class MMatchPO extends X_M_MatchPO
|
||||||
@Override
|
@Override
|
||||||
protected boolean afterSave (boolean newRecord, boolean success)
|
protected boolean afterSave (boolean newRecord, boolean success)
|
||||||
{
|
{
|
||||||
|
//perform matched qty validation
|
||||||
|
if (success)
|
||||||
|
{
|
||||||
|
if (getM_InOutLine_ID() > 0)
|
||||||
|
{
|
||||||
|
MInOutLine line = new MInOutLine(getCtx(), getM_InOutLine_ID(), get_TrxName());
|
||||||
|
BigDecimal matchedQty = DB.getSQLValueBD(get_TrxName(), "SELECT Coalesce(SUM(Qty),0) FROM M_MatchPO WHERE M_InOutLine_ID=?" , getM_InOutLine_ID());
|
||||||
|
if (matchedQty != null && matchedQty.compareTo(line.getMovementQty()) > 0)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("Total matched qty > movement qty. MatchedQty="+matchedQty+", MovementQty="+line.getMovementQty()+", Line="+line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getC_InvoiceLine_ID() > 0)
|
||||||
|
{
|
||||||
|
MInvoiceLine line = new MInvoiceLine(getCtx(), getC_InvoiceLine_ID(), get_TrxName());
|
||||||
|
BigDecimal matchedQty = DB.getSQLValueBD(get_TrxName(), "SELECT Coalesce(SUM(Qty),0) FROM M_MatchPO WHERE C_InvoiceLine_ID=?" , getC_InvoiceLine_ID());
|
||||||
|
if (matchedQty != null && matchedQty.compareTo(line.getQtyInvoiced()) > 0)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("Total matched qty > invoiced qty. MatchedQty="+matchedQty+", InvoicedQty="+line.getQtyInvoiced()+", Line="+line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getC_OrderLine_ID() > 0)
|
||||||
|
{
|
||||||
|
MOrderLine line = new MOrderLine(getCtx(), getC_OrderLine_ID(), get_TrxName());
|
||||||
|
BigDecimal invoicedQty = DB.getSQLValueBD(get_TrxName(), "SELECT Coalesce(SUM(Qty),0) FROM M_MatchPO WHERE C_InvoiceLine_ID > 0 and C_OrderLine_ID=?" , getC_OrderLine_ID());
|
||||||
|
if (invoicedQty != null && invoicedQty.compareTo(line.getQtyOrdered()) > 0)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("Total matched invoiced qty > ordered qty. MatchedInvoicedQty="+invoicedQty+", OrderedQty="+line.getQtyOrdered()+", 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=?" , getC_OrderLine_ID());
|
||||||
|
if (deliveredQty != null && deliveredQty.compareTo(line.getQtyOrdered()) > 0)
|
||||||
|
{
|
||||||
|
throw new IllegalStateException("Total matched delivered qty > ordered qty. MatchedDeliveredQty="+deliveredQty+", OrderedQty="+line.getQtyOrdered()+", Line="+line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Purchase Order Delivered/Invoiced
|
// Purchase Order Delivered/Invoiced
|
||||||
// (Reserved in VMatch and MInOut.completeIt)
|
// (Reserved in VMatch and MInOut.completeIt)
|
||||||
if (success && getC_OrderLine_ID() != 0)
|
if (success && getC_OrderLine_ID() != 0)
|
||||||
|
|
|
@ -21,6 +21,7 @@ import java.sql.Timestamp;
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
import org.adempiere.exceptions.AdempiereException;
|
||||||
import org.compiere.minigrid.IDColumn;
|
import org.compiere.minigrid.IDColumn;
|
||||||
import org.compiere.minigrid.IMiniTable;
|
import org.compiere.minigrid.IMiniTable;
|
||||||
import org.compiere.model.MClient;
|
import org.compiere.model.MClient;
|
||||||
|
@ -38,6 +39,7 @@ import org.compiere.util.Env;
|
||||||
import org.compiere.util.KeyNamePair;
|
import org.compiere.util.KeyNamePair;
|
||||||
import org.compiere.util.Msg;
|
import org.compiere.util.Msg;
|
||||||
import org.compiere.util.Trx;
|
import org.compiere.util.Trx;
|
||||||
|
import org.compiere.util.ValueNamePair;
|
||||||
|
|
||||||
public class Match
|
public class Match
|
||||||
{
|
{
|
||||||
|
@ -416,50 +418,74 @@ public class Match
|
||||||
{
|
{
|
||||||
MMatchInv match = new MMatchInv (iLine, null, qty);
|
MMatchInv match = new MMatchInv (iLine, null, qty);
|
||||||
match.setM_InOutLine_ID(M_InOutLine_ID);
|
match.setM_InOutLine_ID(M_InOutLine_ID);
|
||||||
if (match.save()) {
|
match.saveEx();
|
||||||
success = true;
|
success = true;
|
||||||
if (MClient.isClientAccountingImmediate()) {
|
if (MClient.isClientAccountingImmediate()) {
|
||||||
String ignoreError = DocumentEngine.postImmediate(match.getCtx(), match.getAD_Client_ID(), match.get_Table_ID(), match.get_ID(), true, match.get_TrxName());
|
String ignoreError = DocumentEngine.postImmediate(match.getCtx(), match.getAD_Client_ID(), match.get_Table_ID(), match.get_ID(), true, match.get_TrxName());
|
||||||
|
if (ignoreError != null) {
|
||||||
|
log.info(ignoreError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
log.log(Level.SEVERE, "Inv Match not created: " + match);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
success = true;
|
success = true;
|
||||||
// Create PO - Invoice Link = corrects PO
|
// Create PO - Invoice Link = corrects PO
|
||||||
if (iLine.getC_OrderLine_ID() != 0 && iLine.getM_Product_ID() != 0)
|
if (iLine.getM_Product_ID() != 0)
|
||||||
{
|
{
|
||||||
MMatchPO matchPO = MMatchPO.create(iLine, sLine, null, qty);
|
BigDecimal matchedQty = DB.getSQLValueBD(iLine.get_TrxName(), "SELECT Coalesce(SUM(Qty),0) FROM M_MatchPO WHERE C_InvoiceLine_ID=?" , iLine.getC_InvoiceLine_ID());
|
||||||
matchPO.setC_InvoiceLine_ID(iLine);
|
if (matchedQty.add(qty).compareTo(iLine.getQtyInvoiced()) <= 0)
|
||||||
matchPO.setM_InOutLine_ID(M_InOutLine_ID);
|
{
|
||||||
if (!matchPO.save())
|
MMatchPO matchPO = MMatchPO.create(iLine, sLine, null, qty);
|
||||||
log.log(Level.SEVERE, "PO(Inv) Match not created: " + matchPO);
|
if (matchPO != null)
|
||||||
if (MClient.isClientAccountingImmediate()) {
|
{
|
||||||
String ignoreError = DocumentEngine.postImmediate(matchPO.getCtx(), matchPO.getAD_Client_ID(), matchPO.get_Table_ID(), matchPO.get_ID(), true, matchPO.get_TrxName());
|
matchPO.saveEx();
|
||||||
|
if (MClient.isClientAccountingImmediate()) {
|
||||||
|
String ignoreError = DocumentEngine.postImmediate(matchPO.getCtx(), matchPO.getAD_Client_ID(), matchPO.get_Table_ID(), matchPO.get_ID(), true, matchPO.get_TrxName());
|
||||||
|
if (ignoreError != null)
|
||||||
|
log.info(ignoreError);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else // Shipment - Order
|
else // Shipment - Order
|
||||||
{
|
{
|
||||||
// Update Shipment Line
|
|
||||||
sLine.setC_OrderLine_ID(Line_ID);
|
|
||||||
sLine.saveEx();
|
|
||||||
// Update Order Line
|
// Update Order Line
|
||||||
MOrderLine oLine = new MOrderLine(Env.getCtx(), Line_ID, trxName);
|
MOrderLine oLine = new MOrderLine(Env.getCtx(), Line_ID, trxName);
|
||||||
if (oLine.get_ID() != 0) // other in MInOut.completeIt
|
if (oLine.get_ID() != 0) // other in MInOut.completeIt
|
||||||
{
|
{
|
||||||
oLine.setQtyReserved(oLine.getQtyReserved().subtract(qty));
|
oLine.setQtyReserved(oLine.getQtyReserved().subtract(qty));
|
||||||
if(!oLine.save())
|
oLine.saveEx();
|
||||||
log.severe("QtyReserved not updated - C_OrderLine_ID=" + Line_ID);
|
}
|
||||||
|
|
||||||
|
// Update Shipment Line
|
||||||
|
BigDecimal toDeliver = oLine.getQtyOrdered().subtract(oLine.getQtyDelivered());
|
||||||
|
if (sLine.getMovementQty().compareTo(toDeliver) <= 0)
|
||||||
|
{
|
||||||
|
sLine.setC_OrderLine_ID(Line_ID);
|
||||||
|
sLine.saveEx();
|
||||||
|
}
|
||||||
|
else if (sLine.getC_OrderLine_ID() != 0)
|
||||||
|
{
|
||||||
|
sLine.setC_OrderLine_ID(0);
|
||||||
|
sLine.saveEx();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create PO - Shipment Link
|
// Create PO - Shipment Link
|
||||||
if (sLine.getM_Product_ID() != 0)
|
if (sLine.getM_Product_ID() != 0)
|
||||||
{
|
{
|
||||||
MMatchPO match = new MMatchPO (sLine, null, qty);
|
MMatchPO match = new MMatchPO (sLine, null, qty);
|
||||||
|
match.setC_OrderLine_ID(Line_ID);
|
||||||
if (!match.save())
|
if (!match.save())
|
||||||
log.log(Level.SEVERE, "PO Match not created: " + match);
|
{
|
||||||
|
String msg = "PO Match not created: " + match;
|
||||||
|
ValueNamePair error = CLogger.retrieveError();
|
||||||
|
if (error != null)
|
||||||
|
{
|
||||||
|
msg = msg + ". " + error.getName();
|
||||||
|
}
|
||||||
|
throw new AdempiereException(msg);
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
success = true;
|
success = true;
|
||||||
|
|
Loading…
Reference in New Issue