diff --git a/org.adempiere.base-feature/model.generator.launch b/org.adempiere.base-feature/model.generator.launch index 74596719aa..81e50a2ba2 100644 --- a/org.adempiere.base-feature/model.generator.launch +++ b/org.adempiere.base-feature/model.generator.launch @@ -12,7 +12,7 @@ - + @@ -20,7 +20,7 @@ - + diff --git a/org.adempiere.base/src/org/compiere/model/MInOut.java b/org.adempiere.base/src/org/compiere/model/MInOut.java index 0209dd1fbc..63a8be4ae5 100644 --- a/org.adempiere.base/src/org/compiere/model/MInOut.java +++ b/org.adempiere.base/src/org/compiere/model/MInOut.java @@ -1552,16 +1552,18 @@ public class MInOut extends X_M_InOut implements DocAction log.fine("PO Matching"); // Ship - PO MMatchPO po = MMatchPO.create (null, sLine, getMovementDate(), matchQty); - boolean isNewMatchPO = false; - if (po.get_ID() == 0) - isNewMatchPO = true; - if (!po.save(get_TrxName())) - { - m_processMsg = "Could not create PO Matching"; - return DocAction.STATUS_Invalid; + if (po != null) { + boolean isNewMatchPO = false; + if (po.get_ID() == 0) + isNewMatchPO = true; + if (!po.save(get_TrxName())) + { + m_processMsg = "Could not create PO Matching"; + return DocAction.STATUS_Invalid; + } + if (isNewMatchPO) + addDocsPostProcess(po); } - if (isNewMatchPO) - addDocsPostProcess(po); // Update PO with ASI if ( oLine != null && oLine.getM_AttributeSetInstance_ID() == 0 && 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 MMatchPO po = MMatchPO.create (iLine, sLine, getMovementDate(), matchQty); - boolean isNewMatchPO = false; - if (po.get_ID() == 0) - isNewMatchPO = true; - if (!po.save(get_TrxName())) - { - m_processMsg = "Could not create PO(Inv) Matching"; - return DocAction.STATUS_Invalid; + if (po != null) { + boolean isNewMatchPO = false; + if (po.get_ID() == 0) + isNewMatchPO = true; + if (!po.save(get_TrxName())) + { + m_processMsg = "Could not create PO(Inv) Matching"; + return DocAction.STATUS_Invalid; + } + if (isNewMatchPO) + addDocsPostProcess(po); } - if (isNewMatchPO) - addDocsPostProcess(po); + // 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 && sLine.getMovementQty().compareTo(oLine.getQtyOrdered()) == 0) // just if full match [ 1876965 ] { diff --git a/org.adempiere.base/src/org/compiere/model/MMatchInv.java b/org.adempiere.base/src/org/compiere/model/MMatchInv.java index 5953dec070..c58537f755 100644 --- a/org.adempiere.base/src/org/compiere/model/MMatchInv.java +++ b/org.adempiere.base/src/org/compiere/model/MMatchInv.java @@ -222,6 +222,33 @@ public class MMatchInv extends X_M_MatchInv return true; } // 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 * @return date or null @@ -279,7 +306,9 @@ public class MMatchInv extends X_M_MatchInv deleteMatchInvCostDetail(); // end AZ + // delete m_matchinv doesn't auto make m_matchpo invalid // Get Order and decrease invoices + /* MInvoiceLine iLine = new MInvoiceLine (getCtx(), getC_InvoiceLine_ID(), get_TrxName()); int C_OrderLine_ID = iLine.getC_OrderLine_ID(); if (C_OrderLine_ID == 0) @@ -303,6 +332,7 @@ public class MMatchInv extends X_M_MatchInv mPO[i].saveEx(); } } + */ } return success; } // afterDelete diff --git a/org.adempiere.base/src/org/compiere/model/MMatchPO.java b/org.adempiere.base/src/org/compiere/model/MMatchPO.java index 4f075b44cf..d35723c0ff 100644 --- a/org.adempiere.base/src/org/compiere/model/MMatchPO.java +++ b/org.adempiere.base/src/org/compiere/model/MMatchPO.java @@ -19,6 +19,7 @@ package org.compiere.model; import java.math.BigDecimal; import java.sql.PreparedStatement; import java.sql.ResultSet; +import java.sql.Savepoint; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Properties; @@ -27,6 +28,8 @@ import java.util.logging.Level; import org.compiere.util.CLogger; import org.compiere.util.DB; import org.compiere.util.Env; +import org.compiere.util.Trx; +import org.compiere.util.ValueNamePair; /** * Match PO Model. @@ -100,6 +103,53 @@ public class MMatchPO extends X_M_MatchPO return retValue; } // 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 list = new ArrayList(); + 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 * @param ctx context @@ -249,8 +299,54 @@ public class MMatchPO extends X_M_MatchPO 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; - 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; ResultSet rs = null; try @@ -261,14 +357,17 @@ public class MMatchPO extends X_M_MatchPO while (rs.next ()) { 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 (mpo.getC_InvoiceLine_ID() == 0 - || mpo.getC_InvoiceLine_ID() == iLine.getC_InvoiceLine_ID()) + if ((mpo.getC_InvoiceLine_ID() == 0) + || (mpo.getC_InvoiceLine_ID() == iLine.getC_InvoiceLine_ID())) { - mpo.setC_InvoiceLine_ID(iLine); if (iLine.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 (mpo.getM_InOutLine_ID() == 0 - || mpo.getM_InOutLine_ID() == sLine.getM_InOutLine_ID()) + if ((mpo.getM_InOutLine_ID() == 0) + || (mpo.getM_InOutLine_ID() == sLine.getM_InOutLine_ID())) { - mpo.setM_InOutLine_ID(sLine.getM_InOutLine_ID()); + if (sLine.getM_AttributeSetInstance_ID() != 0) { if (mpo.getM_AttributeSetInstance_ID() == 0) @@ -297,33 +396,152 @@ public class MMatchPO extends X_M_MatchPO else 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; break; } } } + } 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); - rs = null; pstmt = null; } // Create New if (retValue == null) { - if (sLine != null) + BigDecimal sLineMatchedQty = null; + if (sLine != null && iLine != null) { - retValue = new MMatchPO (sLine, dateTrx, qty); - if (iLine != null) - retValue.setC_InvoiceLine_ID(iLine); + 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 (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) { - 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); 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; @@ -632,6 +864,46 @@ public class MMatchPO extends X_M_MatchPO @Override 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 // (Reserved in VMatch and MInOut.completeIt) if (success && getC_OrderLine_ID() != 0) diff --git a/org.adempiere.install/install.app.launch b/org.adempiere.install/install.app.launch index c7e5ebc931..fe68ee2e0a 100644 --- a/org.adempiere.install/install.app.launch +++ b/org.adempiere.install/install.app.launch @@ -19,7 +19,7 @@ - + diff --git a/org.adempiere.install/install.console.app.launch b/org.adempiere.install/install.console.app.launch index ae453f729d..a021f50cdc 100644 --- a/org.adempiere.install/install.console.app.launch +++ b/org.adempiere.install/install.console.app.launch @@ -19,7 +19,7 @@ - + diff --git a/org.adempiere.server-feature/setup/configuration/config.ini b/org.adempiere.server-feature/setup/configuration/config.ini index 4b4ae801d6..99bf459c0b 100644 --- a/org.adempiere.server-feature/setup/configuration/config.ini +++ b/org.adempiere.server-feature/setup/configuration/config.ini @@ -1,5 +1,5 @@ osgi.framework=file\:../plugins/org.eclipse.osgi_3.7.2.v20120110-1415.jar equinox.use.ds=true -osgi.bundles=org.eclipse.core.variables,org.eclipse.ant.core,org.eclipse.core.runtime@start,org.adempiere.base@start,org.compiere.db.oracle.provider,org.compiere.db.postgresql.provider,org.hamcrest.core,org.junit,org.adempiere.install,org.restlet,com.springsource.net.sf.cglib,com.springsource.javax.mail,com.springsource.org.apache.activemq,com.springsource.org.apache.kahadb,org.apache.commons.collections,org.apache.ant,javax.servlet,com.springsource.javax.jms,org.apache.ecs,org.apache.commons.net,org.eclipse.equinox.app,org.eclipse.equinox.registry,org.eclipse.equinox.common@2:start,org.eclipse.core.contenttype,org.apache.poi,org.eclipse.core.jobs,org.eclipse.equinox.preferences,org.apache.commons.logging,com.springsource.org.apache.commons.logging,com.springsource.javax.management.j2ee,org.eclipse.osgi.services,com.springsource.javax.ejb,com.springsource.javax.xml.rpc,com.springsource.javax.xml.soap,javax.xml +osgi.bundles=org.eclipse.equinox.ds@1:start,org.eclipse.equinox.util,org.eclipse.core.variables,org.eclipse.ant.core,org.eclipse.core.runtime@start,org.adempiere.base@start,org.compiere.db.oracle.provider,org.compiere.db.postgresql.provider,org.hamcrest.core,org.junit,org.adempiere.install,org.restlet,com.springsource.net.sf.cglib,com.springsource.javax.mail,com.springsource.org.apache.activemq,com.springsource.org.apache.kahadb,org.apache.commons.collections,org.apache.ant,javax.servlet,com.springsource.javax.jms,org.apache.ecs,org.apache.commons.net,org.eclipse.equinox.app,org.eclipse.equinox.registry,org.eclipse.equinox.common@2:start,org.eclipse.core.contenttype,org.apache.poi,org.eclipse.core.jobs,org.eclipse.equinox.preferences,org.apache.commons.logging,com.springsource.org.apache.commons.logging,com.springsource.javax.management.j2ee,org.eclipse.osgi.services,com.springsource.javax.ejb,com.springsource.javax.xml.rpc,com.springsource.javax.xml.soap,javax.xml osgi.framework.extensions= osgi.bundles.defaultStartLevel=4 diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/CompositeADTabbox.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/CompositeADTabbox.java index 0ab772fb23..c2610c5850 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/CompositeADTabbox.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/CompositeADTabbox.java @@ -419,7 +419,7 @@ public class CompositeADTabbox extends AbstractADTabbox activateDetailADTabpanel(); } - headerTab.setDetailPaneMode(false, isUseVflexForDetailPane()); + headerTab.setDetailPaneMode(false, true); updateBreadCrumb(); } diff --git a/org.adempiere.ui/src/org/compiere/apps/form/Match.java b/org.adempiere.ui/src/org/compiere/apps/form/Match.java index 9aaaf9bf6c..d90baa87fb 100644 --- a/org.adempiere.ui/src/org/compiere/apps/form/Match.java +++ b/org.adempiere.ui/src/org/compiere/apps/form/Match.java @@ -21,6 +21,7 @@ import java.sql.Timestamp; import java.util.Vector; import java.util.logging.Level; +import org.adempiere.exceptions.AdempiereException; import org.compiere.minigrid.IDColumn; import org.compiere.minigrid.IMiniTable; import org.compiere.model.MClient; @@ -38,6 +39,7 @@ import org.compiere.util.Env; import org.compiere.util.KeyNamePair; import org.compiere.util.Msg; import org.compiere.util.Trx; +import org.compiere.util.ValueNamePair; public class Match { @@ -416,50 +418,74 @@ public class Match { MMatchInv match = new MMatchInv (iLine, null, qty); match.setM_InOutLine_ID(M_InOutLine_ID); - if (match.save()) { - success = true; - if (MClient.isClientAccountingImmediate()) { - String ignoreError = DocumentEngine.postImmediate(match.getCtx(), match.getAD_Client_ID(), match.get_Table_ID(), match.get_ID(), true, match.get_TrxName()); + match.saveEx(); + success = true; + if (MClient.isClientAccountingImmediate()) { + 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 success = true; // 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); - matchPO.setC_InvoiceLine_ID(iLine); - matchPO.setM_InOutLine_ID(M_InOutLine_ID); - if (!matchPO.save()) - log.log(Level.SEVERE, "PO(Inv) Match not created: " + matchPO); - if (MClient.isClientAccountingImmediate()) { - String ignoreError = DocumentEngine.postImmediate(matchPO.getCtx(), matchPO.getAD_Client_ID(), matchPO.get_Table_ID(), matchPO.get_ID(), true, matchPO.get_TrxName()); + BigDecimal matchedQty = DB.getSQLValueBD(iLine.get_TrxName(), "SELECT Coalesce(SUM(Qty),0) FROM M_MatchPO WHERE C_InvoiceLine_ID=?" , iLine.getC_InvoiceLine_ID()); + if (matchedQty.add(qty).compareTo(iLine.getQtyInvoiced()) <= 0) + { + MMatchPO matchPO = MMatchPO.create(iLine, sLine, null, qty); + if (matchPO != null) + { + 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 { - // Update Shipment Line - sLine.setC_OrderLine_ID(Line_ID); - sLine.saveEx(); // Update Order Line MOrderLine oLine = new MOrderLine(Env.getCtx(), Line_ID, trxName); if (oLine.get_ID() != 0) // other in MInOut.completeIt { oLine.setQtyReserved(oLine.getQtyReserved().subtract(qty)); - if(!oLine.save()) - log.severe("QtyReserved not updated - C_OrderLine_ID=" + Line_ID); + oLine.saveEx(); + } + + // 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 if (sLine.getM_Product_ID() != 0) { MMatchPO match = new MMatchPO (sLine, null, qty); + match.setC_OrderLine_ID(Line_ID); 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 { success = true;