diff --git a/client/src/org/compiere/apps/form/Allocation.java b/client/src/org/compiere/apps/form/Allocation.java new file mode 100644 index 0000000000..d56842aff9 --- /dev/null +++ b/client/src/org/compiere/apps/form/Allocation.java @@ -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 m_bpartnerCheck = new ArrayList(); + + 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> 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> data = new Vector>(); + 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 line = new Vector(); + 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 getPaymentColumnNames(boolean isMultiCurrency) + { + // Header Info + Vector columnNames = new Vector(); + 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> 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> data = new Vector>(); + 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 line = new Vector(); + 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 getInvoiceColumnNames(boolean isMultiCurrency) + { + // Header Info + Vector columnNames = new Vector(); + 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 paymentList = new ArrayList(pRows); + ArrayList amountList = new ArrayList(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 +} diff --git a/client/src/org/compiere/apps/form/VAllocation.java b/client/src/org/compiere/apps/form/VAllocation.java index f5be245719..ad4c036ae7 100644 --- a/client/src/org/compiere/apps/form/VAllocation.java +++ b/client/src/org/compiere/apps/form/VAllocation.java @@ -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 - *
  • [2792529] lockTrx when you try created a Payment Allocation - *
  • 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 m_bpartnerCheck = new ArrayList(); - /** * 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> data = new Vector>(); - 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 line = new Vector(); - 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 columnNames = new Vector(); - 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>(); - 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 line = new Vector(); - 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(); - 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> data = getPaymentData(multiCurrency.isSelected(), dateField.getValue(), paymentTable); + Vector 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 paymentList = new ArrayList(pRows); - ArrayList amountList = new ArrayList(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 +} \ No newline at end of file diff --git a/zkwebui/WEB-INF/src/org/adempiere/webui/apps/form/WAllocation.java b/zkwebui/WEB-INF/src/org/adempiere/webui/apps/form/WAllocation.java index 28092d4491..1c4c6ba0b7 100755 --- a/zkwebui/WEB-INF/src/org/adempiere/webui/apps/form/WAllocation.java +++ b/zkwebui/WEB-INF/src/org/adempiere/webui/apps/form/WAllocation.java @@ -17,13 +17,6 @@ package org.adempiere.webui.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.EventListener; import java.util.Vector; import java.util.logging.Level; @@ -47,25 +40,19 @@ import org.adempiere.webui.event.ValueChangeListener; import org.adempiere.webui.event.WTableModelEvent; import org.adempiere.webui.event.WTableModelListener; import org.adempiere.webui.panel.ADForm; +import org.adempiere.webui.panel.CustomForm; +import org.adempiere.webui.panel.ICustomForm; import org.adempiere.webui.panel.StatusBarPanel; import org.adempiere.webui.window.FDialog; -import org.compiere.model.MAllocationHdr; -import org.compiere.model.MAllocationLine; -import org.compiere.model.MInvoice; +import org.compiere.apps.form.Allocation; import org.compiere.model.MLookup; import org.compiere.model.MLookupFactory; -import org.compiere.model.MPayment; -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.Trx; -import org.compiere.util.Util; import org.zkoss.zk.ui.event.Event; +import org.zkoss.zk.ui.event.EventListener; import org.zkoss.zkex.zul.Borderlayout; import org.zkoss.zkex.zul.Center; import org.zkoss.zkex.zul.North; @@ -81,28 +68,28 @@ import org.zkoss.zul.Space; * * Contributor : Fabian Aguilar - OFBConsulting - Multiallocation */ -public class WAllocation extends ADForm - implements EventListener, WTableModelListener, ValueChangeListener +public class WAllocation extends Allocation + implements ICustomForm, EventListener, WTableModelListener, ValueChangeListener { /** * */ private static final long serialVersionUID = 7806119329546820204L; + + private CustomForm form = new CustomForm(); /** * Initialize Panel * @param WindowNo window * @param frame frame */ - protected void initForm() + public WAllocation() { - 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); + Env.setContext(Env.getCtx(), form.getWindowNo(), "IsSOTrx", "Y"); // defaults to no try { + super.dynInit(); dynInit(); zkInit(); calculate(); @@ -114,28 +101,7 @@ public class WAllocation extends ADForm log.log(Level.SEVERE, "", e); } } // init - - /** Logger */ - private static CLogger log = CLogger.getCLogger(WAllocation.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_overUnder = 9; - private int i_applied = 10; -// private int i_multiplier = 10; + // private Borderlayout mainLayout = new Borderlayout(); private Panel parameterPanel = new Panel(); @@ -166,8 +132,8 @@ public class WAllocation extends ADForm private Label dateLabel = new Label(); private WDateEditor dateField = new WDateEditor(); private Checkbox autoWriteOff = new Checkbox(); - - private ArrayList m_bpartnerCheck = new ArrayList(); + private Label organizationLabel = new Label(); + private WTableDirEditor organizationPick; private Panel southPanel = new Panel(); @@ -178,7 +144,7 @@ public class WAllocation extends ADForm private void zkInit() throws Exception { // - this.appendChild(mainLayout); + form.appendChild(mainLayout); mainLayout.setWidth("99%"); mainLayout.setHeight("100%"); dateLabel.setText(Msg.getMsg(Env.getCtx(), "Date")); @@ -204,6 +170,8 @@ public class WAllocation extends ADForm multiCurrency.addActionListener(this); allocCurrencyLabel.setText("."); + organizationLabel.setText(Msg.translate(Env.getCtx(), "AD_Org_ID")); + North north = new North(); north.setStyle("border: none"); mainLayout.appendChild(north); @@ -212,25 +180,31 @@ public class WAllocation extends ADForm Rows rows = null; Row row = null; - parameterLayout.setWidth("600px"); + parameterLayout.setWidth("800px"); rows = parameterLayout.newRows(); row = rows.newRow(); row.appendChild(bpartnerLabel.rightAlign()); row.appendChild(bpartnerSearch.getComponent()); row.appendChild(dateLabel.rightAlign()); row.appendChild(dateField.getComponent()); + row.appendChild(organizationLabel.rightAlign()); + row.appendChild(organizationPick.getComponent()); row = rows.newRow(); row.appendChild(currencyLabel.rightAlign()); row.appendChild(currencyPick.getComponent()); row.appendChild(multiCurrency); - row.setSpans("1,1,2"); + row.appendChild(new Space()); + row.appendChild(new Space()); + row.setSpans("1,1,2,1,1"); row = rows.newRow(); row.appendChild(new Space()); row.appendChild(autoWriteOff); row.appendChild(new Space()); row.appendChild(new Space()); + row.appendChild(new Space()); + row.appendChild(new Space()); South south = new South(); south.setStyle("border: none"); @@ -317,18 +291,25 @@ public class WAllocation extends ADForm * 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 - MLookup lookupCur = MLookupFactory.get (Env.getCtx(), m_WindowNo, 0, AD_Column_ID, DisplayType.TableDir); + MLookup lookupCur = MLookupFactory.get (Env.getCtx(), form.getWindowNo(), 0, AD_Column_ID, DisplayType.TableDir); currencyPick = new WTableDirEditor("C_Currency_ID", true, false, true, lookupCur); currencyPick.setValue(new Integer(m_C_Currency_ID)); currencyPick.addValueChangeListener(this); + // Organization filter selection + AD_Column_ID = 839; //C_Period.AD_Org_ID (needed to allow org 0) + MLookup lookupOrg = MLookupFactory.get(Env.getCtx(), form.getWindowNo(), 0, AD_Column_ID, DisplayType.TableDir); + organizationPick = new WTableDirEditor("AD_Org_ID", true, false, true, lookupOrg); + organizationPick.setValue(Env.getAD_Org_ID(Env.getCtx())); + organizationPick.addValueChangeListener(this); + // BPartner AD_Column_ID = 3499; // C_Invoice.C_BPartner_ID - MLookup lookupBP = MLookupFactory.get (Env.getCtx(), m_WindowNo, 0, AD_Column_ID, DisplayType.Search); + MLookup lookupBP = MLookupFactory.get (Env.getCtx(), form.getWindowNo(), 0, AD_Column_ID, DisplayType.Search); bpartnerSearch = new WSearchEditor("C_BPartner_ID", true, false, true, lookupBP); bpartnerSearch.addValueChangeListener(this); @@ -340,272 +321,6 @@ public class WAllocation extends ADForm dateField.setValue(Env.getContextAsDate(Env.getCtx(), "#Date")); dateField.addValueChangeListener(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> data = new Vector>(); - 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.DateTrx,p.C_ConversionType_ID,p.AD_Client_ID,p.AD_Org_ID),"// 6 #1 - + "currencyConvert(paymentAvailable(C_Payment_ID),p.C_Currency_ID,?,p.DateTrx,p.C_ConversionType_ID,p.AD_Client_ID,p.AD_Org_ID)," // 7 #2 - + "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=?"); // #3 - if (!multiCurrency.isSelected()) - sql.append(" AND p.C_Currency_ID=?"); // #4 - sql.append(" ORDER BY p.DateTrx,p.DocumentNo"); - log.fine("PaySQL=" + sql.toString()); - try - { - PreparedStatement pstmt = DB.prepareStatement(sql.toString(), null); - pstmt.setInt(1, m_C_Currency_ID); - pstmt.setInt(2, m_C_Currency_ID); - pstmt.setInt(3, m_C_BPartner_ID); - if (!multiCurrency.isSelected()) - pstmt.setInt(4, m_C_Currency_ID); - ResultSet rs = pstmt.executeQuery(); - while (rs.next()) - { - Vector line = new Vector(); - 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 columnNames = new Vector(); - 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 - ListModelTable modelP = new ListModelTable(data); - modelP.addTableModelListener(this); - paymentTable.setData(modelP, columnNames); - // - 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>(); - 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.DateInvoiced,i.C_ConversionType_ID,i.AD_Client_ID,i.AD_Org_ID), " // 6 #1 Converted - + "currencyConvert(invoiceOpen(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.MultiplierAP, " // 7 #2 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," // #3, #4 - + "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=?"); // #5 - if (!multiCurrency.isSelected()) - sql.append(" AND i.C_Currency_ID=?"); // #6 - sql.append(" ORDER BY i.DateInvoiced, i.DocumentNo"); - log.fine("InvSQL=" + sql.toString()); - try - { - PreparedStatement pstmt = DB.prepareStatement(sql.toString(), null); - pstmt.setInt(1, m_C_Currency_ID); - pstmt.setInt(2, m_C_Currency_ID); - pstmt.setTimestamp(3, (Timestamp)dateField.getValue()); - pstmt.setInt(4, m_C_Currency_ID); - 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 line = new Vector(); - 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-OverUnder - line.add(Env.ZERO); // 8/10-Applied -// 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(); - 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(), "OverUnderAmt")); - columnNames.add(Msg.getMsg(Env.getCtx(), "AppliedAmt")); -// columnNames.add(" "); // Multiplier - - // Set Model - ListModelTable modelI = new ListModelTable(data); - modelI.addTableModelListener(this); - invoiceTable.setData(modelI, columnNames); - // - 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, false); // 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_overUnder = multiCurrency.isSelected() ? 9 : 7; - i_applied = multiCurrency.isSelected() ? 10 : 8; -// i_multiplier = multiCurrency.isSelected() ? 10 : 8; - - // Calculate Totals - calculate(); - } // loadBPartner - - /************************************************************************** * Action Listener. @@ -643,350 +358,18 @@ public class WAllocation extends ADForm return; } - - /** - * Setting defaults - */ - if (m_calculating) // Avoid recursive calls - return; - m_calculating = true; int row = e.getFirstRow(); int col = e.getColumn(); boolean isInvoice = (e.getModel().equals(invoiceTable.getModel())); - log.config("Row=" + row - + ", Col=" + col + ", InvoiceTable=" + isInvoice); - - // Payments - if (!isInvoice) - { - ListModelTable 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 - { - ListModelTable 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 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; - - // if overUnder has same sign as open it is an under payment -> less than open - if ( overUnder.signum() == openSign && overUnder.abs().compareTo(open.abs()) > 0) - overUnder = open; - - /* - * Three rules to maintain: - * 1) |overUnder + writeOff + discount| < open - * 2) |writeOff + discount| < open ( in case overUnder is 'negative') - * 3) 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. - */ - - // comply with rules 1 or 2 - BigDecimal amtOver; - if ( overUnder.signum() == -openSign ) - amtOver = (discount.add(writeOff)).subtract(open); - else - amtOver = (discount.add(writeOff.add(overUnder))).subtract(open); - - if ( amtOver.signum() == openSign ) - { - BigDecimal temp = Env.ZERO; - if ( col != i_overUnder && overUnder.signum() == openSign ) - { - temp = overUnder.subtract(amtOver); - if ( temp.signum() == -openSign ) - { - overUnder = Env.ZERO; - amtOver = temp.negate(); - } - else - { - overUnder = temp; - amtOver = Env.ZERO; - } - } - - if ( col != i_writeOff ) - { - temp = writeOff.subtract(amtOver); - if ( temp.signum() == -openSign ) - { - writeOff = Env.ZERO; - amtOver = temp.negate(); - } - else - { - writeOff = temp; - amtOver = Env.ZERO; - } - } - - if ( col != i_discount ) - { - temp = discount.subtract(amtOver); - if ( temp.signum() == -openSign ) - { - discount = Env.ZERO; - amtOver = temp.negate(); - } - else - { - discount = temp; - amtOver = Env.ZERO; - } - } - } - - - // make everything balance to open - BigDecimal remainder = open.subtract(discount.add(writeOff.add(overUnder.add(applied)))); - - // need to increase something - if ( remainder.signum() == openSign ) - { - BigDecimal temp = Env.ZERO; - BigDecimal amtUnder = amtOver.negate(); - - if ( autoWriteOff.isSelected() && col != i_writeOff ) - { - temp = writeOff.add(remainder); - - if ( temp.abs().compareTo(amtUnder.abs()) > 0 ) - { - writeOff = amtUnder; - remainder = temp.subtract(amtUnder); - } - else - { - writeOff = temp; - remainder = Env.ZERO; - } - } - - if ( col != i_overUnder ) - { - temp = overUnder.add(remainder); - if ( temp.abs().compareTo(amtUnder.abs()) > 0 ) - { - overUnder = amtUnder; - remainder = temp.subtract(amtUnder); - } - else - { - overUnder = temp; - remainder = Env.ZERO; - } - } - - if ( col != i_applied && remainder.signum() != 0 ) - { - applied = applied.add(remainder); - remainder = Env.ZERO; - } - } - - // need to decrease some amount/s - if ( remainder.signum() == -openSign ) - { - BigDecimal temp = Env.ZERO; - - - if ( autoWriteOff.isSelected() && col != i_writeOff ) - { - temp = writeOff.add(remainder); - - if ( temp.signum() == -openSign ) - { - writeOff = Env.ZERO; - remainder = temp; - } - else - { - writeOff = temp; - remainder = Env.ZERO; - } - } - - - - if ( col != i_overUnder && remainder.signum() != 0 ) - { - overUnder = overUnder.add(remainder); - remainder = Env.ZERO; - } - } - - } - - // Warning if write Off > 30% - if (autoWriteOff.isSelected() && writeOff.doubleValue()/open.doubleValue() > .30) - FDialog.warn(m_WindowNo, "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) + FDialog.warn(form.getWindowNo(), "AllocationWriteOffWarn"); - } - - m_calculating = false; calculate(); } // tableChanged - - /** - * Calculate Allocation info - */ - private void calculate () - { - log.config(""); - // - DecimalFormat format = DisplayType.getNumberFormat(DisplayType.Amount); - Timestamp allocDate = null; - - // Payment - ListModelTable 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); - 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 - ListModelTable 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); - 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 @@ -1001,6 +384,17 @@ public class WAllocation extends ADForm log.config(name + "=" + value); if (value == null) return; + + // Organization + if (name.equals("AD_Org_ID")) + { + if (value == null) + m_AD_Org_ID = 0; + else + m_AD_Org_ID = ((Integer) value).intValue(); + + loadBPartner(); + } // BPartner if (name.equals("C_BPartner_ID")) @@ -1019,217 +413,91 @@ public class WAllocation extends ADForm else if (name.equals("Date") && multiCurrency.isSelected()) loadBPartner(); } // vetoableChange + + /** + * Load Business Partner Info + * - Payments + * - Invoices + */ + private void loadBPartner () + { + checkBPartner(); + + Vector> data = getPaymentData(multiCurrency.isSelected(), dateField.getValue(), paymentTable); + Vector columnNames = getPaymentColumnNames(multiCurrency.isSelected()); + + paymentTable.clear(); + + // Remove previous listeners + paymentTable.getModel().removeTableModelListener(this); + + // Set Model + ListModelTable modelP = new ListModelTable(data); + modelP.addTableModelListener(this); + paymentTable.setData(modelP, columnNames); + setPaymentColumnClass(paymentTable, multiCurrency.isSelected()); + // + data = getInvoiceData(multiCurrency.isSelected(), dateField.getValue(), invoiceTable); + columnNames = getInvoiceColumnNames(multiCurrency.isSelected()); + + invoiceTable.clear(); + + // Remove previous listeners + invoiceTable.getModel().removeTableModelListener(this); + + // Set Model + ListModelTable modelI = new ListModelTable(data); + modelI.addTableModelListener(this); + invoiceTable.setData(modelI, columnNames); + setInvoiceColumnClass(invoiceTable, multiCurrency.isSelected()); + // + + calculate(multiCurrency.isSelected()); + + // Calculate Totals + calculate(); + } // loadBPartner + + 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; - - // 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) - { - FDialog.error(m_WindowNo, "Org0NotAllowed", null); - return; - } - // - log.config("Client=" + AD_Client_ID + ", Org=" + AD_Org_ID - + ", BPartner=" + C_BPartner_ID + ", Date=" + DateTrx); - Trx trx = Trx.get(Trx.createTrxName("AL"), true); - - // Payment - Loop and add them to paymentList/amountList - int pRows = paymentTable.getRowCount(); - ListModelTable payment = paymentTable.getModel(); - ArrayList paymentList = new ArrayList(pRows); - ArrayList amountList = new ArrayList(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(); - ListModelTable invoice = invoiceTable.getModel(); - - // Create Allocation - MAllocationHdr alloc = new MAllocationHdr (Env.getCtx(), true, // manual - DateTrx, C_Currency_ID, Env.getContext(Env.getCtx(), "#AD_User_Name"), trx.getTrxName()); - alloc.setAD_Org_ID(AD_Org_ID); - if (!alloc.save()) - { - log.log(Level.SEVERE, "Allocation not created"); - return; - } - - // 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); - if (!aLine.save()) - log.log(Level.SEVERE, "Allocation Line not written - Invoice=" + C_Invoice_ID); - - // 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); - if (!aLine.save(trx.getTrxName())) - log.log(Level.SEVERE, "Allocation Line not written - Invoice=" + C_Invoice_ID); - - 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); - if (!aLine.save(trx.getTrxName())) - log.log(Level.SEVERE, "Allocation Line not saved - Payment=" + C_Payment_ID); - 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.save(); - } - - // 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(trx.getTrxName(), 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, trx.getTrxName()); - 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, trx.getTrxName()); - if (pay.testAllocation()) - pay.save(); - log.config("Payment #" + i + (pay.isAllocated() ? " not" : " is") - + " fully allocated"); - } - paymentList.clear(); - amountList.clear(); + statusBar.setStatusLine(saveData(form.getWindowNo(), dateField.getValue(), paymentTable, invoiceTable, trx.getTrxName())); trx.commit(); trx.close(); - - statusBar.setStatusLine(alloc.getDocumentNo()); } // saveData - - + + /** + * Called by org.adempiere.webui.panel.ADForm.openForm(int) + * @return + */ + public ADForm getForm() + { + return form; + } } // VAllocation