GL Reconciliation contribution

https://sourceforge.net/tracker/?func=detail&aid=3058505&group_id=176962&atid=883808
Integration done by Carlos Ruiz (globalqss) to work from Paul Bowden / Adaxa (phib)
This commit is contained in:
phib 2012-02-29 11:09:19 -05:00
parent 108b3527a5
commit d44998bf12
8 changed files with 5883 additions and 0 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,187 @@
/******************************************************************************
* Product: Adempiere ERP & CRM Smart Business Solution *
* Copyright (C) 1999-2007 ComPiere, Inc. All Rights Reserved. *
* 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. *
* For the text or an alternative of this public license, you may reach us *
* ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA *
* or via info@compiere.org or http://www.compiere.org/license.html *
*****************************************************************************/
package org.compiere.model;
import java.math.BigDecimal;
import java.sql.Timestamp;
import org.compiere.util.KeyNamePair;
/** Generated Interface for Fact_Reconciliation
* @author Adempiere (generated)
* @version 360LTS.013
*/
public interface I_Fact_Reconciliation
{
/** TableName=Fact_Reconciliation */
public static final String Table_Name = "Fact_Reconciliation";
/** AD_Table_ID=53286 */
public static final int Table_ID = MTable.getTable_ID(Table_Name);
KeyNamePair Model = new KeyNamePair(Table_ID, Table_Name);
/** AccessLevel = 3 - Client - Org
*/
BigDecimal accessLevel = BigDecimal.valueOf(3);
/** Load Meta Data */
/** Column name Account_ID */
public static final String COLUMNNAME_Account_ID = "Account_ID";
/** Set Account.
* Account used
*/
public void setAccount_ID (int Account_ID);
/** Get Account.
* Account used
*/
public int getAccount_ID();
public I_C_ElementValue getAccount() throws RuntimeException;
/** Column name AD_Client_ID */
public static final String COLUMNNAME_AD_Client_ID = "AD_Client_ID";
/** Get Client.
* Client/Tenant for this installation.
*/
public int getAD_Client_ID();
/** Column name AD_Org_ID */
public static final String COLUMNNAME_AD_Org_ID = "AD_Org_ID";
/** Set Organization.
* Organizational entity within client
*/
public void setAD_Org_ID (int AD_Org_ID);
/** Get Organization.
* Organizational entity within client
*/
public int getAD_Org_ID();
/** Column name AmtAcct */
public static final String COLUMNNAME_AmtAcct = "AmtAcct";
/** Set Accounted Amount.
* Amount Balance in Currency of Accounting Schema
*/
public void setAmtAcct (BigDecimal AmtAcct);
/** Get Accounted Amount.
* Amount Balance in Currency of Accounting Schema
*/
public BigDecimal getAmtAcct();
/** Column name C_BPartner_ID */
public static final String COLUMNNAME_C_BPartner_ID = "C_BPartner_ID";
/** Set Business Partner .
* Identifies a Business Partner
*/
public void setC_BPartner_ID (int C_BPartner_ID);
/** Get Business Partner .
* Identifies a Business Partner
*/
public int getC_BPartner_ID();
public I_C_BPartner getC_BPartner() throws RuntimeException;
/** Column name Created */
public static final String COLUMNNAME_Created = "Created";
/** Get Created.
* Date this record was created
*/
public Timestamp getCreated();
/** Column name CreatedBy */
public static final String COLUMNNAME_CreatedBy = "CreatedBy";
/** Get Created By.
* User who created this records
*/
public int getCreatedBy();
/** Column name DateAcct */
public static final String COLUMNNAME_DateAcct = "DateAcct";
/** Set Account Date.
* Accounting Date
*/
public void setDateAcct (Timestamp DateAcct);
/** Get Account Date.
* Accounting Date
*/
public Timestamp getDateAcct();
/** Column name Fact_Acct_ID */
public static final String COLUMNNAME_Fact_Acct_ID = "Fact_Acct_ID";
/** Set Accounting Fact */
public void setFact_Acct_ID (int Fact_Acct_ID);
/** Get Accounting Fact */
public int getFact_Acct_ID();
/** Column name IsActive */
public static final String COLUMNNAME_IsActive = "IsActive";
/** Set Active.
* The record is active in the system
*/
public void setIsActive (boolean IsActive);
/** Get Active.
* The record is active in the system
*/
public boolean isActive();
/** Column name MatchCode */
public static final String COLUMNNAME_MatchCode = "MatchCode";
/** Set Match Code.
* String identifying related accounting facts
*/
public void setMatchCode (String MatchCode);
/** Get Match Code.
* String identifying related accounting facts
*/
public String getMatchCode();
/** Column name Updated */
public static final String COLUMNNAME_Updated = "Updated";
/** Get Updated.
* Date this record was updated
*/
public Timestamp getUpdated();
/** Column name UpdatedBy */
public static final String COLUMNNAME_UpdatedBy = "UpdatedBy";
/** Get Updated By.
* User who updated this records
*/
public int getUpdatedBy();
}

View File

@ -0,0 +1,17 @@
package org.compiere.model;
import java.sql.ResultSet;
import java.util.Properties;
public class MFactReconciliation extends X_Fact_Reconciliation {
public MFactReconciliation(Properties ctx, int Fact_Acct_ID,
String trxName) {
super(ctx, Fact_Acct_ID, trxName);
}
public MFactReconciliation(Properties ctx, ResultSet rs, String trxName) {
super(ctx, rs, trxName);
}
}

View File

