IDEMPIERE-5065 Material Receipt Line not available for matching after… (#1019)
* IDEMPIERE-5065 Material Receipt Line not available for matching after reversal of Match PO * IDEMPIERE-5065 Material Receipt Line not available for matching after reversal of Match PO Fix unit test * IDEMPIERE-5065 Material Receipt Line not available for matching after reversal of Match PO Remove unreliable and potentially dangerous match po consolidation
This commit is contained in:
parent
6923fbe18e
commit
74b6604d57
|
@ -53,7 +53,7 @@ public class MatchPOReverse extends SvrProcess {
|
||||||
if (reversalDate == null) {
|
if (reversalDate == null) {
|
||||||
reversalDate = new Timestamp(System.currentTimeMillis());
|
reversalDate = new Timestamp(System.currentTimeMillis());
|
||||||
}
|
}
|
||||||
if (!po.reverse(reversalDate))
|
if (!po.reverse(reversalDate, true))
|
||||||
throw new AdempiereException("Failed to reverse matching");
|
throw new AdempiereException("Failed to reverse matching");
|
||||||
}
|
}
|
||||||
return "@OK@";
|
return "@OK@";
|
||||||
|
|
|
@ -138,7 +138,7 @@ public abstract class Doc
|
||||||
* M_Requisition POR
|
* M_Requisition POR
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
private static final String DOC_TYPE_BY_DOC_BASE_TYPE_SQL = "SELECT C_DocType_ID FROM C_DocType WHERE AD_Client_ID=? AND DocBaseType=? AND IsActive='Y' ORDER BY IsDefault DESC, C_DocType_ID";
|
public static final String DOC_TYPE_BY_DOC_BASE_TYPE_SQL = "SELECT C_DocType_ID FROM C_DocType WHERE AD_Client_ID=? AND DocBaseType=? AND IsActive='Y' ORDER BY IsDefault DESC, C_DocType_ID";
|
||||||
|
|
||||||
/** AR Invoices - ARI */
|
/** AR Invoices - ARI */
|
||||||
public static final String DOCTYPE_ARInvoice = MDocType.DOCBASETYPE_ARInvoice;
|
public static final String DOCTYPE_ARInvoice = MDocType.DOCBASETYPE_ARInvoice;
|
||||||
|
|
|
@ -31,6 +31,10 @@ import java.util.Map;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
|
import org.adempiere.base.Core;
|
||||||
|
import org.adempiere.util.IReservationTracer;
|
||||||
|
import org.adempiere.util.IReservationTracerFactory;
|
||||||
|
import org.compiere.acct.Doc;
|
||||||
import org.compiere.process.DocAction;
|
import org.compiere.process.DocAction;
|
||||||
import org.compiere.util.CLogger;
|
import org.compiere.util.CLogger;
|
||||||
import org.compiere.util.DB;
|
import org.compiere.util.DB;
|
||||||
|
@ -1274,84 +1278,12 @@ public class MMatchPO extends X_M_MatchPO
|
||||||
.append (",C_OrderLine_ID=").append (getC_OrderLine_ID())
|
.append (",C_OrderLine_ID=").append (getC_OrderLine_ID())
|
||||||
.append (",M_InOutLine_ID=").append (getM_InOutLine_ID())
|
.append (",M_InOutLine_ID=").append (getM_InOutLine_ID())
|
||||||
.append (",C_InvoiceLine_ID=").append (getC_InvoiceLine_ID())
|
.append (",C_InvoiceLine_ID=").append (getC_InvoiceLine_ID())
|
||||||
|
.append (",Processed=").append(isProcessed())
|
||||||
|
.append (",Posted=").append(isPosted())
|
||||||
.append ("]");
|
.append ("]");
|
||||||
return sb.toString ();
|
return sb.toString ();
|
||||||
} // toString
|
} // toString
|
||||||
|
|
||||||
/**
|
|
||||||
* Consolidate MPO entries.
|
|
||||||
* (data conversion issue)
|
|
||||||
* @param ctx context
|
|
||||||
*/
|
|
||||||
public static void consolidate(Properties ctx)
|
|
||||||
{
|
|
||||||
String sql = "SELECT * FROM M_MatchPO po "
|
|
||||||
+ "WHERE EXISTS (SELECT 1 FROM M_MatchPO x "
|
|
||||||
+ "WHERE po.C_OrderLine_ID=x.C_OrderLine_ID AND po.Qty=x.Qty "
|
|
||||||
+ "GROUP BY C_OrderLine_ID, Qty "
|
|
||||||
+ "HAVING COUNT(*) = 2) "
|
|
||||||
+ " AND AD_Client_ID=?"
|
|
||||||
+ "ORDER BY C_OrderLine_ID, M_InOutLine_ID";
|
|
||||||
PreparedStatement pstmt = null;
|
|
||||||
ResultSet rs = null;
|
|
||||||
int success = 0;
|
|
||||||
int errors = 0;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
pstmt = DB.prepareStatement (sql, null);
|
|
||||||
pstmt.setInt(1, Env.getAD_Client_ID(ctx));
|
|
||||||
rs = pstmt.executeQuery ();
|
|
||||||
while (rs.next ())
|
|
||||||
{
|
|
||||||
MMatchPO po1 = new MMatchPO (ctx, rs, null);
|
|
||||||
if (rs.next())
|
|
||||||
{
|
|
||||||
MMatchPO po2 = new MMatchPO (ctx, rs, null);
|
|
||||||
if (po1.getM_InOutLine_ID() != 0 && po1.getC_InvoiceLine_ID() == 0
|
|
||||||
&& po2.getM_InOutLine_ID() == 0 && po2.getC_InvoiceLine_ID() != 0)
|
|
||||||
{
|
|
||||||
StringBuilder s1 = new StringBuilder("UPDATE M_MatchPO SET C_InvoiceLine_ID=")
|
|
||||||
.append(po2.getC_InvoiceLine_ID())
|
|
||||||
.append(" WHERE M_MatchPO_ID=").append(po1.getM_MatchPO_ID());
|
|
||||||
int no1 = DB.executeUpdate(s1.toString(), null);
|
|
||||||
if (no1 != 1)
|
|
||||||
{
|
|
||||||
errors++;
|
|
||||||
s_log.warning("Not updated M_MatchPO_ID=" + po1.getM_MatchPO_ID());
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
//
|
|
||||||
String s2 = "DELETE FROM Fact_Acct WHERE AD_Table_ID=473 AND Record_ID=?";
|
|
||||||
int no2 = DB.executeUpdate(s2, po2.getM_MatchPO_ID(), null);
|
|
||||||
String s3 = "DELETE FROM M_MatchPO WHERE M_MatchPO_ID=?";
|
|
||||||
int no3 = DB.executeUpdate(s3, po2.getM_MatchPO_ID(), null);
|
|
||||||
if (no2 == 0 && no3 == 1)
|
|
||||||
success++;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
s_log.warning("M_MatchPO_ID=" + po2.getM_MatchPO_ID()
|
|
||||||
+ " - Deleted=" + no2 + ", Acct=" + no3);
|
|
||||||
errors++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
s_log.log (Level.SEVERE, sql, e);
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
DB.close(rs, pstmt);
|
|
||||||
rs = null; pstmt = null;
|
|
||||||
}
|
|
||||||
if (errors == 0 && success == 0)
|
|
||||||
;
|
|
||||||
else
|
|
||||||
if (s_log.isLoggable(Level.INFO)) s_log.info("Success #" + success + " - Error #" + errors);
|
|
||||||
} // consolidate
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reverse MatchPO.
|
* Reverse MatchPO.
|
||||||
* @param reversalDate
|
* @param reversalDate
|
||||||
|
@ -1359,7 +1291,20 @@ public class MMatchPO extends X_M_MatchPO
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public boolean reverse(Timestamp reversalDate)
|
public boolean reverse(Timestamp reversalDate)
|
||||||
|
{
|
||||||
|
return reverse(reversalDate, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse MatchPO.
|
||||||
|
* @param reversalDate
|
||||||
|
* @param reverseMatchingOnly true if MR is not reverse
|
||||||
|
* @return boolean
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
|
||||||
|
public boolean reverse(Timestamp reversalDate, boolean reverseMatchingOnly)
|
||||||
{
|
{
|
||||||
if (this.isProcessed() && this.getReversal_ID() == 0)
|
if (this.isProcessed() && this.getReversal_ID() == 0)
|
||||||
{
|
{
|
||||||
|
@ -1389,6 +1334,50 @@ public class MMatchPO extends X_M_MatchPO
|
||||||
this.setReversal_ID(reversal.getM_MatchPO_ID());
|
this.setReversal_ID(reversal.getM_MatchPO_ID());
|
||||||
this.saveEx();
|
this.saveEx();
|
||||||
|
|
||||||
|
//update qtyOrdered
|
||||||
|
if (reverseMatchingOnly && reversal.getM_InOutLine_ID() > 0 && reversal.getC_OrderLine_ID() > 0)
|
||||||
|
{
|
||||||
|
MInOutLine sLine = new MInOutLine(Env.getCtx(), reversal.getM_InOutLine_ID(), get_TrxName());
|
||||||
|
if (sLine.getMovementQty().compareTo(this.getQty()) == 0 && sLine.getC_OrderLine_ID() == reversal.getC_OrderLine_ID())
|
||||||
|
{
|
||||||
|
//clear c_orderline from shipment so we can match the shipment again (to the same or different order line)
|
||||||
|
sLine.setC_OrderLine_ID(0);
|
||||||
|
sLine.saveEx();
|
||||||
|
}
|
||||||
|
//add back qtyOrdered
|
||||||
|
MOrderLine oLine = new MOrderLine(Env.getCtx(), reversal.getC_OrderLine_ID(), get_TrxName());
|
||||||
|
BigDecimal storageReservationToUpdate = oLine.getQtyReserved();
|
||||||
|
oLine.setQtyReserved(oLine.getQtyReserved().add(getQty()));
|
||||||
|
BigDecimal reservedAndDelivered = oLine.getQtyDelivered().add(oLine.getQtyReserved());
|
||||||
|
if (reservedAndDelivered.compareTo(oLine.getQtyOrdered()) > 0)
|
||||||
|
{
|
||||||
|
oLine.setQtyReserved(oLine.getQtyReserved().subtract(reservedAndDelivered.subtract(oLine.getQtyOrdered())));
|
||||||
|
if (oLine.getQtyReserved().signum()==-1)
|
||||||
|
oLine.setQtyReserved(Env.ZERO);
|
||||||
|
}
|
||||||
|
oLine.saveEx();
|
||||||
|
storageReservationToUpdate = storageReservationToUpdate.subtract(oLine.getQtyReserved());
|
||||||
|
if (storageReservationToUpdate.signum() != 0)
|
||||||
|
{
|
||||||
|
IReservationTracer tracer = null;
|
||||||
|
IReservationTracerFactory factory = Core.getReservationTracerFactory();
|
||||||
|
if (factory != null)
|
||||||
|
{
|
||||||
|
int docTypeId = DB.getSQLValue((String)null, Doc.DOC_TYPE_BY_DOC_BASE_TYPE_SQL, getAD_Client_ID(), Doc.DOCTYPE_MatMatchPO);
|
||||||
|
tracer = factory.newTracer(docTypeId, reversal.getDocumentNo(), 10,
|
||||||
|
reversal.get_Table_ID(), reversal.get_ID(), oLine.getM_Warehouse_ID(),
|
||||||
|
oLine.getM_Product_ID(), oLine.getM_AttributeSetInstance_ID(), oLine.getParent().isSOTrx(),
|
||||||
|
get_TrxName());
|
||||||
|
}
|
||||||
|
boolean success = MStorageReservation.add (Env.getCtx(), oLine.getM_Warehouse_ID(),
|
||||||
|
oLine.getM_Product_ID(),
|
||||||
|
oLine.getM_AttributeSetInstance_ID(),
|
||||||
|
storageReservationToUpdate.negate(), oLine.getParent().isSOTrx(), get_TrxName(), tracer);
|
||||||
|
if (!success)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// auto create new matchpo if have invoice line
|
// auto create new matchpo if have invoice line
|
||||||
if ( reversal.getC_InvoiceLine_ID() > 0 && reversal.getM_InOutLine_ID() > 0 )
|
if ( reversal.getC_InvoiceLine_ID() > 0 && reversal.getM_InOutLine_ID() > 0 )
|
||||||
{
|
{
|
||||||
|
|
|
@ -55,7 +55,6 @@ import org.adempiere.webui.util.ZKUpdateUtil;
|
||||||
import org.compiere.apps.form.Match;
|
import org.compiere.apps.form.Match;
|
||||||
import org.compiere.minigrid.ColumnInfo;
|
import org.compiere.minigrid.ColumnInfo;
|
||||||
import org.compiere.minigrid.IDColumn;
|
import org.compiere.minigrid.IDColumn;
|
||||||
import org.compiere.model.MMatchPO;
|
|
||||||
import org.compiere.util.CLogger;
|
import org.compiere.util.CLogger;
|
||||||
import org.compiere.util.DisplayType;
|
import org.compiere.util.DisplayType;
|
||||||
import org.compiere.util.Env;
|
import org.compiere.util.Env;
|
||||||
|
@ -112,7 +111,6 @@ public class WMatch extends Match
|
||||||
LayoutUtils.addSclass("status-border", statusBar);
|
LayoutUtils.addSclass("status-border", statusBar);
|
||||||
//
|
//
|
||||||
|
|
||||||
MMatchPO.consolidate(Env.getCtx());
|
|
||||||
cmd_matchTo();
|
cmd_matchTo();
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch(Exception e)
|
||||||
|
|
|
@ -25,6 +25,7 @@ import org.adempiere.base.Core;
|
||||||
import org.adempiere.exceptions.AdempiereException;
|
import org.adempiere.exceptions.AdempiereException;
|
||||||
import org.adempiere.util.IReservationTracer;
|
import org.adempiere.util.IReservationTracer;
|
||||||
import org.adempiere.util.IReservationTracerFactory;
|
import org.adempiere.util.IReservationTracerFactory;
|
||||||
|
import org.compiere.acct.Doc;
|
||||||
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;
|
||||||
|
@ -35,6 +36,7 @@ import org.compiere.model.MMatchPO;
|
||||||
import org.compiere.model.MOrderLine;
|
import org.compiere.model.MOrderLine;
|
||||||
import org.compiere.model.MRole;
|
import org.compiere.model.MRole;
|
||||||
import org.compiere.model.MStorageReservation;
|
import org.compiere.model.MStorageReservation;
|
||||||
|
import org.compiere.model.Query;
|
||||||
import org.compiere.process.DocumentEngine;
|
import org.compiere.process.DocumentEngine;
|
||||||
import org.compiere.util.CLogger;
|
import org.compiere.util.CLogger;
|
||||||
import org.compiere.util.DB;
|
import org.compiere.util.DB;
|
||||||
|
@ -55,39 +57,33 @@ public class Match
|
||||||
Msg.getElement(Env.getCtx(), "C_Invoice_ID", false),
|
Msg.getElement(Env.getCtx(), "C_Invoice_ID", false),
|
||||||
Msg.getElement(Env.getCtx(), "M_InOut_ID", false),
|
Msg.getElement(Env.getCtx(), "M_InOut_ID", false),
|
||||||
Msg.getElement(Env.getCtx(), "C_Order_ID", false) };
|
Msg.getElement(Env.getCtx(), "C_Order_ID", false) };
|
||||||
private static final int MATCH_INVOICE = 0;
|
|
||||||
private static final int MATCH_SHIPMENT = 1;
|
public static final int MATCH_INVOICE = 0;
|
||||||
private static final int MATCH_ORDER = 2;
|
public static final int MATCH_SHIPMENT = 1;
|
||||||
|
public static final int MATCH_ORDER = 2;
|
||||||
|
|
||||||
private static final int MODE_NOTMATCHED = 0;
|
public static final int MODE_NOTMATCHED = 0;
|
||||||
//private static final int MODE_MATCHED = 1;
|
//private static final int MODE_MATCHED = 1;
|
||||||
|
|
||||||
/** Indexes in Table */
|
/** Indexes in Table */
|
||||||
private static final int I_BPartner = 3;
|
public static final int I_BPartner = 3;
|
||||||
private static final int I_Line = 4;
|
public static final int I_Line = 4;
|
||||||
private static final int I_Product = 5;
|
public static final int I_Product = 5;
|
||||||
private static final int I_QTY = 6;
|
public static final int I_QTY = 6;
|
||||||
private static final int I_MATCHED = 7;
|
public static final int I_MATCHED = 7;
|
||||||
//private static final int I_Org = 8; //JAVIER
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private StringBuffer m_sql = null;
|
private StringBuffer m_sql = null;
|
||||||
private String m_dateColumn = "";
|
private String m_dateColumn = "";
|
||||||
private String m_qtyColumn = "";
|
private String m_qtyColumn = "";
|
||||||
private String m_groupBy = "";
|
private String m_groupBy = "";
|
||||||
private StringBuffer m_linetype = null;
|
private StringBuffer m_linetype = null;
|
||||||
//private BigDecimal m_xMatched = Env.ZERO;
|
private String m_trxName = null;
|
||||||
//private BigDecimal m_xMatchedTo = Env.ZERO;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Match From Changed - Fill Match To
|
* Match From Changed - Fill Match To
|
||||||
*/
|
*/
|
||||||
protected Vector<String> cmd_matchFrom(String selection)
|
protected Vector<String> cmd_matchFrom(String selection)
|
||||||
{
|
{
|
||||||
// if (log.isLoggable(Level.FINE)) log.fine( "VMatch.cmd_matchFrom");
|
|
||||||
//String selection = (String)matchFrom.getSelectedItem();
|
|
||||||
Vector<String> vector = new Vector<String>(2);
|
Vector<String> vector = new Vector<String>(2);
|
||||||
if (selection.equals(m_matchOptions[MATCH_INVOICE]))
|
if (selection.equals(m_matchOptions[MATCH_INVOICE]))
|
||||||
vector.add(m_matchOptions[MATCH_SHIPMENT]);
|
vector.add(m_matchOptions[MATCH_SHIPMENT]);
|
||||||
|
@ -103,13 +99,11 @@ public class Match
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search Button Pressed - Fill xMatched
|
* Search Button Pressed - Fill match from
|
||||||
*/
|
*/
|
||||||
protected IMiniTable cmd_search(IMiniTable xMatchedTable, int display, String matchToString, Integer Product, Integer Vendor, Timestamp from, Timestamp to, boolean matched)
|
public IMiniTable cmd_search(IMiniTable xMatchedTable, int display, String matchToString, Integer Product, Integer Vendor, Timestamp from, Timestamp to, boolean matched)
|
||||||
{
|
{
|
||||||
// ** Create SQL **
|
// ** Create SQL **
|
||||||
//int display = matchFrom.getSelectedIndex();
|
|
||||||
//String matchToString = (String)matchTo.getSelectedItem();
|
|
||||||
int matchToType = MATCH_INVOICE;
|
int matchToType = MATCH_INVOICE;
|
||||||
if (matchToString.equals(m_matchOptions[MATCH_SHIPMENT]))
|
if (matchToString.equals(m_matchOptions[MATCH_SHIPMENT]))
|
||||||
matchToType = MATCH_SHIPMENT;
|
matchToType = MATCH_SHIPMENT;
|
||||||
|
@ -132,8 +126,6 @@ public class Match
|
||||||
m_sql.append(" AND hdr.C_BPartner_ID=").append(Vendor);
|
m_sql.append(" AND hdr.C_BPartner_ID=").append(Vendor);
|
||||||
}
|
}
|
||||||
// Date
|
// Date
|
||||||
//Timestamp from = (Timestamp)dateFrom.getValue();
|
|
||||||
//Timestamp to = (Timestamp)dateTo.getValue();
|
|
||||||
if (from != null && to != null)
|
if (from != null && to != null)
|
||||||
m_sql.append(" AND ").append(m_dateColumn).append(" BETWEEN ")
|
m_sql.append(" AND ").append(m_dateColumn).append(" BETWEEN ")
|
||||||
.append(DB.TO_DATE(from)).append(" AND ").append(DB.TO_DATE(to));
|
.append(DB.TO_DATE(from)).append(" AND ").append(DB.TO_DATE(to));
|
||||||
|
@ -152,14 +144,13 @@ public class Match
|
||||||
/**
|
/**
|
||||||
* Process Button Pressed - Process Matching
|
* Process Button Pressed - Process Matching
|
||||||
*/
|
*/
|
||||||
protected void cmd_process(IMiniTable xMatchedTable, IMiniTable xMatchedToTable, int matchMode, int matchFrom, Object matchTo, BigDecimal m_xMatched)
|
public void cmd_process(IMiniTable xMatchedTable, IMiniTable xMatchedToTable, int matchMode, int matchFrom, String matchTo, BigDecimal m_xMatched)
|
||||||
{
|
{
|
||||||
log.config("");
|
log.config("");
|
||||||
// Matched From
|
// Matched From
|
||||||
int matchedRow = xMatchedTable.getSelectedRow();
|
int matchedRow = xMatchedTable.getSelectedRow();
|
||||||
if (matchedRow < 0)
|
if (matchedRow < 0)
|
||||||
return;
|
return;
|
||||||
// KeyNamePair BPartner = (KeyNamePair)xMatchedTable.getValueAt(matchedRow, I_BPartner);
|
|
||||||
KeyNamePair lineMatched = (KeyNamePair)xMatchedTable.getValueAt(matchedRow, I_Line);
|
KeyNamePair lineMatched = (KeyNamePair)xMatchedTable.getValueAt(matchedRow, I_Line);
|
||||||
KeyNamePair Product = (KeyNamePair)xMatchedTable.getValueAt(matchedRow, I_Product);
|
KeyNamePair Product = (KeyNamePair)xMatchedTable.getValueAt(matchedRow, I_Product);
|
||||||
|
|
||||||
|
@ -207,39 +198,45 @@ public class Match
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create it
|
// Create it
|
||||||
String innerTrxName = Trx.createTrxName("Match");
|
String innerTrxName = m_trxName == null ? Trx.createTrxName("Match") : null;
|
||||||
Trx innerTrx = Trx.get(innerTrxName, true);
|
Trx innerTrx = innerTrxName != null ? Trx.get(innerTrxName, true) : null;
|
||||||
innerTrx.setDisplayName(getClass().getName()+"_cmd_process");
|
if (innerTrx != null)
|
||||||
|
innerTrx.setDisplayName(getClass().getName()+"_cmd_process");
|
||||||
|
|
||||||
try{
|
try {
|
||||||
if (createMatchRecord(invoice, M_InOutLine_ID, Line_ID, BigDecimal.valueOf(qty), innerTrxName))
|
if (createMatchRecord(invoice, M_InOutLine_ID, Line_ID, BigDecimal.valueOf(qty), m_trxName != null ? m_trxName : innerTrxName)) {
|
||||||
innerTrx.commit();
|
if (innerTrx != null)
|
||||||
else
|
innerTrx.commit();
|
||||||
|
} else {
|
||||||
|
if (innerTrx != null)
|
||||||
|
innerTrx.rollback();
|
||||||
|
else
|
||||||
|
Trx.get(m_trxName, false).rollback();
|
||||||
|
}
|
||||||
|
} catch(Exception ex) {
|
||||||
|
if (innerTrx != null)
|
||||||
innerTrx.rollback();
|
innerTrx.rollback();
|
||||||
}catch(Exception ex){
|
|
||||||
innerTrx.rollback();
|
|
||||||
throw new AdempiereException(ex);
|
throw new AdempiereException(ex);
|
||||||
}finally{
|
} finally {
|
||||||
innerTrx.close();
|
if (innerTrx != null) {
|
||||||
innerTrx = null;
|
innerTrx.close();
|
||||||
|
innerTrx = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// requery
|
|
||||||
//cmd_search();
|
|
||||||
} // cmd_process
|
} // cmd_process
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fill xMatchedTo
|
* Fill match to
|
||||||
*/
|
*/
|
||||||
protected IMiniTable cmd_searchTo(IMiniTable xMatchedTable, IMiniTable xMatchedToTable, String displayString, int matchToType, boolean sameBPartner, boolean sameProduct, boolean sameQty, boolean matched)
|
public IMiniTable cmd_searchTo(IMiniTable xMatchedTable, IMiniTable xMatchedToTable, String displayString, int matchToType, boolean sameBPartner, boolean sameProduct, boolean sameQty, boolean matched)
|
||||||
{
|
{
|
||||||
int row = xMatchedTable.getSelectedRow();
|
int row = xMatchedTable.getSelectedRow();
|
||||||
if (log.isLoggable(Level.CONFIG)) log.config("Row=" + row);
|
if (log.isLoggable(Level.CONFIG)) log.config("Row=" + row);
|
||||||
|
|
||||||
// ** Create SQL **
|
// ** Create SQL **
|
||||||
//String displayString = (String)matchTo.getSelectedItem();
|
|
||||||
int display = MATCH_INVOICE;
|
int display = MATCH_INVOICE;
|
||||||
if (displayString.equals(m_matchOptions[MATCH_SHIPMENT]))
|
if (displayString.equals(m_matchOptions[MATCH_SHIPMENT]))
|
||||||
display = MATCH_SHIPMENT;
|
display = MATCH_SHIPMENT;
|
||||||
|
@ -248,11 +245,9 @@ public class Match
|
||||||
|
|
||||||
KeyNamePair lineMatched = (KeyNamePair)xMatchedTable.getValueAt(row, I_Line);
|
KeyNamePair lineMatched = (KeyNamePair)xMatchedTable.getValueAt(row, I_Line);
|
||||||
|
|
||||||
//int matchToType = matchFrom.getSelectedIndex();
|
|
||||||
tableInit (display, matchToType, matched, lineMatched); // sets m_sql
|
tableInit (display, matchToType, matched, lineMatched); // sets m_sql
|
||||||
// ** Add Where Clause **
|
// ** Add Where Clause **
|
||||||
KeyNamePair BPartner = (KeyNamePair)xMatchedTable.getValueAt(row, I_BPartner);
|
KeyNamePair BPartner = (KeyNamePair)xMatchedTable.getValueAt(row, I_BPartner);
|
||||||
//KeyNamePair Org = (KeyNamePair)xMatchedTable.getValueAt(row, I_Org); //JAVIER
|
|
||||||
KeyNamePair Product = (KeyNamePair)xMatchedTable.getValueAt(row, I_Product);
|
KeyNamePair Product = (KeyNamePair)xMatchedTable.getValueAt(row, I_Product);
|
||||||
if (log.isLoggable(Level.FINE)) log.fine("BPartner=" + BPartner + " - Product=" + Product);
|
if (log.isLoggable(Level.FINE)) log.fine("BPartner=" + BPartner + " - Product=" + Product);
|
||||||
//
|
//
|
||||||
|
@ -327,7 +322,14 @@ public class Match
|
||||||
m_qtyColumn = "lin.QtyOrdered";
|
m_qtyColumn = "lin.QtyOrdered";
|
||||||
m_sql.append("SELECT hdr.C_Order_ID,hdr.DocumentNo, hdr.DateOrdered, bp.Name,hdr.C_BPartner_ID,"
|
m_sql.append("SELECT hdr.C_Order_ID,hdr.DocumentNo, hdr.DateOrdered, bp.Name,hdr.C_BPartner_ID,"
|
||||||
+ " lin.Line,lin.C_OrderLine_ID, p.Name,lin.M_Product_ID,"
|
+ " lin.Line,lin.C_OrderLine_ID, p.Name,lin.M_Product_ID,"
|
||||||
+ " lin.QtyOrdered,SUM(COALESCE(mo.Qty,0)), org.Name, hdr.AD_Org_ID " //JAVIER
|
+ " lin.QtyOrdered,");
|
||||||
|
if (matchToType == MATCH_SHIPMENT)
|
||||||
|
m_sql.append("SUM(CASE WHEN (mo.M_InOutLine_ID IS NOT NULL) THEN COALESCE(mo.Qty,0) ELSE 0 END), ");
|
||||||
|
else if (matchToType == MATCH_INVOICE)
|
||||||
|
m_sql.append("SUM(CASE WHEN (mo.C_InvoiceLine_ID IS NOT NULL) THEN COALESCE(mo.Qty,0) ELSE 0 END), ");
|
||||||
|
else
|
||||||
|
m_sql.append("SUM(COALESCE(mo.Qty,0)), ");
|
||||||
|
m_sql.append("org.Name, hdr.AD_Org_ID " //JAVIER
|
||||||
+ "FROM C_Order hdr"
|
+ "FROM C_Order hdr"
|
||||||
+ " INNER JOIN AD_Org org ON (hdr.AD_Org_ID=org.AD_Org_ID)" //JAVIER
|
+ " INNER JOIN AD_Org org ON (hdr.AD_Org_ID=org.AD_Org_ID)" //JAVIER
|
||||||
+ " INNER JOIN C_BPartner bp ON (hdr.C_BPartner_ID=bp.C_BPartner_ID)"
|
+ " INNER JOIN C_BPartner bp ON (hdr.C_BPartner_ID=bp.C_BPartner_ID)"
|
||||||
|
@ -355,8 +357,14 @@ public class Match
|
||||||
m_groupBy = " GROUP BY hdr.C_Order_ID,hdr.DocumentNo,hdr.DateOrdered,bp.Name,hdr.C_BPartner_ID,"
|
m_groupBy = " GROUP BY hdr.C_Order_ID,hdr.DocumentNo,hdr.DateOrdered,bp.Name,hdr.C_BPartner_ID,"
|
||||||
+ " lin.Line,lin.C_OrderLine_ID,p.Name,lin.M_Product_ID,lin.QtyOrdered, org.Name, hdr.AD_Org_ID " //JAVIER
|
+ " lin.Line,lin.C_OrderLine_ID,p.Name,lin.M_Product_ID,lin.QtyOrdered, org.Name, hdr.AD_Org_ID " //JAVIER
|
||||||
+ "HAVING "
|
+ "HAVING "
|
||||||
+ (matched ? "0" : "lin.QtyOrdered")
|
+ (matched ? "0" : "lin.QtyOrdered");
|
||||||
+ "<>SUM(COALESCE(mo.Qty,0))";
|
|
||||||
|
if (matchToType == MATCH_SHIPMENT)
|
||||||
|
m_groupBy = m_groupBy + "<>SUM(CASE WHEN (mo.M_InOutLine_ID IS NOT NULL) THEN COALESCE(mo.Qty,0) ELSE 0 END) ";
|
||||||
|
else if (matchToType == MATCH_INVOICE)
|
||||||
|
m_groupBy = m_groupBy + "<>SUM(CASE WHEN (mo.C_InvoiceLine_ID IS NOT NULL) THEN COALESCE(mo.Qty,0) ELSE 0 END) ";
|
||||||
|
else
|
||||||
|
m_groupBy = m_groupBy + "<>SUM(COALESCE(mo.Qty,0)) ";
|
||||||
}
|
}
|
||||||
else // Shipment
|
else // Shipment
|
||||||
{
|
{
|
||||||
|
@ -364,7 +372,12 @@ public class Match
|
||||||
m_qtyColumn = "lin.MovementQty";
|
m_qtyColumn = "lin.MovementQty";
|
||||||
m_sql.append("SELECT hdr.M_InOut_ID,hdr.DocumentNo, hdr.MovementDate, bp.Name,hdr.C_BPartner_ID,"
|
m_sql.append("SELECT hdr.M_InOut_ID,hdr.DocumentNo, hdr.MovementDate, bp.Name,hdr.C_BPartner_ID,"
|
||||||
+ " lin.Line,lin.M_InOutLine_ID, p.Name,lin.M_Product_ID,"
|
+ " lin.Line,lin.M_InOutLine_ID, p.Name,lin.M_Product_ID,"
|
||||||
+ " CASE WHEN (dt.DocBaseType='MMS' AND hdr.issotrx='N') THEN lin.MovementQty * -1 ELSE lin.MovementQty END,SUM(NVL(m.Qty,0)),org.Name, hdr.AD_Org_ID " //JAVIER
|
+ " CASE WHEN (dt.DocBaseType='MMS' AND hdr.issotrx='N') THEN lin.MovementQty * -1 ELSE lin.MovementQty END,");
|
||||||
|
if (matchToType == MATCH_ORDER)
|
||||||
|
m_sql.append("SUM(CASE WHEN m.M_InOutLine_ID IS NOT NULL THEN COALESCE(m.Qty,0) ELSE 0 END),");
|
||||||
|
else
|
||||||
|
m_sql.append("SUM(COALESCE(m.Qty,0)),");
|
||||||
|
m_sql.append("org.Name, hdr.AD_Org_ID " //JAVIER
|
||||||
+ "FROM M_InOut hdr"
|
+ "FROM M_InOut hdr"
|
||||||
+ " INNER JOIN AD_Org org ON (hdr.AD_Org_ID=org.AD_Org_ID)" //JAVIER
|
+ " INNER JOIN AD_Org org ON (hdr.AD_Org_ID=org.AD_Org_ID)" //JAVIER
|
||||||
+ " INNER JOIN C_BPartner bp ON (hdr.C_BPartner_ID=bp.C_BPartner_ID)"
|
+ " INNER JOIN C_BPartner bp ON (hdr.C_BPartner_ID=bp.C_BPartner_ID)"
|
||||||
|
@ -383,10 +396,12 @@ public class Match
|
||||||
m_groupBy = " GROUP BY hdr.M_InOut_ID,hdr.DocumentNo,hdr.MovementDate,bp.Name,hdr.C_BPartner_ID,"
|
m_groupBy = " GROUP BY hdr.M_InOut_ID,hdr.DocumentNo,hdr.MovementDate,bp.Name,hdr.C_BPartner_ID,"
|
||||||
+ " lin.Line,lin.M_InOutLine_ID,p.Name,lin.M_Product_ID,lin.MovementQty, org.Name, hdr.AD_Org_ID, dt.DocBaseType " //JAVIER
|
+ " lin.Line,lin.M_InOutLine_ID,p.Name,lin.M_Product_ID,lin.MovementQty, org.Name, hdr.AD_Org_ID, dt.DocBaseType " //JAVIER
|
||||||
+ "HAVING "
|
+ "HAVING "
|
||||||
+ (matched ? "0" : "CASE WHEN (dt.DocBaseType='MMS' AND hdr.issotrx='N') THEN lin.MovementQty * -1 ELSE lin.MovementQty END")
|
+ (matched ? "0" : "CASE WHEN (dt.DocBaseType='MMS' AND hdr.issotrx='N') THEN lin.MovementQty * -1 ELSE lin.MovementQty END");
|
||||||
+ "<>SUM(NVL(m.Qty,0))";
|
if (matchToType == MATCH_ORDER)
|
||||||
|
m_groupBy = m_groupBy + "<>SUM(CASE WHEN m.M_InOutLine_ID IS NOT NULL THEN COALESCE(m.Qty,0) ELSE 0 END)";
|
||||||
|
else
|
||||||
|
m_groupBy = m_groupBy + "<>SUM(COALESCE(m.Qty,0))";
|
||||||
}
|
}
|
||||||
// Log.trace(7, "VMatch.tableInit", m_sql + "\n" + m_groupBy);
|
|
||||||
} // tableInit
|
} // tableInit
|
||||||
|
|
||||||
|
|
||||||
|
@ -396,7 +411,6 @@ public class Match
|
||||||
*/
|
*/
|
||||||
protected void tableLoad (IMiniTable table)
|
protected void tableLoad (IMiniTable table)
|
||||||
{
|
{
|
||||||
// log.finest(m_sql + " - " + m_groupBy);
|
|
||||||
String sql = MRole.getDefault().addAccessSQL(
|
String sql = MRole.getDefault().addAccessSQL(
|
||||||
m_sql.toString(), "hdr", MRole.SQL_FULLYQUALIFIED, MRole.SQL_RO)
|
m_sql.toString(), "hdr", MRole.SQL_FULLYQUALIFIED, MRole.SQL_RO)
|
||||||
+ m_groupBy;
|
+ m_groupBy;
|
||||||
|
@ -405,7 +419,7 @@ public class Match
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
stmt = DB.createStatement();
|
stmt = DB.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, m_trxName);
|
||||||
rs = stmt.executeQuery(sql);
|
rs = stmt.executeQuery(sql);
|
||||||
table.loadTable(rs);
|
table.loadTable(rs);
|
||||||
}
|
}
|
||||||
|
@ -518,7 +532,7 @@ public class Match
|
||||||
// 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 = getOrCreate(Line_ID, qty, sLine, trxName);
|
||||||
match.setC_OrderLine_ID(Line_ID);
|
match.setC_OrderLine_ID(Line_ID);
|
||||||
if (!match.save())
|
if (!match.save())
|
||||||
{
|
{
|
||||||
|
@ -555,4 +569,43 @@ public class Match
|
||||||
}
|
}
|
||||||
return success;
|
return success;
|
||||||
} // createMatchRecord
|
} // createMatchRecord
|
||||||
|
|
||||||
|
|
||||||
|
private MMatchPO getOrCreate(int C_OrderLine_ID, BigDecimal qty, MInOutLine sLine, String trxName) {
|
||||||
|
Query query = new Query(Env.getCtx(), MMatchPO.Table_Name, "C_OrderLine_ID=? AND Qty=? AND Posted IN (?,?) AND M_InOutLine_ID IS NULL", trxName);
|
||||||
|
MMatchPO matchPO = query.setParameters(C_OrderLine_ID, qty, Doc.STATUS_NotPosted, Doc.STATUS_Deferred).first();
|
||||||
|
if (matchPO != null) {
|
||||||
|
matchPO.setM_InOutLine_ID(sLine.getM_InOutLine_ID());
|
||||||
|
return matchPO;
|
||||||
|
} else {
|
||||||
|
return new MMatchPO (sLine, null, qty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param trxName
|
||||||
|
*/
|
||||||
|
public void setTrxName(String trxName) {
|
||||||
|
m_trxName = trxName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return trxName
|
||||||
|
*/
|
||||||
|
public String getTrxName() {
|
||||||
|
return m_trxName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param matchType MATCH_INVOICE, MATCH_SHIPMENT or MATCH_ORDER
|
||||||
|
* @return display text for match type
|
||||||
|
*/
|
||||||
|
public String getMatchTypeText(int matchType) {
|
||||||
|
if (matchType >= 0 && matchType < m_matchOptions.length)
|
||||||
|
return m_matchOptions[matchType];
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,8 @@ Require-Bundle: org.adempiere.base;bundle-version="9.0.0",
|
||||||
org.adempiere.payment.processor;bundle-version="9.0.0",
|
org.adempiere.payment.processor;bundle-version="9.0.0",
|
||||||
org.compiere.db.postgresql.provider;bundle-version="9.0.0",
|
org.compiere.db.postgresql.provider;bundle-version="9.0.0",
|
||||||
org.idempiere.webservices;bundle-version="9.0.0",
|
org.idempiere.webservices;bundle-version="9.0.0",
|
||||||
org.adempiere.ui.zk;bundle-version="9.0.0"
|
org.adempiere.ui.zk;bundle-version="9.0.0",
|
||||||
|
org.adempiere.ui;bundle-version="9.0.0"
|
||||||
Bundle-ActivationPolicy: lazy
|
Bundle-ActivationPolicy: lazy
|
||||||
Bundle-Activator: org.idempiere.test.TestActivator
|
Bundle-Activator: org.idempiere.test.TestActivator
|
||||||
Bundle-RequiredExecutionEnvironment: JavaSE-11
|
Bundle-RequiredExecutionEnvironment: JavaSE-11
|
||||||
|
|
|
@ -29,7 +29,11 @@ import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
|
||||||
|
import org.compiere.apps.form.Match;
|
||||||
|
import org.compiere.minigrid.ColumnInfo;
|
||||||
|
import org.compiere.minigrid.IDColumn;
|
||||||
import org.compiere.model.MBPartner;
|
import org.compiere.model.MBPartner;
|
||||||
import org.compiere.model.MDocType;
|
import org.compiere.model.MDocType;
|
||||||
import org.compiere.model.MInOut;
|
import org.compiere.model.MInOut;
|
||||||
|
@ -41,12 +45,18 @@ import org.compiere.model.MMatchPO;
|
||||||
import org.compiere.model.MOrder;
|
import org.compiere.model.MOrder;
|
||||||
import org.compiere.model.MOrderLine;
|
import org.compiere.model.MOrderLine;
|
||||||
import org.compiere.model.MProduct;
|
import org.compiere.model.MProduct;
|
||||||
|
import org.compiere.model.MStorageOnHand;
|
||||||
|
import org.compiere.model.MStorageReservation;
|
||||||
import org.compiere.model.MWarehouse;
|
import org.compiere.model.MWarehouse;
|
||||||
import org.compiere.process.DocAction;
|
import org.compiere.process.DocAction;
|
||||||
import org.compiere.process.ProcessInfo;
|
import org.compiere.process.ProcessInfo;
|
||||||
|
import org.compiere.process.ServerProcessCtl;
|
||||||
import org.compiere.util.Env;
|
import org.compiere.util.Env;
|
||||||
|
import org.compiere.util.KeyNamePair;
|
||||||
|
import org.compiere.util.Msg;
|
||||||
import org.compiere.wf.MWorkflow;
|
import org.compiere.wf.MWorkflow;
|
||||||
import org.idempiere.test.AbstractTestCase;
|
import org.idempiere.test.AbstractTestCase;
|
||||||
|
import org.idempiere.test.ui.MiniTableImpl;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -484,4 +494,395 @@ public class MatchPOTest extends AbstractTestCase {
|
||||||
|
|
||||||
rollback();
|
rollback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReverseFullyMatchPO() {
|
||||||
|
MBPartner bpartner = MBPartner.get(Env.getCtx(), 114); // Tree Farm Inc.
|
||||||
|
MProduct product = MProduct.get(Env.getCtx(), 124); // Elm Tree
|
||||||
|
|
||||||
|
int initialOnHand = MStorageOnHand.getQtyOnHand(product.get_ID(), getM_Warehouse_ID(), 0, getTrxName()).intValue();
|
||||||
|
int initialOnOrdered = MStorageReservation.getQty(product.get_ID(), getM_Warehouse_ID(), 0, false, getTrxName()).intValue();
|
||||||
|
|
||||||
|
MOrder order = new MOrder(Env.getCtx(), 0, getTrxName());
|
||||||
|
order.setBPartner(bpartner);
|
||||||
|
order.setIsSOTrx(false);
|
||||||
|
order.setC_DocTypeTarget_ID();
|
||||||
|
order.setDocStatus(DocAction.STATUS_Drafted);
|
||||||
|
order.setDocAction(DocAction.ACTION_Complete);
|
||||||
|
order.saveEx();
|
||||||
|
|
||||||
|
BigDecimal orderQty = new BigDecimal("1");
|
||||||
|
MOrderLine orderLine = new MOrderLine(order);
|
||||||
|
orderLine.setLine(10);
|
||||||
|
orderLine.setProduct(product);
|
||||||
|
orderLine.setQty(orderQty);
|
||||||
|
orderLine.saveEx();
|
||||||
|
|
||||||
|
ProcessInfo info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_Complete);
|
||||||
|
assertFalse(info.isError(), info.getSummary());
|
||||||
|
order.load(getTrxName());
|
||||||
|
assertEquals(DocAction.STATUS_Completed, order.getDocStatus());
|
||||||
|
orderLine.load(getTrxName());
|
||||||
|
assertEquals(1, orderLine.getQtyReserved().intValue(), "Unexpected order line qty ordered value");
|
||||||
|
int newOnOrdered = MStorageReservation.getQty(product.get_ID(), getM_Warehouse_ID(), 0, false, getTrxName()).intValue();
|
||||||
|
assertEquals(initialOnOrdered+1, newOnOrdered, "Unexpected qty on ordered value");
|
||||||
|
|
||||||
|
MInOut receipt = new MInOut(order, 122, order.getDateOrdered()); // MM Receipt
|
||||||
|
receipt.saveEx();
|
||||||
|
|
||||||
|
MWarehouse wh = MWarehouse.get(Env.getCtx(), receipt.getM_Warehouse_ID());
|
||||||
|
int M_Locator_ID = wh.getDefaultLocator().getM_Locator_ID();
|
||||||
|
|
||||||
|
MInOutLine receiptLine = new MInOutLine(receipt);
|
||||||
|
receiptLine.setOrderLine(orderLine, M_Locator_ID, orderQty);
|
||||||
|
receiptLine.setLine(10);
|
||||||
|
receiptLine.setQty(orderQty);
|
||||||
|
receiptLine.saveEx();
|
||||||
|
|
||||||
|
info = MWorkflow.runDocumentActionWorkflow(receipt, DocAction.ACTION_Complete);
|
||||||
|
assertFalse(info.isError(), info.getSummary());
|
||||||
|
receipt.load(getTrxName());
|
||||||
|
assertEquals(DocAction.STATUS_Completed, receipt.getDocStatus());
|
||||||
|
orderLine.load(getTrxName());
|
||||||
|
assertEquals(0, orderLine.getQtyReserved().intValue(), "Unexpected order line qty ordered value");
|
||||||
|
assertEquals(1, orderLine.getQtyDelivered().intValue(), "Unexpected order line qty delivered value");
|
||||||
|
newOnOrdered = MStorageReservation.getQty(product.get_ID(), getM_Warehouse_ID(), 0, false, getTrxName()).intValue();
|
||||||
|
assertEquals(initialOnOrdered, newOnOrdered, "Unexpected qty on ordered value");
|
||||||
|
int newOnHand = MStorageOnHand.getQtyOnHand(product.get_ID(), getM_Warehouse_ID(), 0, getTrxName()).intValue();
|
||||||
|
assertEquals(initialOnHand+1, newOnHand, "Unexpected qty on hand value");
|
||||||
|
|
||||||
|
MMatchPO[] matchPOs = MMatchPO.getOrderLine(Env.getCtx(), orderLine.get_ID(), getTrxName());
|
||||||
|
assertEquals(1, matchPOs.length, "Unexpected number of MatchPO for order line");
|
||||||
|
int matchedPOReverse = 200016;
|
||||||
|
info = new ProcessInfo("MatchPOReverse", matchedPOReverse, MMatchPO.Table_ID, matchPOs[0].get_ID());
|
||||||
|
ServerProcessCtl.process(info, getTrx(), false);
|
||||||
|
assertFalse(info.isError(), info.getSummary());
|
||||||
|
|
||||||
|
orderLine.load(getTrxName());
|
||||||
|
assertEquals(1, orderLine.getQtyReserved().intValue(), "Unexpected order line qty ordered value");
|
||||||
|
assertEquals(0, orderLine.getQtyDelivered().intValue(), "Unexpected order line qty delivered value");
|
||||||
|
receiptLine.load(getTrxName());
|
||||||
|
assertEquals(0, receiptLine.getC_OrderLine_ID(), "Unexpected order line ID value for receipt line");
|
||||||
|
matchPOs = MMatchPO.getOrderLine(Env.getCtx(), orderLine.get_ID(), getTrxName());
|
||||||
|
assertEquals(2, matchPOs.length, "Unexpected number of MatchPO for order line");
|
||||||
|
newOnOrdered = MStorageReservation.getQty(product.get_ID(), getM_Warehouse_ID(), 0, false, getTrxName()).intValue();
|
||||||
|
assertEquals(initialOnOrdered+1, newOnOrdered, "Unexpected qty on ordered value");
|
||||||
|
newOnHand = MStorageOnHand.getQtyOnHand(product.get_ID(), getM_Warehouse_ID(), 0, getTrxName()).intValue();
|
||||||
|
assertEquals(initialOnHand+1, newOnHand, "Unexpected qty on hand value");
|
||||||
|
|
||||||
|
MiniTableImpl fromTable = new MiniTableImpl();
|
||||||
|
MiniTableImpl toTable = new MiniTableImpl();
|
||||||
|
ColumnInfo[] layout = new ColumnInfo[] {
|
||||||
|
new ColumnInfo(" ", ".", IDColumn.class, false, false, ""),
|
||||||
|
new ColumnInfo(Msg.translate(Env.getCtx(), "DocumentNo"), ".", String.class), // 1
|
||||||
|
new ColumnInfo(Msg.translate(Env.getCtx(), "Date"), ".", Timestamp.class),
|
||||||
|
new ColumnInfo(Msg.translate(Env.getCtx(), "C_BPartner_ID"),".", KeyNamePair.class, "."), // 3
|
||||||
|
new ColumnInfo(Msg.translate(Env.getCtx(), "Line"), ".", KeyNamePair.class, "."),
|
||||||
|
new ColumnInfo(Msg.translate(Env.getCtx(), "M_Product_ID"), ".", KeyNamePair.class, "."), // 5
|
||||||
|
new ColumnInfo(Msg.translate(Env.getCtx(), "Qty"), ".", Double.class),
|
||||||
|
new ColumnInfo(Msg.translate(Env.getCtx(), "Matched"), ".", Double.class)
|
||||||
|
};
|
||||||
|
fromTable.prepareTable(layout, null, null, false, null);
|
||||||
|
toTable.prepareTable(layout, null, null, false, null);
|
||||||
|
Match match = new Match();
|
||||||
|
match.setTrxName(getTrxName());
|
||||||
|
match.cmd_search(fromTable, Match.MATCH_SHIPMENT, match.getMatchTypeText(Match.MATCH_ORDER), product.get_ID(), bpartner.get_ID(), null, null, false);
|
||||||
|
assertTrue(fromTable.getRowCount()>0, "Unexpected number of records for not matched Material Receipt: " + fromTable.getRowCount());
|
||||||
|
int selectedRow = -1;
|
||||||
|
for(int i = 0; i < fromTable.getRowCount(); i++) {
|
||||||
|
String docNo = (String)fromTable.getValueAt(i, 1);
|
||||||
|
if (receipt.getDocumentNo().equals(docNo)) {
|
||||||
|
int matched = ((Number)fromTable.getValueAt(i, 7)).intValue();
|
||||||
|
assertEquals(0, matched, "Unexpected matched qty for Material Receipt line");
|
||||||
|
int qty = ((Number)fromTable.getValueAt(i, 6)).intValue();
|
||||||
|
assertEquals(receiptLine.getMovementQty().intValue(), qty, "Unexpected qty for Material Receipt line");
|
||||||
|
selectedRow = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertTrue(selectedRow >= 0, "Can't find not matched Material Receipt line");
|
||||||
|
fromTable.setSelectedRow(selectedRow);
|
||||||
|
match.cmd_searchTo(fromTable, toTable, match.getMatchTypeText(Match.MATCH_ORDER), Match.MATCH_SHIPMENT, true, true, false, false);
|
||||||
|
assertTrue(toTable.getRowCount()>0, "Unexpected number of records for not matched Order Line: " + fromTable.getRowCount());
|
||||||
|
int selectedOrderRow = -1;
|
||||||
|
for(int i = 0; i < toTable.getRowCount(); i++) {
|
||||||
|
String docNo = (String)toTable.getValueAt(i, 1);
|
||||||
|
if (order.getDocumentNo().equals(docNo)) {
|
||||||
|
int matched = ((Number)toTable.getValueAt(i, 7)).intValue();
|
||||||
|
assertEquals(0, matched, "Unexpected matched qty for PO line");
|
||||||
|
int qty = ((Number)toTable.getValueAt(i, 6)).intValue();
|
||||||
|
assertEquals(orderLine.getQtyOrdered().intValue(), qty, "Unexpected qty for PO line");
|
||||||
|
selectedOrderRow = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertTrue(selectedOrderRow >= 0, "Can't find not matched PO line");
|
||||||
|
|
||||||
|
//create vendor invoice
|
||||||
|
MInvoice invoice = new MInvoice(order, MDocType.getOfDocBaseType(Env.getCtx(), MDocType.DOCBASETYPE_APInvoice)[0].getC_DocType_ID(), order.getDateAcct());
|
||||||
|
invoice.setDocStatus(DocAction.STATUS_Drafted);
|
||||||
|
invoice.setDocAction(DocAction.ACTION_Complete);
|
||||||
|
invoice.saveEx();
|
||||||
|
|
||||||
|
MInvoiceLine invoiceLine = new MInvoiceLine(invoice);
|
||||||
|
invoiceLine.setOrderLine(orderLine);
|
||||||
|
invoiceLine.setLine(10);
|
||||||
|
invoiceLine.setProduct(product);
|
||||||
|
invoiceLine.setQty(orderQty);
|
||||||
|
invoiceLine.saveEx();
|
||||||
|
|
||||||
|
info = MWorkflow.runDocumentActionWorkflow(invoice, DocAction.ACTION_Complete);
|
||||||
|
assertFalse(info.isError(), info.getSummary());
|
||||||
|
invoice.load(getTrxName());
|
||||||
|
assertEquals(DocAction.STATUS_Completed, invoice.getDocStatus());
|
||||||
|
orderLine.load(getTrxName());
|
||||||
|
assertEquals(invoiceLine.getQtyInvoiced().intValue(), orderLine.getQtyInvoiced().intValue(), "Unexpected order line qty invoiced");
|
||||||
|
matchPOs = MMatchPO.getOrderLine(Env.getCtx(), orderLine.get_ID(), getTrxName());
|
||||||
|
assertEquals(3, matchPOs.length, "Unexpected number of MatchPO for order line");
|
||||||
|
|
||||||
|
fromTable.prepareTable(layout, null, null, false, null);
|
||||||
|
toTable.prepareTable(layout, null, null, false, null);
|
||||||
|
match.cmd_search(fromTable, Match.MATCH_SHIPMENT, match.getMatchTypeText(Match.MATCH_ORDER), product.get_ID(), bpartner.get_ID(), null, null, false);
|
||||||
|
assertTrue(fromTable.getRowCount()>0, "Unexpected number of records for not matched Material Receipt: " + fromTable.getRowCount());
|
||||||
|
selectedRow = -1;
|
||||||
|
for(int i = 0; i < fromTable.getRowCount(); i++) {
|
||||||
|
String docNo = (String)fromTable.getValueAt(i, 1);
|
||||||
|
if (receipt.getDocumentNo().equals(docNo)) {
|
||||||
|
int matched = ((Number)fromTable.getValueAt(i, 7)).intValue();
|
||||||
|
assertEquals(0, matched, "Unexpected matched qty for Material Receipt line");
|
||||||
|
int qty = ((Number)fromTable.getValueAt(i, 6)).intValue();
|
||||||
|
assertEquals(receiptLine.getMovementQty().intValue(), qty, "Unexpected qty for Material Receipt line");
|
||||||
|
selectedRow = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertTrue(selectedRow >= 0, "Can't find not matched Material Receipt line");
|
||||||
|
fromTable.setSelectedRow(selectedRow);
|
||||||
|
match.cmd_searchTo(fromTable, toTable, match.getMatchTypeText(Match.MATCH_ORDER), Match.MATCH_SHIPMENT, true, true, false, false);
|
||||||
|
assertTrue(toTable.getRowCount()>0, "Unexpected number of records for not matched Order Line: " + fromTable.getRowCount());
|
||||||
|
selectedOrderRow = -1;
|
||||||
|
for(int i = 0; i < toTable.getRowCount(); i++) {
|
||||||
|
String docNo = (String)toTable.getValueAt(i, 1);
|
||||||
|
if (order.getDocumentNo().equals(docNo)) {
|
||||||
|
int matched = ((Number)toTable.getValueAt(i, 7)).intValue();
|
||||||
|
assertEquals(0, matched, "Unexpected matched qty for PO line");
|
||||||
|
int qty = ((Number)toTable.getValueAt(i, 6)).intValue();
|
||||||
|
assertEquals(orderLine.getQtyOrdered().intValue(), qty, "Unexpected qty for PO line");
|
||||||
|
selectedOrderRow = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertTrue(selectedOrderRow >= 0, "Can't find not matched PO line");
|
||||||
|
|
||||||
|
IDColumn idColumn = (IDColumn)toTable.getValueAt(selectedOrderRow, 0);
|
||||||
|
idColumn.setSelected(true);
|
||||||
|
match.cmd_process(fromTable, toTable, Match.MODE_NOTMATCHED, Match.MATCH_SHIPMENT, match.getMatchTypeText(Match.MATCH_ORDER), new BigDecimal(1));
|
||||||
|
|
||||||
|
orderLine.load(getTrxName());
|
||||||
|
assertEquals(0, orderLine.getQtyReserved().intValue(), "Unexpected order line qty ordered value");
|
||||||
|
assertEquals(1, orderLine.getQtyDelivered().intValue(), "Unexpected order line qty delivered value");
|
||||||
|
receiptLine.load(getTrxName());
|
||||||
|
assertEquals(orderLine.getC_OrderLine_ID(), receiptLine.getC_OrderLine_ID(), "Unexpected order line ID value for receipt line");
|
||||||
|
matchPOs = MMatchPO.getOrderLine(Env.getCtx(), orderLine.get_ID(), getTrxName());
|
||||||
|
assertEquals(3, matchPOs.length, "Unexpected number of MatchPO for order line");
|
||||||
|
newOnOrdered = MStorageReservation.getQty(product.get_ID(), getM_Warehouse_ID(), 0, false, getTrxName()).intValue();
|
||||||
|
assertEquals(initialOnOrdered, newOnOrdered, "Unexpected qty on ordered value");
|
||||||
|
newOnHand = MStorageOnHand.getQtyOnHand(product.get_ID(), getM_Warehouse_ID(), 0, getTrxName()).intValue();
|
||||||
|
assertEquals(initialOnHand+1, newOnHand, "Unexpected qty on hand value");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testReversePartialMatchPO() {
|
||||||
|
MBPartner bpartner = MBPartner.get(Env.getCtx(), 114); // Tree Farm Inc.
|
||||||
|
MProduct product = MProduct.get(Env.getCtx(), 124); // Elm Tree
|
||||||
|
|
||||||
|
int initialOnHand = MStorageOnHand.getQtyOnHand(product.get_ID(), getM_Warehouse_ID(), 0, getTrxName()).intValue();
|
||||||
|
int initialOnOrdered = MStorageReservation.getQty(product.get_ID(), getM_Warehouse_ID(), 0, false, getTrxName()).intValue();
|
||||||
|
|
||||||
|
MOrder order = new MOrder(Env.getCtx(), 0, getTrxName());
|
||||||
|
order.setBPartner(bpartner);
|
||||||
|
order.setIsSOTrx(false);
|
||||||
|
order.setC_DocTypeTarget_ID();
|
||||||
|
order.setDocStatus(DocAction.STATUS_Drafted);
|
||||||
|
order.setDocAction(DocAction.ACTION_Complete);
|
||||||
|
order.saveEx();
|
||||||
|
|
||||||
|
BigDecimal orderQty = new BigDecimal("2");
|
||||||
|
MOrderLine orderLine = new MOrderLine(order);
|
||||||
|
orderLine.setLine(10);
|
||||||
|
orderLine.setProduct(product);
|
||||||
|
orderLine.setQty(orderQty);
|
||||||
|
orderLine.saveEx();
|
||||||
|
|
||||||
|
ProcessInfo info = MWorkflow.runDocumentActionWorkflow(order, DocAction.ACTION_Complete);
|
||||||
|
assertFalse(info.isError(), info.getSummary());
|
||||||
|
order.load(getTrxName());
|
||||||
|
assertEquals(DocAction.STATUS_Completed, order.getDocStatus());
|
||||||
|
orderLine.load(getTrxName());
|
||||||
|
assertEquals(2, orderLine.getQtyReserved().intValue(), "Unexpected order line qty ordered value");
|
||||||
|
int newOnOrdered = MStorageReservation.getQty(product.get_ID(), getM_Warehouse_ID(), 0, false, getTrxName()).intValue();
|
||||||
|
assertEquals(initialOnOrdered+2, newOnOrdered, "Unexpected qty on ordered value");
|
||||||
|
|
||||||
|
MInOut receipt = new MInOut(order, 122, order.getDateOrdered()); // MM Receipt
|
||||||
|
receipt.saveEx();
|
||||||
|
|
||||||
|
MWarehouse wh = MWarehouse.get(Env.getCtx(), receipt.getM_Warehouse_ID());
|
||||||
|
int M_Locator_ID = wh.getDefaultLocator().getM_Locator_ID();
|
||||||
|
|
||||||
|
BigDecimal receiptQty = new BigDecimal("1");
|
||||||
|
MInOutLine receiptLine = new MInOutLine(receipt);
|
||||||
|
receiptLine.setOrderLine(orderLine, M_Locator_ID, receiptQty);
|
||||||
|
receiptLine.setLine(10);
|
||||||
|
receiptLine.setQty(receiptQty);
|
||||||
|
receiptLine.saveEx();
|
||||||
|
|
||||||
|
info = MWorkflow.runDocumentActionWorkflow(receipt, DocAction.ACTION_Complete);
|
||||||
|
assertFalse(info.isError(), info.getSummary());
|
||||||
|
receipt.load(getTrxName());
|
||||||
|
assertEquals(DocAction.STATUS_Completed, receipt.getDocStatus());
|
||||||
|
orderLine.load(getTrxName());
|
||||||
|
assertEquals(1, orderLine.getQtyReserved().intValue(), "Unexpected order line qty ordered value");
|
||||||
|
assertEquals(1, orderLine.getQtyDelivered().intValue(), "Unexpected order line qty delivered value");
|
||||||
|
newOnOrdered = MStorageReservation.getQty(product.get_ID(), getM_Warehouse_ID(), 0, false, getTrxName()).intValue();
|
||||||
|
assertEquals(initialOnOrdered+1, newOnOrdered, "Unexpected qty on ordered value");
|
||||||
|
int newOnHand = MStorageOnHand.getQtyOnHand(product.get_ID(), getM_Warehouse_ID(), 0, getTrxName()).intValue();
|
||||||
|
assertEquals(initialOnHand+1, newOnHand, "Unexpected qty on hand value");
|
||||||
|
|
||||||
|
MMatchPO[] matchPOs = MMatchPO.getOrderLine(Env.getCtx(), orderLine.get_ID(), getTrxName());
|
||||||
|
assertEquals(1, matchPOs.length, "Unexpected number of MatchPO for order line");
|
||||||
|
int matchedPOReverse = 200016;
|
||||||
|
info = new ProcessInfo("MatchPOReverse", matchedPOReverse, MMatchPO.Table_ID, matchPOs[0].get_ID());
|
||||||
|
ServerProcessCtl.process(info, getTrx(), false);
|
||||||
|
assertFalse(info.isError(), info.getSummary());
|
||||||
|
|
||||||
|
orderLine.load(getTrxName());
|
||||||
|
assertEquals(2, orderLine.getQtyReserved().intValue(), "Unexpected order line qty ordered value");
|
||||||
|
assertEquals(0, orderLine.getQtyDelivered().intValue(), "Unexpected order line qty delivered value");
|
||||||
|
receiptLine.load(getTrxName());
|
||||||
|
assertEquals(0, receiptLine.getC_OrderLine_ID(), "Unexpected order line ID value for receipt line");
|
||||||
|
matchPOs = MMatchPO.getOrderLine(Env.getCtx(), orderLine.get_ID(), getTrxName());
|
||||||
|
assertEquals(2, matchPOs.length, "Unexpected number of MatchPO for order line");
|
||||||
|
newOnOrdered = MStorageReservation.getQty(product.get_ID(), getM_Warehouse_ID(), 0, false, getTrxName()).intValue();
|
||||||
|
assertEquals(initialOnOrdered+2, newOnOrdered, "Unexpected qty on ordered value");
|
||||||
|
newOnHand = MStorageOnHand.getQtyOnHand(product.get_ID(), getM_Warehouse_ID(), 0, getTrxName()).intValue();
|
||||||
|
assertEquals(initialOnHand+1, newOnHand, "Unexpected qty on hand value");
|
||||||
|
|
||||||
|
MiniTableImpl fromTable = new MiniTableImpl();
|
||||||
|
MiniTableImpl toTable = new MiniTableImpl();
|
||||||
|
ColumnInfo[] layout = new ColumnInfo[] {
|
||||||
|
new ColumnInfo(" ", ".", IDColumn.class, false, false, ""),
|
||||||
|
new ColumnInfo(Msg.translate(Env.getCtx(), "DocumentNo"), ".", String.class), // 1
|
||||||
|
new ColumnInfo(Msg.translate(Env.getCtx(), "Date"), ".", Timestamp.class),
|
||||||
|
new ColumnInfo(Msg.translate(Env.getCtx(), "C_BPartner_ID"),".", KeyNamePair.class, "."), // 3
|
||||||
|
new ColumnInfo(Msg.translate(Env.getCtx(), "Line"), ".", KeyNamePair.class, "."),
|
||||||
|
new ColumnInfo(Msg.translate(Env.getCtx(), "M_Product_ID"), ".", KeyNamePair.class, "."), // 5
|
||||||
|
new ColumnInfo(Msg.translate(Env.getCtx(), "Qty"), ".", Double.class),
|
||||||
|
new ColumnInfo(Msg.translate(Env.getCtx(), "Matched"), ".", Double.class)
|
||||||
|
};
|
||||||
|
fromTable.prepareTable(layout, null, null, false, null);
|
||||||
|
toTable.prepareTable(layout, null, null, false, null);
|
||||||
|
Match match = new Match();
|
||||||
|
match.setTrxName(getTrxName());
|
||||||
|
match.cmd_search(fromTable, Match.MATCH_SHIPMENT, match.getMatchTypeText(Match.MATCH_ORDER), product.get_ID(), bpartner.get_ID(), null, null, false);
|
||||||
|
assertTrue(fromTable.getRowCount()>0, "Unexpected number of records for not matched Material Receipt: " + fromTable.getRowCount());
|
||||||
|
int selectedRow = -1;
|
||||||
|
for(int i = 0; i < fromTable.getRowCount(); i++) {
|
||||||
|
String docNo = (String)fromTable.getValueAt(i, 1);
|
||||||
|
if (receipt.getDocumentNo().equals(docNo)) {
|
||||||
|
int matched = ((Number)fromTable.getValueAt(i, 7)).intValue();
|
||||||
|
assertEquals(0, matched, "Unexpected matched qty for Material Receipt line");
|
||||||
|
int qty = ((Number)fromTable.getValueAt(i, 6)).intValue();
|
||||||
|
assertEquals(receiptLine.getMovementQty().intValue(), qty, "Unexpected qty for Material Receipt line");
|
||||||
|
selectedRow = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertTrue(selectedRow >= 0, "Can't find not matched Material Receipt line");
|
||||||
|
fromTable.setSelectedRow(selectedRow);
|
||||||
|
match.cmd_searchTo(fromTable, toTable, match.getMatchTypeText(Match.MATCH_ORDER), Match.MATCH_SHIPMENT, true, true, false, false);
|
||||||
|
assertTrue(toTable.getRowCount()>0, "Unexpected number of records for not matched Order Line: " + fromTable.getRowCount());
|
||||||
|
int selectedOrderRow = -1;
|
||||||
|
for(int i = 0; i < toTable.getRowCount(); i++) {
|
||||||
|
String docNo = (String)toTable.getValueAt(i, 1);
|
||||||
|
if (order.getDocumentNo().equals(docNo)) {
|
||||||
|
int matched = ((Number)toTable.getValueAt(i, 7)).intValue();
|
||||||
|
assertEquals(0, matched, "Unexpected matched qty for PO line");
|
||||||
|
int qty = ((Number)toTable.getValueAt(i, 6)).intValue();
|
||||||
|
assertEquals(orderLine.getQtyOrdered().intValue(), qty, "Unexpected qty for PO line");
|
||||||
|
selectedOrderRow = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertTrue(selectedOrderRow >= 0, "Can't find not matched PO line");
|
||||||
|
|
||||||
|
//create vendor invoice
|
||||||
|
MInvoice invoice = new MInvoice(order, MDocType.getOfDocBaseType(Env.getCtx(), MDocType.DOCBASETYPE_APInvoice)[0].getC_DocType_ID(), order.getDateAcct());
|
||||||
|
invoice.setDocStatus(DocAction.STATUS_Drafted);
|
||||||
|
invoice.setDocAction(DocAction.ACTION_Complete);
|
||||||
|
invoice.saveEx();
|
||||||
|
|
||||||
|
MInvoiceLine invoiceLine = new MInvoiceLine(invoice);
|
||||||
|
invoiceLine.setOrderLine(orderLine);
|
||||||
|
invoiceLine.setLine(10);
|
||||||
|
invoiceLine.setProduct(product);
|
||||||
|
invoiceLine.setQty(orderQty);
|
||||||
|
invoiceLine.saveEx();
|
||||||
|
|
||||||
|
info = MWorkflow.runDocumentActionWorkflow(invoice, DocAction.ACTION_Complete);
|
||||||
|
assertFalse(info.isError(), info.getSummary());
|
||||||
|
invoice.load(getTrxName());
|
||||||
|
assertEquals(DocAction.STATUS_Completed, invoice.getDocStatus());
|
||||||
|
orderLine.load(getTrxName());
|
||||||
|
assertEquals(invoiceLine.getQtyInvoiced().intValue(), orderLine.getQtyInvoiced().intValue(), "Unexpected order line qty invoiced");
|
||||||
|
|
||||||
|
fromTable.prepareTable(layout, null, null, false, null);
|
||||||
|
toTable.prepareTable(layout, null, null, false, null);
|
||||||
|
match.cmd_search(fromTable, Match.MATCH_SHIPMENT, match.getMatchTypeText(Match.MATCH_ORDER), product.get_ID(), bpartner.get_ID(), null, null, false);
|
||||||
|
assertTrue(fromTable.getRowCount()>0, "Unexpected number of records for not matched Material Receipt: " + fromTable.getRowCount());
|
||||||
|
selectedRow = -1;
|
||||||
|
for(int i = 0; i < fromTable.getRowCount(); i++) {
|
||||||
|
String docNo = (String)fromTable.getValueAt(i, 1);
|
||||||
|
if (receipt.getDocumentNo().equals(docNo)) {
|
||||||
|
int matched = ((Number)fromTable.getValueAt(i, 7)).intValue();
|
||||||
|
assertEquals(0, matched, "Unexpected matched qty for Material Receipt line");
|
||||||
|
int qty = ((Number)fromTable.getValueAt(i, 6)).intValue();
|
||||||
|
assertEquals(receiptLine.getMovementQty().intValue(), qty, "Unexpected qty for Material Receipt line");
|
||||||
|
selectedRow = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertTrue(selectedRow >= 0, "Can't find not matched Material Receipt line");
|
||||||
|
fromTable.setSelectedRow(selectedRow);
|
||||||
|
match.cmd_searchTo(fromTable, toTable, match.getMatchTypeText(Match.MATCH_ORDER), Match.MATCH_SHIPMENT, true, true, false, false);
|
||||||
|
assertTrue(toTable.getRowCount()>0, "Unexpected number of records for not matched Order Line: " + fromTable.getRowCount());
|
||||||
|
selectedOrderRow = -1;
|
||||||
|
for(int i = 0; i < toTable.getRowCount(); i++) {
|
||||||
|
String docNo = (String)toTable.getValueAt(i, 1);
|
||||||
|
if (order.getDocumentNo().equals(docNo)) {
|
||||||
|
int matched = ((Number)toTable.getValueAt(i, 7)).intValue();
|
||||||
|
assertEquals(0, matched, "Unexpected matched qty for PO line");
|
||||||
|
int qty = ((Number)toTable.getValueAt(i, 6)).intValue();
|
||||||
|
assertEquals(orderLine.getQtyOrdered().intValue(), qty, "Unexpected qty for PO line");
|
||||||
|
selectedOrderRow = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assertTrue(selectedOrderRow >= 0, "Can't find not matched PO line");
|
||||||
|
|
||||||
|
IDColumn idColumn = (IDColumn)toTable.getValueAt(selectedOrderRow, 0);
|
||||||
|
idColumn.setSelected(true);
|
||||||
|
match.cmd_process(fromTable, toTable, Match.MODE_NOTMATCHED, Match.MATCH_SHIPMENT, match.getMatchTypeText(Match.MATCH_ORDER), new BigDecimal(1));
|
||||||
|
|
||||||
|
orderLine.load(getTrxName());
|
||||||
|
assertEquals(1, orderLine.getQtyReserved().intValue(), "Unexpected order line qty ordered value");
|
||||||
|
assertEquals(1, orderLine.getQtyDelivered().intValue(), "Unexpected order line qty delivered value");
|
||||||
|
receiptLine.load(getTrxName());
|
||||||
|
assertEquals(orderLine.getC_OrderLine_ID(), receiptLine.getC_OrderLine_ID(), "Unexpected order line ID value for receipt line");
|
||||||
|
matchPOs = MMatchPO.getOrderLine(Env.getCtx(), orderLine.get_ID(), getTrxName());
|
||||||
|
assertEquals(4, matchPOs.length, "Unexpected number of MatchPO for order line");
|
||||||
|
newOnOrdered = MStorageReservation.getQty(product.get_ID(), getM_Warehouse_ID(), 0, false, getTrxName()).intValue();
|
||||||
|
assertEquals(initialOnOrdered+1, newOnOrdered, "Unexpected qty on ordered value");
|
||||||
|
newOnHand = MStorageOnHand.getQtyOnHand(product.get_ID(), getM_Warehouse_ID(), 0, getTrxName()).intValue();
|
||||||
|
assertEquals(initialOnHand+1, newOnHand, "Unexpected qty on hand value");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,343 @@
|
||||||
|
/***********************************************************************
|
||||||
|
* This file is part of iDempiere ERP Open Source *
|
||||||
|
* http://www.idempiere.org *
|
||||||
|
* *
|
||||||
|
* Copyright (C) Contributors *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or *
|
||||||
|
* modify it under the terms of the GNU General Public License *
|
||||||
|
* as published by the Free Software Foundation; either version 2 *
|
||||||
|
* of the License, or (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
|
||||||
|
* MA 02110-1301, USA. *
|
||||||
|
* *
|
||||||
|
* Contributors: *
|
||||||
|
* - hengsin *
|
||||||
|
**********************************************************************/
|
||||||
|
package org.idempiere.test.ui;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.compiere.minigrid.ColumnInfo;
|
||||||
|
import org.compiere.minigrid.IDColumn;
|
||||||
|
import org.compiere.minigrid.IMiniTable;
|
||||||
|
import org.compiere.model.PO;
|
||||||
|
import org.compiere.util.KeyNamePair;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author hengsin
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class MiniTableImpl implements IMiniTable {
|
||||||
|
|
||||||
|
/** Array of table details. */
|
||||||
|
private List<TableColumn> m_tableColumns = new ArrayList<TableColumn>();
|
||||||
|
|
||||||
|
private List<Map<String, Object>> model = new ArrayList<Map<String,Object>>();
|
||||||
|
|
||||||
|
private ColumnInfo[] m_layout;
|
||||||
|
|
||||||
|
private int m_keyColumnIndex;
|
||||||
|
|
||||||
|
private int m_selectedRow;
|
||||||
|
|
||||||
|
public MiniTableImpl() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCellEditable(int row, int column) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object getValueAt(int row, int column) {
|
||||||
|
if (column < m_tableColumns.size()) {
|
||||||
|
String columnName = m_tableColumns.get(column).getHeaderValue();
|
||||||
|
if (row < model.size()) {
|
||||||
|
return model.get(row).get(columnName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setValueAt(Object value, int row, int column) {
|
||||||
|
if (column < m_tableColumns.size()) {
|
||||||
|
String columnName = m_tableColumns.get(column).getHeaderValue();
|
||||||
|
if (row < model.size()) {
|
||||||
|
model.get(row).put(columnName, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int convertColumnIndexToModel(int viewColumnIndex) {
|
||||||
|
return viewColumnIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setColumnReadOnly(int index, boolean readOnly) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String prepareTable(ColumnInfo[] layout, String from, String where, boolean multiSelection,
|
||||||
|
String tableName) {
|
||||||
|
m_layout = layout;
|
||||||
|
m_tableColumns.clear();
|
||||||
|
model.clear();
|
||||||
|
for (int columnIndex = 0; columnIndex < layout.length; columnIndex++) {
|
||||||
|
addColumn(layout[columnIndex].getColHeader(), layout[columnIndex].getColDescription(), layout[columnIndex].getAD_Reference_ID(), layout[columnIndex].getColClass());
|
||||||
|
if (layout[columnIndex].getColClass() == IDColumn.class)
|
||||||
|
{
|
||||||
|
m_keyColumnIndex = columnIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addColumn(String header) {
|
||||||
|
addColumn(header, null, 0, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setColumnClass(int index, Class<?> classType, boolean readOnly, String header) {
|
||||||
|
if (index < m_tableColumns.size()) {
|
||||||
|
m_tableColumns.get(index).setColumnClass(classType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setColumnClass(int index, Class<?> classType, boolean readOnly) {
|
||||||
|
if (index < m_tableColumns.size()) {
|
||||||
|
m_tableColumns.get(index).setColumnClass(classType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadTable(ResultSet rs) {
|
||||||
|
model.clear();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (rs.next())
|
||||||
|
{
|
||||||
|
Map<String, Object> row = new HashMap<String, Object>();
|
||||||
|
int rsColOffset = 1;
|
||||||
|
for (int col = 0; col < m_layout.length; col++)
|
||||||
|
{
|
||||||
|
//reset the data value
|
||||||
|
Object data = null;
|
||||||
|
Class<?> columnClass = m_layout[col].getColClass();
|
||||||
|
int rsColIndex = col + rsColOffset;
|
||||||
|
|
||||||
|
if (columnClass == IDColumn.class)
|
||||||
|
{
|
||||||
|
data = new IDColumn(rs.getInt(rsColIndex));
|
||||||
|
}
|
||||||
|
else if (columnClass == Boolean.class)
|
||||||
|
{
|
||||||
|
data = Boolean.valueOf(rs.getString(rsColIndex).equals("Y"));
|
||||||
|
}
|
||||||
|
else if (columnClass == Timestamp.class)
|
||||||
|
{
|
||||||
|
data = rs.getTimestamp(rsColIndex);
|
||||||
|
}
|
||||||
|
else if (columnClass == BigDecimal.class)
|
||||||
|
{
|
||||||
|
data = rs.getBigDecimal(rsColIndex);
|
||||||
|
}
|
||||||
|
else if (columnClass == Double.class)
|
||||||
|
{
|
||||||
|
data = Double.valueOf(rs.getDouble(rsColIndex));
|
||||||
|
}
|
||||||
|
else if (columnClass == Integer.class)
|
||||||
|
{
|
||||||
|
data = Integer.valueOf(rs.getInt(rsColIndex));
|
||||||
|
}
|
||||||
|
else if (columnClass == KeyNamePair.class)
|
||||||
|
{
|
||||||
|
String display = rs.getString(rsColIndex);
|
||||||
|
int key = rs.getInt(rsColIndex + 1);
|
||||||
|
data = new KeyNamePair(key, display);
|
||||||
|
rsColOffset++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
String s = rs.getString(rsColIndex);
|
||||||
|
if (s != null)
|
||||||
|
{
|
||||||
|
data = s.trim(); // problems with NCHAR
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data=null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// store in underlying model
|
||||||
|
row.put(m_tableColumns.get(col).headerValue, data);
|
||||||
|
}
|
||||||
|
model.add(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (SQLException exception)
|
||||||
|
{
|
||||||
|
throw new RuntimeException(exception);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadTable(PO[] pos) {
|
||||||
|
model.clear();
|
||||||
|
for (int poIndex = 0; poIndex < pos.length; poIndex++)
|
||||||
|
{
|
||||||
|
PO myPO = pos[poIndex];
|
||||||
|
Map<String, Object> row = new HashMap<String, Object>();
|
||||||
|
|
||||||
|
for (int col = 0; col < m_layout.length; col++)
|
||||||
|
{
|
||||||
|
String columnName = m_layout[col].getColSQL();
|
||||||
|
Object data = myPO.get_Value(columnName);
|
||||||
|
if (data != null)
|
||||||
|
{
|
||||||
|
Class<?> columnClass = m_layout[col].getColClass();
|
||||||
|
|
||||||
|
if (columnClass == IDColumn.class)
|
||||||
|
{
|
||||||
|
data = new IDColumn(((Integer)data).intValue());
|
||||||
|
}
|
||||||
|
else if (columnClass == Double.class)
|
||||||
|
{
|
||||||
|
data = Double.valueOf(((BigDecimal)data).doubleValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// store
|
||||||
|
row.put(m_tableColumns.get(col).headerValue, data);
|
||||||
|
}
|
||||||
|
model.add(row);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer getSelectedRowKey() {
|
||||||
|
int row = getSelectedRow();
|
||||||
|
|
||||||
|
// make common function
|
||||||
|
return getRowKeyAt (row);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* get key of record at index
|
||||||
|
* @param index
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public Integer getRowKeyAt (int index){
|
||||||
|
if (index < 0 || m_keyColumnIndex < 0 || index >= model.size())
|
||||||
|
return null;
|
||||||
|
|
||||||
|
|
||||||
|
Object data = model.get(index).get(m_tableColumns.get(m_keyColumnIndex).headerValue);
|
||||||
|
|
||||||
|
if (data instanceof IDColumn)
|
||||||
|
{
|
||||||
|
data = ((IDColumn)data).getRecord_ID();
|
||||||
|
}
|
||||||
|
if (data instanceof Integer)
|
||||||
|
{
|
||||||
|
return (Integer)data;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSelectedRow() {
|
||||||
|
return m_selectedRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSelectedRow(int selected) {
|
||||||
|
if (selected < model.size())
|
||||||
|
m_selectedRow = selected;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setRowCount(int rowCount) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ColumnInfo[] getLayoutInfo() {
|
||||||
|
return m_layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getColumnCount() {
|
||||||
|
return m_tableColumns.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRowCount() {
|
||||||
|
return model.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setMultiSelection(boolean multiSelection) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMultiSelection() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getColorCode(int row) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setColorCompare(Object dataCompare) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void repaint() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void autoSize() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setShowTotals(boolean show) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add Table Column and specify the column header.
|
||||||
|
*
|
||||||
|
* @param header name of column header
|
||||||
|
* @param description
|
||||||
|
* @param colClass
|
||||||
|
*/
|
||||||
|
public void addColumn (String header, String description, int AD_Reference_ID, Class<?> colClass)
|
||||||
|
{
|
||||||
|
TableColumn column = new TableColumn();
|
||||||
|
column.setHeaderValue(header);
|
||||||
|
column.setTooltipText(description);
|
||||||
|
column.setAD_Reference_ID(AD_Reference_ID);
|
||||||
|
column.setColumnClass(colClass);
|
||||||
|
m_tableColumns.add(column);
|
||||||
|
} // addColumn
|
||||||
|
}
|
|
@ -0,0 +1,122 @@
|
||||||
|
/***********************************************************************
|
||||||
|
* This file is part of iDempiere ERP Open Source *
|
||||||
|
* http://www.idempiere.org *
|
||||||
|
* *
|
||||||
|
* Copyright (C) Contributors *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or *
|
||||||
|
* modify it under the terms of the GNU General Public License *
|
||||||
|
* as published by the Free Software Foundation; either version 2 *
|
||||||
|
* of the License, or (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the Free Software *
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, *
|
||||||
|
* MA 02110-1301, USA. *
|
||||||
|
* *
|
||||||
|
* Contributors: *
|
||||||
|
* - hengsin *
|
||||||
|
**********************************************************************/
|
||||||
|
|
||||||
|
package org.idempiere.test.ui;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author hengsin
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class TableColumn
|
||||||
|
{
|
||||||
|
/** The header value of the column. */
|
||||||
|
protected String headerValue;
|
||||||
|
|
||||||
|
protected Class<?> columnClass;
|
||||||
|
|
||||||
|
protected String tooltipText;
|
||||||
|
|
||||||
|
private int AD_Reference_ID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cover method, using a default width of 75
|
||||||
|
* @see #WTableColumn(int)
|
||||||
|
*/
|
||||||
|
public TableColumn() {
|
||||||
|
headerValue = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the <code>Object</code> whose string representation will be
|
||||||
|
* used as the value for the <code>headerRenderer</code>. When the
|
||||||
|
* <code>WTableColumn</code> is created, the default <code>headerValue</code>
|
||||||
|
* is <code>null</code>.
|
||||||
|
*
|
||||||
|
* @param headerValue the new headerValue
|
||||||
|
* @see #getHeaderValue
|
||||||
|
*/
|
||||||
|
public void setHeaderValue(String headerValue)
|
||||||
|
{
|
||||||
|
this.headerValue = headerValue;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the <code>Object</code> used as the value for the header
|
||||||
|
* renderer.
|
||||||
|
*
|
||||||
|
* @return the <code>headerValue</code> property
|
||||||
|
* @see #setHeaderValue
|
||||||
|
*/
|
||||||
|
public String getHeaderValue()
|
||||||
|
{
|
||||||
|
return headerValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @return Class
|
||||||
|
*/
|
||||||
|
public Class<?> getColumnClass()
|
||||||
|
{
|
||||||
|
return columnClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param columnClass
|
||||||
|
*/
|
||||||
|
public void setColumnClass(Class<?> columnClass)
|
||||||
|
{
|
||||||
|
this.columnClass = columnClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return tooltip text
|
||||||
|
*/
|
||||||
|
public String getTooltipText() {
|
||||||
|
return tooltipText;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param tooltipText
|
||||||
|
*/
|
||||||
|
public void setTooltipText(String tooltipText) {
|
||||||
|
this.tooltipText = tooltipText;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getAD_Reference_ID() {
|
||||||
|
return AD_Reference_ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAD_Reference_ID(int AD_Reference_ID) {
|
||||||
|
this.AD_Reference_ID=AD_Reference_ID;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue