Refactor custom form - ID: 2787613

This commit is contained in:
Heng Sin Low 2009-05-29 04:38:03 +00:00
parent a890145e50
commit 0d919012ce
3 changed files with 990 additions and 1637 deletions

View File

@ -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
}

View File

@ -1,6 +1,6 @@
/****************************************************************************** /******************************************************************************
* Product: Adempiere ERP & CRM Smart Business Solution * * Copyright (C) 2009 Low Heng Sin *
* Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. * * Copyright (C) 2009 Idalica Corporation *
* This program is free software; you can redistribute it and/or modify it * * 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 * * 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 * * 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 * * 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., * * with this program; if not, write to the Free Software Foundation, Inc., *
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * * 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; package org.compiere.apps.form;
@ -26,12 +23,6 @@ import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.VetoableChangeListener; import java.beans.VetoableChangeListener;
import java.math.BigDecimal; import java.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.Vector;
import java.util.logging.Level; import java.util.logging.Level;
@ -45,49 +36,25 @@ import javax.swing.SwingConstants;
import javax.swing.event.TableModelEvent; import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener; import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel; import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import org.adempiere.exceptions.AdempiereException;
import org.adempiere.plaf.AdempierePLAF; import org.adempiere.plaf.AdempierePLAF;
import org.compiere.apps.ADialog; import org.compiere.apps.ADialog;
import org.compiere.apps.StatusBar; import org.compiere.apps.StatusBar;
import org.compiere.grid.ed.VDate; import org.compiere.grid.ed.VDate;
import org.compiere.grid.ed.VLookup; import org.compiere.grid.ed.VLookup;
import org.compiere.minigrid.MiniTable; 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.MLookup;
import org.compiere.model.MLookupFactory; import org.compiere.model.MLookupFactory;
import org.compiere.model.MPayment;
import org.compiere.model.MRole;
import org.compiere.plaf.CompiereColor; import org.compiere.plaf.CompiereColor;
import org.compiere.process.DocAction;
import org.compiere.swing.CPanel; import org.compiere.swing.CPanel;
import org.compiere.swing.CTextField; import org.compiere.swing.CTextField;
import org.compiere.util.CLogger;
import org.compiere.util.DB;
import org.compiere.util.DisplayType; import org.compiere.util.DisplayType;
import org.compiere.util.Env; import org.compiere.util.Env;
import org.compiere.util.KeyNamePair;
import org.compiere.util.Msg; import org.compiere.util.Msg;
import org.compiere.util.TimeUtil;
import org.compiere.util.Trx; import org.compiere.util.Trx;
import org.compiere.util.TrxRunnable; import org.compiere.util.TrxRunnable;
import org.compiere.util.Util;
/** public class VAllocation extends Allocation
* 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
implements FormPanel, ActionListener, TableModelListener, VetoableChangeListener implements FormPanel, ActionListener, TableModelListener, VetoableChangeListener
{ {
@ -95,6 +62,8 @@ public class VAllocation extends CPanel
* *
*/ */
private static final long serialVersionUID = -5322824600164192235L; private static final long serialVersionUID = -5322824600164192235L;
private CPanel panel = new CPanel();
/** /**
* Initialize Panel * Initialize Panel
@ -106,11 +75,9 @@ public class VAllocation extends CPanel
m_WindowNo = WindowNo; m_WindowNo = WindowNo;
m_frame = frame; m_frame = frame;
Env.setContext(Env.getCtx(), m_WindowNo, "IsSOTrx", "Y"); // defaults to no 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 try
{ {
super.dynInit();
dynInit(); dynInit();
jbInit(); jbInit();
calculate(); calculate();
@ -127,28 +94,7 @@ public class VAllocation extends CPanel
private int m_WindowNo = 0; private int m_WindowNo = 0;
/** FormFrame */ /** FormFrame */
private FormFrame m_frame; 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 CPanel mainPanel = new CPanel();
private BorderLayout mainLayout = new BorderLayout(); private BorderLayout mainLayout = new BorderLayout();
private CPanel parameterPanel = new CPanel(); private CPanel parameterPanel = new CPanel();
@ -181,19 +127,16 @@ public class VAllocation extends CPanel
private JLabel dateLabel = new JLabel(); private JLabel dateLabel = new JLabel();
private VDate dateField = new VDate(); private VDate dateField = new VDate();
private JCheckBox autoWriteOff = new JCheckBox(); private JCheckBox autoWriteOff = new JCheckBox();
private int m_AD_Org_ID = 0;
private JLabel organizationLabel = new JLabel(); private JLabel organizationLabel = new JLabel();
private VLookup organizationPick = null; private VLookup organizationPick = null;
private ArrayList<Integer> m_bpartnerCheck = new ArrayList<Integer>();
/** /**
* Static Init * Static Init
* @throws Exception * @throws Exception
*/ */
private void jbInit() throws Exception private void jbInit() throws Exception
{ {
CompiereColor.setBackground(this); CompiereColor.setBackground(panel);
// //
mainPanel.setLayout(mainLayout); mainPanel.setLayout(mainLayout);
dateLabel.setText(Msg.getMsg(Env.getCtx(), "Date")); dateLabel.setText(Msg.getMsg(Env.getCtx(), "Date"));
@ -300,7 +243,7 @@ public class VAllocation extends CPanel
* Dynamic Init (prepare dynamic fields) * Dynamic Init (prepare dynamic fields)
* @throws Exception if Lookups cannot be initialized * @throws Exception if Lookups cannot be initialized
*/ */
private void dynInit() throws Exception public void dynInit() throws Exception
{ {
// Currency // Currency
int AD_Column_ID = 3505; // C_Invoice.C_Currency_ID 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 = new VLookup("AD_Org_ID", true, false, true, lookupOrg);
organizationPick.setValue(Env.getAD_Org_ID(Env.getCtx())); organizationPick.setValue(Env.getAD_Org_ID(Env.getCtx()));
organizationPick.addVetoableChangeListener(this); organizationPick.addVetoableChangeListener(this);
m_AD_Org_ID = Env.getAD_Org_ID(Env.getCtx());
// BPartner // BPartner
AD_Column_ID = 3499; // C_Invoice.C_BPartner_ID 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.setValue(Env.getContextAsDate(Env.getCtx(), "#Date"));
dateField.addVetoableChangeListener(this); dateField.addVetoableChangeListener(this);
} // dynInit } // 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. * Action Listener.
@ -652,239 +310,18 @@ public class VAllocation extends CPanel
return; return;
} }
/**
* Setting defaults
*/
if (m_calculating) // Avoid recursive calls
return;
m_calculating = true;
int row = e.getFirstRow(); int row = e.getFirstRow();
int col = e.getColumn(); int col = e.getColumn();
boolean isInvoice = (e.getSource().equals(invoiceTable.getModel())); boolean isInvoice = (e.getSource().equals(invoiceTable.getModel()));
log.config("Row=" + row boolean isAutoWriteOff = autoWriteOff.isSelected();
+ ", Col=" + col + ", InvoiceTable=" + isInvoice);
String msg = writeOff(row, col, isInvoice, paymentTable, invoiceTable, isAutoWriteOff);
// Payments if(msg != null && msg.length() > 0)
if (!isInvoice) ADialog.warn(m_WindowNo, panel, "AllocationWriteOffWarn");
{
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
}
m_calculating = false;
calculate(); calculate();
} // tableChanged } // 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. * Vetoable Change Listener.
* - Business Partner * - Business Partner
@ -898,19 +335,19 @@ public class VAllocation extends CPanel
Object value = e.getNewValue(); Object value = e.getNewValue();
log.config(name + "=" + value); log.config(name + "=" + value);
if (value == null)
return;
// Organization // Organization
if (name.equals("AD_Org_ID")) if (name.equals("AD_Org_ID"))
{ {
if (value == null) if (value == null)
m_AD_Org_ID = 0; m_AD_Org_ID = 0;
else else
m_AD_Org_ID = ((Integer) value).intValue(); m_AD_Org_ID = ((Integer) value).intValue();
loadBPartner(); loadBPartner();
} }
if (value == null)
return;
// BPartner // BPartner
if (name.equals("C_BPartner_ID")) if (name.equals("C_BPartner_ID"))
@ -929,217 +366,84 @@ public class VAllocation extends CPanel
else if (name.equals("Date") && multiCurrency.isSelected()) else if (name.equals("Date") && multiCurrency.isSelected())
loadBPartner(); loadBPartner();
} // vetoableChange } // 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 * Save Data
*/ */
private void saveData() public void saveData()
{ {
if (m_noInvoices + m_noPayments == 0)
return;
try try
{ {
Trx.run(new TrxRunnable() Trx.run(new TrxRunnable()
{ {
public void run(String trxName) public void run(String trxName)
{ {
// fixed fields statusBar.setStatusLine(saveData(m_WindowNo, dateField.getValue(), paymentTable, invoiceTable, trxName));
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());
}});
} }
catch (Exception e) catch (Exception e)
{ {
ADialog.error(m_WindowNo, this, "Error", e.getLocalizedMessage()); ADialog.error(m_WindowNo, panel, "Error", e.getLocalizedMessage());
return; return;
} }
} // saveData } // saveData
}
} // VAllocation