@ -0,0 +1,203 @@
/******************************************************************************
* Product: Adempiere ERP & CRM Smart Business Solution *
* Copyright (C) 1999-2007 ComPiere, Inc. All Rights Reserved. *
* 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. *
* For the text or an alternative of this public license, you may reach us *
* ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA *
* or via info@compiere.org or http://www.compiere.org/license.html *
*****************************************************************************/
/** Generated Model - DO NOT CHANGE */
package org.compiere.model;
import java.math.BigDecimal;
import java.sql.ResultSet;
import java.sql.Timestamp;
import java.util.Properties;
import org.compiere.util.Env;
import org.compiere.util.KeyNamePair;
/** Generated Model for Fact_Reconciliation
* @author Adempiere (generated)
* @version 360LTS.013 - $Id$ */
public class X_Fact_Reconciliation extends PO implements I_Fact_Reconciliation, I_Persistent
{
/**
*
*/
private static final long serialVersionUID = 20111102L;
/** Standard Constructor */
public X_Fact_Reconciliation (Properties ctx, int Fact_Reconciliation_ID, String trxName)
{
super (ctx, Fact_Reconciliation_ID, trxName);
/** if (Fact_Reconciliation_ID == 0)
{
setFact_Acct_ID (0);
} */
}
/** Load Constructor */
public X_Fact_Reconciliation (Properties ctx, ResultSet rs, String trxName)
{
super (ctx, rs, trxName);
}
/** AccessLevel
* @return 3 - Client - Org
*/
protected int get_AccessLevel()
{
return accessLevel.intValue();
}
/** Load Meta Data */
protected POInfo initPO (Properties ctx)
{
POInfo poi = POInfo.getPOInfo (ctx, Table_ID, get_TrxName());
return poi;
}
public String toString()
{
StringBuffer sb = new StringBuffer ("X_Fact_Reconciliation[")
.append(get_ID()).append("]");
return sb.toString();
}
public I_C_ElementValue getAccount() throws RuntimeException
{
return (I_C_ElementValue)MTable.get(getCtx(), I_C_ElementValue.Table_Name)
.getPO(getAccount_ID(), get_TrxName()); }
/** Set Account.
@param Account_ID
Account used
*/
public void setAccount_ID (int Account_ID)
{
throw new IllegalArgumentException ("Account_ID is virtual column"); }
/** Get Account.
@return Account used
*/
public int getAccount_ID ()
{
Integer ii = (Integer)get_Value(COLUMNNAME_Account_ID);
if (ii == null)
return 0;
return ii.intValue();
}
/** Set Accounted Amount.
@param AmtAcct
Amount Balance in Currency of Accounting Schema
*/
public void setAmtAcct (BigDecimal AmtAcct)
{
throw new IllegalArgumentException ("AmtAcct is virtual column"); }
/** Get Accounted Amount.
@return Amount Balance in Currency of Accounting Schema
*/
public BigDecimal getAmtAcct ()
{
BigDecimal bd = (BigDecimal)get_Value(COLUMNNAME_AmtAcct);
if (bd == null)
return Env.ZERO;
return bd;
}
public I_C_BPartner getC_BPartner() throws RuntimeException
{
return (I_C_BPartner)MTable.get(getCtx(), I_C_BPartner.Table_Name)
.getPO(getC_BPartner_ID(), get_TrxName()); }
/** Set Business Partner .
@param C_BPartner_ID
Identifies a Business Partner
*/
public void setC_BPartner_ID (int C_BPartner_ID)
{
throw new IllegalArgumentException ("C_BPartner_ID is virtual column"); }
/** Get Business Partner .
@return Identifies a Business Partner
*/
public int getC_BPartner_ID ()
{
Integer ii = (Integer)get_Value(COLUMNNAME_C_BPartner_ID);
if (ii == null)
return 0;
return ii.intValue();
}
/** Set Account Date.
@param DateAcct
Accounting Date
*/
public void setDateAcct (Timestamp DateAcct)
{
throw new IllegalArgumentException ("DateAcct is virtual column"); }
/** Get Account Date.
@return Accounting Date
*/
public Timestamp getDateAcct ()
{
return (Timestamp)get_Value(COLUMNNAME_DateAcct);
}
/** Set Accounting Fact.
@param Fact_Acct_ID Accounting Fact */
public void setFact_Acct_ID (int Fact_Acct_ID)
{
if (Fact_Acct_ID < 1)
set_ValueNoCheck (COLUMNNAME_Fact_Acct_ID, null);
else
set_ValueNoCheck (COLUMNNAME_Fact_Acct_ID, Integer.valueOf(Fact_Acct_ID));
}
/** Get Accounting Fact.
@return Accounting Fact */
public int getFact_Acct_ID ()
{
Integer ii = (Integer)get_Value(COLUMNNAME_Fact_Acct_ID);
if (ii == null)
return 0;
return ii.intValue();
}
/** Get Record ID/ColumnName
@return ID/ColumnName pair
*/
public KeyNamePair getKeyNamePair()
{
return new KeyNamePair(get_ID(), String.valueOf(getFact_Acct_ID()));
}
/** Set Match Code.
@param MatchCode
String identifying related accounting facts
*/
public void setMatchCode (String MatchCode)
{
set_Value (COLUMNNAME_MatchCode, MatchCode);
}
/** Get Match Code.
@return String identifying related accounting facts
*/
public String getMatchCode ()
{
return (String)get_Value(COLUMNNAME_MatchCode);
}
}

View File

