Refactor custom form - ID: 2787613
This commit is contained in:
parent
a890145e50
commit
0d919012ce
|
@ -0,0 +1,781 @@
|
|||
/******************************************************************************
|
||||
* Copyright (C) 2009 Low Heng Sin *
|
||||
* Copyright (C) 2009 Idalica Corporation *
|
||||
* This program is free software; you can redistribute it and/or modify it *
|
||||
* under the terms version 2 of the GNU General Public License as published *
|
||||
* by the Free Software Foundation. This program is distributed in the hope *
|
||||
* that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
||||
* See the GNU General Public License for more details. *
|
||||
* You should have received a copy of the GNU General Public License along *
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., *
|
||||
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
|
||||
*****************************************************************************/
|
||||
package org.compiere.apps.form;
|
||||
|
||||
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.util.ArrayList;
|
||||
import java.util.Vector;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.adempiere.exceptions.AdempiereException;
|
||||
import org.compiere.minigrid.IMiniTable;
|
||||
import org.compiere.model.MAllocationHdr;
|
||||
import org.compiere.model.MAllocationLine;
|
||||
import org.compiere.model.MInvoice;
|
||||
import org.compiere.model.MPayment;
|
||||
import org.compiere.model.MRole;
|
||||
import org.compiere.process.DocAction;
|
||||
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;
|
||||
import org.compiere.util.TimeUtil;
|
||||
import org.compiere.util.Util;
|
||||
|
||||
public class Allocation
|
||||
{
|
||||
public DecimalFormat format = DisplayType.getNumberFormat(DisplayType.Amount);
|
||||
|
||||
/** Logger */
|
||||
public static CLogger log = CLogger.getCLogger(Allocation.class);
|
||||
|
||||
private boolean m_calculating = false;
|
||||
public int m_C_Currency_ID = 0;
|
||||
public int m_C_BPartner_ID = 0;
|
||||
private int m_noInvoices = 0;
|
||||
private int m_noPayments = 0;
|
||||
public BigDecimal totalInv = new BigDecimal(0.0);
|
||||
public BigDecimal totalPay = new BigDecimal(0.0);
|
||||
public BigDecimal totalDiff = new BigDecimal(0.0);
|
||||
|
||||
public Timestamp allocDate = null;
|
||||
|
||||
// Index changed if multi-currency
|
||||
private int i_payment = 7;
|
||||
//
|
||||
private int i_open = 6;
|
||||
private int i_discount = 7;
|
||||
private int i_writeOff = 8;
|
||||
private int i_applied = 9;
|
||||
private int i_overUnder = 10;
|
||||
// private int i_multiplier = 10;
|
||||
|
||||
public int m_AD_Org_ID = 0;
|
||||
|
||||
private ArrayList<Integer> m_bpartnerCheck = new ArrayList<Integer>();
|
||||
|
||||
public void dynInit() throws Exception
|
||||
{
|
||||
m_C_Currency_ID = Env.getContextAsInt(Env.getCtx(), "$C_Currency_ID"); // default
|
||||
//
|
||||
log.info("Currency=" + m_C_Currency_ID);
|
||||
|
||||
m_AD_Org_ID = Env.getAD_Org_ID(Env.getCtx());
|
||||
}
|
||||
|
||||
/**
|
||||
* Load Business Partner Info
|
||||
* - Payments
|
||||
* - Invoices
|
||||
*/
|
||||
public void checkBPartner()
|
||||
{
|
||||
log.config("BPartner=" + m_C_BPartner_ID + ", Cur=" + m_C_Currency_ID);
|
||||
// Need to have both values
|
||||
if (m_C_BPartner_ID == 0 || m_C_Currency_ID == 0)
|
||||
return;
|
||||
|
||||
// Async BPartner Test
|
||||
Integer key = new Integer(m_C_BPartner_ID);
|
||||
if (!m_bpartnerCheck.contains(key))
|
||||
{
|
||||
new Thread()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
MPayment.setIsAllocated (Env.getCtx(), m_C_BPartner_ID, null);
|
||||
MInvoice.setIsPaid (Env.getCtx(), m_C_BPartner_ID, null);
|
||||
}
|
||||
}.start();
|
||||
m_bpartnerCheck.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
public Vector<Vector<Object>> getPaymentData(boolean isMultiCurrency, Object date, IMiniTable paymentTable)
|
||||
{
|
||||
/********************************
|
||||
* Load unallocated Payments
|
||||
* 1-TrxDate, 2-DocumentNo, (3-Currency, 4-PayAmt,)
|
||||
* 5-ConvAmt, 6-ConvOpen, 7-Allocated
|
||||
*/
|
||||
Vector<Vector<Object>> data = new Vector<Vector<Object>>();
|
||||
StringBuffer sql = new StringBuffer("SELECT p.DateTrx,p.DocumentNo,p.C_Payment_ID," // 1..3
|
||||
+ "c.ISO_Code,p.PayAmt," // 4..5
|
||||
+ "currencyConvert(p.PayAmt,p.C_Currency_ID,?,?,p.C_ConversionType_ID,p.AD_Client_ID,p.AD_Org_ID),"// 6 #1, #2
|
||||
+ "currencyConvert(paymentAvailable(C_Payment_ID),p.C_Currency_ID,?,?,p.C_ConversionType_ID,p.AD_Client_ID,p.AD_Org_ID)," // 7 #3, #4
|
||||
+ "p.MultiplierAP "
|
||||
+ "FROM C_Payment_v p" // Corrected for AP/AR
|
||||
+ " INNER JOIN C_Currency c ON (p.C_Currency_ID=c.C_Currency_ID) "
|
||||
+ "WHERE p.IsAllocated='N' AND p.Processed='Y'"
|
||||
+ " AND p.C_Charge_ID IS NULL" // Prepayments OK
|
||||
+ " AND p.C_BPartner_ID=?"); // #5
|
||||
if (!isMultiCurrency)
|
||||
sql.append(" AND p.C_Currency_ID=?"); // #6
|
||||
if (m_AD_Org_ID != 0 )
|
||||
sql.append(" AND p.AD_Org_ID=" + m_AD_Org_ID);
|
||||
sql.append(" ORDER BY p.DateTrx,p.DocumentNo");
|
||||
|
||||
// role security
|
||||
sql = new StringBuffer( MRole.getDefault(Env.getCtx(), false).addAccessSQL( sql.toString(), "p", MRole.SQL_FULLYQUALIFIED, MRole.SQL_RO ) );
|
||||
|
||||
log.fine("PaySQL=" + sql.toString());
|
||||
try
|
||||
{
|
||||
PreparedStatement pstmt = DB.prepareStatement(sql.toString(), null);
|
||||
pstmt.setInt(1, m_C_Currency_ID);
|
||||
pstmt.setTimestamp(2, (Timestamp)date);
|
||||
pstmt.setInt(3, m_C_Currency_ID);
|
||||
pstmt.setTimestamp(4, (Timestamp)date);
|
||||
pstmt.setInt(5, m_C_BPartner_ID);
|
||||
if (!isMultiCurrency)
|
||||
pstmt.setInt(6, m_C_Currency_ID);
|
||||
ResultSet rs = pstmt.executeQuery();
|
||||
while (rs.next())
|
||||
{
|
||||
Vector<Object> line = new Vector<Object>();
|
||||
line.add(new Boolean(false)); // 0-Selection
|
||||
line.add(rs.getTimestamp(1)); // 1-TrxDate
|
||||
KeyNamePair pp = new KeyNamePair(rs.getInt(3), rs.getString(2));
|
||||
line.add(pp); // 2-DocumentNo
|
||||
if (isMultiCurrency)
|
||||
{
|
||||
line.add(rs.getString(4)); // 3-Currency
|
||||
line.add(rs.getBigDecimal(5)); // 4-PayAmt
|
||||
}
|
||||
line.add(rs.getBigDecimal(6)); // 3/5-ConvAmt
|
||||
BigDecimal available = rs.getBigDecimal(7);
|
||||
if (available == null || available.signum() == 0) // nothing available
|
||||
continue;
|
||||
line.add(available); // 4/6-ConvOpen/Available
|
||||
line.add(Env.ZERO); // 5/7-Payment
|
||||
// line.add(rs.getBigDecimal(8)); // 6/8-Multiplier
|
||||
//
|
||||
data.add(line);
|
||||
}
|
||||
rs.close();
|
||||
pstmt.close();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
log.log(Level.SEVERE, sql.toString(), e);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public Vector<String> getPaymentColumnNames(boolean isMultiCurrency)
|
||||
{
|
||||
// Header Info
|
||||
Vector<String> columnNames = new Vector<String>();
|
||||
columnNames.add(Msg.getMsg(Env.getCtx(), "Select"));
|
||||
columnNames.add(Msg.translate(Env.getCtx(), "Date"));
|
||||
columnNames.add(Util.cleanAmp(Msg.translate(Env.getCtx(), "DocumentNo")));
|
||||
if (isMultiCurrency)
|
||||
{
|
||||
columnNames.add(Msg.getMsg(Env.getCtx(), "TrxCurrency"));
|
||||
columnNames.add(Msg.translate(Env.getCtx(), "Amount"));
|
||||
}
|
||||
columnNames.add(Msg.getMsg(Env.getCtx(), "ConvertedAmount"));
|
||||
columnNames.add(Msg.getMsg(Env.getCtx(), "OpenAmt"));
|
||||
columnNames.add(Msg.getMsg(Env.getCtx(), "AppliedAmt"));
|
||||
// columnNames.add(" "); // Multiplier
|
||||
|
||||
return columnNames;
|
||||
}
|
||||
|
||||
public void setPaymentColumnClass(IMiniTable paymentTable, boolean isMultiCurrency)
|
||||
{
|
||||
int i = 0;
|
||||
paymentTable.setColumnClass(i++, Boolean.class, false); // 0-Selection
|
||||
paymentTable.setColumnClass(i++, Timestamp.class, true); // 1-TrxDate
|
||||
paymentTable.setColumnClass(i++, String.class, true); // 2-Value
|
||||
if (isMultiCurrency)
|
||||
{
|
||||
paymentTable.setColumnClass(i++, String.class, true); // 3-Currency
|
||||
paymentTable.setColumnClass(i++, BigDecimal.class, true); // 4-PayAmt
|
||||
}
|
||||
paymentTable.setColumnClass(i++, BigDecimal.class, true); // 5-ConvAmt
|
||||
paymentTable.setColumnClass(i++, BigDecimal.class, true); // 6-ConvOpen
|
||||
paymentTable.setColumnClass(i++, BigDecimal.class, false); // 7-Allocated
|
||||
// paymentTable.setColumnClass(i++, BigDecimal.class, true); // 8-Multiplier
|
||||
|
||||
//
|
||||
i_payment = isMultiCurrency ? 7 : 5;
|
||||
|
||||
|
||||
// Table UI
|
||||
paymentTable.autoSize();
|
||||
}
|
||||
|
||||
public Vector<Vector<Object>> getInvoiceData(boolean isMultiCurrency, Object date, IMiniTable invoiceTable)
|
||||
{
|
||||
/********************************
|
||||
* Load unpaid Invoices
|
||||
* 1-TrxDate, 2-Value, (3-Currency, 4-InvAmt,)
|
||||
* 5-ConvAmt, 6-ConvOpen, 7-ConvDisc, 8-WriteOff, 9-Applied
|
||||
*
|
||||
SELECT i.DateInvoiced,i.DocumentNo,i.C_Invoice_ID,c.ISO_Code,
|
||||
i.GrandTotal*i.MultiplierAP "GrandTotal",
|
||||
currencyConvert(i.GrandTotal*i.MultiplierAP,i.C_Currency_ID,i.C_Currency_ID,i.DateInvoiced,i.C_ConversionType_ID,i.AD_Client_ID,i.AD_Org_ID) "GrandTotal $",
|
||||
invoiceOpen(C_Invoice_ID,C_InvoicePaySchedule_ID) "Open",
|
||||
currencyConvert(invoiceOpen(C_Invoice_ID,C_InvoicePaySchedule_ID),i.C_Currency_ID,i.C_Currency_ID,i.DateInvoiced,i.C_ConversionType_ID,i.AD_Client_ID,i.AD_Org_ID)*i.MultiplierAP "Open $",
|
||||
invoiceDiscount(i.C_Invoice_ID,SysDate,C_InvoicePaySchedule_ID) "Discount",
|
||||
currencyConvert(invoiceDiscount(i.C_Invoice_ID,SysDate,C_InvoicePaySchedule_ID),i.C_Currency_ID,i.C_Currency_ID,i.DateInvoiced,i.C_ConversionType_ID,i.AD_Client_ID,i.AD_Org_ID)*i.Multiplier*i.MultiplierAP "Discount $",
|
||||
i.MultiplierAP, i.Multiplier
|
||||
FROM C_Invoice_v i INNER JOIN C_Currency c ON (i.C_Currency_ID=c.C_Currency_ID)
|
||||
WHERE -- i.IsPaid='N' AND i.Processed='Y' AND i.C_BPartner_ID=1000001
|
||||
*/
|
||||
Vector<Vector<Object>> data = new Vector<Vector<Object>>();
|
||||
StringBuffer sql = new StringBuffer("SELECT i.DateInvoiced,i.DocumentNo,i.C_Invoice_ID," // 1..3
|
||||
+ "c.ISO_Code,i.GrandTotal*i.MultiplierAP, " // 4..5 Orig Currency
|
||||
+ "currencyConvert(i.GrandTotal*i.MultiplierAP,i.C_Currency_ID,?,?,i.C_ConversionType_ID,i.AD_Client_ID,i.AD_Org_ID), " // 6 #1 Converted, #2 Date
|
||||
+ "currencyConvert(invoiceOpen(C_Invoice_ID,C_InvoicePaySchedule_ID),i.C_Currency_ID,?,?,i.C_ConversionType_ID,i.AD_Client_ID,i.AD_Org_ID)*i.MultiplierAP, " // 7 #3, #4 Converted Open
|
||||
+ "currencyConvert(invoiceDiscount" // 8 AllowedDiscount
|
||||
+ "(i.C_Invoice_ID,?,C_InvoicePaySchedule_ID),i.C_Currency_ID,?,i.DateInvoiced,i.C_ConversionType_ID,i.AD_Client_ID,i.AD_Org_ID)*i.Multiplier*i.MultiplierAP," // #5, #6
|
||||
+ "i.MultiplierAP "
|
||||
+ "FROM C_Invoice_v i" // corrected for CM/Split
|
||||
+ " INNER JOIN C_Currency c ON (i.C_Currency_ID=c.C_Currency_ID) "
|
||||
+ "WHERE i.IsPaid='N' AND i.Processed='Y'"
|
||||
+ " AND i.C_BPartner_ID=?"); // #7
|
||||
if (!isMultiCurrency)
|
||||
sql.append(" AND i.C_Currency_ID=?"); // #8
|
||||
if (m_AD_Org_ID != 0 )
|
||||
sql.append(" AND i.AD_Org_ID=" + m_AD_Org_ID);
|
||||
sql.append(" ORDER BY i.DateInvoiced, i.DocumentNo");
|
||||
log.fine("InvSQL=" + sql.toString());
|
||||
|
||||
// role security
|
||||
sql = new StringBuffer( MRole.getDefault(Env.getCtx(), false).addAccessSQL( sql.toString(), "i", MRole.SQL_FULLYQUALIFIED, MRole.SQL_RO ) );
|
||||
|
||||
try
|
||||
{
|
||||
PreparedStatement pstmt = DB.prepareStatement(sql.toString(), null);
|
||||
pstmt.setInt(1, m_C_Currency_ID);
|
||||
pstmt.setTimestamp(2, (Timestamp)date);
|
||||
pstmt.setInt(3, m_C_Currency_ID);
|
||||
pstmt.setTimestamp(4, (Timestamp)date);
|
||||
pstmt.setTimestamp(5, (Timestamp)date);
|
||||
pstmt.setInt(6, m_C_Currency_ID);
|
||||
pstmt.setInt(7, m_C_BPartner_ID);
|
||||
if (!isMultiCurrency)
|
||||
pstmt.setInt(8, m_C_Currency_ID);
|
||||
ResultSet rs = pstmt.executeQuery();
|
||||
while (rs.next())
|
||||
{
|
||||
Vector<Object> line = new Vector<Object>();
|
||||
line.add(new Boolean(false)); // 0-Selection
|
||||
line.add(rs.getTimestamp(1)); // 1-TrxDate
|
||||
KeyNamePair pp = new KeyNamePair(rs.getInt(3), rs.getString(2));
|
||||
line.add(pp); // 2-Value
|
||||
if (isMultiCurrency)
|
||||
{
|
||||
line.add(rs.getString(4)); // 3-Currency
|
||||
line.add(rs.getBigDecimal(5)); // 4-Orig Amount
|
||||
}
|
||||
line.add(rs.getBigDecimal(6)); // 3/5-ConvAmt
|
||||
BigDecimal open = rs.getBigDecimal(7);
|
||||
if (open == null) // no conversion rate
|
||||
open = Env.ZERO;
|
||||
line.add(open); // 4/6-ConvOpen
|
||||
BigDecimal discount = rs.getBigDecimal(8);
|
||||
if (discount == null) // no concersion rate
|
||||
discount = Env.ZERO;
|
||||
line.add(discount); // 5/7-ConvAllowedDisc
|
||||
line.add(Env.ZERO); // 6/8-WriteOff
|
||||
line.add(Env.ZERO); // 7/9-Applied
|
||||
line.add(open); // 8/10-OverUnder
|
||||
|
||||
// line.add(rs.getBigDecimal(9)); // 8/10-Multiplier
|
||||
// Add when open <> 0 (i.e. not if no conversion rate)
|
||||
if (Env.ZERO.compareTo(open) != 0)
|
||||
data.add(line);
|
||||
}
|
||||
rs.close();
|
||||
pstmt.close();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
log.log(Level.SEVERE, sql.toString(), e);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public Vector<String> getInvoiceColumnNames(boolean isMultiCurrency)
|
||||
{
|
||||
// Header Info
|
||||
Vector<String> columnNames = new Vector<String>();
|
||||
columnNames.add(Msg.getMsg(Env.getCtx(), "Select"));
|
||||
columnNames.add(Msg.translate(Env.getCtx(), "Date"));
|
||||
columnNames.add(Util.cleanAmp(Msg.translate(Env.getCtx(), "DocumentNo")));
|
||||
if (isMultiCurrency)
|
||||
{
|
||||
columnNames.add(Msg.getMsg(Env.getCtx(), "TrxCurrency"));
|
||||
columnNames.add(Msg.translate(Env.getCtx(), "Amount"));
|
||||
}
|
||||
columnNames.add(Msg.getMsg(Env.getCtx(), "ConvertedAmount"));
|
||||
columnNames.add(Msg.getMsg(Env.getCtx(), "OpenAmt"));
|
||||
columnNames.add(Msg.getMsg(Env.getCtx(), "Discount"));
|
||||
columnNames.add(Msg.getMsg(Env.getCtx(), "WriteOff"));
|
||||
columnNames.add(Msg.getMsg(Env.getCtx(), "AppliedAmt"));
|
||||
columnNames.add(Msg.getMsg(Env.getCtx(), "OverUnderAmt"));
|
||||
// columnNames.add(" "); // Multiplier
|
||||
|
||||
return columnNames;
|
||||
}
|
||||
|
||||
public void setInvoiceColumnClass(IMiniTable invoiceTable, boolean isMultiCurrency)
|
||||
{
|
||||
int i = 0;
|
||||
invoiceTable.setColumnClass(i++, Boolean.class, false); // 0-Selection
|
||||
invoiceTable.setColumnClass(i++, Timestamp.class, true); // 1-TrxDate
|
||||
invoiceTable.setColumnClass(i++, String.class, true); // 2-Value
|
||||
if (isMultiCurrency)
|
||||
{
|
||||
invoiceTable.setColumnClass(i++, String.class, true); // 3-Currency
|
||||
invoiceTable.setColumnClass(i++, BigDecimal.class, true); // 4-Amt
|
||||
}
|
||||
invoiceTable.setColumnClass(i++, BigDecimal.class, true); // 5-ConvAmt
|
||||
invoiceTable.setColumnClass(i++, BigDecimal.class, true); // 6-ConvAmt Open
|
||||
invoiceTable.setColumnClass(i++, BigDecimal.class, false); // 7-Conv Discount
|
||||
invoiceTable.setColumnClass(i++, BigDecimal.class, false); // 8-Conv WriteOff
|
||||
invoiceTable.setColumnClass(i++, BigDecimal.class, false); // 9-Conv OverUnder
|
||||
invoiceTable.setColumnClass(i++, BigDecimal.class, true); // 10-Conv Applied
|
||||
// invoiceTable.setColumnClass(i++, BigDecimal.class, true); // 10-Multiplier
|
||||
// Table UI
|
||||
invoiceTable.autoSize();
|
||||
}
|
||||
|
||||
public void calculate(boolean isMultiCurrency)
|
||||
{
|
||||
i_open = isMultiCurrency ? 6 : 4;
|
||||
i_discount = isMultiCurrency ? 7 : 5;
|
||||
i_writeOff = isMultiCurrency ? 8 : 6;
|
||||
i_applied = isMultiCurrency ? 9 : 7;
|
||||
i_overUnder = isMultiCurrency ? 10 : 8;
|
||||
// i_multiplier = isMultiCurrency ? 10 : 8;
|
||||
} // loadBPartner
|
||||
|
||||
public String writeOff(int row, int col, boolean isInvoice, IMiniTable payment, IMiniTable invoice, boolean isAutoWriteOff)
|
||||
{
|
||||
String msg = "";
|
||||
/**
|
||||
* Setting defaults
|
||||
*/
|
||||
if (m_calculating) // Avoid recursive calls
|
||||
return msg;
|
||||
m_calculating = true;
|
||||
|
||||
log.config("Row=" + row
|
||||
+ ", Col=" + col + ", InvoiceTable=" + isInvoice);
|
||||
|
||||
// Payments
|
||||
if (!isInvoice)
|
||||
{
|
||||
BigDecimal open = (BigDecimal)payment.getValueAt(row, i_open);
|
||||
BigDecimal applied = (BigDecimal)payment.getValueAt(row, i_payment);
|
||||
|
||||
if (col == 0)
|
||||
{
|
||||
// selection of payment row
|
||||
if (((Boolean)payment.getValueAt(row, 0)).booleanValue())
|
||||
{
|
||||
applied = open; // Open Amount
|
||||
if (totalDiff.abs().compareTo(applied.abs()) < 0 // where less is available to allocate than open
|
||||
&& totalDiff.signum() == -applied.signum() ) // and the available amount has the opposite sign
|
||||
applied = totalDiff.negate(); // reduce the amount applied to what's available
|
||||
|
||||
}
|
||||
else // de-selected
|
||||
applied = Env.ZERO;
|
||||
}
|
||||
|
||||
|
||||
if (col == i_payment)
|
||||
{
|
||||
if ( applied.signum() == -open.signum() )
|
||||
applied = applied.negate();
|
||||
if ( open.abs().compareTo( applied.abs() ) < 0 )
|
||||
applied = open;
|
||||
}
|
||||
|
||||
payment.setValueAt(applied, row, i_payment);
|
||||
}
|
||||
|
||||
// Invoice
|
||||
else
|
||||
{
|
||||
boolean selected = ((Boolean) invoice.getValueAt(row, 0)).booleanValue();
|
||||
BigDecimal open = (BigDecimal)invoice.getValueAt(row, i_open);
|
||||
BigDecimal discount = (BigDecimal)invoice.getValueAt(row, i_discount);
|
||||
BigDecimal applied = (BigDecimal)invoice.getValueAt(row, i_applied);
|
||||
BigDecimal writeOff = (BigDecimal) invoice.getValueAt(row, i_writeOff);
|
||||
BigDecimal overUnder = (BigDecimal) invoice.getValueAt(row, i_overUnder);
|
||||
int openSign = open.signum();
|
||||
|
||||
if (col == 0) //selection
|
||||
{
|
||||
// selected - set applied amount
|
||||
if ( selected )
|
||||
{
|
||||
applied = open; // Open Amount
|
||||
applied = applied.subtract(discount);
|
||||
writeOff = Env.ZERO; // to be sure
|
||||
overUnder = Env.ZERO;
|
||||
|
||||
if (totalDiff.abs().compareTo(applied.abs()) < 0 // where less is available to allocate than open
|
||||
&& totalDiff.signum() == applied.signum() ) // and the available amount has the same sign
|
||||
applied = totalDiff; // reduce the amount applied to what's available
|
||||
|
||||
if ( isAutoWriteOff )
|
||||
writeOff = open.subtract(applied.add(discount));
|
||||
else
|
||||
overUnder = open.subtract(applied.add(discount));
|
||||
}
|
||||
else // de-selected
|
||||
{
|
||||
writeOff = Env.ZERO;
|
||||
applied = Env.ZERO;
|
||||
overUnder = Env.ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
// check entered values are sensible and possibly auto write-off
|
||||
if ( selected && col != 0 )
|
||||
{
|
||||
|
||||
// values should have same sign as open except possibly over/under
|
||||
if ( discount.signum() == -openSign )
|
||||
discount = discount.negate();
|
||||
if ( writeOff.signum() == -openSign)
|
||||
writeOff = writeOff.negate();
|
||||
if ( applied.signum() == -openSign )
|
||||
applied = applied.negate();
|
||||
|
||||
// discount and write-off must be less than open amount
|
||||
if ( discount.abs().compareTo(open.abs()) > 0)
|
||||
discount = open;
|
||||
if ( writeOff.abs().compareTo(open.abs()) > 0)
|
||||
writeOff = open;
|
||||
|
||||
|
||||
/*
|
||||
* Two rules to maintain:
|
||||
*
|
||||
* 1) |writeOff + discount| < |open|
|
||||
* 2) discount + writeOff + overUnder + applied = 0
|
||||
*
|
||||
* As only one column is edited at a time and the initial position was one of compliance
|
||||
* with the rules, we only need to redistribute the increase/decrease in the edited column to
|
||||
* the others.
|
||||
*/
|
||||
BigDecimal newTotal = discount.add(writeOff).add(applied).add(overUnder); // all have same sign
|
||||
BigDecimal difference = newTotal.subtract(open);
|
||||
|
||||
// rule 2
|
||||
BigDecimal diffWOD = writeOff.add(discount).subtract(open);
|
||||
|
||||
if ( diffWOD.signum() == open.signum() ) // writeOff and discount are too large
|
||||
{
|
||||
if ( col == i_discount ) // then edit writeoff
|
||||
{
|
||||
writeOff = writeOff.subtract(diffWOD);
|
||||
}
|
||||
else // col = i_writeoff
|
||||
{
|
||||
discount = discount.subtract(diffWOD);
|
||||
}
|
||||
|
||||
difference = difference.subtract(diffWOD);
|
||||
}
|
||||
|
||||
// rule 1
|
||||
if ( col == i_applied )
|
||||
overUnder = overUnder.subtract(difference);
|
||||
else
|
||||
applied = applied.subtract(difference);
|
||||
|
||||
}
|
||||
|
||||
// Warning if write Off > 30%
|
||||
if (isAutoWriteOff && writeOff.doubleValue()/open.doubleValue() > .30)
|
||||
msg = "AllocationWriteOffWarn";
|
||||
|
||||
invoice.setValueAt(discount, row, i_discount);
|
||||
invoice.setValueAt(applied, row, i_applied);
|
||||
invoice.setValueAt(writeOff, row, i_writeOff);
|
||||
invoice.setValueAt(overUnder, row, i_overUnder);
|
||||
|
||||
invoice.repaint(); // update r/o
|
||||
}
|
||||
|
||||
m_calculating = false;
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate Allocation info
|
||||
*/
|
||||
public String calculatePayment(IMiniTable payment, boolean isMultiCurrency)
|
||||
{
|
||||
log.config("");
|
||||
|
||||
// Payment
|
||||
totalPay = new BigDecimal(0.0);
|
||||
int rows = payment.getRowCount();
|
||||
m_noPayments = 0;
|
||||
for (int i = 0; i < rows; i++)
|
||||
{
|
||||
if (((Boolean)payment.getValueAt(i, 0)).booleanValue())
|
||||
{
|
||||
Timestamp ts = (Timestamp)payment.getValueAt(i, 1);
|
||||
if ( !isMultiCurrency ) // the converted amounts are only valid for the selected date
|
||||
allocDate = TimeUtil.max(allocDate, ts);
|
||||
BigDecimal bd = (BigDecimal)payment.getValueAt(i, i_payment);
|
||||
totalPay = totalPay.add(bd); // Applied Pay
|
||||
m_noPayments++;
|
||||
log.fine("Payment_" + i + " = " + bd + " - Total=" + totalPay);
|
||||
}
|
||||
}
|
||||
return String.valueOf(m_noPayments) + " - "
|
||||
+ Msg.getMsg(Env.getCtx(), "Sum") + " " + format.format(totalPay) + " ";
|
||||
}
|
||||
|
||||
public String calculateInvoice(IMiniTable invoice, boolean isMultiCurrency)
|
||||
{
|
||||
// Invoices
|
||||
totalInv = new BigDecimal(0.0);
|
||||
int rows = invoice.getRowCount();
|
||||
m_noInvoices = 0;
|
||||
|
||||
for (int i = 0; i < rows; i++)
|
||||
{
|
||||
if (((Boolean)invoice.getValueAt(i, 0)).booleanValue())
|
||||
{
|
||||
Timestamp ts = (Timestamp)invoice.getValueAt(i, 1);
|
||||
if ( !isMultiCurrency ) // converted amounts only valid for selected date
|
||||
allocDate = TimeUtil.max(allocDate, ts);
|
||||
BigDecimal bd = (BigDecimal)invoice.getValueAt(i, i_applied);
|
||||
totalInv = totalInv.add(bd); // Applied Inv
|
||||
m_noInvoices++;
|
||||
log.fine("Invoice_" + i + " = " + bd + " - Total=" + totalPay);
|
||||
}
|
||||
}
|
||||
return String.valueOf(m_noInvoices) + " - "
|
||||
+ Msg.getMsg(Env.getCtx(), "Sum") + " " + format.format(totalInv) + " ";
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Save Data
|
||||
*/
|
||||
public String saveData(int m_WindowNo, Object date, IMiniTable payment, IMiniTable invoice, String trxName)
|
||||
{
|
||||
if (m_noInvoices + m_noPayments == 0)
|
||||
return "";
|
||||
|
||||
// fixed fields
|
||||
int AD_Client_ID = Env.getContextAsInt(Env.getCtx(), m_WindowNo, "AD_Client_ID");
|
||||
int AD_Org_ID = Env.getContextAsInt(Env.getCtx(), m_WindowNo, "AD_Org_ID");
|
||||
int C_BPartner_ID = m_C_BPartner_ID;
|
||||
int C_Order_ID = 0;
|
||||
int C_CashLine_ID = 0;
|
||||
Timestamp DateTrx = (Timestamp)date;
|
||||
int C_Currency_ID = m_C_Currency_ID; // the allocation currency
|
||||
//
|
||||
if (AD_Org_ID == 0)
|
||||
{
|
||||
//ADialog.error(m_WindowNo, this, "Org0NotAllowed", null);
|
||||
new AdempiereException("@Org0NotAllowed@");
|
||||
}
|
||||
//
|
||||
log.config("Client=" + AD_Client_ID + ", Org=" + AD_Org_ID
|
||||
+ ", BPartner=" + C_BPartner_ID + ", Date=" + DateTrx);
|
||||
|
||||
// Payment - Loop and add them to paymentList/amountList
|
||||
int pRows = payment.getRowCount();
|
||||
ArrayList<Integer> paymentList = new ArrayList<Integer>(pRows);
|
||||
ArrayList<BigDecimal> amountList = new ArrayList<BigDecimal>(pRows);
|
||||
BigDecimal paymentAppliedAmt = Env.ZERO;
|
||||
for (int i = 0; i < pRows; i++)
|
||||
{
|
||||
// Payment line is selected
|
||||
if (((Boolean)payment.getValueAt(i, 0)).booleanValue())
|
||||
{
|
||||
KeyNamePair pp = (KeyNamePair)payment.getValueAt(i, 2); // Value
|
||||
// Payment variables
|
||||
int C_Payment_ID = pp.getKey();
|
||||
paymentList.add(new Integer(C_Payment_ID));
|
||||
//
|
||||
BigDecimal PaymentAmt = (BigDecimal)payment.getValueAt(i, i_payment); // Applied Payment
|
||||
amountList.add(PaymentAmt);
|
||||
//
|
||||
paymentAppliedAmt = paymentAppliedAmt.add(PaymentAmt);
|
||||
//
|
||||
log.fine("C_Payment_ID=" + C_Payment_ID
|
||||
+ " - PaymentAmt=" + PaymentAmt); // + " * " + Multiplier + " = " + PaymentAmtAbs);
|
||||
}
|
||||
}
|
||||
log.config("Number of Payments=" + paymentList.size() + " - Total=" + paymentAppliedAmt);
|
||||
|
||||
// Invoices - Loop and generate allocations
|
||||
int iRows = invoice.getRowCount();
|
||||
|
||||
// Create Allocation
|
||||
MAllocationHdr alloc = new MAllocationHdr (Env.getCtx(), true, // manual
|
||||
DateTrx, C_Currency_ID, Env.getContext(Env.getCtx(), "#AD_User_Name"), trxName);
|
||||
alloc.setAD_Org_ID(AD_Org_ID);
|
||||
alloc.saveEx();
|
||||
// For all invoices
|
||||
int invoiceLines = 0;
|
||||
BigDecimal unmatchedApplied = Env.ZERO;
|
||||
for (int i = 0; i < iRows; i++)
|
||||
{
|
||||
// Invoice line is selected
|
||||
if (((Boolean)invoice.getValueAt(i, 0)).booleanValue())
|
||||
{
|
||||
invoiceLines++;
|
||||
KeyNamePair pp = (KeyNamePair)invoice.getValueAt(i, 2); // Value
|
||||
// Invoice variables
|
||||
int C_Invoice_ID = pp.getKey();
|
||||
BigDecimal AppliedAmt = (BigDecimal)invoice.getValueAt(i, i_applied);
|
||||
// semi-fixed fields (reset after first invoice)
|
||||
BigDecimal DiscountAmt = (BigDecimal)invoice.getValueAt(i, i_discount);
|
||||
BigDecimal WriteOffAmt = (BigDecimal)invoice.getValueAt(i, i_writeOff);
|
||||
// OverUnderAmt needs to be in Allocation Currency
|
||||
BigDecimal OverUnderAmt = ((BigDecimal)invoice.getValueAt(i, i_open))
|
||||
.subtract(AppliedAmt).subtract(DiscountAmt).subtract(WriteOffAmt);
|
||||
|
||||
log.config("Invoice #" + i + " - AppliedAmt=" + AppliedAmt);// + " -> " + AppliedAbs);
|
||||
// loop through all payments until invoice applied
|
||||
|
||||
for (int j = 0; j < paymentList.size() && AppliedAmt.signum() != 0; j++)
|
||||
{
|
||||
int C_Payment_ID = ((Integer)paymentList.get(j)).intValue();
|
||||
BigDecimal PaymentAmt = (BigDecimal)amountList.get(j);
|
||||
if (PaymentAmt.signum() == AppliedAmt.signum()) // only match same sign (otherwise appliedAmt increases)
|
||||
{ // and not zero (appliedAmt was checked earlier)
|
||||
log.config(".. with payment #" + j + ", Amt=" + PaymentAmt);
|
||||
|
||||
BigDecimal amount = AppliedAmt;
|
||||
if (amount.abs().compareTo(PaymentAmt.abs()) > 0) // if there's more open on the invoice
|
||||
amount = PaymentAmt; // than left in the payment
|
||||
|
||||
// Allocation Line
|
||||
MAllocationLine aLine = new MAllocationLine (alloc, amount,
|
||||
DiscountAmt, WriteOffAmt, OverUnderAmt);
|
||||
aLine.setDocInfo(C_BPartner_ID, C_Order_ID, C_Invoice_ID);
|
||||
aLine.setPaymentInfo(C_Payment_ID, C_CashLine_ID);
|
||||
aLine.saveEx();
|
||||
|
||||
// Apply Discounts and WriteOff only first time
|
||||
DiscountAmt = Env.ZERO;
|
||||
WriteOffAmt = Env.ZERO;
|
||||
// subtract amount from Payment/Invoice
|
||||
AppliedAmt = AppliedAmt.subtract(amount);
|
||||
PaymentAmt = PaymentAmt.subtract(amount);
|
||||
log.fine("Allocation Amount=" + amount + " - Remaining Applied=" + AppliedAmt + ", Payment=" + PaymentAmt);
|
||||
amountList.set(j, PaymentAmt); // update
|
||||
} // for all applied amounts
|
||||
} // loop through payments for invoice
|
||||
|
||||
if ( AppliedAmt.signum() == 0 && DiscountAmt.signum() == 0 && WriteOffAmt.signum() == 0)
|
||||
continue;
|
||||
else { // remainder will need to match against other invoices
|
||||
int C_Payment_ID = 0;
|
||||
|
||||
// Allocation Line
|
||||
MAllocationLine aLine = new MAllocationLine (alloc, AppliedAmt,
|
||||
DiscountAmt, WriteOffAmt, OverUnderAmt);
|
||||
aLine.setDocInfo(C_BPartner_ID, C_Order_ID, C_Invoice_ID);
|
||||
aLine.setPaymentInfo(C_Payment_ID, C_CashLine_ID);
|
||||
aLine.saveEx();
|
||||
log.fine("Allocation Amount=" + AppliedAmt);
|
||||
unmatchedApplied = unmatchedApplied.add(AppliedAmt);
|
||||
}
|
||||
} // invoice selected
|
||||
} // invoice loop
|
||||
|
||||
// check for unapplied payment amounts (eg from payment reversals)
|
||||
for (int i = 0; i < paymentList.size(); i++) {
|
||||
BigDecimal payAmt = (BigDecimal) amountList.get(i);
|
||||
if ( payAmt.signum() == 0 )
|
||||
continue;
|
||||
int C_Payment_ID = ((Integer)paymentList.get(i)).intValue();
|
||||
log.fine("Payment=" + C_Payment_ID
|
||||
+ ", Amount=" + payAmt);
|
||||
|
||||
// Allocation Line
|
||||
MAllocationLine aLine = new MAllocationLine (alloc, payAmt,
|
||||
Env.ZERO, Env.ZERO, Env.ZERO);
|
||||
aLine.setDocInfo(C_BPartner_ID, 0, 0);
|
||||
aLine.setPaymentInfo(C_Payment_ID, 0);
|
||||
aLine.saveEx();
|
||||
unmatchedApplied = unmatchedApplied.subtract(payAmt);
|
||||
}
|
||||
|
||||
if ( unmatchedApplied.signum() != 0 )
|
||||
log.log(Level.SEVERE, "Allocation not balanced -- out by " + unmatchedApplied );
|
||||
|
||||
// Should start WF
|
||||
if (alloc.get_ID() != 0)
|
||||
{
|
||||
alloc.processIt(DocAction.ACTION_Complete);
|
||||
alloc.saveEx();
|
||||
}
|
||||
|
||||
// Test/Set IsPaid for Invoice - requires that allocation is posted
|
||||
for (int i = 0; i < iRows; i++)
|
||||
{
|
||||
// Invoice line is selected
|
||||
if (((Boolean)invoice.getValueAt(i, 0)).booleanValue())
|
||||
{
|
||||
KeyNamePair pp = (KeyNamePair)invoice.getValueAt(i, 2); // Value
|
||||
// Invoice variables
|
||||
int C_Invoice_ID = pp.getKey();
|
||||
String sql = "SELECT invoiceOpen(C_Invoice_ID, 0) "
|
||||
+ "FROM C_Invoice WHERE C_Invoice_ID=?";
|
||||
BigDecimal open = DB.getSQLValueBD(trxName, sql, C_Invoice_ID);
|
||||
if (open != null && open.signum() == 0) {
|
||||
sql = "UPDATE C_Invoice SET IsPaid='Y' "
|
||||
+ "WHERE C_Invoice_ID=" + C_Invoice_ID;
|
||||
int no = DB.executeUpdate(sql, trxName);
|
||||
log.config("Invoice #" + i + " is paid - updated=" + no);
|
||||
} else
|
||||
log.config("Invoice #" + i + " is not paid - " + open);
|
||||
}
|
||||
}
|
||||
// Test/Set Payment is fully allocated
|
||||
for (int i = 0; i < paymentList.size(); i++)
|
||||
{
|
||||
int C_Payment_ID = ((Integer)paymentList.get(i)).intValue();
|
||||
MPayment pay = new MPayment (Env.getCtx(), C_Payment_ID, trxName);
|
||||
if (pay.testAllocation())
|
||||
pay.saveEx();
|
||||
log.config("Payment #" + i + (pay.isAllocated() ? " not" : " is")
|
||||
+ " fully allocated");
|
||||
}
|
||||
paymentList.clear();
|
||||
amountList.clear();
|
||||
|
||||
return alloc.getDocumentNo();
|
||||
} // saveData
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/******************************************************************************
|
||||
* Product: Adempiere ERP & CRM Smart Business Solution *
|
||||
* Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. *
|
||||
* Copyright (C) 2009 Low Heng Sin *
|
||||
* Copyright (C) 2009 Idalica Corporation *
|
||||
* 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 *
|
||||
|
@ -10,9 +10,6 @@
|
|||
* 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.apps.form;
|
||||
|
||||
|
@ -26,12 +23,6 @@ import java.awt.event.ActionListener;
|
|||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.VetoableChangeListener;
|
||||
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.util.ArrayList;
|
||||
import java.util.Vector;
|
||||
import java.util.logging.Level;
|
||||
|
||||
|
@ -45,49 +36,25 @@ import javax.swing.SwingConstants;
|
|||
import javax.swing.event.TableModelEvent;
|
||||
import javax.swing.event.TableModelListener;
|
||||
import javax.swing.table.DefaultTableModel;
|
||||
import javax.swing.table.TableModel;
|
||||
|
||||
import org.adempiere.exceptions.AdempiereException;
|
||||
import org.adempiere.plaf.AdempierePLAF;
|
||||
import org.compiere.apps.ADialog;
|
||||
import org.compiere.apps.StatusBar;
|
||||
import org.compiere.grid.ed.VDate;
|
||||
import org.compiere.grid.ed.VLookup;
|
||||
import org.compiere.minigrid.MiniTable;
|
||||
import org.compiere.model.MAllocationHdr;
|
||||
import org.compiere.model.MAllocationLine;
|
||||
import org.compiere.model.MInvoice;
|
||||
import org.compiere.model.MLookup;
|
||||
import org.compiere.model.MLookupFactory;
|
||||
import org.compiere.model.MPayment;
|
||||
import org.compiere.model.MRole;
|
||||
import org.compiere.plaf.CompiereColor;
|
||||
import org.compiere.process.DocAction;
|
||||
import org.compiere.swing.CPanel;
|
||||
import org.compiere.swing.CTextField;
|
||||
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;
|
||||
import org.compiere.util.TimeUtil;
|
||||
import org.compiere.util.Trx;
|
||||
import org.compiere.util.TrxRunnable;
|
||||
import org.compiere.util.Util;
|
||||
|
||||
/**
|
||||
* Allocation Form
|
||||
*
|
||||
* @author Jorg Janke
|
||||
* @author Victor Perez, e-Evolucion
|
||||
* <li> [2792529] lockTrx when you try created a Payment Allocation
|
||||
* <li> https://sourceforge.net/tracker/?func=detail&aid=2792529&group_id=176962&atid=879332
|
||||
* @version $Id: VAllocation.java,v 1.2 2006/07/30 00:51:28 jjanke Exp $
|
||||
*
|
||||
* Contributor : Fabian Aguilar - OFBConsulting - Multiallocation
|
||||
*/
|
||||
public class VAllocation extends CPanel
|
||||
public class VAllocation extends Allocation
|
||||
implements FormPanel, ActionListener, TableModelListener, VetoableChangeListener
|
||||
{
|
||||
|
||||
|
@ -95,6 +62,8 @@ public class VAllocation extends CPanel
|
|||
*
|
||||
*/
|
||||
private static final long serialVersionUID = -5322824600164192235L;
|
||||
|
||||
private CPanel panel = new CPanel();
|
||||
|
||||
/**
|
||||
* Initialize Panel
|
||||
|
@ -106,11 +75,9 @@ public class VAllocation extends CPanel
|
|||
m_WindowNo = WindowNo;
|
||||
m_frame = frame;
|
||||
Env.setContext(Env.getCtx(), m_WindowNo, "IsSOTrx", "Y"); // defaults to no
|
||||
m_C_Currency_ID = Env.getContextAsInt(Env.getCtx(), "$C_Currency_ID"); // default
|
||||
//
|
||||
log.info("Currency=" + m_C_Currency_ID);
|
||||
try
|
||||
{
|
||||
super.dynInit();
|
||||
dynInit();
|
||||
jbInit();
|
||||
calculate();
|
||||
|
@ -127,28 +94,7 @@ public class VAllocation extends CPanel
|
|||
private int m_WindowNo = 0;
|
||||
/** FormFrame */
|
||||
private FormFrame m_frame;
|
||||
/** Logger */
|
||||
private static CLogger log = CLogger.getCLogger(VAllocation.class);
|
||||
|
||||
private boolean m_calculating = false;
|
||||
private int m_C_Currency_ID = 0;
|
||||
private int m_C_BPartner_ID = 0;
|
||||
private int m_noInvoices = 0;
|
||||
private int m_noPayments = 0;
|
||||
private BigDecimal totalInv = new BigDecimal(0.0);
|
||||
private BigDecimal totalPay = new BigDecimal(0.0);
|
||||
private BigDecimal totalDiff = new BigDecimal(0.0);
|
||||
|
||||
// Index changed if multi-currency
|
||||
private int i_payment = 7;
|
||||
//
|
||||
private int i_open = 6;
|
||||
private int i_discount = 7;
|
||||
private int i_writeOff = 8;
|
||||
private int i_applied = 9;
|
||||
private int i_overUnder = 10;
|
||||
// private int i_multiplier = 10;
|
||||
//
|
||||
private CPanel mainPanel = new CPanel();
|
||||
private BorderLayout mainLayout = new BorderLayout();
|
||||
private CPanel parameterPanel = new CPanel();
|
||||
|
@ -181,19 +127,16 @@ public class VAllocation extends CPanel
|
|||
private JLabel dateLabel = new JLabel();
|
||||
private VDate dateField = new VDate();
|
||||
private JCheckBox autoWriteOff = new JCheckBox();
|
||||
private int m_AD_Org_ID = 0;
|
||||
private JLabel organizationLabel = new JLabel();
|
||||
private VLookup organizationPick = null;
|
||||
|
||||
private ArrayList<Integer> m_bpartnerCheck = new ArrayList<Integer>();
|
||||
|
||||
/**
|
||||
* Static Init
|
||||
* @throws Exception
|
||||
*/
|
||||
private void jbInit() throws Exception
|
||||
{
|
||||
CompiereColor.setBackground(this);
|
||||
CompiereColor.setBackground(panel);
|
||||
//
|
||||
mainPanel.setLayout(mainLayout);
|
||||
dateLabel.setText(Msg.getMsg(Env.getCtx(), "Date"));
|
||||
|
@ -300,7 +243,7 @@ public class VAllocation extends CPanel
|
|||
* Dynamic Init (prepare dynamic fields)
|
||||
* @throws Exception if Lookups cannot be initialized
|
||||
*/
|
||||
private void dynInit() throws Exception
|
||||
public void dynInit() throws Exception
|
||||
{
|
||||
// Currency
|
||||
int AD_Column_ID = 3505; // C_Invoice.C_Currency_ID
|
||||
|
@ -315,8 +258,6 @@ public class VAllocation extends CPanel
|
|||
organizationPick = new VLookup("AD_Org_ID", true, false, true, lookupOrg);
|
||||
organizationPick.setValue(Env.getAD_Org_ID(Env.getCtx()));
|
||||
organizationPick.addVetoableChangeListener(this);
|
||||
|
||||
m_AD_Org_ID = Env.getAD_Org_ID(Env.getCtx());
|
||||
|
||||
// BPartner
|
||||
AD_Column_ID = 3499; // C_Invoice.C_BPartner_ID
|
||||
|
@ -332,289 +273,6 @@ public class VAllocation extends CPanel
|
|||
dateField.setValue(Env.getContextAsDate(Env.getCtx(), "#Date"));
|
||||
dateField.addVetoableChangeListener(this);
|
||||
} // dynInit
|
||||
|
||||
/**
|
||||
* Load Business Partner Info
|
||||
* - Payments
|
||||
* - Invoices
|
||||
*/
|
||||
private void loadBPartner ()
|
||||
{
|
||||
log.config("BPartner=" + m_C_BPartner_ID + ", Cur=" + m_C_Currency_ID);
|
||||
// Need to have both values
|
||||
if (m_C_BPartner_ID == 0 || m_C_Currency_ID == 0)
|
||||
return;
|
||||
|
||||
// Async BPartner Test
|
||||
Integer key = new Integer(m_C_BPartner_ID);
|
||||
if (!m_bpartnerCheck.contains(key))
|
||||
{
|
||||
new Thread()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
MPayment.setIsAllocated (Env.getCtx(), m_C_BPartner_ID, null);
|
||||
MInvoice.setIsPaid (Env.getCtx(), m_C_BPartner_ID, null);
|
||||
}
|
||||
}.start();
|
||||
m_bpartnerCheck.add(key);
|
||||
}
|
||||
|
||||
/********************************
|
||||
* Load unallocated Payments
|
||||
* 1-TrxDate, 2-DocumentNo, (3-Currency, 4-PayAmt,)
|
||||
* 5-ConvAmt, 6-ConvOpen, 7-Allocated
|
||||
*/
|
||||
Vector<Vector<Object>> data = new Vector<Vector<Object>>();
|
||||
StringBuffer sql = new StringBuffer("SELECT p.DateTrx,p.DocumentNo,p.C_Payment_ID," // 1..3
|
||||
+ "c.ISO_Code,p.PayAmt," // 4..5
|
||||
+ "currencyConvert(p.PayAmt,p.C_Currency_ID,?,?,p.C_ConversionType_ID,p.AD_Client_ID,p.AD_Org_ID),"// 6 #1, #2
|
||||
+ "currencyConvert(paymentAvailable(C_Payment_ID),p.C_Currency_ID,?,?,p.C_ConversionType_ID,p.AD_Client_ID,p.AD_Org_ID)," // 7 #3, #4
|
||||
+ "p.MultiplierAP "
|
||||
+ "FROM C_Payment_v p" // Corrected for AP/AR
|
||||
+ " INNER JOIN C_Currency c ON (p.C_Currency_ID=c.C_Currency_ID) "
|
||||
+ "WHERE p.IsAllocated='N' AND p.Processed='Y'"
|
||||
+ " AND p.C_Charge_ID IS NULL" // Prepayments OK
|
||||
+ " AND p.C_BPartner_ID=?"); // #5
|
||||
if (!multiCurrency.isSelected())
|
||||
sql.append(" AND p.C_Currency_ID=?"); // #6
|
||||
if (m_AD_Org_ID != 0 )
|
||||
sql.append(" AND p.AD_Org_ID=" + m_AD_Org_ID);
|
||||
sql.append(" ORDER BY p.DateTrx,p.DocumentNo");
|
||||
|
||||
// role security
|
||||
sql = new StringBuffer( MRole.getDefault(Env.getCtx(), false).addAccessSQL( sql.toString(), "p", MRole.SQL_FULLYQUALIFIED, MRole.SQL_RO ) );
|
||||
|
||||
log.fine("PaySQL=" + sql.toString());
|
||||
try
|
||||
{
|
||||
PreparedStatement pstmt = DB.prepareStatement(sql.toString(), null);
|
||||
pstmt.setInt(1, m_C_Currency_ID);
|
||||
pstmt.setTimestamp(2, (Timestamp)dateField.getValue());
|
||||
pstmt.setInt(3, m_C_Currency_ID);
|
||||
pstmt.setTimestamp(4, (Timestamp)dateField.getValue());
|
||||
pstmt.setInt(5, m_C_BPartner_ID);
|
||||
if (!multiCurrency.isSelected())
|
||||
pstmt.setInt(6, m_C_Currency_ID);
|
||||
ResultSet rs = pstmt.executeQuery();
|
||||
while (rs.next())
|
||||
{
|
||||
Vector<Object> line = new Vector<Object>();
|
||||
line.add(new Boolean(false)); // 0-Selection
|
||||
line.add(rs.getTimestamp(1)); // 1-TrxDate
|
||||
KeyNamePair pp = new KeyNamePair(rs.getInt(3), rs.getString(2));
|
||||
line.add(pp); // 2-DocumentNo
|
||||
if (multiCurrency.isSelected())
|
||||
{
|
||||
line.add(rs.getString(4)); // 3-Currency
|
||||
line.add(rs.getBigDecimal(5)); // 4-PayAmt
|
||||
}
|
||||
line.add(rs.getBigDecimal(6)); // 3/5-ConvAmt
|
||||
BigDecimal available = rs.getBigDecimal(7);
|
||||
if (available == null || available.signum() == 0) // nothing available
|
||||
continue;
|
||||
line.add(available); // 4/6-ConvOpen/Available
|
||||
line.add(Env.ZERO); // 5/7-Payment
|
||||
// line.add(rs.getBigDecimal(8)); // 6/8-Multiplier
|
||||
//
|
||||
data.add(line);
|
||||
}
|
||||
rs.close();
|
||||
pstmt.close();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
log.log(Level.SEVERE, sql.toString(), e);
|
||||
}
|
||||
// Remove previous listeners
|
||||
paymentTable.getModel().removeTableModelListener(this);
|
||||
// Header Info
|
||||
Vector<String> columnNames = new Vector<String>();
|
||||
columnNames.add(Msg.getMsg(Env.getCtx(), "Select"));
|
||||
columnNames.add(Msg.translate(Env.getCtx(), "Date"));
|
||||
columnNames.add(Util.cleanAmp(Msg.translate(Env.getCtx(), "DocumentNo")));
|
||||
if (multiCurrency.isSelected())
|
||||
{
|
||||
columnNames.add(Msg.getMsg(Env.getCtx(), "TrxCurrency"));
|
||||
columnNames.add(Msg.translate(Env.getCtx(), "Amount"));
|
||||
}
|
||||
columnNames.add(Msg.getMsg(Env.getCtx(), "ConvertedAmount"));
|
||||
columnNames.add(Msg.getMsg(Env.getCtx(), "OpenAmt"));
|
||||
columnNames.add(Msg.getMsg(Env.getCtx(), "AppliedAmt"));
|
||||
// columnNames.add(" "); // Multiplier
|
||||
|
||||
// Set Model
|
||||
DefaultTableModel modelP = new DefaultTableModel(data, columnNames);
|
||||
modelP.addTableModelListener(this);
|
||||
paymentTable.setModel(modelP);
|
||||
//
|
||||
int i = 0;
|
||||
paymentTable.setColumnClass(i++, Boolean.class, false); // 0-Selection
|
||||
paymentTable.setColumnClass(i++, Timestamp.class, true); // 1-TrxDate
|
||||
paymentTable.setColumnClass(i++, String.class, true); // 2-Value
|
||||
if (multiCurrency.isSelected())
|
||||
{
|
||||
paymentTable.setColumnClass(i++, String.class, true); // 3-Currency
|
||||
paymentTable.setColumnClass(i++, BigDecimal.class, true); // 4-PayAmt
|
||||
}
|
||||
paymentTable.setColumnClass(i++, BigDecimal.class, true); // 5-ConvAmt
|
||||
paymentTable.setColumnClass(i++, BigDecimal.class, true); // 6-ConvOpen
|
||||
paymentTable.setColumnClass(i++, BigDecimal.class, false); // 7-Allocated
|
||||
// paymentTable.setColumnClass(i++, BigDecimal.class, true); // 8-Multiplier
|
||||
|
||||
//
|
||||
i_payment = multiCurrency.isSelected() ? 7 : 5;
|
||||
|
||||
|
||||
// Table UI
|
||||
paymentTable.autoSize();
|
||||
|
||||
|
||||
/********************************
|
||||
* Load unpaid Invoices
|
||||
* 1-TrxDate, 2-Value, (3-Currency, 4-InvAmt,)
|
||||
* 5-ConvAmt, 6-ConvOpen, 7-ConvDisc, 8-WriteOff, 9-Applied
|
||||
*
|
||||
SELECT i.DateInvoiced,i.DocumentNo,i.C_Invoice_ID,c.ISO_Code,
|
||||
i.GrandTotal*i.MultiplierAP "GrandTotal",
|
||||
currencyConvert(i.GrandTotal*i.MultiplierAP,i.C_Currency_ID,i.C_Currency_ID,i.DateInvoiced,i.C_ConversionType_ID,i.AD_Client_ID,i.AD_Org_ID) "GrandTotal $",
|
||||
invoiceOpen(C_Invoice_ID,C_InvoicePaySchedule_ID) "Open",
|
||||
currencyConvert(invoiceOpen(C_Invoice_ID,C_InvoicePaySchedule_ID),i.C_Currency_ID,i.C_Currency_ID,i.DateInvoiced,i.C_ConversionType_ID,i.AD_Client_ID,i.AD_Org_ID)*i.MultiplierAP "Open $",
|
||||
invoiceDiscount(i.C_Invoice_ID,SysDate,C_InvoicePaySchedule_ID) "Discount",
|
||||
currencyConvert(invoiceDiscount(i.C_Invoice_ID,SysDate,C_InvoicePaySchedule_ID),i.C_Currency_ID,i.C_Currency_ID,i.DateInvoiced,i.C_ConversionType_ID,i.AD_Client_ID,i.AD_Org_ID)*i.Multiplier*i.MultiplierAP "Discount $",
|
||||
i.MultiplierAP, i.Multiplier
|
||||
FROM C_Invoice_v i INNER JOIN C_Currency c ON (i.C_Currency_ID=c.C_Currency_ID)
|
||||
WHERE -- i.IsPaid='N' AND i.Processed='Y' AND i.C_BPartner_ID=1000001
|
||||
*/
|
||||
data = new Vector<Vector<Object>>();
|
||||
sql = new StringBuffer("SELECT i.DateInvoiced,i.DocumentNo,i.C_Invoice_ID," // 1..3
|
||||
+ "c.ISO_Code,i.GrandTotal*i.MultiplierAP, " // 4..5 Orig Currency
|
||||
+ "currencyConvert(i.GrandTotal*i.MultiplierAP,i.C_Currency_ID,?,?,i.C_ConversionType_ID,i.AD_Client_ID,i.AD_Org_ID), " // 6 #1 Converted, #2 Date
|
||||
+ "currencyConvert(invoiceOpen(C_Invoice_ID,C_InvoicePaySchedule_ID),i.C_Currency_ID,?,?,i.C_ConversionType_ID,i.AD_Client_ID,i.AD_Org_ID)*i.MultiplierAP, " // 7 #3, #4 Converted Open
|
||||
+ "currencyConvert(invoiceDiscount" // 8 AllowedDiscount
|
||||
+ "(i.C_Invoice_ID,?,C_InvoicePaySchedule_ID),i.C_Currency_ID,?,i.DateInvoiced,i.C_ConversionType_ID,i.AD_Client_ID,i.AD_Org_ID)*i.Multiplier*i.MultiplierAP," // #5, #6
|
||||
+ "i.MultiplierAP "
|
||||
+ "FROM C_Invoice_v i" // corrected for CM/Split
|
||||
+ " INNER JOIN C_Currency c ON (i.C_Currency_ID=c.C_Currency_ID) "
|
||||
+ "WHERE i.IsPaid='N' AND i.Processed='Y'"
|
||||
+ " AND i.C_BPartner_ID=?"); // #7
|
||||
if (!multiCurrency.isSelected())
|
||||
sql.append(" AND i.C_Currency_ID=?"); // #8
|
||||
if (m_AD_Org_ID != 0 )
|
||||
sql.append(" AND i.AD_Org_ID=" + m_AD_Org_ID);
|
||||
sql.append(" ORDER BY i.DateInvoiced, i.DocumentNo");
|
||||
log.fine("InvSQL=" + sql.toString());
|
||||
|
||||
// role security
|
||||
sql = new StringBuffer( MRole.getDefault(Env.getCtx(), false).addAccessSQL( sql.toString(), "i", MRole.SQL_FULLYQUALIFIED, MRole.SQL_RO ) );
|
||||
|
||||
try
|
||||
{
|
||||
PreparedStatement pstmt = DB.prepareStatement(sql.toString(), null);
|
||||
pstmt.setInt(1, m_C_Currency_ID);
|
||||
pstmt.setTimestamp(2, (Timestamp)dateField.getValue());
|
||||
pstmt.setInt(3, m_C_Currency_ID);
|
||||
pstmt.setTimestamp(4, (Timestamp)dateField.getValue());
|
||||
pstmt.setTimestamp(5, (Timestamp)dateField.getValue());
|
||||
pstmt.setInt(6, m_C_Currency_ID);
|
||||
pstmt.setInt(7, m_C_BPartner_ID);
|
||||
if (!multiCurrency.isSelected())
|
||||
pstmt.setInt(8, m_C_Currency_ID);
|
||||
ResultSet rs = pstmt.executeQuery();
|
||||
while (rs.next())
|
||||
{
|
||||
Vector<Object> line = new Vector<Object>();
|
||||
line.add(new Boolean(false)); // 0-Selection
|
||||
line.add(rs.getTimestamp(1)); // 1-TrxDate
|
||||
KeyNamePair pp = new KeyNamePair(rs.getInt(3), rs.getString(2));
|
||||
line.add(pp); // 2-Value
|
||||
if (multiCurrency.isSelected())
|
||||
{
|
||||
line.add(rs.getString(4)); // 3-Currency
|
||||
line.add(rs.getBigDecimal(5)); // 4-Orig Amount
|
||||
}
|
||||
line.add(rs.getBigDecimal(6)); // 3/5-ConvAmt
|
||||
BigDecimal open = rs.getBigDecimal(7);
|
||||
if (open == null) // no conversion rate
|
||||
open = Env.ZERO;
|
||||
line.add(open); // 4/6-ConvOpen
|
||||
BigDecimal discount = rs.getBigDecimal(8);
|
||||
if (discount == null) // no concersion rate
|
||||
discount = Env.ZERO;
|
||||
line.add(discount); // 5/7-ConvAllowedDisc
|
||||
line.add(Env.ZERO); // 6/8-WriteOff
|
||||
line.add(Env.ZERO); // 7/9-Applied
|
||||
line.add(open); // 8/10-OverUnder
|
||||
|
||||
// line.add(rs.getBigDecimal(9)); // 8/10-Multiplier
|
||||
// Add when open <> 0 (i.e. not if no conversion rate)
|
||||
if (Env.ZERO.compareTo(open) != 0)
|
||||
data.add(line);
|
||||
}
|
||||
rs.close();
|
||||
pstmt.close();
|
||||
}
|
||||
catch (SQLException e)
|
||||
{
|
||||
log.log(Level.SEVERE, sql.toString(), e);
|
||||
}
|
||||
|
||||
// Remove previous listeners
|
||||
invoiceTable.getModel().removeTableModelListener(this);
|
||||
// Header Info
|
||||
columnNames = new Vector<String>();
|
||||
columnNames.add(Msg.getMsg(Env.getCtx(), "Select"));
|
||||
columnNames.add(Msg.translate(Env.getCtx(), "Date"));
|
||||
columnNames.add(Util.cleanAmp(Msg.translate(Env.getCtx(), "DocumentNo")));
|
||||
if (multiCurrency.isSelected())
|
||||
{
|
||||
columnNames.add(Msg.getMsg(Env.getCtx(), "TrxCurrency"));
|
||||
columnNames.add(Msg.translate(Env.getCtx(), "Amount"));
|
||||
}
|
||||
columnNames.add(Msg.getMsg(Env.getCtx(), "ConvertedAmount"));
|
||||
columnNames.add(Msg.getMsg(Env.getCtx(), "OpenAmt"));
|
||||
columnNames.add(Msg.getMsg(Env.getCtx(), "Discount"));
|
||||
columnNames.add(Msg.getMsg(Env.getCtx(), "WriteOff"));
|
||||
columnNames.add(Msg.getMsg(Env.getCtx(), "AppliedAmt"));
|
||||
columnNames.add(Msg.getMsg(Env.getCtx(), "OverUnderAmt"));
|
||||
// columnNames.add(" "); // Multiplier
|
||||
|
||||
// Set Model
|
||||
DefaultTableModel modelI = new DefaultTableModel(data, columnNames);
|
||||
modelI.addTableModelListener(this);
|
||||
invoiceTable.setModel(modelI);
|
||||
//
|
||||
i = 0;
|
||||
invoiceTable.setColumnClass(i++, Boolean.class, false); // 0-Selection
|
||||
invoiceTable.setColumnClass(i++, Timestamp.class, true); // 1-TrxDate
|
||||
invoiceTable.setColumnClass(i++, String.class, true); // 2-Value
|
||||
if (multiCurrency.isSelected())
|
||||
{
|
||||
invoiceTable.setColumnClass(i++, String.class, true); // 3-Currency
|
||||
invoiceTable.setColumnClass(i++, BigDecimal.class, true); // 4-Amt
|
||||
}
|
||||
invoiceTable.setColumnClass(i++, BigDecimal.class, true); // 5-ConvAmt
|
||||
invoiceTable.setColumnClass(i++, BigDecimal.class, true); // 6-ConvAmt Open
|
||||
invoiceTable.setColumnClass(i++, BigDecimal.class, false); // 7-Conv Discount
|
||||
invoiceTable.setColumnClass(i++, BigDecimal.class, false); // 8-Conv WriteOff
|
||||
invoiceTable.setColumnClass(i++, BigDecimal.class, false); // 9-Conv OverUnder
|
||||
invoiceTable.setColumnClass(i++, BigDecimal.class, true); // 10-Conv Applied
|
||||
// invoiceTable.setColumnClass(i++, BigDecimal.class, true); // 10-Multiplier
|
||||
// Table UI
|
||||
invoiceTable.autoSize();
|
||||
|
||||
i_open = multiCurrency.isSelected() ? 6 : 4;
|
||||
i_discount = multiCurrency.isSelected() ? 7 : 5;
|
||||
i_writeOff = multiCurrency.isSelected() ? 8 : 6;
|
||||
i_applied = multiCurrency.isSelected() ? 9 : 7;
|
||||
i_overUnder = multiCurrency.isSelected() ? 10 : 8;
|
||||
// i_multiplier = multiCurrency.isSelected() ? 10 : 8;
|
||||
|
||||
// Calculate Totals
|
||||
calculate();
|
||||
} // loadBPartner
|
||||
|
||||
|
||||
|
||||
/**************************************************************************
|
||||
* Action Listener.
|
||||
|
@ -652,239 +310,18 @@ public class VAllocation extends CPanel
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Setting defaults
|
||||
*/
|
||||
if (m_calculating) // Avoid recursive calls
|
||||
return;
|
||||
m_calculating = true;
|
||||
int row = e.getFirstRow();
|
||||
int col = e.getColumn();
|
||||
boolean isInvoice = (e.getSource().equals(invoiceTable.getModel()));
|
||||
log.config("Row=" + row
|
||||
+ ", Col=" + col + ", InvoiceTable=" + isInvoice);
|
||||
|
||||
// Payments
|
||||
if (!isInvoice)
|
||||
{
|
||||
TableModel payment = paymentTable.getModel();
|
||||
|
||||
BigDecimal open = (BigDecimal)payment.getValueAt(row, i_open);
|
||||
BigDecimal applied = (BigDecimal)payment.getValueAt(row, i_payment);
|
||||
|
||||
if (col == 0)
|
||||
{
|
||||
// selection of payment row
|
||||
if (((Boolean)payment.getValueAt(row, 0)).booleanValue())
|
||||
{
|
||||
applied = open; // Open Amount
|
||||
if (totalDiff.abs().compareTo(applied.abs()) < 0 // where less is available to allocate than open
|
||||
&& totalDiff.signum() == -applied.signum() ) // and the available amount has the opposite sign
|
||||
applied = totalDiff.negate(); // reduce the amount applied to what's available
|
||||
|
||||
}
|
||||
else // de-selected
|
||||
applied = Env.ZERO;
|
||||
}
|
||||
|
||||
|
||||
if (col == i_payment)
|
||||
{
|
||||
if ( applied.signum() == -open.signum() )
|
||||
applied = applied.negate();
|
||||
if ( open.abs().compareTo( applied.abs() ) < 0 )
|
||||
applied = open;
|
||||
}
|
||||
|
||||
payment.setValueAt(applied, row, i_payment);
|
||||
}
|
||||
|
||||
// Invoice
|
||||
else
|
||||
{
|
||||
TableModel invoice = invoiceTable.getModel();
|
||||
boolean selected = ((Boolean) invoice.getValueAt(row, 0)).booleanValue();
|
||||
BigDecimal open = (BigDecimal)invoice.getValueAt(row, i_open);
|
||||
BigDecimal discount = (BigDecimal)invoice.getValueAt(row, i_discount);
|
||||
BigDecimal applied = (BigDecimal)invoice.getValueAt(row, i_applied);
|
||||
BigDecimal writeOff = (BigDecimal) invoice.getValueAt(row, i_writeOff);
|
||||
BigDecimal overUnder = (BigDecimal) invoice.getValueAt(row, i_overUnder);
|
||||
int openSign = open.signum();
|
||||
|
||||
if (col == 0) //selection
|
||||
{
|
||||
// selected - set applied amount
|
||||
if ( selected )
|
||||
{
|
||||
applied = open; // Open Amount
|
||||
applied = applied.subtract(discount);
|
||||
writeOff = Env.ZERO; // to be sure
|
||||
overUnder = Env.ZERO;
|
||||
|
||||
if (totalDiff.abs().compareTo(applied.abs()) < 0 // where less is available to allocate than open
|
||||
&& totalDiff.signum() == applied.signum() ) // and the available amount has the same sign
|
||||
applied = totalDiff; // reduce the amount applied to what's available
|
||||
|
||||
if ( autoWriteOff.isSelected() )
|
||||
writeOff = open.subtract(applied.add(discount));
|
||||
else
|
||||
overUnder = open.subtract(applied.add(discount));
|
||||
}
|
||||
else // de-selected
|
||||
{
|
||||
writeOff = Env.ZERO;
|
||||
applied = Env.ZERO;
|
||||
overUnder = Env.ZERO;
|
||||
}
|
||||
}
|
||||
|
||||
// check entered values are sensible and possibly auto write-off
|
||||
if ( selected && col != 0 )
|
||||
{
|
||||
|
||||
// values should have same sign as open except possibly over/under
|
||||
if ( discount.signum() == -openSign )
|
||||
discount = discount.negate();
|
||||
if ( writeOff.signum() == -openSign)
|
||||
writeOff = writeOff.negate();
|
||||
if ( applied.signum() == -openSign )
|
||||
applied = applied.negate();
|
||||
|
||||
// discount and write-off must be less than open amount
|
||||
if ( discount.abs().compareTo(open.abs()) > 0)
|
||||
discount = open;
|
||||
if ( writeOff.abs().compareTo(open.abs()) > 0)
|
||||
writeOff = open;
|
||||
|
||||
|
||||
/*
|
||||
* Two rules to maintain:
|
||||
*
|
||||
* 1) |writeOff + discount| < |open|
|
||||
* 2) discount + writeOff + overUnder + applied = 0
|
||||
*
|
||||
* As only one column is edited at a time and the initial position was one of compliance
|
||||
* with the rules, we only need to redistribute the increase/decrease in the edited column to
|
||||
* the others.
|
||||
*/
|
||||
BigDecimal newTotal = discount.add(writeOff).add(applied).add(overUnder); // all have same sign
|
||||
BigDecimal difference = newTotal.subtract(open);
|
||||
|
||||
// rule 2
|
||||
BigDecimal diffWOD = writeOff.add(discount).subtract(open);
|
||||
|
||||
if ( diffWOD.signum() == open.signum() ) // writeOff and discount are too large
|
||||
{
|
||||
if ( col == i_discount ) // then edit writeoff
|
||||
{
|
||||
writeOff = writeOff.subtract(diffWOD);
|
||||
}
|
||||
else // col = i_writeoff
|
||||
{
|
||||
discount = discount.subtract(diffWOD);
|
||||
}
|
||||
|
||||
difference = difference.subtract(diffWOD);
|
||||
}
|
||||
|
||||
// rule 1
|
||||
if ( col == i_applied )
|
||||
overUnder = overUnder.subtract(difference);
|
||||
else
|
||||
applied = applied.subtract(difference);
|
||||
|
||||
}
|
||||
|
||||
// Warning if write Off > 30%
|
||||
if (autoWriteOff.isSelected() && writeOff.doubleValue()/open.doubleValue() > .30)
|
||||
ADialog.warn(m_WindowNo, this, "AllocationWriteOffWarn");
|
||||
|
||||
|
||||
invoice.setValueAt(discount, row, i_discount);
|
||||
invoice.setValueAt(applied, row, i_applied);
|
||||
invoice.setValueAt(writeOff, row, i_writeOff);
|
||||
invoice.setValueAt(overUnder, row, i_overUnder);
|
||||
|
||||
invoiceTable.repaint(); // update r/o
|
||||
|
||||
|
||||
boolean isAutoWriteOff = autoWriteOff.isSelected();
|
||||
|
||||
String msg = writeOff(row, col, isInvoice, paymentTable, invoiceTable, isAutoWriteOff);
|
||||
if(msg != null && msg.length() > 0)
|
||||
ADialog.warn(m_WindowNo, panel, "AllocationWriteOffWarn");
|
||||
|
||||
}
|
||||
|
||||
m_calculating = false;
|
||||
calculate();
|
||||
} // tableChanged
|
||||
|
||||
/**
|
||||
* Calculate Allocation info
|
||||
*/
|
||||
private void calculate ()
|
||||
{
|
||||
log.config("");
|
||||
//
|
||||
DecimalFormat format = DisplayType.getNumberFormat(DisplayType.Amount);
|
||||
Timestamp allocDate = null;
|
||||
|
||||
// Payment
|
||||
TableModel payment = paymentTable.getModel();
|
||||
totalPay = new BigDecimal(0.0);
|
||||
int rows = payment.getRowCount();
|
||||
m_noPayments = 0;
|
||||
for (int i = 0; i < rows; i++)
|
||||
{
|
||||
if (((Boolean)payment.getValueAt(i, 0)).booleanValue())
|
||||
{
|
||||
Timestamp ts = (Timestamp)payment.getValueAt(i, 1);
|
||||
if ( !multiCurrency.isSelected() ) // the converted amounts are only valid for the selected date
|
||||
allocDate = TimeUtil.max(allocDate, ts);
|
||||
BigDecimal bd = (BigDecimal)payment.getValueAt(i, i_payment);
|
||||
totalPay = totalPay.add(bd); // Applied Pay
|
||||
m_noPayments++;
|
||||
log.fine("Payment_" + i + " = " + bd + " - Total=" + totalPay);
|
||||
}
|
||||
}
|
||||
paymentInfo.setText(String.valueOf(m_noPayments) + " - "
|
||||
+ Msg.getMsg(Env.getCtx(), "Sum") + " " + format.format(totalPay) + " ");
|
||||
|
||||
// Invoices
|
||||
TableModel invoice = invoiceTable.getModel();
|
||||
totalInv = new BigDecimal(0.0);
|
||||
rows = invoice.getRowCount();
|
||||
m_noInvoices = 0;
|
||||
|
||||
for (int i = 0; i < rows; i++)
|
||||
{
|
||||
if (((Boolean)invoice.getValueAt(i, 0)).booleanValue())
|
||||
{
|
||||
Timestamp ts = (Timestamp)invoice.getValueAt(i, 1);
|
||||
if ( !multiCurrency.isSelected() ) // converted amounts only valid for selected date
|
||||
allocDate = TimeUtil.max(allocDate, ts);
|
||||
BigDecimal bd = (BigDecimal)invoice.getValueAt(i, i_applied);
|
||||
totalInv = totalInv.add(bd); // Applied Inv
|
||||
m_noInvoices++;
|
||||
log.fine("Invoice_" + i + " = " + bd + " - Total=" + totalPay);
|
||||
}
|
||||
}
|
||||
invoiceInfo.setText(String.valueOf(m_noInvoices) + " - "
|
||||
+ Msg.getMsg(Env.getCtx(), "Sum") + " " + format.format(totalInv) + " ");
|
||||
|
||||
// Set AllocationDate
|
||||
if (allocDate != null)
|
||||
dateField.setValue(allocDate);
|
||||
// Set Allocation Currency
|
||||
allocCurrencyLabel.setText(currencyPick.getDisplay());
|
||||
// Difference
|
||||
totalDiff = totalPay.subtract(totalInv);
|
||||
differenceField.setText(format.format(totalDiff));
|
||||
|
||||
if (totalDiff.compareTo(new BigDecimal(0.0)) == 0)
|
||||
allocateButton.setEnabled(true);
|
||||
else
|
||||
allocateButton.setEnabled(false);
|
||||
|
||||
} // calculate
|
||||
|
||||
/**
|
||||
* Vetoable Change Listener.
|
||||
* - Business Partner
|
||||
|
@ -898,19 +335,19 @@ public class VAllocation extends CPanel
|
|||
Object value = e.getNewValue();
|
||||
log.config(name + "=" + value);
|
||||
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
// Organization
|
||||
if (name.equals("AD_Org_ID"))
|
||||
{
|
||||
if (value == null)
|
||||
if (value == null)
|
||||
m_AD_Org_ID = 0;
|
||||
else
|
||||
m_AD_Org_ID = ((Integer) value).intValue();
|
||||
|
||||
loadBPartner();
|
||||
}
|
||||
|
||||
if (value == null)
|
||||
return;
|
||||
|
||||
// BPartner
|
||||
if (name.equals("C_BPartner_ID"))
|
||||
|
@ -929,217 +366,84 @@ public class VAllocation extends CPanel
|
|||
else if (name.equals("Date") && multiCurrency.isSelected())
|
||||
loadBPartner();
|
||||
} // vetoableChange
|
||||
|
||||
public void loadBPartner()
|
||||
{
|
||||
checkBPartner();
|
||||
|
||||
Vector<Vector<Object>> data = getPaymentData(multiCurrency.isSelected(), dateField.getValue(), paymentTable);
|
||||
Vector<String> columnNames = getPaymentColumnNames(multiCurrency.isSelected());
|
||||
|
||||
// Remove previous listeners
|
||||
paymentTable.getModel().removeTableModelListener(this);
|
||||
|
||||
// Set Model
|
||||
DefaultTableModel modelP = new DefaultTableModel(data, columnNames);
|
||||
modelP.addTableModelListener(this);
|
||||
paymentTable.setModel(modelP);
|
||||
setPaymentColumnClass(paymentTable, multiCurrency.isSelected());
|
||||
//
|
||||
|
||||
data = getInvoiceData(multiCurrency.isSelected(), dateField.getValue(), invoiceTable);
|
||||
columnNames = getInvoiceColumnNames(multiCurrency.isSelected());
|
||||
|
||||
// Remove previous listeners
|
||||
invoiceTable.getModel().removeTableModelListener(this);
|
||||
|
||||
// Set Model
|
||||
DefaultTableModel modelI = new DefaultTableModel(data, columnNames);
|
||||
modelI.addTableModelListener(this);
|
||||
invoiceTable.setModel(modelI);
|
||||
setInvoiceColumnClass(invoiceTable, multiCurrency.isSelected());
|
||||
//
|
||||
|
||||
calculate(multiCurrency.isSelected());
|
||||
|
||||
// Calculate Totals
|
||||
calculate();
|
||||
}
|
||||
|
||||
public void calculate()
|
||||
{
|
||||
allocDate = null;
|
||||
|
||||
paymentInfo.setText(calculatePayment(paymentTable, multiCurrency.isSelected()));
|
||||
invoiceInfo.setText(calculateInvoice(invoiceTable, multiCurrency.isSelected()));
|
||||
|
||||
// Set AllocationDate
|
||||
if (allocDate != null)
|
||||
dateField.setValue(allocDate);
|
||||
// Set Allocation Currency
|
||||
allocCurrencyLabel.setText(currencyPick.getDisplay());
|
||||
// Difference
|
||||
totalDiff = totalPay.subtract(totalInv);
|
||||
differenceField.setText(format.format(totalDiff));
|
||||
|
||||
if (totalDiff.compareTo(new BigDecimal(0.0)) == 0)
|
||||
allocateButton.setEnabled(true);
|
||||
else
|
||||
allocateButton.setEnabled(false);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
* Save Data
|
||||
*/
|
||||
private void saveData()
|
||||
public void saveData()
|
||||
{
|
||||
if (m_noInvoices + m_noPayments == 0)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
Trx.run(new TrxRunnable()
|
||||
{
|
||||
public void run(String trxName)
|
||||
{
|
||||
// fixed fields
|
||||
int AD_Client_ID = Env.getContextAsInt(Env.getCtx(), m_WindowNo, "AD_Client_ID");
|
||||
int AD_Org_ID = Env.getContextAsInt(Env.getCtx(), m_WindowNo, "AD_Org_ID");
|
||||
int C_BPartner_ID = m_C_BPartner_ID;
|
||||
int C_Order_ID = 0;
|
||||
int C_CashLine_ID = 0;
|
||||
Timestamp DateTrx = (Timestamp)dateField.getValue();
|
||||
int C_Currency_ID = m_C_Currency_ID; // the allocation currency
|
||||
//
|
||||
if (AD_Org_ID == 0)
|
||||
{
|
||||
//ADialog.error(m_WindowNo, this, "Org0NotAllowed", null);
|
||||
new AdempiereException("@Org0NotAllowed@");
|
||||
}
|
||||
//
|
||||
log.config("Client=" + AD_Client_ID + ", Org=" + AD_Org_ID
|
||||
+ ", BPartner=" + C_BPartner_ID + ", Date=" + DateTrx);
|
||||
|
||||
// Payment - Loop and add them to paymentList/amountList
|
||||
int pRows = paymentTable.getRowCount();
|
||||
TableModel payment = paymentTable.getModel();
|
||||
ArrayList<Integer> paymentList = new ArrayList<Integer>(pRows);
|
||||
ArrayList<BigDecimal> amountList = new ArrayList<BigDecimal>(pRows);
|
||||
BigDecimal paymentAppliedAmt = Env.ZERO;
|
||||
for (int i = 0; i < pRows; i++)
|
||||
{
|
||||
// Payment line is selected
|
||||
if (((Boolean)payment.getValueAt(i, 0)).booleanValue())
|
||||
{
|
||||
KeyNamePair pp = (KeyNamePair)payment.getValueAt(i, 2); // Value
|
||||
// Payment variables
|
||||
int C_Payment_ID = pp.getKey();
|
||||
paymentList.add(new Integer(C_Payment_ID));
|
||||
//
|
||||
BigDecimal PaymentAmt = (BigDecimal)payment.getValueAt(i, i_payment); // Applied Payment
|
||||
amountList.add(PaymentAmt);
|
||||
//
|
||||
paymentAppliedAmt = paymentAppliedAmt.add(PaymentAmt);
|
||||
//
|
||||
log.fine("C_Payment_ID=" + C_Payment_ID
|
||||
+ " - PaymentAmt=" + PaymentAmt); // + " * " + Multiplier + " = " + PaymentAmtAbs);
|
||||
}
|
||||
}
|
||||
log.config("Number of Payments=" + paymentList.size() + " - Total=" + paymentAppliedAmt);
|
||||
|
||||
// Invoices - Loop and generate allocations
|
||||
int iRows = invoiceTable.getRowCount();
|
||||
TableModel invoice = invoiceTable.getModel();
|
||||
|
||||
// Create Allocation
|
||||
MAllocationHdr alloc = new MAllocationHdr (Env.getCtx(), true, // manual
|
||||
DateTrx, C_Currency_ID, Env.getContext(Env.getCtx(), "#AD_User_Name"), trxName);
|
||||
alloc.setAD_Org_ID(AD_Org_ID);
|
||||
alloc.saveEx();
|
||||
// For all invoices
|
||||
int invoiceLines = 0;
|
||||
BigDecimal unmatchedApplied = Env.ZERO;
|
||||
for (int i = 0; i < iRows; i++)
|
||||
{
|
||||
// Invoice line is selected
|
||||
if (((Boolean)invoice.getValueAt(i, 0)).booleanValue())
|
||||
{
|
||||
invoiceLines++;
|
||||
KeyNamePair pp = (KeyNamePair)invoice.getValueAt(i, 2); // Value
|
||||
// Invoice variables
|
||||
int C_Invoice_ID = pp.getKey();
|
||||
BigDecimal AppliedAmt = (BigDecimal)invoice.getValueAt(i, i_applied);
|
||||
// semi-fixed fields (reset after first invoice)
|
||||
BigDecimal DiscountAmt = (BigDecimal)invoice.getValueAt(i, i_discount);
|
||||
BigDecimal WriteOffAmt = (BigDecimal)invoice.getValueAt(i, i_writeOff);
|
||||
// OverUnderAmt needs to be in Allocation Currency
|
||||
BigDecimal OverUnderAmt = ((BigDecimal)invoice.getValueAt(i, i_open))
|
||||
.subtract(AppliedAmt).subtract(DiscountAmt).subtract(WriteOffAmt);
|
||||
|
||||
log.config("Invoice #" + i + " - AppliedAmt=" + AppliedAmt);// + " -> " + AppliedAbs);
|
||||
// loop through all payments until invoice applied
|
||||
|
||||
for (int j = 0; j < paymentList.size() && AppliedAmt.signum() != 0; j++)
|
||||
{
|
||||
int C_Payment_ID = ((Integer)paymentList.get(j)).intValue();
|
||||
BigDecimal PaymentAmt = (BigDecimal)amountList.get(j);
|
||||
if (PaymentAmt.signum() == AppliedAmt.signum()) // only match same sign (otherwise appliedAmt increases)
|
||||
{ // and not zero (appliedAmt was checked earlier)
|
||||
log.config(".. with payment #" + j + ", Amt=" + PaymentAmt);
|
||||
|
||||
BigDecimal amount = AppliedAmt;
|
||||
if (amount.abs().compareTo(PaymentAmt.abs()) > 0) // if there's more open on the invoice
|
||||
amount = PaymentAmt; // than left in the payment
|
||||
|
||||
// Allocation Line
|
||||
MAllocationLine aLine = new MAllocationLine (alloc, amount,
|
||||
DiscountAmt, WriteOffAmt, OverUnderAmt);
|
||||
aLine.setDocInfo(C_BPartner_ID, C_Order_ID, C_Invoice_ID);
|
||||
aLine.setPaymentInfo(C_Payment_ID, C_CashLine_ID);
|
||||
aLine.saveEx();
|
||||
|
||||
// Apply Discounts and WriteOff only first time
|
||||
DiscountAmt = Env.ZERO;
|
||||
WriteOffAmt = Env.ZERO;
|
||||
// subtract amount from Payment/Invoice
|
||||
AppliedAmt = AppliedAmt.subtract(amount);
|
||||
PaymentAmt = PaymentAmt.subtract(amount);
|
||||
log.fine("Allocation Amount=" + amount + " - Remaining Applied=" + AppliedAmt + ", Payment=" + PaymentAmt);
|
||||
amountList.set(j, PaymentAmt); // update
|
||||
} // for all applied amounts
|
||||
} // loop through payments for invoice
|
||||
|
||||
if ( AppliedAmt.signum() == 0 && DiscountAmt.signum() == 0 && WriteOffAmt.signum() == 0)
|
||||
continue;
|
||||
else { // remainder will need to match against other invoices
|
||||
int C_Payment_ID = 0;
|
||||
|
||||
// Allocation Line
|
||||
MAllocationLine aLine = new MAllocationLine (alloc, AppliedAmt,
|
||||
DiscountAmt, WriteOffAmt, OverUnderAmt);
|
||||
aLine.setDocInfo(C_BPartner_ID, C_Order_ID, C_Invoice_ID);
|
||||
aLine.setPaymentInfo(C_Payment_ID, C_CashLine_ID);
|
||||
aLine.saveEx();
|
||||
log.fine("Allocation Amount=" + AppliedAmt);
|
||||
unmatchedApplied = unmatchedApplied.add(AppliedAmt);
|
||||
}
|
||||
} // invoice selected
|
||||
} // invoice loop
|
||||
|
||||
// check for unapplied payment amounts (eg from payment reversals)
|
||||
for (int i = 0; i < paymentList.size(); i++) {
|
||||
BigDecimal payAmt = (BigDecimal) amountList.get(i);
|
||||
if ( payAmt.signum() == 0 )
|
||||
continue;
|
||||
int C_Payment_ID = ((Integer)paymentList.get(i)).intValue();
|
||||
log.fine("Payment=" + C_Payment_ID
|
||||
+ ", Amount=" + payAmt);
|
||||
|
||||
// Allocation Line
|
||||
MAllocationLine aLine = new MAllocationLine (alloc, payAmt,
|
||||
Env.ZERO, Env.ZERO, Env.ZERO);
|
||||
aLine.setDocInfo(C_BPartner_ID, 0, 0);
|
||||
aLine.setPaymentInfo(C_Payment_ID, 0);
|
||||
aLine.saveEx();
|
||||
unmatchedApplied = unmatchedApplied.subtract(payAmt);
|
||||
}
|
||||
|
||||
if ( unmatchedApplied.signum() != 0 )
|
||||
log.log(Level.SEVERE, "Allocation not balanced -- out by " + unmatchedApplied );
|
||||
|
||||
// Should start WF
|
||||
if (alloc.get_ID() != 0)
|
||||
{
|
||||
alloc.processIt(DocAction.ACTION_Complete);
|
||||
alloc.saveEx();
|
||||
}
|
||||
|
||||
// Test/Set IsPaid for Invoice - requires that allocation is posted
|
||||
for (int i = 0; i < iRows; i++)
|
||||
{
|
||||
// Invoice line is selected
|
||||
if (((Boolean)invoice.getValueAt(i, 0)).booleanValue())
|
||||
{
|
||||
KeyNamePair pp = (KeyNamePair)invoice.getValueAt(i, 2); // Value
|
||||
// Invoice variables
|
||||
int C_Invoice_ID = pp.getKey();
|
||||
String sql = "SELECT invoiceOpen(C_Invoice_ID, 0) "
|
||||
+ "FROM C_Invoice WHERE C_Invoice_ID=?";
|
||||
BigDecimal open = DB.getSQLValueBD(trxName, sql, C_Invoice_ID);
|
||||
if (open != null && open.signum() == 0) {
|
||||
sql = "UPDATE C_Invoice SET IsPaid='Y' "
|
||||
+ "WHERE C_Invoice_ID=" + C_Invoice_ID;
|
||||
int no = DB.executeUpdate(sql, trxName);
|
||||
log.config("Invoice #" + i + " is paid - updated=" + no);
|
||||
} else
|
||||
log.config("Invoice #" + i + " is not paid - " + open);
|
||||
}
|
||||
}
|
||||
// Test/Set Payment is fully allocated
|
||||
for (int i = 0; i < paymentList.size(); i++)
|
||||
{
|
||||
int C_Payment_ID = ((Integer)paymentList.get(i)).intValue();
|
||||
MPayment pay = new MPayment (Env.getCtx(), C_Payment_ID, trxName);
|
||||
if (pay.testAllocation())
|
||||
pay.saveEx();
|
||||
log.config("Payment #" + i + (pay.isAllocated() ? " not" : " is")
|
||||
+ " fully allocated");
|
||||
}
|
||||
paymentList.clear();
|
||||
amountList.clear();
|
||||
|
||||
statusBar.setStatusLine(alloc.getDocumentNo());
|
||||
}});
|
||||
statusBar.setStatusLine(saveData(m_WindowNo, dateField.getValue(), paymentTable, invoiceTable, trxName));
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
ADialog.error(m_WindowNo, this, "Error", e.getLocalizedMessage());
|
||||
ADialog.error(m_WindowNo, panel, "Error", e.getLocalizedMessage());
|
||||
return;
|
||||
}
|
||||
} // saveData
|
||||
|
||||
|
||||
} // VAllocation
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue