IDEMPIERE-4006 Wrong matched PO quanity for vendor credit memo

This commit is contained in:
Heng Sin Low 2019-09-18 18:39:25 +08:00
parent 9508dfe8fe
commit fc09db1278
14 changed files with 687 additions and 228 deletions

View File

@ -0,0 +1,42 @@
SET SQLBLANKLINES ON
SET DEFINE OFF
-- IDEMPIERE-4006 Wrong matched PO quanity for vendor credit memo
-- Sep 3, 2019, 5:51:11 PM SGT
INSERT INTO AD_Element (AD_Element_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,ColumnName,Name,PrintName,EntityType,AD_Element_UU) VALUES (203363,0,0,'Y',TO_DATE('2019-09-03 17:51:10','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2019-09-03 17:51:10','YYYY-MM-DD HH24:MI:SS'),100,'Ref_MatchPO_ID','Referenced Match PO','Referenced Match PO','U','880834ea-81fe-4813-95de-7390350cee95')
;
-- Sep 3, 2019, 5:51:15 PM SGT
UPDATE AD_Element SET EntityType='D',Updated=TO_DATE('2019-09-03 17:51:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Element_ID=203363
;
-- Sep 3, 2019, 5:52:04 PM SGT
INSERT INTO AD_Column (AD_Column_ID,Version,Name,AD_Table_ID,ColumnName,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Reference_Value_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,SeqNoSelection,IsToolbarButton,IsSecure,FKConstraintType,IsHtml) VALUES (214044,0,'Referenced Match PO',473,'Ref_MatchPO_ID',10,'N','N','N','N','N',0,'N',30,200017,0,0,'Y',TO_DATE('2019-09-03 17:52:03','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2019-09-03 17:52:03','YYYY-MM-DD HH24:MI:SS'),100,203363,'Y','N','U','N','N','N','Y','50fc1a1d-5bb0-4631-94c3-92c2fa9ec13a','Y',0,'N','N','N','N')
;
-- Sep 3, 2019, 5:52:16 PM SGT
UPDATE AD_Column SET EntityType='D',Updated=TO_DATE('2019-09-03 17:52:16','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=214044
;
-- Sep 3, 2019, 5:52:21 PM SGT
UPDATE AD_Column SET FKConstraintName='RefMatchPO_MMatchPO', FKConstraintType='N',Updated=TO_DATE('2019-09-03 17:52:21','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=214044
;
-- Sep 3, 2019, 5:52:21 PM SGT
ALTER TABLE M_MatchPO ADD Ref_MatchPO_ID NUMBER(10) DEFAULT NULL
;
-- Sep 3, 2019, 5:52:22 PM SGT
ALTER TABLE M_MatchPO ADD CONSTRAINT RefMatchPO_MMatchPO FOREIGN KEY (Ref_MatchPO_ID) REFERENCES m_matchpo(m_matchpo_id) DEFERRABLE INITIALLY DEFERRED
;
-- Sep 4, 2019, 5:39:23 PM SGT
INSERT INTO AD_Field (AD_Field_ID,Name,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLength,SeqNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,ColumnSpan) VALUES (206171,'Referenced Match PO',409,214044,'Y',10,180,'N','N','N','N',0,0,'Y',TO_DATE('2019-09-04 17:39:22','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2019-09-04 17:39:22','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','e69ff166-dfc2-4b3d-b432-744b10440827','Y',180,2)
;
-- Sep 4, 2019, 5:41:04 PM SGT
UPDATE AD_Field SET SeqNo=65, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, SeqNoGrid=65, XPosition=4, IsToolbarButton=NULL,Updated=TO_DATE('2019-09-04 17:41:04','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=206171
;
SELECT register_migration_script('201909061600_IDEMPIERE-4006.sql') FROM dual
;

View File

@ -0,0 +1,39 @@
-- IDEMPIERE-4006 Wrong matched PO quanity for vendor credit memo
-- Sep 3, 2019, 5:51:11 PM SGT
INSERT INTO AD_Element (AD_Element_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,ColumnName,Name,PrintName,EntityType,AD_Element_UU) VALUES (203363,0,0,'Y',TO_TIMESTAMP('2019-09-03 17:51:10','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2019-09-03 17:51:10','YYYY-MM-DD HH24:MI:SS'),100,'Ref_MatchPO_ID','Referenced Match PO','Referenced Match PO','U','880834ea-81fe-4813-95de-7390350cee95')
;
-- Sep 3, 2019, 5:51:15 PM SGT
UPDATE AD_Element SET EntityType='D',Updated=TO_TIMESTAMP('2019-09-03 17:51:15','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Element_ID=203363
;
-- Sep 3, 2019, 5:52:04 PM SGT
INSERT INTO AD_Column (AD_Column_ID,Version,Name,AD_Table_ID,ColumnName,FieldLength,IsKey,IsParent,IsMandatory,IsTranslated,IsIdentifier,SeqNo,IsEncrypted,AD_Reference_ID,AD_Reference_Value_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Element_ID,IsUpdateable,IsSelectionColumn,EntityType,IsSyncDatabase,IsAlwaysUpdateable,IsAutocomplete,IsAllowLogging,AD_Column_UU,IsAllowCopy,SeqNoSelection,IsToolbarButton,IsSecure,FKConstraintType,IsHtml) VALUES (214044,0,'Referenced Match PO',473,'Ref_MatchPO_ID',10,'N','N','N','N','N',0,'N',30,200017,0,0,'Y',TO_TIMESTAMP('2019-09-03 17:52:03','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2019-09-03 17:52:03','YYYY-MM-DD HH24:MI:SS'),100,203363,'Y','N','U','N','N','N','Y','50fc1a1d-5bb0-4631-94c3-92c2fa9ec13a','Y',0,'N','N','N','N')
;
-- Sep 3, 2019, 5:52:16 PM SGT
UPDATE AD_Column SET EntityType='D',Updated=TO_TIMESTAMP('2019-09-03 17:52:16','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=214044
;
-- Sep 3, 2019, 5:52:21 PM SGT
UPDATE AD_Column SET FKConstraintName='RefMatchPO_MMatchPO', FKConstraintType='N',Updated=TO_TIMESTAMP('2019-09-03 17:52:21','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Column_ID=214044
;
-- Sep 3, 2019, 5:52:21 PM SGT
ALTER TABLE M_MatchPO ADD COLUMN Ref_MatchPO_ID NUMERIC(10) DEFAULT NULL
;
-- Sep 3, 2019, 5:52:22 PM SGT
ALTER TABLE M_MatchPO ADD CONSTRAINT RefMatchPO_MMatchPO FOREIGN KEY (Ref_MatchPO_ID) REFERENCES m_matchpo(m_matchpo_id) DEFERRABLE INITIALLY DEFERRED
;
-- Sep 4, 2019, 5:39:23 PM SGT
INSERT INTO AD_Field (AD_Field_ID,Name,AD_Tab_ID,AD_Column_ID,IsDisplayed,DisplayLength,SeqNo,IsSameLine,IsHeading,IsFieldOnly,IsEncrypted,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,IsReadOnly,IsCentrallyMaintained,EntityType,AD_Field_UU,IsDisplayedGrid,SeqNoGrid,ColumnSpan) VALUES (206171,'Referenced Match PO',409,214044,'Y',10,180,'N','N','N','N',0,0,'Y',TO_TIMESTAMP('2019-09-04 17:39:22','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2019-09-04 17:39:22','YYYY-MM-DD HH24:MI:SS'),100,'N','Y','D','e69ff166-dfc2-4b3d-b432-744b10440827','Y',180,2)
;
-- Sep 4, 2019, 5:41:04 PM SGT
UPDATE AD_Field SET SeqNo=65, AD_Reference_Value_ID=NULL, AD_Val_Rule_ID=NULL, SeqNoGrid=65, XPosition=4, IsToolbarButton=NULL,Updated=TO_TIMESTAMP('2019-09-04 17:41:04','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=206171
;
SELECT register_migration_script('201909061600_IDEMPIERE-4006.sql') FROM dual
;

View File

@ -19,6 +19,7 @@ package org.compiere.process;
import java.util.logging.Level; import java.util.logging.Level;
import org.compiere.model.MMatchInv; import org.compiere.model.MMatchInv;
import org.compiere.model.MMatchPO;
import org.compiere.util.AdempiereUserError; import org.compiere.util.AdempiereUserError;
import org.compiere.util.CLogger; import org.compiere.util.CLogger;
import org.compiere.util.ValueNamePair; import org.compiere.util.ValueNamePair;
@ -51,19 +52,28 @@ public class MatchInvDelete extends SvrProcess
protected String doIt() throws Exception protected String doIt() throws Exception
{ {
if (log.isLoggable(Level.INFO)) log.info ("M_MatchInv_ID=" + p_M_MatchInv_ID); if (log.isLoggable(Level.INFO)) log.info ("M_MatchInv_ID=" + p_M_MatchInv_ID);
String msg = "";
MMatchInv inv = new MMatchInv (getCtx(), p_M_MatchInv_ID, get_TrxName()); MMatchInv inv = new MMatchInv (getCtx(), p_M_MatchInv_ID, get_TrxName());
if (inv.get_ID() == 0) if (inv.get_ID() == 0)
throw new AdempiereUserError("@NotFound@ @M_MatchInv_ID@ " + p_M_MatchInv_ID); throw new AdempiereUserError("@NotFound@ @M_MatchInv_ID@ " + p_M_MatchInv_ID);
if (inv.delete(true)) int reversalId = inv.getReversal_ID();
return "@OK@"; if (!inv.delete(true))
return "@Error@";
String msg = null; msg += "@Deleted@";
ValueNamePair err = CLogger.retrieveError();
if (err != null) if (reversalId > 0) {
msg = err.getName(); MMatchInv invrev = new MMatchInv (getCtx(), reversalId, get_TrxName());
if (msg == null || msg.length() == 0) if (invrev.get_ID() == 0)
msg = " - Check log"; throw new AdempiereUserError("@NotFound@ @M_MatchInv_ID@ " + reversalId);
return "@Error@: " + msg; if (!invrev.delete(true)) {
return "@Error@ @Reversal_ID@";
}
msg += " + @Deleted@ @Reversal_ID@";
}
return msg;
} // doIt } // doIt
} // MatchInvDelete } // MatchInvDelete

View File

@ -41,6 +41,7 @@ import org.compiere.model.MOrderLandedCostAllocation;
import org.compiere.model.MOrderLine; import org.compiere.model.MOrderLine;
import org.compiere.model.MProduct; import org.compiere.model.MProduct;
import org.compiere.model.MTax; import org.compiere.model.MTax;
import org.compiere.model.MatchPOAutoMatch;
import org.compiere.model.ProductCost; import org.compiere.model.ProductCost;
import org.compiere.model.X_M_InOut; import org.compiere.model.X_M_InOut;
import org.compiere.process.DocAction; import org.compiere.process.DocAction;
@ -114,7 +115,7 @@ public class Doc_MatchPO extends Doc
List<MMatchPO> noInvoiceLines = new ArrayList<MMatchPO>(); List<MMatchPO> noInvoiceLines = new ArrayList<MMatchPO>();
Map<Integer, BigDecimal[]> noShipmentLines = new HashMap<>(); Map<Integer, BigDecimal[]> noShipmentLines = new HashMap<>();
Map<Integer, BigDecimal[]> postedNoShipmentLines = new HashMap<>(); Map<Integer, BigDecimal[]> postedNoShipmentLines = new HashMap<>();
MMatchPO[] matchPOs = MMatchPO.getOrderLine(getCtx(), m_oLine.getC_OrderLine_ID(), getTrxName()); List<MMatchPO> matchPOs = MatchPOAutoMatch.getNotMatchedMatchPOList(getCtx(), m_oLine.getC_OrderLine_ID(), getTrxName());
for (MMatchPO matchPO : matchPOs) for (MMatchPO matchPO : matchPOs)
{ {
if (matchPO.getM_InOutLine_ID() > 0 && matchPO.getC_InvoiceLine_ID() == 0 && matchPO.getReversal_ID()==0) if (matchPO.getM_InOutLine_ID() > 0 && matchPO.getC_InvoiceLine_ID() == 0 && matchPO.getReversal_ID()==0)
@ -188,6 +189,7 @@ public class Doc_MatchPO extends Doc
if (m_M_InOutLine_ID == 0) // Defer posting if not matched to Shipment if (m_M_InOutLine_ID == 0) // Defer posting if not matched to Shipment
{ {
if (m_matchPO.getRef_MatchPO_ID() == 0)
m_deferPosting = true; m_deferPosting = true;
} }
else else
@ -264,6 +266,9 @@ public class Doc_MatchPO extends Doc
if (m_M_InOutLine_ID == 0) // No posting if not matched to Shipment if (m_M_InOutLine_ID == 0) // No posting if not matched to Shipment
{ {
if (m_matchPO.getRef_MatchPO_ID() > 0)
return facts;
p_Error = "No posting if not matched to Shipment"; p_Error = "No posting if not matched to Shipment";
return null; return null;
} }

View File

@ -327,6 +327,17 @@ public interface I_M_MatchPO
*/ */
public BigDecimal getQty(); public BigDecimal getQty();
/** Column name Ref_MatchPO_ID */
public static final String COLUMNNAME_Ref_MatchPO_ID = "Ref_MatchPO_ID";
/** Set Referenced Match PO */
public void setRef_MatchPO_ID (int Ref_MatchPO_ID);
/** Get Referenced Match PO */
public int getRef_MatchPO_ID();
public org.compiere.model.I_M_MatchPO getRef_MatchPO() throws RuntimeException;
/** Column name Reversal_ID */ /** Column name Reversal_ID */
public static final String COLUMNNAME_Reversal_ID = "Reversal_ID"; public static final String COLUMNNAME_Reversal_ID = "Reversal_ID";

View File

@ -1144,6 +1144,7 @@ public class MInvoice extends X_C_Invoice implements DocAction
int no = DB.executeUpdate(sql.toString(), get_TrxName()); int no = DB.executeUpdate(sql.toString(), get_TrxName());
if (log.isLoggable(Level.FINE)) log.fine("Lines -> #" + no); if (log.isLoggable(Level.FINE)) log.fine("Lines -> #" + no);
} }
return true; return true;
} // afterSave } // afterSave
@ -1831,10 +1832,11 @@ public class MInvoice extends X_C_Invoice implements DocAction
&& !isReversal()) && !isReversal())
{ {
MInOutLine receiptLine = new MInOutLine (getCtx(),line.getM_InOutLine_ID(), get_TrxName()); MInOutLine receiptLine = new MInOutLine (getCtx(),line.getM_InOutLine_ID(), get_TrxName());
BigDecimal matchQty = line.getQtyInvoiced(); BigDecimal movementQty = receiptLine.getM_InOut().getMovementType().charAt(1) == '-' ? receiptLine.getMovementQty().negate() : receiptLine.getMovementQty();
BigDecimal matchQty = isCreditMemo() ? line.getQtyInvoiced().negate() : line.getQtyInvoiced();
if (receiptLine.getMovementQty().compareTo(matchQty) < 0) if (movementQty.compareTo(matchQty) < 0)
matchQty = receiptLine.getMovementQty(); matchQty = movementQty;
MMatchInv inv = new MMatchInv(line, getDateInvoiced(), matchQty); MMatchInv inv = new MMatchInv(line, getDateInvoiced(), matchQty);
if (!inv.save(get_TrxName())) if (!inv.save(get_TrxName()))
@ -1869,7 +1871,7 @@ public class MInvoice extends X_C_Invoice implements DocAction
&& !isReversal()) && !isReversal())
{ {
// MatchPO is created also from MInOut when Invoice exists before Shipment // MatchPO is created also from MInOut when Invoice exists before Shipment
BigDecimal matchQty = line.getQtyInvoiced(); BigDecimal matchQty = isCreditMemo() ? line.getQtyInvoiced().negate() : line.getQtyInvoiced();
MMatchPO po = MMatchPO.create (line, null, MMatchPO po = MMatchPO.create (line, null,
getDateInvoiced(), matchQty); getDateInvoiced(), matchQty);
if (po != null) if (po != null)
@ -2425,6 +2427,9 @@ public class MInvoice extends X_C_Invoice implements DocAction
} }
addDocsPostProcess(new MMatchInv(Env.getCtx(), mInv[i].getReversal_ID(), get_TrxName())); addDocsPostProcess(new MMatchInv(Env.getCtx(), mInv[i].getReversal_ID(), get_TrxName()));
} }
MatchPOAutoMatch.unmatch(getCtx(), getC_Invoice_ID(), get_TrxName());
MMatchPO[] mPO = MMatchPO.getInvoice(getCtx(), getC_Invoice_ID(), get_TrxName()); MMatchPO[] mPO = MMatchPO.getInvoice(getCtx(), getC_Invoice_ID(), get_TrxName());
for (int i = 0; i < mPO.length; i++) for (int i = 0; i < mPO.length; i++)
{ {

View File

@ -352,17 +352,11 @@ public class MMatchPO extends X_M_MatchPO
MInOutLine sLine, int C_OrderLine_ID, Timestamp dateTrx, MInOutLine sLine, int C_OrderLine_ID, Timestamp dateTrx,
BigDecimal qty, String trxName) { BigDecimal qty, String trxName) {
MMatchPO retValue = null; MMatchPO retValue = null;
String sql = "SELECT * FROM M_MatchPO WHERE C_OrderLine_ID=? and Reversal_ID IS NULL ORDER BY M_MatchPO_ID"; List<MMatchPO> matchPOList = MatchPOAutoMatch.getNotMatchedMatchPOList(ctx, C_OrderLine_ID, trxName);
PreparedStatement pstmt = null; if (!matchPOList.isEmpty())
ResultSet rs = null;
try
{ {
pstmt = DB.prepareStatement (sql, trxName); for (MMatchPO mpo : matchPOList)
pstmt.setInt (1, C_OrderLine_ID);
rs = pstmt.executeQuery ();
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 toMatch = qty;
@ -408,7 +402,7 @@ public class MMatchPO extends X_M_MatchPO
{ {
//verify m_matchinv not created for other invoice //verify m_matchinv not created for other invoice
int cnt = DB.getSQLValue(iLine.get_TrxName(), "SELECT Count(*) FROM M_MatchInv WHERE M_InOutLine_ID="+mpo.getM_InOutLine_ID() int cnt = DB.getSQLValue(iLine.get_TrxName(), "SELECT Count(*) FROM M_MatchInv WHERE M_InOutLine_ID="+mpo.getM_InOutLine_ID()
+" AND C_InvoiceLine_ID != "+iLine.getC_InvoiceLine_ID()); +" AND C_InvoiceLine_ID != "+iLine.getC_InvoiceLine_ID() + " AND Reversal_ID=0");
if (cnt > 0) if (cnt > 0)
continue; continue;
} }
@ -429,46 +423,10 @@ public class MMatchPO extends X_M_MatchPO
+" AND C_InvoiceLine_ID="+C_InvoiceLine_ID); +" AND C_InvoiceLine_ID="+C_InvoiceLine_ID);
if (cnt <= 0) if (cnt <= 0)
{ {
Trx trx = trxName != null ? Trx.get(trxName, false) : null; MMatchInv matchInv = createMatchInv(mpo, C_InvoiceLine_ID, M_InOutLine_ID, mpo.getQty(), dateTrx, trxName);
Savepoint savepoint = trx != null ? trx.getConnection().setSavepoint() : null; if (matchInv == 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);
matchInv.setProcessed(true);
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; continue;
}
mpo.setMatchInvCreated(matchInv); mpo.setMatchInvCreated(matchInv);
if (savepoint != null)
{
try {
trx.getConnection().releaseSavepoint(savepoint);
} catch (Exception e) {}
}
} }
} }
if (iLine != null) if (iLine != null)
@ -499,22 +457,6 @@ public class MMatchPO extends X_M_MatchPO
} }
} }
} }
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);
}
// Create New // Create New
if (retValue == null) if (retValue == null)
@ -528,7 +470,7 @@ public class MMatchPO extends X_M_MatchPO
if (sLine != null && (sLine.getC_OrderLine_ID() == C_OrderLine_ID || iLine == null) if (sLine != null && (sLine.getC_OrderLine_ID() == C_OrderLine_ID || iLine == null)
&& (sLineMatchedQty == null || sLineMatchedQty.signum() <= 0)) && (sLineMatchedQty == null || sLineMatchedQty.signum() <= 0))
{ {
if (qty.signum() > 0) if (qty.signum() != 0)
{ {
retValue = new MMatchPO (sLine, dateTrx, qty); retValue = new MMatchPO (sLine, dateTrx, qty);
retValue.setC_OrderLine_ID(C_OrderLine_ID); retValue.setC_OrderLine_ID(C_OrderLine_ID);
@ -562,52 +504,8 @@ public class MMatchPO extends X_M_MatchPO
//auto create matchinv //auto create matchinv
if (otherMatchPO != null) if (otherMatchPO != null)
{ {
Savepoint savepoint = null; MMatchInv matchInv = createMatchInv(retValue, otherMatchPO.getC_InvoiceLine_ID(), retValue.getM_InOutLine_ID(), retValue.getQty(), dateTrx, trxName);
Trx trx = null;
try
{
trx = trxName != null ? Trx.get(trxName, false) : null;
savepoint = trx != null ? trx.getConnection().setSavepoint() : null;
MMatchInv matchInv = new MMatchInv(retValue.getCtx(), 0, retValue.get_TrxName());
matchInv.setC_InvoiceLine_ID(otherMatchPO.getC_InvoiceLine_ID());
matchInv.setM_Product_ID(retValue.getM_Product_ID());
matchInv.setM_InOutLine_ID(retValue.getM_InOutLine_ID());
matchInv.setAD_Client_ID(retValue.getAD_Client_ID());
matchInv.setAD_Org_ID(retValue.getAD_Org_ID());
matchInv.setM_AttributeSetInstance_ID(retValue.getM_AttributeSetInstance_ID());
matchInv.setQty(retValue.getQty());
matchInv.setDateTrx(dateTrx);
matchInv.setProcessed(true);
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();
}
s_log.severe(msg);
}
retValue.setMatchInvCreated(matchInv); retValue.setMatchInvCreated(matchInv);
} catch (Exception e) {
s_log.log(Level.SEVERE, "Failed to auto match Invoice.", e);
} finally {
if (savepoint != null)
{
try {
trx.getConnection().releaseSavepoint(savepoint);
} catch (Exception e) {}
}
}
if (otherMatchPO.getQty().signum() == 0 ) if (otherMatchPO.getQty().signum() == 0 )
otherMatchPO.deleteEx(true); otherMatchPO.deleteEx(true);
} }
@ -626,7 +524,7 @@ public class MMatchPO extends X_M_MatchPO
} }
else if (iLine != null) else if (iLine != null)
{ {
if (qty.signum() > 0) if (qty.signum() != 0)
{ {
retValue = new MMatchPO (iLine, dateTrx, qty); retValue = new MMatchPO (iLine, dateTrx, qty);
retValue.setC_OrderLine_ID(C_OrderLine_ID); retValue.setC_OrderLine_ID(C_OrderLine_ID);
@ -652,7 +550,7 @@ public class MMatchPO extends X_M_MatchPO
if (matchPO.getM_MatchPO_ID() == retValue.getM_MatchPO_ID()) if (matchPO.getM_MatchPO_ID() == retValue.getM_MatchPO_ID())
continue; continue;
if (matchPO.getM_InOutLine_ID() > 0 && matchPO.getReversal_ID() == 0) if (matchPO.getM_InOutLine_ID() > 0 && matchPO.getReversal_ID() == 0 && matchPO.getRef_MatchPO_ID() == 0)
{ {
if (matchPO.getC_InvoiceLine_ID() == 0) if (matchPO.getC_InvoiceLine_ID() == 0)
{ {
@ -737,6 +635,27 @@ public class MMatchPO extends X_M_MatchPO
toMatch = toMatch.subtract(autoMatchQty); toMatch = toMatch.subtract(autoMatchQty);
} }
if (autoMatchQty != null && autoMatchQty.signum() > 0) if (autoMatchQty != null && autoMatchQty.signum() > 0)
{
MMatchInv matchInv = createMatchInv(retValue, retValue.getC_InvoiceLine_ID(), matchPO.getM_InOutLine_ID(), autoMatchQty, dateTrx, trxName);
retValue.setMatchInvCreated(matchInv);
if (matchInv == null)
break;
}
}
if (toMatch.signum() <= 0)
break;
}
}
}
}
if (C_OrderLine_ID > 0 && retValue != null)
MatchPOAutoMatch.match(ctx, C_OrderLine_ID, retValue, trxName);
return retValue;
} // create
private static MMatchInv createMatchInv(MMatchPO mpo, int C_InvoiceLine_ID, int M_InOutLine_ID, BigDecimal qty, Timestamp dateTrx, String trxName)
{ {
Savepoint savepoint = null; Savepoint savepoint = null;
Trx trx = null; Trx trx = null;
@ -745,14 +664,14 @@ public class MMatchPO extends X_M_MatchPO
{ {
trx = trxName != null ? Trx.get(trxName, false) : null; trx = trxName != null ? Trx.get(trxName, false) : null;
savepoint = trx != null ? trx.getConnection().setSavepoint() : null; savepoint = trx != null ? trx.getConnection().setSavepoint() : null;
matchInv = new MMatchInv(retValue.getCtx(), 0, retValue.get_TrxName()); matchInv = new MMatchInv(mpo.getCtx(), 0, mpo.get_TrxName());
matchInv.setC_InvoiceLine_ID(retValue.getC_InvoiceLine_ID()); matchInv.setC_InvoiceLine_ID(C_InvoiceLine_ID);
matchInv.setM_Product_ID(retValue.getM_Product_ID()); matchInv.setM_Product_ID(mpo.getM_Product_ID());
matchInv.setM_InOutLine_ID(matchPO.getM_InOutLine_ID()); matchInv.setM_InOutLine_ID(M_InOutLine_ID);
matchInv.setAD_Client_ID(retValue.getAD_Client_ID()); matchInv.setAD_Client_ID(mpo.getAD_Client_ID());
matchInv.setAD_Org_ID(retValue.getAD_Org_ID()); matchInv.setAD_Org_ID(mpo.getAD_Org_ID());
matchInv.setM_AttributeSetInstance_ID(retValue.getM_AttributeSetInstance_ID()); matchInv.setM_AttributeSetInstance_ID(mpo.getM_AttributeSetInstance_ID());
matchInv.setQty(autoMatchQty); matchInv.setQty(qty);
matchInv.setDateTrx(dateTrx); matchInv.setDateTrx(dateTrx);
matchInv.setProcessed(true); matchInv.setProcessed(true);
if (!matchInv.save()) if (!matchInv.save())
@ -786,20 +705,9 @@ public class MMatchPO extends X_M_MatchPO
} catch (Exception e) {} } catch (Exception e) {}
} }
} }
if (matchInv == null)
break;
}
}
if (toMatch.signum() <= 0)
break;
}
}
}
}
return retValue;
} // create
return matchInv;
}
protected MMatchInv m_matchInv; protected MMatchInv m_matchInv;
@ -1450,6 +1358,7 @@ public class MMatchPO extends X_M_MatchPO
reversal.set_ValueNoCheck ("DocumentNo", null); reversal.set_ValueNoCheck ("DocumentNo", null);
reversal.setPosted (false); reversal.setPosted (false);
reversal.setProcessed(true); reversal.setProcessed(true);
reversal.setRef_MatchPO_ID(getRef_MatchPO_ID());
reversal.setReversal_ID(getM_MatchPO_ID()); reversal.setReversal_ID(getM_MatchPO_ID());
reversal.saveEx(); reversal.saveEx();

View File

@ -0,0 +1,385 @@
/******************************************************************************
* Product: iDempiere ERP & CRM Smart Business Solution *
* Copyright (C) 2019 Elaine Tan *
* *
* This program is free software; you can redistribute it and/or modify it *
* under the terms version 2 of the GNU General Public License as published *
* by the Free Software Foundation. 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., *
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
*****************************************************************************/
package org.compiere.model;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Properties;
import org.compiere.process.DocAction;
import org.compiere.util.Env;
/**
*
* @author hengsin
*
*/
public class MatchPOAutoMatch {
/**
*
* @param ctx
* @param C_OrderLine_ID
* @param trxName
* @return not fully matched matchpo records
*/
public static List<MMatchPO> getNotMatchedMatchPOList(Properties ctx, int C_OrderLine_ID, String trxName)
{
List<MMatchPO> notMatchedMatchPOList = new ArrayList<MMatchPO>();
List<MMatchPO> creditMemoMatchPOList = new ArrayList<MMatchPO>();
List<MMatchPO> notMatchedCreditMemoMatchPOList = new ArrayList<MMatchPO>();
MMatchPO[] mpos = MMatchPO.getOrderLine(ctx, C_OrderLine_ID, trxName);
for (MMatchPO mpo : mpos)
{
if (mpo.getReversal_ID() == 0 && mpo.getRef_MatchPO_ID() == 0)
{
if (mpo.getQty().signum() < 0)
{
if (mpo.getC_InvoiceLine_ID() > 0 && mpo.getM_InOutLine_ID() == 0)
{
String docStatus = mpo.getC_InvoiceLine().getC_Invoice().getDocStatus();
if (docStatus.equals(DocAction.STATUS_Completed) || docStatus.equals(DocAction.STATUS_Closed)) {
creditMemoMatchPOList.add(mpo);
}
}
continue;
}
notMatchedMatchPOList.add(mpo);
}
}
if (!notMatchedMatchPOList.isEmpty())
{
Collections.sort(notMatchedMatchPOList, new Comparator<MMatchPO>() {
@Override
public int compare(MMatchPO arg0, MMatchPO arg1) {
return arg0.getM_MatchPO_ID() > arg1.getM_MatchPO_ID()
? 1
: (arg0.getM_MatchPO_ID()==arg1.getM_MatchPO_ID() ? 0 : -1);
}
});
}
if (!creditMemoMatchPOList.isEmpty())
{
BigDecimal totalNotMatchingCreditMemoQty = Env.ZERO;
for (MMatchPO matchPOCreditMemo : creditMemoMatchPOList)
{
boolean found = false;
int Ref_InvoiceLine_ID = matchPOCreditMemo.getC_InvoiceLine().getRef_InvoiceLine_ID();
if (Ref_InvoiceLine_ID > 0)
{
for (MMatchPO matchPO : notMatchedMatchPOList)
{
if (!matchPO.isPosted() && matchPO.getC_InvoiceLine_ID() == Ref_InvoiceLine_ID && matchPO.getM_InOutLine_ID() == 0)
{
if (matchPO.getQty().compareTo(matchPOCreditMemo.getQty().negate()) == 0)
{
notMatchedMatchPOList.remove(matchPO);
found = true;
break;
}
}
}
}
if (found)
continue;
for (MMatchPO matchPO : notMatchedMatchPOList)
{
if (!matchPO.isPosted() && matchPO.getC_InvoiceLine_ID() > 0 && matchPO.getM_InOutLine_ID() == 0)
{
if (matchPO.getQty().compareTo(matchPOCreditMemo.getQty().negate()) == 0)
{
notMatchedMatchPOList.remove(matchPO);
found = true;
break;
}
}
}
if (!found)
{
totalNotMatchingCreditMemoQty = totalNotMatchingCreditMemoQty.add(matchPOCreditMemo.getQty().negate());
notMatchedCreditMemoMatchPOList.add(matchPOCreditMemo);
}
}
if (totalNotMatchingCreditMemoQty.signum() != 0)
{
BigDecimal totalInvoiceQty = Env.ZERO;
for (MMatchPO matchPO : notMatchedMatchPOList)
{
if (!matchPO.isPosted() && matchPO.getC_InvoiceLine_ID() > 0 && matchPO.getM_InOutLine_ID() == 0)
totalInvoiceQty = totalInvoiceQty.add(matchPO.getQty());
}
if (totalNotMatchingCreditMemoQty.compareTo(totalInvoiceQty) == 0)
notMatchedMatchPOList.clear();
}
}
return notMatchedMatchPOList;
}
/**
* auto match matchpo
* @param ctx
* @param C_OrderLine_ID
* @param currentPO
* @param trxName
*/
public static void match(Properties ctx, int C_OrderLine_ID, MMatchPO currentPO, String trxName)
{
List<MMatchPO> notMatchedMatchPOList = new ArrayList<MMatchPO>();
List<MMatchPO> creditMemoMatchPOList = new ArrayList<MMatchPO>();
List<MMatchPO> matchedMatchPOList = new ArrayList<MMatchPO>();
MMatchPO[] mpos = MMatchPO.getOrderLine(ctx, C_OrderLine_ID, trxName);
for (MMatchPO mpo : mpos)
{
if (mpo.getReversal_ID() == 0 && mpo.getRef_MatchPO_ID() == 0)
{
if (mpo.getQty().signum() < 0)
{
if (mpo.getC_InvoiceLine_ID() > 0 && mpo.getM_InOutLine_ID() == 0)
{
String docStatus = mpo.getC_InvoiceLine().getC_Invoice().getDocStatus();
if ((currentPO != null && mpo.getM_MatchPO_ID() == currentPO.getM_MatchPO_ID())
|| docStatus.equals(DocAction.STATUS_Completed)
|| docStatus.equals(DocAction.STATUS_Closed)) {
creditMemoMatchPOList.add(mpo);
}
}
continue;
}
notMatchedMatchPOList.add(mpo);
}
}
if (!notMatchedMatchPOList.isEmpty())
{
Collections.sort(notMatchedMatchPOList, new Comparator<MMatchPO>() {
@Override
public int compare(MMatchPO arg0, MMatchPO arg1) {
return arg0.getM_MatchPO_ID() > arg1.getM_MatchPO_ID()
? 1
: (arg0.getM_MatchPO_ID()==arg1.getM_MatchPO_ID() ? 0 : -1);
}
});
}
if (!creditMemoMatchPOList.isEmpty())
{
for (MMatchPO matchPOCreditMemo : creditMemoMatchPOList)
{
BigDecimal creditMemoQty = matchPOCreditMemo.getQty().negate();
int Ref_InvoiceLine_ID = matchPOCreditMemo.getC_InvoiceLine().getRef_InvoiceLine_ID();
if (Ref_InvoiceLine_ID > 0)
{
for (MMatchPO matchPO : notMatchedMatchPOList)
{
if (!matchPO.isPosted() && matchPO.getC_InvoiceLine_ID() == Ref_InvoiceLine_ID && matchPO.getM_InOutLine_ID() == 0)
{
if (matchPO.getQty().compareTo(creditMemoQty) > 0)
{
matchPO.setQty(matchPO.getQty().subtract(creditMemoQty));
matchPO.saveEx(trxName);
MInvoiceLine iLine = new MInvoiceLine(ctx, matchPO.getC_InvoiceLine_ID(), trxName);
MMatchPO po = new MMatchPO(iLine, iLine.getC_Invoice().getDateInvoiced(), creditMemoQty);
po.setC_OrderLine_ID(C_OrderLine_ID);
po.setRef_MatchPO_ID(matchPOCreditMemo.getM_MatchPO_ID());
po.setPosted(true);
po.saveEx(trxName);
matchPOCreditMemo.setRef_MatchPO_ID(po.getM_MatchPO_ID());
matchPOCreditMemo.setPosted(true);
matchPOCreditMemo.saveEx(trxName);
matchedMatchPOList.add(po);
creditMemoQty = creditMemoQty.subtract(po.getQty());
}
else if (matchPO.getQty().compareTo(creditMemoQty) == 0)
{
matchPO.setRef_MatchPO_ID(matchPOCreditMemo.getM_MatchPO_ID());
matchPO.setPosted(true);
matchPO.saveEx(trxName);
matchPOCreditMemo.setRef_MatchPO_ID(matchPO.getM_MatchPO_ID());
matchPOCreditMemo.setPosted(true);
matchPOCreditMemo.saveEx(trxName);
matchedMatchPOList.add(matchPO);
creditMemoQty = creditMemoQty.subtract(matchPO.getQty());
}
else if (matchPO.getQty().compareTo(creditMemoQty) < 0)
{
matchPOCreditMemo.setQty(matchPOCreditMemo.getQty().add(matchPO.getQty()));
matchPOCreditMemo.saveEx(trxName);
MInvoiceLine iLine = new MInvoiceLine(ctx, matchPOCreditMemo.getC_InvoiceLine_ID(), trxName);
MMatchPO po = new MMatchPO(iLine, iLine.getC_Invoice().getDateInvoiced(), matchPO.getQty().negate());
po.setC_OrderLine_ID(C_OrderLine_ID);
po.setRef_MatchPO_ID(matchPO.getM_MatchPO_ID());
po.setPosted(true);
po.saveEx(trxName);
matchPO.setRef_MatchPO_ID(po.getM_MatchPO_ID());
matchPO.setPosted(true);
matchPO.saveEx(trxName);
matchedMatchPOList.add(matchPO);
creditMemoQty = creditMemoQty.subtract(matchPO.getQty());
}
if (creditMemoQty.signum() == 0)
break;
}
}
for (MMatchPO matchedMatchPO : matchedMatchPOList)
notMatchedMatchPOList.remove(matchedMatchPO);
}
if (creditMemoQty.signum() == 0)
continue;
for (MMatchPO matchPO : notMatchedMatchPOList)
{
if (!matchPO.isPosted() && matchPO.getC_InvoiceLine_ID() > 0 && matchPO.getM_InOutLine_ID() == 0)
{
if (matchPO.getQty().compareTo(creditMemoQty) > 0)
{
matchPO.setQty(matchPO.getQty().subtract(creditMemoQty));
matchPO.saveEx(trxName);
MInvoiceLine iLine = new MInvoiceLine(ctx, matchPO.getC_InvoiceLine_ID(), trxName);
MMatchPO po = new MMatchPO(iLine, iLine.getC_Invoice().getDateInvoiced(), creditMemoQty);
po.setC_OrderLine_ID(C_OrderLine_ID);
po.setRef_MatchPO_ID(matchPOCreditMemo.getM_MatchPO_ID());
po.setPosted(true);
po.saveEx(trxName);
matchPOCreditMemo.setRef_MatchPO_ID(po.getM_MatchPO_ID());
matchPOCreditMemo.setPosted(true);
matchPOCreditMemo.saveEx(trxName);
matchedMatchPOList.add(po);
creditMemoQty = creditMemoQty.subtract(po.getQty());
}
else if (matchPO.getQty().compareTo(creditMemoQty) == 0)
{
matchPO.setRef_MatchPO_ID(matchPOCreditMemo.getM_MatchPO_ID());
matchPO.setPosted(true);
matchPO.saveEx(trxName);
matchPOCreditMemo.setRef_MatchPO_ID(matchPO.getM_MatchPO_ID());
matchPOCreditMemo.setPosted(true);
matchPOCreditMemo.saveEx(trxName);
matchedMatchPOList.add(matchPO);
creditMemoQty = creditMemoQty.subtract(matchPO.getQty());
}
else if (matchPO.getQty().compareTo(creditMemoQty) < 0)
{
matchPOCreditMemo.setQty(matchPOCreditMemo.getQty().add(matchPO.getQty()));
matchPOCreditMemo.saveEx(trxName);
MInvoiceLine iLine = new MInvoiceLine(ctx, matchPOCreditMemo.getC_InvoiceLine_ID(), trxName);
MMatchPO po = new MMatchPO(iLine, iLine.getC_Invoice().getDateInvoiced(), matchPO.getQty().negate());
po.setC_OrderLine_ID(C_OrderLine_ID);
po.setRef_MatchPO_ID(matchPO.getM_MatchPO_ID());
po.setPosted(true);
po.saveEx(trxName);
matchPO.setRef_MatchPO_ID(po.getM_MatchPO_ID());
matchPO.setPosted(true);
matchPO.saveEx(trxName);
matchedMatchPOList.add(matchPO);
creditMemoQty = creditMemoQty.subtract(matchPO.getQty());
}
if (creditMemoQty.signum() == 0)
break;
}
}
for (MMatchPO matchedMatchPO : matchedMatchPOList)
notMatchedMatchPOList.remove(matchedMatchPO);
}
}
if (currentPO != null)
{
for (MMatchPO matchPOCreditMemo : creditMemoMatchPOList)
{
if (matchPOCreditMemo.getM_MatchPO_ID() == currentPO.getM_MatchPO_ID())
{
if (matchPOCreditMemo.getReversal_ID() == 0 && matchPOCreditMemo.getRef_MatchPO_ID() == 0)
throw new RuntimeException("Failed to find the corresponding invoice matched po");
}
}
}
}
/**
* remove match between vendor invoice and vendor cm
* @param ctx
* @param C_Invoice_ID
* @param trxName
*/
public static void unmatch(Properties ctx, int C_Invoice_ID, String trxName)
{
List<Integer> unmatchedOrderLineID = new ArrayList<Integer>();
MMatchPO[] mpos = MMatchPO.getInvoice(ctx, C_Invoice_ID, trxName);
for (MMatchPO mpo : mpos)
{
if (mpo.getReversal_ID() > 0 || mpo.getRef_MatchPO_ID() == 0)
continue;
int C_OrderLine_ID = mpo.getC_OrderLine_ID();
if (!unmatchedOrderLineID.contains(C_OrderLine_ID))
{
unmatchedOrderLineID.add(C_OrderLine_ID);
MMatchPO[] pos = MMatchPO.getOrderLine(ctx, C_OrderLine_ID, trxName);
for (MMatchPO po : pos)
{
if (po.getReversal_ID() == 0 && po.getC_InvoiceLine_ID() > 0 && po.getRef_MatchPO_ID() > 0)
{
if (po.getC_InvoiceLine().getC_Invoice_ID() == C_Invoice_ID)
{
po.setRef_MatchPO_ID(0);
po.setPosted(false);
po.saveEx(trxName);
}
else if (po.getRef_MatchPO().getC_InvoiceLine().getC_Invoice_ID() == C_Invoice_ID)
{
po.setRef_MatchPO_ID(0);
po.setPosted(false);
po.saveEx(trxName);
}
}
}
}
}
}
}