@ -0,0 +1,192 @@
/******************************************************************************
* Product: Adempiere ERP & CRM Smart Business Solution *
* Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. *
* 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. *
* For the text or an alternative of this public license, you may reach us *
* ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA *
* or via info@compiere.org or http://www.compiere.org/license.html *
*****************************************************************************/
package org.compiere.process;
import java.math.*;
import java.sql.*;
import java.util.logging.*;
import org.compiere.model.*;
import org.compiere.util.*;
/**
* Suspense account reconciliation report
* @author Paul Bowden (phib)
*/
public class FactReconcile extends SvrProcess
{
private MElementValue account;
private String type;
private int ruleID;
/**
* Prepare - e.g., get Parameters.
*/
protected void prepare()
{
int accountID = 0;
ProcessInfoParameter[] para = getParameter();
for (int i = 0; i < para.length; i++)
{
String name = para[i].getParameterName();
if (para[i].getParameter() == null)
;
else if (name.equals("AD_Rule_ID"))
ruleID = para[i].getParameterAsInt();
else if (name.equals("Account_ID"))
accountID = para[i].getParameterAsInt();
else
log.log(Level.SEVERE, "Unknown Parameter: " + name);
if ( accountID > 0 )
account = new MElementValue(getCtx(), accountID, get_TrxName());
}
} // prepare
/**
* DoIt
* @return Message
* @throws Exception
*/
protected String doIt() throws Exception
{
String result;
log.info("Reconcile Account: " + account.getName());
String subselect = "null";
MRule rule = MRule.get(getCtx(), ruleID);
if ( rule == null || rule.is_new() || !rule.getRuleType().equals("Q") || ! rule.getEventType().equals("R") )
return "Invalid rule for account reconciliation.";
else
subselect = rule.getScript();
log.log(Level.FINE, "Rule subselect: " + subselect);
/* example matching rules:
*
*
// ar/ap TRade (Receivables/Vendor Liability)
if ( type.equals("TR") )
subselect = " (CASE WHEN fa.AD_Table_ID = " + MInvoice.Table_ID +
" THEN 'C_Invoice:' || fa.Record_ID " +
" WHEN fa.AD_Table_ID = " + MAllocationHdr.Table_ID +
" THEN (SELECT 'C_Invoice:' || al.C_Invoice_ID FROM C_AllocationLine al " +
" WHERE al.C_AllocationHdr_ID = fa.Record_ID " +
" AND al.C_AllocationLine_ID = fa.Line_ID ) END)";
// Bank in Transit
else if ( type.equals("BT"))
subselect = " (CASE WHEN fa.AD_Table_ID = " + MPayment.Table_ID +
" THEN 'C_Payment:' || fa.Record_ID " +
" WHEN fa.AD_Table_ID = " + MBankStatement.Table_ID +
" THEN (SELECT 'C_Payment:' || bsl.C_Payment_ID FROM C_BankStatementLine bsl " +
" WHERE bsl.C_BankStatement_ID = fa.Record_ID " +
" AND bsl.C_BankStatementLine_ID = fa.Line_ID ) END)";
// Payment Clearing (unallocated cash/payment selection)
else if ( type.equals("PC") )
subselect = " (CASE WHEN fa.AD_Table_ID = " + MPayment.Table_ID +
" THEN 'C_Payment:' || fa.Record_ID " +
" WHEN fa.AD_Table_ID = " + MAllocationHdr.Table_ID +
" THEN (SELECT 'C_Payment:' || al.C_Payment_ID FROM C_AllocationLine al " +
" WHERE al.C_AllocationHdr_ID = fa.Record_ID " +
" AND al.C_AllocationLine_ID = fa.Line_ID ) END)";
*/
String sql = "";
log.info("AD_PInstance_ID= " + getAD_PInstance_ID());
PreparedStatement pstmt = null;
ResultSet rs = null;
int count;
int unmatched;
try
{
// add new facts into reconciliation table
sql = "INSERT into Fact_Reconciliation " +
"(AD_Client_ID, AD_Org_ID, Created, CreatedBy, Updated, UpdatedBy, " +
"IsActive, Fact_Acct_ID) " +
"SELECT AD_Client_ID, AD_Org_ID, Created, CreatedBy, " +
"Updated, UpdatedBy, IsActive, " +
"Fact_Acct_ID " +
"FROM Fact_Acct f " +
"WHERE Account_ID = ? " +
"AND NOT EXISTS (SELECT 1 FROM Fact_Reconciliation r " +
"WHERE r.Fact_Acct_ID = f.Fact_Acct_ID) ";
pstmt = DB.prepareStatement(sql, get_TrxName());
pstmt.setInt(1, account.get_ID());
count = pstmt.executeUpdate();
log.log(Level.FINE, "Inserted " + count + " new facts into Fact_Reconciliation");
// set the matchcode based on the rule found in AD_Rule
// which is a sql fragment that returns a string based on the accounting fact
sql = "UPDATE Fact_Reconciliation " +
"SET MatchCode = (" + subselect +
" ) " +
"WHERE MatchCode is null " +
"AND (SELECT f.Account_ID FROM Fact_Acct f " +
" WHERE f.Fact_Acct_ID = Fact_Reconciliation.Fact_Acct_ID ) = ? " +
"AND ( " + subselect +
" ) IS NOT NULL " ;
pstmt = DB.prepareStatement(sql, get_TrxName());
pstmt.setInt(1, account.get_ID());
count = pstmt.executeUpdate();
log.log(Level.FINE, "Updated " + count + " match codes.");
// remove any matchcodes that don't balance to zero
sql = "UPDATE Fact_Reconciliation " +
"SET MatchCode = null " +
" WHERE (SELECT f1.Account_ID FROM Fact_Acct f1 " +
" WHERE f1.Fact_Acct_ID=Fact_Reconciliation.Fact_Acct_ID) = ? " +
" AND (SELECT SUM(f2.amtacctdr-f2.amtacctcr) FROM Fact_Reconciliation r " +
" INNER JOIN Fact_Acct f2 ON (f2.Fact_Acct_ID = r.Fact_Acct_ID) " +
" WHERE r.MatchCode=Fact_Reconciliation.MatchCode" +
" AND f2.Account_ID = ?) <> 0 " +
" AND MatchCode IS NOT NULL";
pstmt = DB.prepareStatement(sql, get_TrxName());
pstmt.setInt(1, account.get_ID());
pstmt.setInt(2, account.get_ID());
unmatched = pstmt.executeUpdate();
log.log(Level.FINE, "Cleared match codes from " + unmatched + " unreconciled facts.");
}
catch (SQLException e)
{
log.log(Level.SEVERE, sql, e);
return e.getLocalizedMessage();
}
finally
{
DB.close(rs, pstmt);
rs = null; pstmt = null;
}
return "Matched " + (count-unmatched) + " facts";
} // doIt
} // FactReconcile

