/****************************************************************************** * Product: Adempiere ERP & CRM Smart Business Solution * * Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. * * This program is free software; you can redistribute it and/or modify it * * under the terms version 2 of the GNU General Public License as published * * by the Free Software Foundation. This program is distributed in the hope * * that it will be useful, but WITHOUT ANY WARRANTY; without even the implied * * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * * with this program; if not, write to the Free Software Foundation, Inc., * * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. * * For the text or an alternative of this public license, you may reach us * * ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA * * or via info@compiere.org or http://www.compiere.org/license.html * *****************************************************************************/ package org.compiere.model; import java.math.BigDecimal; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Timestamp; import java.util.ArrayList; import java.util.Date; import java.util.Properties; import java.util.logging.Level; import org.adempiere.exceptions.AdempiereException; import org.compiere.acct.Doc; import org.compiere.process.DocAction; import org.compiere.util.CLogger; import org.compiere.util.DB; import org.compiere.util.Env; import org.compiere.util.Msg; import org.compiere.util.Trx; import org.compiere.util.Util; /** * Payment Print/Export model. * * @author Jorg Janke * @version $Id: MPaySelectionCheck.java,v 1.3 2006/07/30 00:51:02 jjanke Exp $ */ public class MPaySelectionCheck extends X_C_PaySelectionCheck { /** * generated serial id */ private static final long serialVersionUID = 2130445794890189020L; /** * Get Pay Selection Check for Payment * @param ctx context * @param C_Payment_ID id * @param trxName transaction * @return pay selection check for payment or null */ public static MPaySelectionCheck getOfPayment (Properties ctx, int C_Payment_ID, String trxName) { MPaySelectionCheck retValue = null; String sql = "SELECT * FROM C_PaySelectionCheck WHERE C_Payment_ID=?"; int count = 0; PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement (sql, trxName); pstmt.setInt (1, C_Payment_ID); rs = pstmt.executeQuery (); while (rs.next ()) { MPaySelectionCheck psc = new MPaySelectionCheck (ctx, rs, trxName); if (retValue == null) retValue = psc; else if (!retValue.isProcessed() && psc.isProcessed()) retValue = psc; count++; } } catch (Exception e) { s_log.log(Level.SEVERE, sql, e); } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } if (count > 1) s_log.warning ("More then one for C_Payment_ID=" + C_Payment_ID); return retValue; } // getOfPayment /** * Create Pay Selection and Pay Selection Check for Payment * @param ctx context * @param C_Payment_ID id * @param trxName transaction * @return MPaySelectionCheck for payment or null */ public static MPaySelectionCheck createForPayment (Properties ctx, int C_Payment_ID, String trxName) { if (C_Payment_ID == 0) return null; MPayment payment = new MPayment (ctx, C_Payment_ID, null); // Map Payment Rule <- Tender Type String PaymentRule = PAYMENTRULE_Check; if (payment.getTenderType().equals(X_C_Payment.TENDERTYPE_CreditCard)) PaymentRule = PAYMENTRULE_CreditCard; else if (payment.getTenderType().equals(X_C_Payment.TENDERTYPE_DirectDebit)) PaymentRule = PAYMENTRULE_DirectDebit; else if (payment.getTenderType().equals(X_C_Payment.TENDERTYPE_DirectDeposit)) PaymentRule = PAYMENTRULE_DirectDeposit; else if (payment.getTenderType().equals(X_C_Payment.TENDERTYPE_Cash)) PaymentRule = PAYMENTRULE_Cash; // Create new PaySelection MPaySelection ps = new MPaySelection(ctx, 0, trxName); ps.setAD_Org_ID(payment.getAD_Org_ID()); ps.setC_BankAccount_ID (payment.getC_BankAccount_ID()); ps.setName (Msg.translate(ctx, "C_Payment_ID") + ": " + payment.getDocumentNo()); ps.setDescription(payment.getDescription()); ps.setPayDate (payment.getDateTrx()); ps.setTotalAmt (payment.getPayAmt()); ps.setIsApproved (true); ps.saveEx(); // Create new PaySelection Check MPaySelectionCheck psc = new MPaySelectionCheck(ps, PaymentRule); psc.setC_BPartner_ID (payment.getC_BPartner_ID()); psc.setC_Payment_ID(payment.getC_Payment_ID()); psc.setIsReceipt(payment.isReceipt()); psc.setPayAmt (payment.getPayAmt()); psc.setDiscountAmt(payment.getDiscountAmt()); psc.setWriteOffAmt(payment.getWriteOffAmt()); psc.setQty (1); psc.setDocumentNo(payment.getDocumentNo()); psc.setProcessed(true); // afalcone - [ 1871567 ] Wrong value in Payment document psc.setIsGeneratedDraft( ! payment.isProcessed() ); // psc.saveEx(); // Create new PaySelection Line MPaySelectionLine psl = null; if (payment.getC_Invoice_ID() != 0) { psl = new MPaySelectionLine (ps, 10, PaymentRule); psl.setC_Invoice_ID(payment.getC_Invoice_ID()); psl.setIsSOTrx (payment.isReceipt()); psl.setOpenAmt(payment.getPayAmt().add(payment.getDiscountAmt())); psl.setPayAmt (payment.getPayAmt()); psl.setDiscountAmt(payment.getDiscountAmt()); psl.setWriteOffAmt(payment.getWriteOffAmt()); psl.setDifferenceAmt (Env.ZERO); psl.setC_PaySelectionCheck_ID(psc.getC_PaySelectionCheck_ID()); psl.setProcessed(true); psl.saveEx(); } else { // globalqss - CarlosRuiz - fix bug [ 1803054 ] Empty Remittance lines on payments // look for existence of C_PaymentAllocate records // Allocate to multiple Payments based on entry MPaymentAllocate[] pAllocs = MPaymentAllocate.get(payment); if (pAllocs.length != 0) { int numInv = 0; for (int i = 0; i < pAllocs.length; i++) { MPaymentAllocate pAlloc = pAllocs[i]; if (pAlloc.getC_Invoice_ID() != 0) { MPaySelectionLine psla = null; psla = new MPaySelectionLine (ps, 10 * (i+1), PaymentRule); psla.setC_Invoice_ID(pAlloc.getC_Invoice_ID()); psla.setIsSOTrx (payment.isReceipt()); psla.setOpenAmt(pAlloc.getAmount().add(pAlloc.getDiscountAmt())); psla.setPayAmt (pAlloc.getAmount()); psla.setDiscountAmt(pAlloc.getDiscountAmt()); psla.setWriteOffAmt(pAlloc.getWriteOffAmt()); psla.setDifferenceAmt (Env.ZERO); psla.setC_PaySelectionCheck_ID(psc.getC_PaySelectionCheck_ID()); psla.setProcessed(true); psla.saveEx(); numInv++; } } if (numInv > 0) { psc.setQty (numInv); psc.saveEx(); } } } // Indicate Done ps.setProcessed(true); ps.saveEx(); return psc; } // createForPayment /** * Get Pay Selection Check records * * @param C_PaySelection_ID Payment Selection * @param PaymentRule Payment Rule * @param trxName transaction * @return array of MPaySelectionCheck */ public static MPaySelectionCheck[] get (int C_PaySelection_ID, String PaymentRule, String trxName) { if (s_log.isLoggable(Level.FINE)) s_log.fine("C_PaySelection_ID=" + C_PaySelection_ID + ", PaymentRule=" + PaymentRule); ArrayList list = new ArrayList(); String sql = "SELECT * FROM C_PaySelectionCheck " + "WHERE C_PaySelection_ID=? AND PaymentRule=? " + "ORDER BY C_PaySelectionCheck_ID"; // order by the C_PaySelectionCheck_ID PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement(sql, trxName); pstmt.setInt(1, C_PaySelection_ID); pstmt.setString(2, PaymentRule); rs = pstmt.executeQuery(); while (rs.next()) { MPaySelectionCheck check = new MPaySelectionCheck (Env.getCtx(), rs, trxName); list.add(check); } } catch (SQLException e) { s_log.log(Level.SEVERE, sql, e); } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } // convert to Array MPaySelectionCheck[] retValue = new MPaySelectionCheck[list.size()]; list.toArray(retValue); return retValue; } // get /** * Get Payment Selection Check records and set new Check Document No. * * @param C_PaySelection_ID Payment Selection * @param PaymentRule Payment Rule * @param startDocumentNo starting document no * @param trxName transaction * @return array of MPaySelectionCheck */ static public MPaySelectionCheck[] get (int C_PaySelection_ID, String PaymentRule, int startDocumentNo, String trxName) { MPaySelectionCheck[] checks = get(C_PaySelection_ID, PaymentRule, trxName); int docNo = startDocumentNo; for (MPaySelectionCheck check : checks) { // Set new Check Document No check.setDocumentNo(String.valueOf(docNo++)); check.saveEx(); } return checks; } // get /** * Confirm Print for a payment selection check record. * Create Payment if not created yet (i.e check.getC_Payment_ID() == 0). * @param check check * @param batch batch */ public static void confirmPrint (MPaySelectionCheck check, MPaymentBatch batch) { boolean localTrx = false; String trxName = check.get_TrxName(); Trx trx = null; if (trxName == null) { localTrx = true; trxName = Trx.createTrxName("ConfirmPrintSingle"); trx = Trx.get(trxName, true); trx.setDisplayName(MPaySelectionCheck.class.getName()+"_confirmPrint"); check.set_TrxName(trxName); } try { MPayment payment = new MPayment(check.getCtx(), check.getC_Payment_ID(), trxName); // Existing Payment if (check.getC_Payment_ID() != 0) { // Update check number if (check.getPaymentRule().equals(PAYMENTRULE_Check)) { payment.setCheckNo(check.getDocumentNo()); payment.saveEx(); } } else // New Payment { payment = new MPayment(check.getCtx(), 0, trxName); payment.setAD_Org_ID(check.getAD_Org_ID()); // if (check.getPaymentRule().equals(PAYMENTRULE_Check)) payment.setBankCheck (check.getParent().getC_BankAccount_ID(), false, check.getDocumentNo()); else if (check.getPaymentRule().equals(PAYMENTRULE_CreditCard)) payment.setTenderType(X_C_Payment.TENDERTYPE_CreditCard); else if (check.getPaymentRule().equals(PAYMENTRULE_DirectDeposit) || check.getPaymentRule().equals(PAYMENTRULE_DirectDebit)) payment.setBankACH(check); else { s_log.log(Level.SEVERE, "Unsupported Payment Rule=" + check.getPaymentRule()); return; } payment.setTrxType(X_C_Payment.TRXTYPE_CreditPayment); payment.setAmount(check.getParent().getC_Currency_ID(), check.getPayAmt()); payment.setDiscountAmt(check.getDiscountAmt()); payment.setWriteOffAmt(check.getWriteOffAmt()); payment.setDateTrx(check.getParent().getPayDate()); payment.setDateAcct(payment.getDateTrx()); // globalqss [ 2030685 ] payment.setC_BPartner_ID(check.getC_BPartner_ID()); // Link to Batch if (batch != null) { if (batch.getC_PaymentBatch_ID() == 0) batch.saveEx(trxName); // new payment.setC_PaymentBatch_ID(batch.getC_PaymentBatch_ID()); } // Link to Invoice MPaySelectionLine[] psls = check.getPaySelectionLines(true); if (s_log.isLoggable(Level.FINE)) s_log.fine("confirmPrint - " + check + " (#SelectionLines=" + psls.length + ")"); if (check.getQty() == 1 && psls != null && psls.length == 1) { MPaySelectionLine psl = psls[0]; if (s_log.isLoggable(Level.FINE)) s_log.fine("Map to Invoice " + psl); // payment.setC_Invoice_ID (psl.getC_Invoice_ID()); payment.setDiscountAmt (psl.getDiscountAmt()); payment.setWriteOffAmt (psl.getWriteOffAmt()); BigDecimal overUnder = psl.getOpenAmt().subtract(psl.getPayAmt()) .subtract(psl.getDiscountAmt()).subtract(psl.getWriteOffAmt()).subtract(psl.getDifferenceAmt()); payment.setOverUnderAmt(overUnder); } else { payment.setWriteOffAmt(Env.ZERO); payment.setDiscountAmt(Env.ZERO); } payment.saveEx(); // int C_Payment_ID = payment.get_ID(); if (C_Payment_ID < 1) s_log.log(Level.SEVERE, "Payment not created=" + check); else { check.setC_Payment_ID (C_Payment_ID); check.saveEx(); // Payment process needs it // added AdempiereException by zuhri if (!payment.processIt(DocAction.ACTION_Complete)) throw new AdempiereException(Msg.getMsg(Env.getCtx(), "FailedProcessingDocument") + " - " + payment.getProcessMsg()); // end added payment.saveEx(); } } // new Payment check.setIsPrinted(true); check.setProcessed(true); check.saveEx(); } catch (Exception e) { if (localTrx && trx != null) { trx.rollback(); trx.close(); trx = null; } throw new AdempiereException(e); } finally { if (localTrx && trx != null) { trx.commit(); trx.close(); } } } // confirmPrint /** * Confirm Print for payment selection check records.
* For each payment selection check record, call {@link #confirmPrint(MPaySelectionCheck, MPaymentBatch)}. * @param checks checks * @param batch batch * @param createDepositBatch create deposit batch * @return last Document number or 0 if nothing printed */ public static int confirmPrint (MPaySelectionCheck[] checks, MPaymentBatch batch, boolean createDepositBatch) { boolean localTrx = false; String trxName = null; int lastDocumentNo = 0; if (checks.length > 0) { trxName = checks[0].get_TrxName(); Properties ctx = checks[0].getCtx(); int c_BankAccount_ID = checks[0].getC_PaySelection().getC_BankAccount_ID() ; String paymentRule = checks[0].getPaymentRule() ; Boolean isDebit ; if (MInvoice.PAYMENTRULE_DirectDeposit.compareTo(paymentRule) == 0 || MInvoice.PAYMENTRULE_Check.compareTo(paymentRule) == 0 || MInvoice.PAYMENTRULE_OnCredit.compareTo(paymentRule) == 0) { isDebit = false ; } else if (MInvoice.PAYMENTRULE_DirectDebit.compareTo(paymentRule) == 0) { isDebit = true ; } else { isDebit = false ; createDepositBatch = false ; } Trx trx = null; if (trxName == null) { localTrx = true; trxName = Trx.createTrxName("ConfirmPrintMulti"); trx = Trx.get(trxName, true); } try { MDepositBatch depositBatch = null; if (createDepositBatch) { depositBatch = new MDepositBatch(ctx, 0, trxName) ; depositBatch.setC_BankAccount_ID(c_BankAccount_ID); if (isDebit) { depositBatch.setC_DocType_ID(MDocType.getDocType(Doc.DOCTYPE_ARReceipt)); } else { depositBatch.setC_DocType_ID(MDocType.getDocType(Doc.DOCTYPE_APPayment)); } depositBatch.setDateDeposit(new Timestamp((new Date()).getTime())); depositBatch.setDateDoc(new Timestamp((new Date()).getTime())); depositBatch.saveEx(); } for (int i = 0; i < checks.length; i++) { MPaySelectionCheck check = checks[i]; if (localTrx) check.set_TrxName(trxName); confirmPrint(check, batch); if (createDepositBatch) { MDepositBatchLine depositBatchLine = new MDepositBatchLine(depositBatch) ; depositBatchLine.setC_Payment_ID(check.getC_Payment_ID()); depositBatchLine.setProcessed(true); depositBatchLine.saveEx(); } // Get Check Document No try { int no = Integer.parseInt(check.getDocumentNo()); if (lastDocumentNo < no) lastDocumentNo = no; } catch (NumberFormatException ex) { s_log.log(Level.SEVERE, "DocumentNo=" + check.getDocumentNo(), ex); } } // all checks if (createDepositBatch) { depositBatch.setProcessed(true); depositBatch.saveEx(); } } catch (Exception e) { if (localTrx && trx != null) { trx.rollback(); trx.close(); trx = null; } throw new AdempiereException(e); } finally { if (localTrx && trx != null) { trx.commit(); trx.close(); } } } if (s_log.isLoggable(Level.FINE)) s_log.fine("Last Document No = " + lastDocumentNo); return lastDocumentNo; } // confirmPrint /** * Call {@link #confirmPrint(MPaySelectionCheck[], MPaymentBatch, boolean)}. * @param checks checks * @param batch batch * @return last Document number or 0 if nothing printed */ public static int confirmPrint (MPaySelectionCheck[] checks, MPaymentBatch batch) { return confirmPrint (checks,batch,false) ; } // confirmPrint /** Logger */ static private CLogger s_log = CLogger.getCLogger (MPaySelectionCheck.class); /** * UUID based Constructor * @param ctx Context * @param C_PaySelectionCheck_UU UUID key * @param trxName Transaction */ public MPaySelectionCheck(Properties ctx, String C_PaySelectionCheck_UU, String trxName) { super(ctx, C_PaySelectionCheck_UU, trxName); if (Util.isEmpty(C_PaySelectionCheck_UU)) setInitialDefaults(); } /** * @param ctx context * @param C_PaySelectionCheck_ID C_PaySelectionCheck_ID * @param trxName transaction */ public MPaySelectionCheck (Properties ctx, int C_PaySelectionCheck_ID, String trxName) { super(ctx, C_PaySelectionCheck_ID, trxName); if (C_PaySelectionCheck_ID == 0) setInitialDefaults(); } // MPaySelectionCheck /** * Set the initial defaults for a new record */ private void setInitialDefaults() { setPayAmt (Env.ZERO); setDiscountAmt(Env.ZERO); setWriteOffAmt(Env.ZERO); setIsPrinted (false); setIsReceipt (false); setQty (0); } /** * Load Constructor * @param ctx context * @param rs result set * @param trxName transaction */ public MPaySelectionCheck(Properties ctx, ResultSet rs, String trxName) { super(ctx, rs, trxName); } // MPaySelectionCheck /** * Create from Payment Selection Line * @param line payment selection line * @param PaymentRule payment rule (PAYMENTRULE_*) */ public MPaySelectionCheck (MPaySelectionLine line, String PaymentRule) { this (line.getCtx(), 0, line.get_TrxName()); setClientOrg(line); setC_PaySelection_ID (line.getC_PaySelection_ID()); int C_BPartner_ID = line.getInvoice().getC_BPartner_ID(); setC_BPartner_ID (C_BPartner_ID); // if (X_C_Order.PAYMENTRULE_DirectDebit.equals(PaymentRule)) { MBPBankAccount[] bas = MBPBankAccount.getOfBPartner (line.getCtx(), C_BPartner_ID); for (int i = 0; i < bas.length; i++) { MBPBankAccount account = bas[i]; if (account.isDirectDebit()) { setC_BP_BankAccount_ID(account.getC_BP_BankAccount_ID()); break; } } } else if (X_C_Order.PAYMENTRULE_DirectDeposit.equals(PaymentRule)) { MBPBankAccount[] bas = MBPBankAccount.getOfBPartner (line.getCtx(), C_BPartner_ID); for (int i = 0; i < bas.length; i++) { MBPBankAccount account = bas[i]; if (account.isDirectDeposit()) { setC_BP_BankAccount_ID(account.getC_BP_BankAccount_ID()); break; } } } setPaymentRule (PaymentRule); // setIsReceipt(line.isSOTrx()); setPayAmt (line.getPayAmt()); setDiscountAmt(line.getDiscountAmt()); setWriteOffAmt(line.getWriteOffAmt()); setQty (1); } // MPaySelectionCheck /** * Create from Pay Selection * @param ps payment selection * @param PaymentRule payment rule (PAYMENTRULE_*) */ public MPaySelectionCheck (MPaySelection ps, String PaymentRule) { this (ps.getCtx(), 0, ps.get_TrxName()); setClientOrg(ps); setC_PaySelection_ID (ps.getC_PaySelection_ID()); setPaymentRule (PaymentRule); } // MPaySelectionCheck /** Parent */ private MPaySelection m_parent = null; /** Payment Selection lines of this check */ private MPaySelectionLine[] m_lines = null; /** * Add Payment Selection Line * @param line Payment Selection Line */ public void addLine (MPaySelectionLine line) { if (getC_BPartner_ID() != line.getInvoice().getC_BPartner_ID()) throw new IllegalArgumentException("Line for different BPartner"); // if (isReceipt() == line.isSOTrx()) { setPayAmt (getPayAmt().add(line.getPayAmt())); setDiscountAmt(getDiscountAmt().add(line.getDiscountAmt())); setWriteOffAmt(getWriteOffAmt().add(line.getWriteOffAmt())); } else { setPayAmt (getPayAmt().subtract(line.getPayAmt())); setDiscountAmt(getDiscountAmt().subtract(line.getDiscountAmt())); setWriteOffAmt(getWriteOffAmt().subtract(line.getWriteOffAmt())); } setQty (getQty()+1); } // addLine /** * Get Parent * @return parent MPaySelection record */ public MPaySelection getParent() { if (m_parent == null) m_parent = new MPaySelection (getCtx(), getC_PaySelection_ID(), get_TrxName()); return m_parent; } // getParent /** * Is this a valid Prepared Payment * @return true if valid */ public boolean isValid() { if (getC_BP_BankAccount_ID() != 0) return true; return !isDirect(); } // isValid /** * Is this with Direct Debit or Direct Deposit payment rule * @return true if is with Direct Debit or Direct Deposit payment rule */ public boolean isDirect() { return (X_C_Order.PAYMENTRULE_DirectDeposit.equals(getPaymentRule()) || X_C_Order.PAYMENTRULE_DirectDebit.equals(getPaymentRule())); } // isDirect /** * String Representation * @return info */ @Override public String toString() { StringBuilder sb = new StringBuilder("MPaymentCheck["); sb.append(get_ID()).append("-").append(getDocumentNo()) .append("-").append(getPayAmt()) .append(",PaymentRule=").append(getPaymentRule()) .append(",Qty=").append(getQty()) .append("]"); return sb.toString(); } // toString /** * Get Payment Selection Lines * @param requery true to re-query from DB * @return array of payment selection lines */ public MPaySelectionLine[] getPaySelectionLines (boolean requery) { if (m_lines != null && !requery) { set_TrxName(m_lines, get_TrxName()); return m_lines; } ArrayList list = new ArrayList(); String sql = "SELECT * FROM C_PaySelectionLine WHERE C_PaySelectionCheck_ID=? ORDER BY Line"; PreparedStatement pstmt = null; ResultSet rs = null; try { pstmt = DB.prepareStatement (sql, get_TrxName()); pstmt.setInt (1, getC_PaySelectionCheck_ID()); rs = pstmt.executeQuery (); while (rs.next ()) list.add (new MPaySelectionLine(getCtx(), rs, get_TrxName())); } catch (Exception e) { log.log(Level.SEVERE, sql, e); } finally { DB.close(rs, pstmt); rs = null; pstmt = null; } // m_lines = new MPaySelectionLine[list.size ()]; list.toArray (m_lines); return m_lines; } // getPaySelectionLines /** * Delete Payment Selection records that are generated as Draft (Print Preview) * @param ctx context * @param C_Payment_ID id * @param trxName transaction * @return false if there are errors */ public static boolean deleteGeneratedDraft(Properties ctx, int C_Payment_ID, String trxName) { MPaySelectionCheck mpsc = MPaySelectionCheck.getOfPayment (ctx, C_Payment_ID, trxName); if (mpsc != null && mpsc.isGeneratedDraft()) { MPaySelection mps = new MPaySelection(ctx, mpsc.getC_PaySelection_ID(),trxName); MPaySelectionLine[] mpsl = mps.getLines(true); // Delete Pay Selection lines for (int i = 0; i < mpsl.length; i++) { if (!mpsl[i].delete(true, trxName)) return false; } // Delete Pay Selection Check if (!mpsc.delete(true, trxName)) return false; // Delete Pay Selection if (!mps.delete(true, trxName)) return false; } return true; } } // MPaySelectionCheck