View File

@ -33,7 +33,7 @@ public class X_M_MatchPO extends PO implements I_M_MatchPO, I_Persistent
/** /**
* *
*/ */
private static final long serialVersionUID = 20190106L; private static final long serialVersionUID = 20190903L;
/** Standard Constructor */ /** Standard Constructor */
public X_M_MatchPO (Properties ctx, int M_MatchPO_ID, String trxName) public X_M_MatchPO (Properties ctx, int M_MatchPO_ID, String trxName)
@ -488,6 +488,31 @@ public class X_M_MatchPO extends PO implements I_M_MatchPO, I_Persistent
return bd; return bd;
} }
public org.compiere.model.I_M_MatchPO getRef_MatchPO() throws RuntimeException
{
return (org.compiere.model.I_M_MatchPO)MTable.get(getCtx(), org.compiere.model.I_M_MatchPO.Table_Name)
.getPO(getRef_MatchPO_ID(), get_TrxName()); }
/** Set Referenced Match PO.
@param Ref_MatchPO_ID Referenced Match PO */
public void setRef_MatchPO_ID (int Ref_MatchPO_ID)
{
if (Ref_MatchPO_ID < 1)
set_Value (COLUMNNAME_Ref_MatchPO_ID, null);
else
set_Value (COLUMNNAME_Ref_MatchPO_ID, Integer.valueOf(Ref_MatchPO_ID));
}
/** Get Referenced Match PO.
@return Referenced Match PO */
public int getRef_MatchPO_ID ()
{
Integer ii = (Integer)get_Value(COLUMNNAME_Ref_MatchPO_ID);
if (ii == null)
return 0;
return ii.intValue();
}
public org.compiere.model.I_M_MatchPO getReversal() throws RuntimeException public org.compiere.model.I_M_MatchPO getReversal() throws RuntimeException
{ {
return (org.compiere.model.I_M_MatchPO)MTable.get(getCtx(), org.compiere.model.I_M_MatchPO.Table_Name) return (org.compiere.model.I_M_MatchPO)MTable.get(getCtx(), org.compiere.model.I_M_MatchPO.Table_Name)

File diff suppressed because one or more lines are too long

View File

@ -21,6 +21,7 @@ import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.VetoableChangeListener; import java.beans.VetoableChangeListener;
import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Vector; import java.util.Vector;
import java.util.logging.Level; import java.util.logging.Level;
@ -94,6 +95,8 @@ public class VCreateFromInvoiceUI extends CreateFromInvoice implements ActionLis
/** Combo box for selecting RMA document */ /** Combo box for selecting RMA document */
private JComboBox<Object> rmaField = new JComboBox<Object>(); private JComboBox<Object> rmaField = new JComboBox<Object>();
private boolean isCreditMemo = false;
/** /**
* Dynamic Init * Dynamic Init
* @throws Exception if Lookups cannot be initialized * @throws Exception if Lookups cannot be initialized
@ -116,6 +119,9 @@ public class VCreateFromInvoiceUI extends CreateFromInvoice implements ActionLis
rmaField.setVisible(false); rmaField.setVisible(false);
} }
isCreditMemo = MDocType.DOCBASETYPE_APCreditMemo.equals(docType.getDocBaseType())
|| MDocType.DOCBASETYPE_ARCreditMemo.equals(docType.getDocBaseType());
initBPartner(true); initBPartner(true);
bPartnerField.addVetoableChangeListener(this); bPartnerField.addVetoableChangeListener(this);
@ -276,7 +282,7 @@ public class VCreateFromInvoiceUI extends CreateFromInvoice implements ActionLis
orderField.removeAllItems(); orderField.removeAllItems();
orderField.addItem(pp); orderField.addItem(pp);
ArrayList<KeyNamePair> list = loadOrderData(C_BPartner_ID, forInvoice, false); ArrayList<KeyNamePair> list = loadOrderData(C_BPartner_ID, forInvoice, false, isCreditMemo);
for(KeyNamePair knp : list) for(KeyNamePair knp : list)
orderField.addItem(knp); orderField.addItem(knp);
@ -343,7 +349,7 @@ public class VCreateFromInvoiceUI extends CreateFromInvoice implements ActionLis
*/ */
protected void loadOrder (int C_Order_ID, boolean forInvoice) protected void loadOrder (int C_Order_ID, boolean forInvoice)
{ {
loadTableOIS(getOrderData(C_Order_ID, forInvoice)); loadTableOIS(getOrderData(C_Order_ID, forInvoice, isCreditMemo));
} // LoadOrder } // LoadOrder
protected void loadRMA (int M_RMA_ID) protected void loadRMA (int M_RMA_ID)

View File

@ -13,6 +13,7 @@
*****************************************************************************/ *****************************************************************************/
package org.adempiere.webui.apps.form; package org.adempiere.webui.apps.form;
import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Vector; import java.util.Vector;
import java.util.logging.Level; import java.util.logging.Level;
@ -105,6 +106,8 @@ public class WCreateFromInvoiceUI extends CreateFromInvoice implements EventList
private Grid parameterStdLayout; private Grid parameterStdLayout;
private boolean isCreditMemo = false;
/** /**
* Dynamic Init * Dynamic Init
* @throws Exception if Lookups cannot be initialized * @throws Exception if Lookups cannot be initialized
@ -127,6 +130,9 @@ public class WCreateFromInvoiceUI extends CreateFromInvoice implements EventList
rmaField.setVisible(false); rmaField.setVisible(false);
} }
isCreditMemo = MDocType.DOCBASETYPE_APCreditMemo.equals(docType.getDocBaseType())
|| MDocType.DOCBASETYPE_ARCreditMemo.equals(docType.getDocBaseType());
initBPartner(true); initBPartner(true);
bPartnerField.addValueChangeListener(this); bPartnerField.addValueChangeListener(this);
@ -315,7 +321,7 @@ public class WCreateFromInvoiceUI extends CreateFromInvoice implements EventList
orderField.removeAllItems(); orderField.removeAllItems();
orderField.addItem(pp); orderField.addItem(pp);
ArrayList<KeyNamePair> list = loadOrderData(C_BPartner_ID, forInvoice, false); ArrayList<KeyNamePair> list = loadOrderData(C_BPartner_ID, forInvoice, false, isCreditMemo);
for(KeyNamePair knp : list) for(KeyNamePair knp : list)
orderField.addItem(knp); orderField.addItem(knp);
@ -381,7 +387,7 @@ public class WCreateFromInvoiceUI extends CreateFromInvoice implements EventList
*/ */
protected void loadOrder (int C_Order_ID, boolean forInvoice) protected void loadOrder (int C_Order_ID, boolean forInvoice)
{ {
loadTableOIS(getOrderData(C_Order_ID, forInvoice)); loadTableOIS(getOrderData(C_Order_ID, forInvoice, isCreditMemo));
} // LoadOrder } // LoadOrder
protected void loadRMA (int M_RMA_ID) protected void loadRMA (int M_RMA_ID)

View File

@ -88,6 +88,11 @@ public abstract class CreateFrom implements ICreateFrom
* @param forInvoice for invoice * @param forInvoice for invoice
*/ */
protected ArrayList<KeyNamePair> loadOrderData (int C_BPartner_ID, boolean forInvoice, boolean sameWarehouseOnly) protected ArrayList<KeyNamePair> loadOrderData (int C_BPartner_ID, boolean forInvoice, boolean sameWarehouseOnly)
{
return loadOrderData(C_BPartner_ID, forInvoice, sameWarehouseOnly, false);
}
protected ArrayList<KeyNamePair> loadOrderData (int C_BPartner_ID, boolean forInvoice, boolean sameWarehouseOnly, boolean forCreditMemo)
{ {
ArrayList<KeyNamePair> list = new ArrayList<KeyNamePair>(); ArrayList<KeyNamePair> list = new ArrayList<KeyNamePair>();
@ -109,13 +114,19 @@ public abstract class CreateFrom implements ICreateFrom
.append(display) .append(display)
.append(" FROM C_Order o WHERE ") .append(" FROM C_Order o WHERE ")
.append(colBP) .append(colBP)
.append("=? AND o.IsSOTrx=? AND o.DocStatus IN ('CL','CO') AND o.C_Order_ID IN (SELECT ol.C_Order_ID FROM C_OrderLine ol WHERE ol.QtyOrdered-") .append("=? AND o.IsSOTrx=? AND o.DocStatus IN ('CL','CO') AND o.C_Order_ID IN (SELECT ol.C_Order_ID FROM C_OrderLine ol WHERE ");
.append(column) if (forCreditMemo)
.append("!=0) "); sql.append(column).append(">0 AND (CASE WHEN ol.QtyDelivered>=ol.QtyOrdered THEN ol.QtyDelivered-ol.QtyInvoiced!=0 ELSE 1=1 END)) ");
else
sql.append("ol.QtyOrdered-").append(column).append("!=0) ");
if(sameWarehouseOnly) if(sameWarehouseOnly)
{ {
sql = sql.append(" AND o.M_Warehouse_ID=? "); sql = sql.append(" AND o.M_Warehouse_ID=? ");
} }
if (forCreditMemo)
sql = sql.append("ORDER BY o.DateOrdered DESC,o.DocumentNo DESC");
else
sql = sql.append("ORDER BY o.DateOrdered,o.DocumentNo"); sql = sql.append("ORDER BY o.DateOrdered,o.DocumentNo");
// //
PreparedStatement pstmt = null; PreparedStatement pstmt = null;
@ -155,6 +166,11 @@ public abstract class CreateFrom implements ICreateFrom
* @param forInvoice true if for invoice vs. delivery qty * @param forInvoice true if for invoice vs. delivery qty
*/ */
protected Vector<Vector<Object>> getOrderData (int C_Order_ID, boolean forInvoice) protected Vector<Vector<Object>> getOrderData (int C_Order_ID, boolean forInvoice)
{
return getOrderData (C_Order_ID, forInvoice, false);
}
protected Vector<Vector<Object>> getOrderData (int C_Order_ID, boolean forInvoice, boolean forCreditMemo)
{ {
/** /**
* Selected - 0 * Selected - 0
@ -170,9 +186,9 @@ public abstract class CreateFrom implements ICreateFrom
p_order = new MOrder (Env.getCtx(), C_Order_ID, null); p_order = new MOrder (Env.getCtx(), C_Order_ID, null);
Vector<Vector<Object>> data = new Vector<Vector<Object>>(); Vector<Vector<Object>> data = new Vector<Vector<Object>>();
StringBuilder sql = new StringBuilder("SELECT " StringBuilder sql = new StringBuilder("SELECT ");
+ "l.QtyOrdered-SUM(COALESCE(m.Qty,0))," // 1 sql.append(forCreditMemo ? "SUM(COALESCE(m.Qty,0))," : "l.QtyOrdered-SUM(COALESCE(m.Qty,0)),"); // 1
+ "CASE WHEN l.QtyOrdered=0 THEN 0 ELSE l.QtyEntered/l.QtyOrdered END," // 2 sql.append("CASE WHEN l.QtyOrdered=0 THEN 0 ELSE l.QtyEntered/l.QtyOrdered END," // 2
+ " l.C_UOM_ID,COALESCE(uom.UOMSymbol,uom.Name)," // 3..4 + " l.C_UOM_ID,COALESCE(uom.UOMSymbol,uom.Name)," // 3..4
+ " COALESCE(l.M_Product_ID,0),COALESCE(p.Name,c.Name),po.VendorProductNo," // 5..7 + " COALESCE(l.M_Product_ID,0),COALESCE(p.Name,c.Name),po.VendorProductNo," // 5..7
+ " l.C_OrderLine_ID,l.Line " // 8..9 + " l.C_OrderLine_ID,l.Line " // 8..9
@ -180,7 +196,7 @@ public abstract class CreateFrom implements ICreateFrom
+ " LEFT OUTER JOIN M_Product_PO po ON (l.M_Product_ID = po.M_Product_ID AND l.C_BPartner_ID = po.C_BPartner_ID) " + " LEFT OUTER JOIN M_Product_PO po ON (l.M_Product_ID = po.M_Product_ID AND l.C_BPartner_ID = po.C_BPartner_ID) "
+ " LEFT OUTER JOIN M_MatchPO m ON (l.C_OrderLine_ID=m.C_OrderLine_ID AND "); + " LEFT OUTER JOIN M_MatchPO m ON (l.C_OrderLine_ID=m.C_OrderLine_ID AND ");
sql.append(forInvoice ? "m.C_InvoiceLine_ID" : "m.M_InOutLine_ID"); sql.append(forInvoice ? "m.C_InvoiceLine_ID" : "m.M_InOutLine_ID");
sql.append(" IS NOT NULL)") sql.append(" IS NOT NULL AND COALESCE(m.Reversal_ID,0)=0)")
.append(" LEFT OUTER JOIN M_Product p ON (l.M_Product_ID=p.M_Product_ID)" .append(" LEFT OUTER JOIN M_Product p ON (l.M_Product_ID=p.M_Product_ID)"
+ " LEFT OUTER JOIN C_Charge c ON (l.C_Charge_ID=c.C_Charge_ID)"); + " LEFT OUTER JOIN C_Charge c ON (l.C_Charge_ID=c.C_Charge_ID)");
if (Env.isBaseLanguage(Env.getCtx(), "C_UOM")) if (Env.isBaseLanguage(Env.getCtx(), "C_UOM"))

View File

@ -365,7 +365,7 @@ public abstract class CreateFromInvoice extends CreateFrom
protected void configureMiniTable (IMiniTable miniTable) protected void configureMiniTable (IMiniTable miniTable)
{ {
miniTable.setColumnClass(0, Boolean.class, false); // 0-Selection miniTable.setColumnClass(0, Boolean.class, false); // 0-Selection
miniTable.setColumnClass(1, BigDecimal.class, true); // 1-Qty miniTable.setColumnClass(1, BigDecimal.class, false); // 1-Qty
miniTable.setColumnClass(2, String.class, true); // 2-UOM miniTable.setColumnClass(2, String.class, true); // 2-UOM
miniTable.setColumnClass(3, String.class, true); // 3-Product miniTable.setColumnClass(3, String.class, true); // 3-Product
miniTable.setColumnClass(4, String.class, true); // 4-VendorProductNo miniTable.setColumnClass(4, String.class, true); // 4-VendorProductNo