View File

@ -0,0 +1,118 @@
package org.compiere.process;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.logging.Level;
import org.compiere.util.DB;
import org.compiere.util.Msg;
/**
*
*/
public class FactReconciliation extends SvrProcess
{
private Timestamp p_DateAcct_From = null;
private Timestamp p_DateAcct_To = null;
private int p_Account_ID = 0;
/** Start Time */
private long m_start = System.currentTimeMillis();
/**
* Prepare - e.g., get Parameters.
*/
protected void prepare()
{
StringBuffer sb = new StringBuffer ("AD_PInstance_ID=")
.append(getAD_PInstance_ID());
// Parameter
ProcessInfoParameter[] para = getParameter();
for (int i = 0; i < para.length; i++)
{
String name = para[i].getParameterName();
if (name.equals("DateAcct"))
{
p_DateAcct_From = (Timestamp)para[i].getParameter();
p_DateAcct_To = (Timestamp)para[i].getParameter_To();
}
else if (name.equals("Account_ID"))
p_Account_ID = ((BigDecimal)para[i].getParameter()).intValue();
else
log.log(Level.SEVERE, "Unknown Parameter: " + name);
}
} // prepare
/**************************************************************************
* Perform process.
* @return Message to be translated
*/
protected String doIt()
{
PreparedStatement pstmt = null;
ResultSet rs = null;
String sql = "INSERT into T_Reconciliation " +
"(AD_Client_ID, AD_Org_ID, Created, CreatedBy, Updated, UpdatedBy, " +
"IsActive, Fact_Acct_ID, " +
"AD_PInstance_ID, MatchCode) " +
"SELECT f.AD_Client_ID, f.AD_Org_ID, f.Created, f.CreatedBy, " +
"f.Updated, f.UpdatedBy, f.IsActive, " +
"f.Fact_Acct_ID, ?, r.MatchCode " +
"FROM Fact_Acct f " +
"LEFT OUTER JOIN Fact_Reconciliation r ON (f.Fact_Acct_ID=r.Fact_Acct_ID) " +
"WHERE Account_ID = ? " +
"AND DateAcct BETWEEN ? AND ? ";
try
{
pstmt = DB.prepareStatement(sql, get_TrxName());
pstmt.setInt(1, getAD_PInstance_ID());
pstmt.setInt(2, p_Account_ID);
pstmt.setTimestamp(3, p_DateAcct_From);
pstmt.setTimestamp(4, p_DateAcct_To);
int count = pstmt.executeUpdate();
String result = Msg.getMsg(getCtx(),"@Created@") + ": " + count + ", ";
log.log(Level.FINE, result);
sql = "DELETE FROM T_Reconciliation t " +
"WHERE (SELECT SUM(f.amtacctdr-f.amtacctcr) FROM T_Reconciliation r " +
" INNER JOIN Fact_Acct f ON (f.Fact_Acct_ID = r.Fact_Acct_ID) " +
" WHERE r.MatchCode=t.MatchCode" +
" AND r.AD_PInstance_ID = t.AD_PInstance_ID) = 0 " +
"AND t.AD_PInstance_ID = ?";
pstmt = DB.prepareStatement(sql, get_TrxName());
pstmt.setInt(1, getAD_PInstance_ID());
count = pstmt.executeUpdate();
result = Msg.getMsg(getCtx(), "@Deleted@") + ": " + count;
log.log(Level.FINE, result);
}
catch (SQLException e)
{
log.log(Level.SEVERE, sql, e);
return e.getLocalizedMessage();
}
finally
{
DB.close(rs, pstmt);
rs = null; pstmt = null;
}
log.fine((System.currentTimeMillis() - m_start) + " ms");
return "";
} // doIt
}

View File

@ -0,0 +1,680 @@
/******************************************************************************
* Product: Adempiere ERP & CRM Smart Business Solution *
* Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. *
* 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. *
* For the text or an alternative of this public license, you may reach us *
* ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA *
* or via info@compiere.org or http://www.compiere.org/license.html *
* Contributors: *
* Colin Rooney (croo) Patch 1605368 Fixed Payment Terms & Only due *
*****************************************************************************/
package org.compiere.apps.form;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Properties;
import java.util.logging.Level;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.SwingConstants;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import net.miginfocom.swing.MigLayout;
import org.adempiere.plaf.AdempierePLAF;
import org.compiere.apps.AEnv;
import org.compiere.apps.ConfirmPanel;
import org.compiere.grid.ed.AutoCompletion;
import org.compiere.grid.ed.VCheckBox;
import org.compiere.grid.ed.VComboBox;
import org.compiere.grid.ed.VDate;
import org.compiere.grid.ed.VLookup;
import org.compiere.minigrid.ColumnInfo;
import org.compiere.minigrid.IDColumn;
import org.compiere.minigrid.MiniTable;
import org.compiere.model.MClient;
import org.compiere.model.MFactReconciliation;
import org.compiere.model.MLookup;
import org.compiere.model.MLookupFactory;
import org.compiere.model.MRole;
import org.compiere.model.Query;
import org.compiere.plaf.CompiereColor;
import org.compiere.process.ProcessInfo;
import org.compiere.swing.CLabel;
import org.compiere.swing.CPanel;
import org.compiere.swing.CTextField;
import org.compiere.util.ASyncProcess;
import org.compiere.util.CLogger;
import org.compiere.util.DB;
import org.compiere.util.DisplayType;
import org.compiere.util.Env;
import org.compiere.util.KeyNamePair;
import org.compiere.util.Msg;
/**
* Create manual match of accounting facts
*/
public class VFactReconcile extends CPanel
implements FormPanel, ActionListener, TableModelListener, ASyncProcess
{
/**
* Initialize Panel
* @param WindowNo window
* @param frame frame
*/
public void init (int WindowNo, FormFrame frame)
{
log.info("");
m_WindowNo = WindowNo;
m_frame = frame;
try
{
dynInit();
jbInit();
frame.getContentPane().add(commandPanel, BorderLayout.SOUTH);
frame.getContentPane().add(mainPanel, BorderLayout.CENTER);
}
catch(Exception e)
{
log.log(Level.SEVERE, "", e);
}
} // init
/** Window No */
private int m_WindowNo = 0;
/** FormFrame */
private FormFrame m_frame;
/** Format */
private DecimalFormat m_format = DisplayType.getNumberFormat(DisplayType.Amount);
/** SQL for Query */
private String m_sql;
/** Number of selected rows */
private int m_noSelected = 0;
/** Client ID */
private int m_AD_Client_ID = 0;
/**/
private boolean m_isLocked = false;
/** Logger */
private static CLogger log = CLogger.getCLogger(VFactReconcile.class);
//
private CPanel mainPanel = new CPanel();
private BorderLayout mainLayout = new BorderLayout();
private CPanel parameterPanel = new CPanel();
private CLabel labelAcctSchema = new CLabel();
private VLookup fieldAcctSchema = null;
private MigLayout parameterLayout = null;
private CLabel labelOrg = new CLabel();
private VLookup fieldOrg = null;
private VCheckBox isReconciled = new VCheckBox();
private CLabel labelAccount = new CLabel();
private VComboBox fieldAccount = new VComboBox();
private CLabel labelBPartner = new CLabel();
private VLookup fieldBPartner = null;
private JLabel dataStatus = new JLabel();
private JScrollPane dataPane = new JScrollPane();
private MiniTable miniTable = new MiniTable();
private CPanel commandPanel = new CPanel();
private JButton bCancel = ConfirmPanel.createCancelButton(true);
private JButton bGenerate = ConfirmPanel.createProcessButton(true);
private JButton bReset = ConfirmPanel.createResetButton(true);
private JButton bZoom = ConfirmPanel.createZoomButton(true);
private FlowLayout commandLayout = new FlowLayout();
private JButton bRefresh = ConfirmPanel.createRefreshButton(true);
private CLabel labelDateAcct = new CLabel();
private VDate fieldDateAcct = new VDate();
private CLabel labelDateAcct2 = new CLabel();
private VDate fieldDateAcct2 = new VDate();
private CLabel labelProduct = new CLabel();
private VLookup fieldProduct = null;
private boolean loading = false;
private int idColIndex = 3;
private int amtColIndex = 1;
private CLabel differenceLabel = new CLabel();
private CTextField differenceField = new CTextField();
/**
* Static Init
* @throws Exception
*/
private void jbInit() throws Exception
{
CompiereColor.setBackground(this);
//
mainPanel.setLayout(mainLayout);
parameterLayout = new MigLayout("fillx, wrap 4, hidemode 0", " [150:150][250:250][100:100][200:200]");
parameterPanel.setLayout(parameterLayout);
bRefresh.addActionListener(this);
bReset.addActionListener(this);
bZoom.addActionListener(this);
bGenerate.setEnabled(false);
bReset.setEnabled(false);
//bRefresh.setText(Msg.getMsg(Env.getCtx(), "Query"));
bGenerate.setText(Msg.getMsg(Env.getCtx(),"Process"));
bReset.setText(Msg.getMsg(Env.getCtx(),"Reset"));
bZoom.setText(Msg.translate(Env.getCtx(), "Fact_Acct_ID"));
//
labelAcctSchema.setText(Msg.translate(Env.getCtx(), "C_AcctSchema_ID"));
labelAccount.setText(Msg.translate(Env.getCtx(), "Account_ID"));
labelBPartner.setText(Msg.translate(Env.getCtx(), "C_BPartner_ID"));
labelDateAcct.setText(Msg.translate(Env.getCtx(), "DateAcct"));
labelDateAcct2.setText("-");
labelProduct.setText(Msg.translate(Env.getCtx(), "M_Product_ID"));
//
labelOrg.setText(Msg.translate(Env.getCtx(), "AD_Org_ID"));
isReconciled.setText(Msg.translate(Env.getCtx(), "IsReconciled"));
dataStatus.setText(" ");
differenceLabel.setText(Msg.getMsg(Env.getCtx(), "Difference"));
differenceField.setBackground(AdempierePLAF.getFieldBackground_Inactive());
differenceField.setEditable(false);
differenceField.setText("0");
differenceField.setColumns(8);
differenceField.setHorizontalAlignment(SwingConstants.RIGHT);
//
bGenerate.addActionListener(this);
bCancel.addActionListener(this);
//
mainPanel.add(parameterPanel, BorderLayout.NORTH);
parameterPanel.add(labelAcctSchema, "");
parameterPanel.add(fieldAcctSchema, "growx");
parameterPanel.add(labelOrg, "");
parameterPanel.add(fieldOrg, "growx");
parameterPanel.add(labelAccount, "");
parameterPanel.add(fieldAccount, "wmax 250");
parameterPanel.add(isReconciled, "skip 1");
parameterPanel.add(labelBPartner, "");
parameterPanel.add(fieldBPartner, "growx");
parameterPanel.add(labelProduct, "");
parameterPanel.add(fieldProduct, "growx");
parameterPanel.add(labelDateAcct, "");
parameterPanel.add(fieldDateAcct, "growx");
parameterPanel.add(labelDateAcct2, "");
parameterPanel.add(fieldDateAcct2, "growx");
parameterPanel.add(bRefresh, "growx");
mainPanel.add(dataStatus, BorderLayout.SOUTH);
mainPanel.add(dataPane, BorderLayout.CENTER);
dataPane.getViewport().add(miniTable, null);
//
commandPanel.setLayout(commandLayout);
commandLayout.setAlignment(FlowLayout.RIGHT);
commandLayout.setHgap(10);
commandPanel.add(bZoom, null);
commandPanel.add(differenceLabel, null);
commandPanel.add(differenceField, null);
commandPanel.add(bGenerate, null);
commandPanel.add(bReset, null);
commandPanel.add(bCancel, null);
} // jbInit
/**
* Dynamic Init.
* - Load Bank Info
* - Load BPartner
* - Load Document Type
* - Init Table
*/
private void dynInit()
{
Properties ctx = Env.getCtx();
//
m_AD_Client_ID = Env.getAD_Client_ID(Env.getCtx());
int AD_Column_ID = 2513; // Fact_Acct.C_AcctSchema_ID
MLookup lookupAS = MLookupFactory.get (Env.getCtx(), m_WindowNo, 0, AD_Column_ID, DisplayType.TableDir);
fieldAcctSchema = new VLookup("C_AcctSchema_ID", true, false, true, lookupAS);
fieldAcctSchema.addActionListener(this);
MClient.get(Env.getCtx()).getAcctSchema().getC_AcctSchema_ID();
fieldAcctSchema.setValue(MClient.get(Env.getCtx()).getAcctSchema().getC_AcctSchema_ID());
Dimension dim = fieldAcctSchema.getPreferredSize();
dim.width = 300;
fieldAcctSchema.setPreferredSize(dim);
// Organization filter selection
AD_Column_ID = 839; //C_Period.AD_Org_ID (needed to allow org 0)
MLookup lookupOrg = MLookupFactory.get(Env.getCtx(), m_WindowNo, 0, AD_Column_ID, DisplayType.TableDir);
fieldOrg = new VLookup("AD_Org_ID", true, false, true, lookupOrg);
if (lookupOrg.containsKey(0))
fieldOrg.setValue(0);
else
fieldOrg.setValue(Env.getAD_Org_ID(Env.getCtx()));
dim = fieldOrg.getPreferredSize();
dim.width = 300;
fieldOrg.setPreferredSize(dim);
// BPartner
AD_Column_ID = 3499; // C_Invoice.C_BPartner_ID
MLookup lookupBP = MLookupFactory.get (Env.getCtx(), m_WindowNo, 0, AD_Column_ID, DisplayType.Search);
fieldBPartner = new VLookup("C_BPartner_ID", false, false, true, lookupBP);
// Product
AD_Column_ID = 2527; // Fact_Acct.M_Product_ID
MLookup lookupProduct = MLookupFactory.get (Env.getCtx(), m_WindowNo, 0, AD_Column_ID, DisplayType.Search);
fieldProduct = new VLookup("M_Product_ID", false, false, true, lookupProduct);
// Account
KeyNamePair pp;
String sql = MRole.getDefault().addAccessSQL(
"SELECT ev.C_ElementValue_ID, ev.Value || ' ' || ev.Name FROM C_ElementValue ev", "ev",
MRole.SQL_FULLYQUALIFIED, MRole.SQL_RO)
+ "AND ev.IsActive='Y' AND ev.IsSummary='N' "
+ "AND ev.C_Element_ID IN (SELECT C_Element_ID FROM C_AcctSchema_Element ase "
+ "WHERE ase.ElementType='AC' AND ase.AD_Client_ID=" + m_AD_Client_ID + ") "
+ "ORDER BY 2";
try
{
PreparedStatement pstmt = DB.prepareStatement(sql, null);
ResultSet rs = pstmt.executeQuery();
while (rs.next())
{
pp = new KeyNamePair(rs.getInt(1), rs.getString(2));
fieldAccount.addItem(pp);
}
rs.close();
pstmt.close();
}
catch (SQLException e)
{
log.log(Level.SEVERE, sql, e);
}
AutoCompletion.enable(fieldAccount);
fieldAccount.setMandatory(true);
fieldAccount.setSelectedIndex(0);
m_sql = miniTable.prepareTable(new ColumnInfo[] {
new ColumnInfo(Msg.translate(ctx, "Amt"), "abs(fa.amtacctdr-fa.amtacctcr)", BigDecimal.class),
new ColumnInfo(Msg.translate(ctx, "AmtAcct"), "(fa.amtacctdr-fa.amtacctcr)", BigDecimal.class,true,true,null),
new ColumnInfo("DR/CR", "(CASE WHEN (fa.amtacctdr-fa.amtacctcr) < 0 THEN 'CR' ELSE 'DR' END)", String.class),
new ColumnInfo(" ", "fa.Fact_Acct_ID", IDColumn.class, false, false, null),
new ColumnInfo(Msg.translate(ctx, "C_BPartner_ID"), "bp.Name", String.class),
new ColumnInfo(Msg.translate(ctx, "DateAcct"), "fa.DateAcct", Timestamp.class),
new ColumnInfo(Msg.translate(ctx, "GL_Category_ID"), "glc.Name", String.class),
new ColumnInfo(Msg.translate(ctx, "M_Product_ID"), "p.Value", String.class),
new ColumnInfo(Msg.translate(ctx, "Qty"), "Qty", BigDecimal.class),
new ColumnInfo(Msg.translate(ctx, "Description"), "fa.Description", String.class),
new ColumnInfo(Msg.translate(ctx, "MatchCode"), "r.MatchCode", String.class),
new ColumnInfo(Msg.translate(ctx, "DateTrx"), "fa.DateTrx", Timestamp.class),
new ColumnInfo(Msg.translate(ctx, "AD_Org_ID"), "o.Value", String.class)},
// FROM
"Fact_Acct fa"
+ " LEFT OUTER JOIN Fact_Reconciliation r ON (fa.Fact_Acct_ID=r.Fact_Acct_ID)"
+ " LEFT OUTER JOIN C_BPartner bp ON (fa.C_BPartner_ID=bp.C_BPartner_ID)"
+ " LEFT OUTER JOIN AD_Org o ON (o.AD_Org_ID=fa.AD_Org_ID)"
+ " LEFT OUTER JOIN M_Product p ON (p.M_Product_ID=fa.M_Product_ID)"
+ " LEFT OUTER JOIN GL_Category glc ON (fa.GL_Category_ID=glc.GL_Category_ID)",
// WHERE
" fa.AD_Client_ID=?", // additional where & order in loadTableInfo()
true, "fa");
//
miniTable.getModel().addTableModelListener(this);
miniTable.setColumnVisibility(miniTable.getColumnModel().getColumn(1), false);
} // dynInit
/**
* Query and create TableInfo
*/
private void loadTableInfo()
{
log.config("");
// not yet initialized
if (m_sql == null)
return;
loading = true;
String sql = m_sql;
KeyNamePair pp = (KeyNamePair)fieldAccount.getSelectedItem();
int Account_ID = pp.getKey();
if (Account_ID != 0)
sql += " AND fa.Account_ID=?";
if ( ((Integer) fieldAcctSchema.getValue()) > 0 )
sql += " AND fa.C_AcctSchema_ID = ?";
sql += " AND ((SELECT SUM(f.amtacctdr-f.amtacctcr) FROM Fact_Reconciliation rec " +
" INNER JOIN Fact_Acct f ON (f.Fact_Acct_ID = rec.Fact_Acct_ID) " +
" WHERE r.MatchCode=rec.MatchCode) ";
if ( isReconciled.isSelected() )
sql += "= 0) ";
else
sql += "<> 0 OR r.MatchCode IS NULL) ";
if ( fieldBPartner.getValue() != null )
sql += " AND fa.C_BPartner_ID = ?";
if ( fieldProduct.getValue() != null )
sql += " AND fa.M_Product_ID = ?";
if ( fieldDateAcct.getValue() != null )
sql += " AND fa.DateAcct >= ?";
if ( fieldDateAcct2.getValue() != null )
sql += " AND fa.DateAcct <= ?";
sql += " ORDER BY 1,5,3,6";
log.finest(sql + "Account_ID =" + Account_ID );
// Get facts
try
{
int index = 1;
PreparedStatement pstmt = DB.prepareStatement(sql, null);
pstmt.setInt(index++, m_AD_Client_ID); // Client
pstmt.setInt(index++, (Integer) fieldAccount.getValue()); // account
if ( ((Integer) fieldAcctSchema.getValue()) > 0 )
pstmt.setInt(index++, (Integer) fieldAcctSchema.getValue());
if ( fieldBPartner.getValue() != null )
pstmt.setInt(index++, (Integer) fieldBPartner.getValue());
if ( fieldProduct.getValue() != null )
pstmt.setInt(index++, (Integer) fieldProduct.getValue());
if ( fieldDateAcct.getValue() != null )
pstmt.setTimestamp(index++, (Timestamp) fieldDateAcct.getValue());
if ( fieldDateAcct2.getValue() != null )
pstmt.setTimestamp(index++, (Timestamp) fieldDateAcct2.getValue());
ResultSet rs = pstmt.executeQuery();
miniTable.loadTable(rs);
rs.close();
pstmt.close();
log.log(Level.FINE, sql);
}
catch (SQLException e)
{
log.log(Level.SEVERE, sql, e);
}
loading = false;
calculateSelection();
} // loadTableInfo
/**
* Dispose
*/
public void dispose()
{
if (m_frame != null)
m_frame.dispose();
m_frame = null;
} // dispose
/**************************************************************************
* ActionListener
* @param e event
*/
public void actionPerformed (ActionEvent e)
{
// Generate Reconciliation
if (e.getSource() == bGenerate)
{
generateReconciliation();
}
else if (e.getSource() == bReset)
{
resetReconciliation();
}
else if (e.getSource() == bZoom)
{
zoom();
}
else if (e.getSource() == bCancel)
dispose();
// Update
else if (e.getSource() == bRefresh)
loadTableInfo();
} // actionPerformed
/**
* Zoom to target
* @param AD_Window_ID window id
* @param zoomQuery zoom query
*/
protected void zoom ()
{
log.info("");
int selected = miniTable.getSelectedRow();
if ( selected == -1 )
return;
int factId = ((IDColumn) miniTable.getModel().getValueAt(selected, idColIndex)).getRecord_ID();
AEnv.zoom(270, factId);
} // zoom
private void resetReconciliation() {
log.info("");
//
miniTable.stopEditor(true);
if (miniTable.getRowCount() == 0)
return;
miniTable.setRowSelectionInterval(0,0);
calculateSelection();
if (m_noSelected == 0)
return;
for ( int r = 0; r < miniTable.getModel().getRowCount(); r++ )
{
if ( ((IDColumn) miniTable.getModel().getValueAt(r, idColIndex)).isSelected() )
{
int factId = ((IDColumn) miniTable.getModel().getValueAt(r, idColIndex )).getRecord_ID();
MFactReconciliation rec = new Query(Env.getCtx(), MFactReconciliation.Table_Name, "Fact_Acct_ID = ?", null)
.setParameters(new Object[] {factId}).first();
if ( rec == null )
{
continue;
}
rec.setMatchCode(null);
rec.saveEx();
((DefaultTableModel) miniTable.getModel()).removeRow(r--);
}
}
}
/**
* Table Model Listener
* @param e event
*/
public void tableChanged(TableModelEvent e)
{
if (! loading )
calculateSelection();
} // valueChanged
/**
* Calculate selected rows.
* - add up selected rows
*/
public void calculateSelection()
{
m_noSelected = 0;
BigDecimal selectedAmt = new BigDecimal(0.0);
int rows = miniTable.getRowCount();
for (int i = 0; i < rows; i++)
{
IDColumn id = (IDColumn)miniTable.getModel().getValueAt(i, idColIndex);
if (id.isSelected())
{
BigDecimal amt = (BigDecimal)miniTable.getModel().getValueAt(i, amtColIndex);
if (amt != null)
selectedAmt = selectedAmt.add(amt);
m_noSelected++;
}
}
// Information
StringBuffer info = new StringBuffer();
info.append(m_noSelected).append(" ").append(Msg.getMsg(Env.getCtx(), "Selected")).append(" / ").append(miniTable.getRowCount());
differenceField.setText(m_format.format(selectedAmt));
dataStatus.setText(info.toString());
//
bGenerate.setEnabled(m_noSelected != 0 && Env.ZERO.compareTo(selectedAmt) == 0 && !isReconciled.isSelected());
bReset.setEnabled(m_noSelected > 0 && isReconciled.isSelected());
} // calculateSelection
/**
* Generate Reconciliation record
*/
private void generateReconciliation()
{
log.info("");
//
miniTable.stopEditor(true);
if (miniTable.getRowCount() == 0)
return;
miniTable.setRowSelectionInterval(0,0);
calculateSelection();
if (m_noSelected == 0)
return;
String format = "yyyy-MM-dd HH:mm:ss.SSS";
Calendar cal = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat(format);
String time = sdf.format(cal.getTime());
String matchcode = "Manual: " + Env.getContext(Env.getCtx(), "#AD_User_Name") + " " + time;
for ( int r = 0; r < miniTable.getModel().getRowCount(); r++ )
{
if ( ((IDColumn) miniTable.getModel().getValueAt(r, idColIndex)).isSelected() )
{
int factId = ((IDColumn) miniTable.getModel().getValueAt(r, idColIndex )).getRecord_ID();
MFactReconciliation rec = new Query(Env.getCtx(), MFactReconciliation.Table_Name, "Fact_Acct_ID = ?", null)
.setParameters(new Object[] {factId}).first();
if ( rec == null )
{
rec = new MFactReconciliation(Env.getCtx(), 0, null);
rec.setFact_Acct_ID(factId);
}
rec.setMatchCode(matchcode);
rec.saveEx();
((DefaultTableModel) miniTable.getModel()).removeRow(r--);
}
}
}
/**
* Lock User Interface
* Called from the Worker before processing
* @param pi process info
*/
public void lockUI (ProcessInfo pi)
{
this.setEnabled(false);
m_isLocked = true;
} // lockUI
/**
* Unlock User Interface.
* Called from the Worker when processing is done
* @param pi process info
*/
public void unlockUI (ProcessInfo pi)
{
this.setEnabled(true);
m_isLocked = false;
} // unlockUI
/**
* Is the UI locked (Internal method)
* @return true, if UI is locked
*/
public boolean isUILocked()
{
return m_isLocked;
} // isLoacked
/**
* Method to be executed async.
* Called from the ASyncProcess worker
* @param pi process info
*/
public void executeASync (ProcessInfo pi)
{
log.config("-");
} // executeASync
} // VPaySelect