/******************************************************************************
* 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.io.File;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
import java.util.logging.Level;
import org.adempiere.exceptions.AdempiereException;
import org.compiere.process.DocAction;
import org.compiere.process.DocumentEngine;
import org.compiere.process.ProcessCall;
import org.compiere.process.ProcessInfo;
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.ValueNamePair;
/**
* Payment Model.
* - retrieve and create payments for invoice
* <pre>
* Event chain
* - Payment inserted
* C_Payment_Trg fires
* update DocumentNo with payment summary
* - Payment posted (C_Payment_Post)
* create allocation line
* C_Allocation_Trg fires
* Update C_BPartner Open Item Amount
* update invoice (IsPaid)
* link invoice-payment if batch
*
* Lifeline:
* - Created by VPayment or directly
* - When changed in VPayment
* - old payment is reversed
* - new payment created
*
* When Payment is posed, the Allocation is made
* </pre>
* @author Jorg Janke
* @author victor.perez@e-evolution.com, e-Evolution http://www.e-evolution.com
* <li>FR [ 1948157 ] Is necessary the reference for document reverse
* @see http://sourceforge.net/tracker/?func=detail&atid=879335&aid=1948157&group_id=176962
* <li> FR [ 1866214 ]
* @sse http://sourceforge.net/tracker/index.php?func=detail&aid=1866214&group_id=176962&atid=879335
* <li> FR [ 2520591 ] Support multiples calendar for Org
* @see http://sourceforge.net/tracker2/?func=detail&atid=879335&aid=2520591&group_id=176962
*
* @author Carlos Ruiz - globalqss [ 2141475 ] Payment <> allocations must not be completed - implement lots of validations on prepareIt
* @version $Id: MPayment.java,v 1.4 2006/10/02 05:18:39 jjanke Exp $
*/
public final class MPayment extends X_C_Payment
implements DocAction, ProcessCall
{
/**
*
*/
private static final long serialVersionUID = 6200327948230438741L;
/**
* Get Payments Of BPartner
* @param ctx context
* @param C_BPartner_ID id
* @param trxName transaction
* @return array
*/
public static MPayment[] getOfBPartner (Properties ctx, int C_BPartner_ID, String trxName)
{
//FR: [ 2214883 ] Remove SQL code and Replace for Query - red1
final String whereClause = "C_BPartner_ID=?";
List <MPayment> list = new Query(ctx, I_C_Payment.Table_Name, whereClause, trxName)
.setParameters(C_BPartner_ID)
.list();
//
MPayment[] retValue = new MPayment[list.size()];
list.toArray(retValue);
return retValue;
} // getOfBPartner
/**************************************************************************
* Default Constructor
* @param ctx context
* @param C_Payment_ID payment to load, (0 create new payment)
* @param trxName trx name
*/
public MPayment (Properties ctx, int C_Payment_ID, String trxName)
{
super (ctx, C_Payment_ID, trxName);
// New
if (C_Payment_ID == 0)
{
setDocAction(DOCACTION_Complete);
setDocStatus(DOCSTATUS_Drafted);
setTrxType(TRXTYPE_Sales);
//
setR_AvsAddr (R_AVSZIP_Unavailable);
setR_AvsZip (R_AVSZIP_Unavailable);
//
setIsReceipt (true);
setIsApproved (false);
setIsReconciled (false);
setIsAllocated(false);
setIsOnline (false);
setIsSelfService(false);
setIsDelayedCapture (false);
setIsPrepayment(false);
setProcessed(false);
setProcessing(false);
setPosted (false);
//
setPayAmt(Env.ZERO);
setDiscountAmt(Env.ZERO);
setTaxAmt(Env.ZERO);
setWriteOffAmt(Env.ZERO);
setIsOverUnderPayment (true);
setOverUnderAmt(Env.ZERO);
//
setDateTrx (new Timestamp(System.currentTimeMillis()));
setDateAcct (getDateTrx());
setTenderType(TENDERTYPE_Check);
}
} // MPayment
/**
* Load Constructor
* @param ctx context
* @param rs result set record
* @param trxName transaction
*/
public MPayment (Properties ctx, ResultSet rs, String trxName)
{
super(ctx, rs, trxName);
} // MPayment
/** Temporary Payment Processors */
private MPaymentProcessor[] m_mPaymentProcessors = null;
/** Temporary Payment Processor */
private MPaymentProcessor m_mPaymentProcessor = null;
/** Logger */
private static CLogger s_log = CLogger.getCLogger (MPayment.class);
/** Error Message */
private String m_errorMessage = null;
/** Reversal Indicator */
public static String REVERSE_INDICATOR = "^";
/**
* Reset Payment to new status
*/
public void resetNew()
{
setC_Payment_ID(0); // forces new Record
set_ValueNoCheck ("DocumentNo", null);
setDocAction(DOCACTION_Prepare);
setDocStatus(DOCSTATUS_Drafted);
setProcessed(false);
setPosted (false);
setIsReconciled (false);
setIsAllocated(false);
setIsOnline(false);
setIsDelayedCapture (false);
// setC_BPartner_ID(0);
setC_Invoice_ID(0);
setC_Order_ID(0);
setC_Charge_ID(0);
setC_Project_ID(0);
setIsPrepayment(false);
} // resetNew
/**
* Is Cashbook Transfer Trx
* @return true if Cash Trx
*/
public boolean isCashTrx()
{
return "X".equals(getTenderType());
} // isCashTrx
/**************************************************************************
* Set Credit Card.
* Need to set PatmentProcessor after Amount/Currency Set
*
* @param TrxType Transaction Type see TRX_
* @param creditCardType CC type
* @param creditCardNumber CC number
* @param creditCardVV CC verification
* @param creditCardExpMM CC Exp MM
* @param creditCardExpYY CC Exp YY
* @return true if valid
*/
public boolean setCreditCard (String TrxType, String creditCardType, String creditCardNumber,
String creditCardVV, int creditCardExpMM, int creditCardExpYY)
{
setTenderType(TENDERTYPE_CreditCard);
setTrxType(TrxType);
//
setCreditCardType (creditCardType);
setCreditCardNumber (creditCardNumber);
setCreditCardVV (creditCardVV);
setCreditCardExpMM (creditCardExpMM);
setCreditCardExpYY (creditCardExpYY);
//
int check = MPaymentValidate.validateCreditCardNumber(creditCardNumber, creditCardType).length()
+ MPaymentValidate.validateCreditCardExp(creditCardExpMM, creditCardExpYY).length();
if (creditCardVV.length() > 0)
check += MPaymentValidate.validateCreditCardVV(creditCardVV, creditCardType).length();
return check == 0;
} // setCreditCard
/**
* Set Credit Card - Exp.
* Need to set PatmentProcessor after Amount/Currency Set
*
* @param TrxType Transaction Type see TRX_
* @param creditCardType CC type
* @param creditCardNumber CC number
* @param creditCardVV CC verification
* @param creditCardExp CC Exp
* @return true if valid
*/
public boolean setCreditCard (String TrxType, String creditCardType, String creditCardNumber,
String creditCardVV, String creditCardExp)
{
return setCreditCard(TrxType, creditCardType, creditCardNumber,
creditCardVV, MPaymentValidate.getCreditCardExpMM(creditCardExp),
MPaymentValidate.getCreditCardExpYY(creditCardExp));
} // setCreditCard
/**
* Set ACH BankAccount Info
*
* @param C_BankAccount_ID bank account
* @param isReceipt true if receipt
* @return true if valid
*/
public boolean setBankACH (MPaySelectionCheck preparedPayment)
{
// Our Bank
setC_BankAccount_ID(preparedPayment.getParent().getC_BankAccount_ID());
// Target Bank
int C_BP_BankAccount_ID = preparedPayment.getC_BP_BankAccount_ID();
MBPBankAccount ba = new MBPBankAccount (preparedPayment.getCtx(), C_BP_BankAccount_ID, null);
setRoutingNo(ba.getRoutingNo());
setAccountNo(ba.getAccountNo());
setDescription(preparedPayment.getC_PaySelection().getName());
setIsReceipt (X_C_Order.PAYMENTRULE_DirectDebit.equals // AR only
(preparedPayment.getPaymentRule()));
if ( MPaySelectionCheck.PAYMENTRULE_DirectDebit.equals(preparedPayment.getPaymentRule()) )
setTenderType(MPayment.TENDERTYPE_DirectDebit);
else if ( MPaySelectionCheck.PAYMENTRULE_DirectDeposit.equals(preparedPayment.getPaymentRule()))
setTenderType(MPayment.TENDERTYPE_DirectDeposit);
//
int check = MPaymentValidate.validateRoutingNo(getRoutingNo()).length()
+ MPaymentValidate.validateAccountNo(getAccountNo()).length();
return check == 0;
} // setBankACH
/**
* Set ACH BankAccount Info
*
* @param C_BankAccount_ID bank account
* @param isReceipt true if receipt
* @param tenderType - Direct Debit or Direct Deposit
* @param routingNo routing
* @param accountNo account
* @return true if valid
*/
public boolean setBankACH (int C_BankAccount_ID, boolean isReceipt, String tenderType,
String routingNo, String accountNo)
{
setTenderType (tenderType);
setIsReceipt (isReceipt);
//
if (C_BankAccount_ID > 0
&& (routingNo == null || routingNo.length() == 0 || accountNo == null || accountNo.length() == 0))
setBankAccountDetails(C_BankAccount_ID);
else
{
setC_BankAccount_ID(C_BankAccount_ID);
setRoutingNo (routingNo);
setAccountNo (accountNo);
}
setCheckNo ("");
//
int check = MPaymentValidate.validateRoutingNo(routingNo).length()
+ MPaymentValidate.validateAccountNo(accountNo).length();
return check == 0;
} // setBankACH
/**
* Set Cash BankAccount Info
*
* @param C_BankAccount_ID bank account
* @param isReceipt true if receipt
* @param tenderType - Cash (Payment)
* @return true if valid
*/
public boolean setBankCash (int C_BankAccount_ID, boolean isReceipt, String tenderType)
{
setTenderType (tenderType);
setIsReceipt (isReceipt);
//
if (C_BankAccount_ID > 0)
setBankAccountDetails(C_BankAccount_ID);
else
{
setC_BankAccount_ID(C_BankAccount_ID);
}
//
return true;
} // setBankCash
/**
* Set Check BankAccount Info
*
* @param C_BankAccount_ID bank account
* @param isReceipt true if receipt
* @param checkNo check no
* @return true if valid
*/
public boolean setBankCheck (int C_BankAccount_ID, boolean isReceipt, String checkNo)
{
return setBankCheck (C_BankAccount_ID, isReceipt, null, null, checkNo);
} // setBankCheck
/**
* Set Check BankAccount Info
*
* @param C_BankAccount_ID bank account
* @param isReceipt true if receipt
* @param routingNo routing no
* @param accountNo account no
* @param checkNo chack no
* @return true if valid
*/
public boolean setBankCheck (int C_BankAccount_ID, boolean isReceipt,
String routingNo, String accountNo, String checkNo)
{
setTenderType (TENDERTYPE_Check);
setIsReceipt (isReceipt);
//
if (C_BankAccount_ID > 0
&& (routingNo == null || routingNo.length() == 0
|| accountNo == null || accountNo.length() == 0))
setBankAccountDetails(C_BankAccount_ID);
else
{
setC_BankAccount_ID(C_BankAccount_ID);
setRoutingNo (routingNo);
setAccountNo (accountNo);
}
setCheckNo (checkNo);
//
int check = MPaymentValidate.validateRoutingNo(routingNo).length()
+ MPaymentValidate.validateAccountNo(accountNo).length()
+ MPaymentValidate.validateCheckNo(checkNo).length();
return check == 0; // no error message
} // setBankCheck
/**
* Set Bank Account Details.
* Look up Routing No & Bank Acct No
* @param C_BankAccount_ID bank account
*/
public void setBankAccountDetails (int C_BankAccount_ID)
{
if (C_BankAccount_ID == 0)
return;
setC_BankAccount_ID(C_BankAccount_ID);
//
String sql = "SELECT b.RoutingNo, ba.AccountNo "
+ "FROM C_BankAccount ba"
+ " INNER JOIN C_Bank b ON (ba.C_Bank_ID=b.C_Bank_ID) "
+ "WHERE C_BankAccount_ID=?";
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
pstmt = DB.prepareStatement(sql, get_TrxName());
pstmt.setInt(1, C_BankAccount_ID);
rs = pstmt.executeQuery();
if (rs.next())
{
setRoutingNo (rs.getString(1));
setAccountNo (rs.getString(2));
}
}
catch (SQLException e)
{
log.log(Level.SEVERE, sql, e);
}
finally
{
DB.close(rs, pstmt);
rs = null;
pstmt = null;
}
} // setBankAccountDetails
/**
* Set Account Address
*
* @param name name
* @param street street
* @param city city
* @param state state
* @param zip zip
* @param country country
*/
public void setAccountAddress (String name, String street,
String city, String state, String zip, String country)
{
setA_Name (name);
setA_Street (street);
setA_City (city);
setA_State (state);
setA_Zip (zip);
setA_Country(country);
} // setAccountAddress
/**************************************************************************
* Process Payment
* @return true if approved
*/
public boolean processOnline()
{
log.info ("Amt=" + getPayAmt());
//
setIsOnline(true);
setErrorMessage(null);
// prevent charging twice
if (isApproved())
{
log.info("Already processed - " + getR_Result() + " - " + getR_RespMsg());
setErrorMessage("Payment already Processed");
return true;
}
if (m_mPaymentProcessor == null)
setPaymentProcessor();
if (m_mPaymentProcessor == null)
{
log.log(Level.WARNING, "No Payment Processor Model");
setErrorMessage("No Payment Processor Model");
return false;
}
boolean approved = false;
try
{
PaymentProcessor pp = PaymentProcessor.create(m_mPaymentProcessor, this);
if (pp == null)
setErrorMessage("No Payment Processor");
else
{
// Validate before trying to process
String msg = pp.validate();
if (msg!=null && msg.trim().length()>0) {
setErrorMessage(Msg.getMsg(getCtx(), msg));
} else {
// Process if validation succeeds
approved = pp.processCC ();
if (approved)
setErrorMessage(null);
else
setErrorMessage("From " + getCreditCardName() + ": " + getR_RespMsg());
}
}
}
catch (Exception e)
{
log.log(Level.SEVERE, "processOnline", e);
setErrorMessage("Payment Processor Error: " + e.getMessage());
}
setIsApproved(approved);
return approved;
} // processOnline
/**
* Process Online Payment.
* implements ProcessCall after standard constructor
* Called when pressing the Process_Online button in C_Payment
*
* @param ctx Context
* @param pi Process Info
* @param trx transaction
* @return true if the next process should be performed
*/
public boolean startProcess (Properties ctx, ProcessInfo pi, Trx trx)
{
log.info("startProcess - " + pi.getRecord_ID());
boolean retValue = false;
//
if (pi.getRecord_ID() != get_ID())
{
log.log(Level.SEVERE, "startProcess - Not same Payment - " + pi.getRecord_ID());
return false;
}
// Process it
retValue = processOnline();
saveEx();
return retValue; // Payment processed
} // startProcess
protected boolean afterDelete(boolean success)
{
int LAR_PaymentHeader_ID = get_ValueAsInt("LAR_PaymentHeader_ID");
// Si el pago/cobro tiene un header, recalculo los descuentos.
if (LAR_PaymentHeader_ID > 0)
{
// @fchiappano Obtengo todas las facturas asignadas a la cabecera
final List<MPaymentAllocate> facturas = SearchPaymentHeaderAttribute.getInvoices(getCtx(),
LAR_PaymentHeader_ID);
if (!facturas.isEmpty())
{
int pagoNro = 0;
BigDecimal resto = Env.ZERO;
BigDecimal saldoImpago = Env.ZERO;
BigDecimal descuento = Env.ZERO;
List<MPayment> pagos = SearchPaymentHeaderAttribute.getPayments(getCtx(), LAR_PaymentHeader_ID);
for (MPaymentAllocate factura : facturas)
{
saldoImpago = factura.getAmount();
for (int x = pagoNro; x < pagos.size(); x++)
{
MPayment pago = pagos.get(x);
// Si no hay resto sobrante del pago, tomo el payAmt.
if (resto.compareTo(Env.ZERO) == 0)
{
resto = pago.getPayAmt();
descuento = Env.ZERO;
}
if (resto.compareTo(saldoImpago) >= 0)
{
resto = resto.subtract(saldoImpago);
saldoImpago = Env.ZERO;
pagoNro = x;
descuento = descuento.add(factura.getDiscountAmt());
}
else
{
saldoImpago = saldoImpago.subtract(resto);
pagoNro = x + 1;
resto = Env.ZERO;
}
pago.setDiscountAmt(descuento);
pago.saveEx();
// Si la factura fue pagada en su totalidad, paso a la siguiente.
if (saldoImpago.compareTo(Env.ZERO) == 0)
break;
}
}
}
}
return true;
} // afterDelete
/**
* Before Save
* @param newRecord new
* @return save
*/
protected boolean beforeSave (boolean newRecord)
{
/* @emmie
// @Trifon - CashPayments
//if ( getTenderType().equals("X") ) {
if ( isCashTrx() && !MSysConfig.getBooleanValue("CASH_AS_PAYMENT", true , getAD_Client_ID())) {
// Cash Book Is mandatory
if ( getC_CashBook_ID() <= 0 ) {
log.saveError("Error", Msg.parseTranslation(getCtx(), "@Mandatory@: @C_CashBook_ID@"));
return false;
}
} else {
// Bank Account Is mandatory
if ( getC_BankAccount_ID() <= 0 ) {
log.saveError("Error", Msg.parseTranslation(getCtx(), "@Mandatory@: @C_BankAccount_ID@"));
return false;
}
}
// end @Trifon - CashPayments
@emmie */
// @emmie begin - Bank Account Is mandatory
if ( getC_BankAccount_ID() <= 0 ) {
log.saveError("Error", Msg.parseTranslation(getCtx(), "@Mandatory@: @C_BankAccount_ID@"));
return false;
}
// @emmie end
// We have a charge
if (getC_Charge_ID() != 0)
{
if (newRecord || is_ValueChanged("C_Charge_ID"))
{
setC_Order_ID(0);
setC_Invoice_ID(0);
setWriteOffAmt(Env.ZERO);
setDiscountAmt(Env.ZERO);
setIsOverUnderPayment(false);
setOverUnderAmt(Env.ZERO);
setIsPrepayment(false);
}
}
// We need a BPartner
else if (getC_BPartner_ID() == 0 && !isCashTrx())
{
if (getC_Invoice_ID() != 0)
;
else if (getC_Order_ID() != 0)
;
else
{
log.saveError("Error", Msg.parseTranslation(getCtx(), "@NotFound@: @C_BPartner_ID@"));
return false;
}
}
// Prepayment: No charge and order or project (not as acct dimension)
if (newRecord
|| is_ValueChanged("C_Charge_ID") || is_ValueChanged("C_Invoice_ID")
|| is_ValueChanged("C_Order_ID") || is_ValueChanged("C_Project_ID"))
{
// Si el cobro fue generado desde una POS Order, se asume que provino
// del POS por lo tanto no es un pago anticipado (Prepayment)
MOrder order = new MOrder(this.getCtx(), this.getC_Order_ID(), this.get_TrxName());
MDocType dt = new MDocType(this.getCtx(), order.getC_DocTypeTarget_ID(), this.get_TrxName());
if (dt.getDocSubTypeSO() != null
&& (dt.getDocSubTypeSO().equals(MDocType.DOCSUBTYPESO_POSOrder)))
this.setIsPrepayment(false);
else
setIsPrepayment (getC_Charge_ID() == 0
&& getC_BPartner_ID() != 0
&& (getC_Order_ID() != 0
|| (getC_Project_ID() != 0 && getC_Invoice_ID() == 0)));
}
if (isPrepayment())
{
if (newRecord
|| is_ValueChanged("C_Order_ID") || is_ValueChanged("C_Project_ID"))
{
setWriteOffAmt(Env.ZERO);
setDiscountAmt(Env.ZERO);
setIsOverUnderPayment(false);
setOverUnderAmt(Env.ZERO);
}
}
// Document Type/Receipt
if (getC_DocType_ID() == 0)
setC_DocType_ID();
else
{
MDocType dt = MDocType.get(getCtx(), getC_DocType_ID());
setIsReceipt(dt.isSOTrx());
}
setDocumentNo();
//
if (getDateAcct() == null)
setDateAcct(getDateTrx());
//
if (!isOverUnderPayment())
setOverUnderAmt(Env.ZERO);
// Organization
/* if ((newRecord || is_ValueChanged("C_BankAccount_ID"))
&& getC_Charge_ID() == 0) // allow different org for charge
{
MBankAccount ba = MBankAccount.get(getCtx(), getC_BankAccount_ID());
if (ba.getAD_Org_ID() != 0)
setAD_Org_ID(ba.getAD_Org_ID());
} */
// [ adempiere-Bugs-1885417 ] Validate BP on Payment Prepare or BeforeSave
// there is bp and (invoice or order)
if (getC_BPartner_ID() != 0 && (getC_Invoice_ID() != 0 || getC_Order_ID() != 0)) {
if (getC_Invoice_ID() != 0) {
MInvoice inv = new MInvoice(getCtx(), getC_Invoice_ID(), get_TrxName());
if (inv.getC_BPartner_ID() != getC_BPartner_ID()) {
log.saveError("Error", Msg.parseTranslation(getCtx(), "BP different from BP Invoice"));
return false;
}
}
if (getC_Order_ID() != 0) {
MOrder ord = new MOrder(getCtx(), getC_Order_ID(), get_TrxName());
if (ord.getC_BPartner_ID() != getC_BPartner_ID()) {
log.saveError("Error", Msg.parseTranslation(getCtx(), "BP different from BP Order"));
return false;
}
}
}
return true;
} // beforeSave
/**
* Get Allocated Amt in Payment Currency
* @return amount or null
*/
public BigDecimal getAllocatedAmt ()
{
BigDecimal retValue = null;
// begin @emmie issue #17
if (getC_Charge_ID() != 0 && !get_ValueAsBoolean("EsRetencionIIBB"))
// end @emmie
return getPayAmt();
// @mzuniga Se agrega COALESCE (Evita Null Pointer Exception cuando
// no se trabaja en una Cabecera)
String sql = "SELECT COALESCE(SUM(currencyConvert(al.Amount,"
+ "ah.C_Currency_ID, p.C_Currency_ID,ah.DateTrx,p.C_ConversionType_ID, al.AD_Client_ID,al.AD_Org_ID)), 0) "
+ "FROM C_AllocationLine al"
+ " INNER JOIN C_AllocationHdr ah ON (al.C_AllocationHdr_ID=ah.C_AllocationHdr_ID) "
+ " INNER JOIN C_Payment p ON (al.C_Payment_ID=p.C_Payment_ID) "
+ "WHERE al.C_Payment_ID=?"
+ " AND ah.IsActive='Y' AND al.IsActive='Y'";
// + " AND al.C_Invoice_ID IS NOT NULL";
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
pstmt = DB.prepareStatement(sql, get_TrxName());
pstmt.setInt(1, getC_Payment_ID());
rs = pstmt.executeQuery();
if (rs.next())
retValue = rs.getBigDecimal(1);
}
catch (Exception e)
{
log.log(Level.SEVERE, "getAllocatedAmt", e);
}
finally
{
DB.close(rs, pstmt);
rs = null;
pstmt = null;
}
// log.fine("getAllocatedAmt - " + retValue);
// ? ROUND(NVL(v_AllocatedAmt,0), 2);
return retValue;
} // getAllocatedAmt
/**
* Test Allocation (and set allocated flag)
* @return true if updated
*/
public boolean testAllocation()
{
// Cash Trx always allocated!!! WHY???
/* @Trifon - CashPayments
if (isCashTrx())
{
if (!isAllocated())
{
setIsAllocated(true);
return true;
}
return false;
}
*/
//
BigDecimal alloc = getAllocatedAmt();
if (alloc == null)
alloc = Env.ZERO;
BigDecimal total = getPayAmt();
if (!isReceipt())
total = total.negate();
// @mzuniga - Si es retención, marca el pago como asignado
if (get_ValueAsBoolean("EsRetencionSufrida"))
{
setIsAllocated(true);
log.fine("Allocated=" + true
+ " (" + alloc + "= Es Retención Sufrida )");
return true;
}
else
{
boolean test = total.compareTo(alloc) == 0;
boolean change = test != isAllocated();
if (change)
setIsAllocated(test);
log.fine("Allocated=" + test
+ " (" + alloc + "=" + total + ")");
return change;
}
} // testAllocation
/**
* Set Allocated Flag for payments
* @param ctx context
* @param C_BPartner_ID if 0 all
* @param trxName trx
*/
public static void setIsAllocated (Properties ctx, int C_BPartner_ID, String trxName)
{
int counter = 0;
String sql = "SELECT * FROM C_Payment "
+ "WHERE IsAllocated='N' AND DocStatus IN ('CO','CL')";
if (C_BPartner_ID > 1)
sql += " AND C_BPartner_ID=?";
else
sql += " AND AD_Client_ID=" + Env.getAD_Client_ID(ctx);
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
pstmt = DB.prepareStatement (sql, trxName);
if (C_BPartner_ID > 1)
pstmt.setInt (1, C_BPartner_ID);
rs = pstmt.executeQuery ();
while (rs.next ())
{
MPayment pay = new MPayment (ctx, rs, trxName);
if (pay.testAllocation())
if (pay.save())
counter++;
}
}
catch (Exception e)
{
s_log.log(Level.SEVERE, sql, e);
}
finally
{
DB.close(rs, pstmt);
rs = null;
pstmt = null;
}
s_log.config("#" + counter);
} // setIsAllocated
/**************************************************************************
* Set Error Message
* @param errorMessage error message
*/
public void setErrorMessage(String errorMessage)
{
m_errorMessage = errorMessage;
} // setErrorMessage
/**
* Get Error Message
* @return error message
*/
public String getErrorMessage()
{
return m_errorMessage;
} // getErrorMessage
/**
* Set Bank Account for Payment.
* @param C_BankAccount_ID C_BankAccount_ID
*/
public void setC_BankAccount_ID (int C_BankAccount_ID)
{
if (C_BankAccount_ID == 0)
{
setPaymentProcessor();
if (getC_BankAccount_ID() == 0)
throw new IllegalArgumentException("Can't find Bank Account");
}
else
super.setC_BankAccount_ID(C_BankAccount_ID);
} // setC_BankAccount_ID
/**
* Set BankAccount and PaymentProcessor
* @return true if found
*/
public boolean setPaymentProcessor ()
{
return setPaymentProcessor (getTenderType(), getCreditCardType());
} // setPaymentProcessor
/**
* Set BankAccount and PaymentProcessor
* @param tender TenderType see TENDER_
* @param CCType CC Type see CC_
* @return true if found
*/
public boolean setPaymentProcessor (String tender, String CCType)
{
m_mPaymentProcessor = null;
// Get Processor List
if (m_mPaymentProcessors == null || m_mPaymentProcessors.length == 0)
m_mPaymentProcessors = MPaymentProcessor.find (getCtx(), tender, CCType, getAD_Client_ID(),
getC_Currency_ID(), getPayAmt(), get_TrxName());
// Relax Amount
if (m_mPaymentProcessors == null || m_mPaymentProcessors.length == 0)
m_mPaymentProcessors = MPaymentProcessor.find (getCtx(), tender, CCType, getAD_Client_ID(),
getC_Currency_ID(), Env.ZERO, get_TrxName());
if (m_mPaymentProcessors == null || m_mPaymentProcessors.length == 0)
return false;
// Find the first right one
for (int i = 0; i < m_mPaymentProcessors.length; i++)
{
if (m_mPaymentProcessors[i].accepts (tender, CCType))
{
m_mPaymentProcessor = m_mPaymentProcessors[i];
}
}
if (m_mPaymentProcessor != null)
setC_BankAccount_ID (m_mPaymentProcessor.getC_BankAccount_ID());
//
return m_mPaymentProcessor != null;
} // setPaymentProcessor
/**
* Get Accepted Credit Cards for PayAmt (default 0)
* @return credit cards
*/
public ValueNamePair[] getCreditCards ()
{
return getCreditCards(getPayAmt());
} // getCreditCards
/**
* Get Accepted Credit Cards for amount
* @param amt trx amount
* @return credit cards
*/
public ValueNamePair[] getCreditCards (BigDecimal amt)
{
try
{
if (m_mPaymentProcessors == null || m_mPaymentProcessors.length == 0)
m_mPaymentProcessors = MPaymentProcessor.find (getCtx (), null, null,
getAD_Client_ID (), getC_Currency_ID (), amt, get_TrxName());
//
HashMap<String,ValueNamePair> map = new HashMap<String,ValueNamePair>(); // to eliminate duplicates
for (int i = 0; i < m_mPaymentProcessors.length; i++)
{
if (m_mPaymentProcessors[i].isAcceptAMEX ())
map.put (CREDITCARDTYPE_Amex, getCreditCardPair (CREDITCARDTYPE_Amex));
if (m_mPaymentProcessors[i].isAcceptDiners ())
map.put (CREDITCARDTYPE_Diners, getCreditCardPair (CREDITCARDTYPE_Diners));
if (m_mPaymentProcessors[i].isAcceptDiscover ())
map.put (CREDITCARDTYPE_Discover, getCreditCardPair (CREDITCARDTYPE_Discover));
if (m_mPaymentProcessors[i].isAcceptMC ())
map.put (CREDITCARDTYPE_MasterCard, getCreditCardPair (CREDITCARDTYPE_MasterCard));
if (m_mPaymentProcessors[i].isAcceptCorporate ())
map.put (CREDITCARDTYPE_PurchaseCard, getCreditCardPair (CREDITCARDTYPE_PurchaseCard));
if (m_mPaymentProcessors[i].isAcceptVisa ())
map.put (CREDITCARDTYPE_Visa, getCreditCardPair (CREDITCARDTYPE_Visa));
} // for all payment processors
//
ValueNamePair[] retValue = new ValueNamePair[map.size ()];
map.values ().toArray (retValue);
log.fine("getCreditCards - #" + retValue.length + " - Processors=" + m_mPaymentProcessors.length);
return retValue;
}
catch (Exception ex)
{
ex.printStackTrace();
return null;
}
} // getCreditCards
/**
* Get Type and name pair
* @param CreditCardType credit card Type
* @return pair
*/
private ValueNamePair getCreditCardPair (String CreditCardType)
{
return new ValueNamePair (CreditCardType, getCreditCardName(CreditCardType));
} // getCreditCardPair
/**************************************************************************
* Credit Card Number
* @param CreditCardNumber CreditCard Number
*/
public void setCreditCardNumber (String CreditCardNumber)
{
super.setCreditCardNumber (MPaymentValidate.checkNumeric(CreditCardNumber));
} // setCreditCardNumber
/**
* Verification Code
* @param newCreditCardVV CC verification
*/
public void setCreditCardVV(String newCreditCardVV)
{
super.setCreditCardVV (MPaymentValidate.checkNumeric(newCreditCardVV));
} // setCreditCardVV
/**
* Two Digit CreditCard MM
* @param CreditCardExpMM Exp month
*/
public void setCreditCardExpMM (int CreditCardExpMM)
{
if (CreditCardExpMM < 1 || CreditCardExpMM > 12)
;
else
super.setCreditCardExpMM (CreditCardExpMM);
} // setCreditCardExpMM
/**
* Two digit CreditCard YY (til 2020)
* @param newCreditCardExpYY 2 or 4 digit year
*/
public void setCreditCardExpYY (int newCreditCardExpYY)
{
int CreditCardExpYY = newCreditCardExpYY;
if (newCreditCardExpYY > 1999)
CreditCardExpYY = newCreditCardExpYY-2000;
super.setCreditCardExpYY(CreditCardExpYY);
} // setCreditCardExpYY
/**
* CreditCard Exp MMYY
* @param mmyy Exp in form of mmyy
* @return true if valid
*/
public boolean setCreditCardExp (String mmyy)
{
if (MPaymentValidate.validateCreditCardExp(mmyy).length() != 0)
return false;
//
String exp = MPaymentValidate.checkNumeric(mmyy);
String mmStr = exp.substring(0,2);
String yyStr = exp.substring(2,4);
setCreditCardExpMM (Integer.parseInt(mmStr));
setCreditCardExpYY (Integer.parseInt(yyStr));
return true;
} // setCreditCardExp
/**
* CreditCard Exp MMYY
* @param delimiter / - or null
* @return Exp
*/
public String getCreditCardExp(String delimiter)
{
String mm = String.valueOf(getCreditCardExpMM());
String yy = String.valueOf(getCreditCardExpYY());
StringBuffer retValue = new StringBuffer();
if (mm.length() == 1)
retValue.append("0");
retValue.append(mm);
//
if (delimiter != null)
retValue.append(delimiter);
//
if (yy.length() == 1)
retValue.append("0");
retValue.append(yy);
//
return (retValue.toString());
} // getCreditCardExp
/**
* MICR
* @param MICR MICR
*/
public void setMicr (String MICR)
{
super.setMicr (MPaymentValidate.checkNumeric(MICR));
} // setBankMICR
/**
* Routing No
* @param RoutingNo Routing No
*/
public void setRoutingNo(String RoutingNo)
{
// super.setRoutingNo (MPaymentValidate.checkNumeric(RoutingNo));
super.setRoutingNo (RoutingNo);
} // setBankRoutingNo
/**
* Bank Account No
* @param AccountNo AccountNo
*/
public void setAccountNo (String AccountNo)
{
super.setAccountNo (MPaymentValidate.checkNumeric(AccountNo));
} // setBankAccountNo
/**
* Check No
* @param CheckNo Check No
*/
public void setCheckNo(String CheckNo)
{
super.setCheckNo(MPaymentValidate.checkNumeric(CheckNo));
} // setBankCheckNo
/**
* Set DocumentNo to Payment info.
* If there is a R_PnRef that is set automatically
*/
private void setDocumentNo()
{
// Cash Transfer
if ("X".equals(getTenderType()))
return;
// Current Document No
String documentNo = getDocumentNo();
// Existing reversal
if (documentNo != null
&& documentNo.indexOf(REVERSE_INDICATOR) >= 0)
return;
// If external number exists - enforce it
if (getR_PnRef() != null && getR_PnRef().length() > 0)
{
if (!getR_PnRef().equals(documentNo))
setDocumentNo(getR_PnRef());
return;
}
documentNo = "";
// globalqss - read configuration to assign credit card or check number number for Payments
// Credit Card
if (TENDERTYPE_CreditCard.equals(getTenderType()))
{
if (MSysConfig.getBooleanValue("PAYMENT_OVERWRITE_DOCUMENTNO_WITH_CREDIT_CARD", true, getAD_Client_ID())) {
documentNo = getCreditCardType()
+ " " + Obscure.obscure(getCreditCardNumber())
+ " " + getCreditCardExpMM()
+ "/" + getCreditCardExpYY();
}
}
// Own Check No
else if (TENDERTYPE_Check.equals(getTenderType())
&& !isReceipt()
&& getCheckNo() != null && getCheckNo().length() > 0)
{
if (MSysConfig.getBooleanValue("PAYMENT_OVERWRITE_DOCUMENTNO_WITH_CHECK_ON_PAYMENT", true, getAD_Client_ID())) {
documentNo = getCheckNo();
}
}
// Customer Check: Routing: Account #Check
else if (TENDERTYPE_Check.equals(getTenderType())
&& isReceipt())
{
if (MSysConfig.getBooleanValue("PAYMENT_OVERWRITE_DOCUMENTNO_WITH_CHECK_ON_RECEIPT", true, getAD_Client_ID())) {
if (getRoutingNo() != null)
documentNo = getRoutingNo() + ": ";
if (getAccountNo() != null)
documentNo += getAccountNo();
if (getCheckNo() != null)
{
if (documentNo.length() > 0)
documentNo += " ";
documentNo += "#" + getCheckNo();
}
}
}
// Set Document No
documentNo = documentNo.trim();
if (documentNo.length() > 0)
setDocumentNo(documentNo);
} // setDocumentNo
/**
* Set Refernce No (and Document No)
* @param R_PnRef reference
*/
public void setR_PnRef (String R_PnRef)
{
super.setR_PnRef (R_PnRef);
if (R_PnRef != null)
setDocumentNo (R_PnRef);
} // setR_PnRef
// ---------------
/**
* Set Payment Amount
* @param PayAmt Pay Amt
*/
public void setPayAmt (BigDecimal PayAmt)
{
super.setPayAmt(PayAmt == null ? Env.ZERO : PayAmt);
} // setPayAmt
/**
* Set Payment Amount
*
* @param C_Currency_ID currency
* @param payAmt amount
*/
public void setAmount (int C_Currency_ID, BigDecimal payAmt)
{
if (C_Currency_ID == 0)
C_Currency_ID = MClient.get(getCtx()).getC_Currency_ID();
setC_Currency_ID(C_Currency_ID);
setPayAmt(payAmt);
} // setAmount
/**
* Discount Amt
* @param DiscountAmt Discount
*/
public void setDiscountAmt (BigDecimal DiscountAmt)
{
super.setDiscountAmt (DiscountAmt == null ? Env.ZERO : DiscountAmt);
} // setDiscountAmt
/**
* WriteOff Amt
* @param WriteOffAmt WriteOff
*/
public void setWriteOffAmt (BigDecimal WriteOffAmt)
{
super.setWriteOffAmt (WriteOffAmt == null ? Env.ZERO : WriteOffAmt);
} // setWriteOffAmt
/**
* OverUnder Amt
* @param OverUnderAmt OverUnder
*/
public void setOverUnderAmt (BigDecimal OverUnderAmt)
{
super.setOverUnderAmt (OverUnderAmt == null ? Env.ZERO : OverUnderAmt);
setIsOverUnderPayment(getOverUnderAmt().compareTo(Env.ZERO) != 0);
} // setOverUnderAmt
/**
* Tax Amt
* @param TaxAmt Tax
*/
public void setTaxAmt (BigDecimal TaxAmt)
{
super.setTaxAmt (TaxAmt == null ? Env.ZERO : TaxAmt);
} // setTaxAmt
/**
* Set Info from BP Bank Account
* @param ba BP bank account
*/
public void setBP_BankAccount (MBPBankAccount ba)
{
log.fine("" + ba);
if (ba == null)
return;
setC_BPartner_ID(ba.getC_BPartner_ID());
setAccountAddress(ba.getA_Name(), ba.getA_Street(), ba.getA_City(),
ba.getA_State(), ba.getA_Zip(), ba.getA_Country());
setA_EMail(ba.getA_EMail());
setA_Ident_DL(ba.getA_Ident_DL());
setA_Ident_SSN(ba.getA_Ident_SSN());
// CC
if (ba.getCreditCardType() != null)
setCreditCardType(ba.getCreditCardType());
if (ba.getCreditCardNumber() != null)
setCreditCardNumber(ba.getCreditCardNumber());
if (ba.getCreditCardExpMM() != 0)
setCreditCardExpMM(ba.getCreditCardExpMM());
if (ba.getCreditCardExpYY() != 0)
setCreditCardExpYY(ba.getCreditCardExpYY());
if (ba.getCreditCardVV() != null)
setCreditCardVV(ba.getCreditCardVV());
// Bank
if (ba.getAccountNo() != null)
setAccountNo(ba.getAccountNo());
if (ba.getRoutingNo() != null)
setRoutingNo(ba.getRoutingNo());
} // setBP_BankAccount
/**
* Save Info from BP Bank Account
* @param ba BP bank account
* @return true if saved
*/
public boolean saveToBP_BankAccount (MBPBankAccount ba)
{
if (ba == null)
return false;
ba.setA_Name(getA_Name());
ba.setA_Street(getA_Street());
ba.setA_City(getA_City());
ba.setA_State(getA_State());
ba.setA_Zip(getA_Zip());
ba.setA_Country(getA_Country());
ba.setA_EMail(getA_EMail());
ba.setA_Ident_DL(getA_Ident_DL());
ba.setA_Ident_SSN(getA_Ident_SSN());
// CC
ba.setCreditCardType(getCreditCardType());
ba.setCreditCardNumber(getCreditCardNumber());
ba.setCreditCardExpMM(getCreditCardExpMM());
ba.setCreditCardExpYY(getCreditCardExpYY());
ba.setCreditCardVV(getCreditCardVV());
// Bank
if (getAccountNo() != null)
ba.setAccountNo(getAccountNo());
if (getRoutingNo() != null)
ba.setRoutingNo(getRoutingNo());
// Trx
ba.setR_AvsAddr(getR_AvsAddr());
ba.setR_AvsZip(getR_AvsZip());
//
boolean ok = ba.save(get_TrxName());
log.fine("saveToBP_BankAccount - " + ba);
return ok;
} // setBP_BankAccount
/**
* Set Doc Type bases on IsReceipt
*/
private void setC_DocType_ID ()
{
setC_DocType_ID(isReceipt());
} // setC_DocType_ID
/**
* Set Doc Type
* @param isReceipt is receipt
*/
public void setC_DocType_ID (boolean isReceipt)
{
setIsReceipt(isReceipt);
String sql = "SELECT C_DocType_ID FROM C_DocType WHERE IsActive='Y' AND AD_Client_ID=? AND DocBaseType=? ORDER BY IsDefault DESC";
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
pstmt = DB.prepareStatement(sql, get_TrxName());
pstmt.setInt(1, getAD_Client_ID());
if (isReceipt)
pstmt.setString(2, X_C_DocType.DOCBASETYPE_ARReceipt);
else
pstmt.setString(2, X_C_DocType.DOCBASETYPE_APPayment);
rs = pstmt.executeQuery();
if (rs.next())
setC_DocType_ID(rs.getInt(1));
else
log.warning ("setDocType - NOT found - isReceipt=" + isReceipt);
}
catch (SQLException e)
{
log.log(Level.SEVERE, sql, e);
}
finally
{
DB.close(rs, pstmt);
rs = null;
pstmt = null;
}
} // setC_DocType_ID
/**
* Set Document Type
* @param C_DocType_ID doc type
*/
public void setC_DocType_ID (int C_DocType_ID)
{
// if (getDocumentNo() != null && getC_DocType_ID() != C_DocType_ID)
// setDocumentNo(null);
super.setC_DocType_ID(C_DocType_ID);
} // setC_DocType_ID
/**
* Verify Document Type with Invoice
* @param pAllocs
* @return true if ok
*/
private boolean verifyDocType(MPaymentAllocate[] pAllocs)
{
if (getC_DocType_ID() == 0)
return false;
//
Boolean documentSO = null;
// Check Invoice First
if (getC_Invoice_ID() > 0)
{
String sql = "SELECT idt.IsSOTrx "
+ "FROM C_Invoice i"
+ " INNER JOIN C_DocType idt ON (i.C_DocType_ID=idt.C_DocType_ID) "
+ "WHERE i.C_Invoice_ID=?";
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
pstmt = DB.prepareStatement(sql, get_TrxName());
pstmt.setInt(1, getC_Invoice_ID());
rs = pstmt.executeQuery();
if (rs.next())
documentSO = new Boolean ("Y".equals(rs.getString(1)));
}
catch (Exception e)
{
log.log(Level.SEVERE, sql, e);
}
finally
{
DB.close(rs, pstmt);
rs = null;
pstmt = null;
}
} // now Order - in Adempiere is allowed to pay PO or receive SO
else if (getC_Order_ID() > 0)
{
String sql = "SELECT odt.IsSOTrx "
+ "FROM C_Order o"
+ " INNER JOIN C_DocType odt ON (o.C_DocType_ID=odt.C_DocType_ID) "
+ "WHERE o.C_Order_ID=?";
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
pstmt = DB.prepareStatement(sql, get_TrxName());
pstmt.setInt(1, getC_Order_ID());
rs = pstmt.executeQuery();
if (rs.next())
documentSO = new Boolean ("Y".equals(rs.getString(1)));
}
catch (Exception e)
{
log.log(Level.SEVERE, sql, e);
}
finally
{
DB.close(rs, pstmt);
rs = null;
pstmt = null;
}
} // now Charge
else if (getC_Charge_ID() > 0)
{
// do nothing about charge
} // now payment allocate
else
{
if (pAllocs.length > 0) {
for (MPaymentAllocate pAlloc : pAllocs) {
String sql = "SELECT idt.IsSOTrx "
+ "FROM C_Invoice i"
+ " INNER JOIN C_DocType idt ON (i.C_DocType_ID=idt.C_DocType_ID) "
+ "WHERE i.C_Invoice_ID=?";
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
pstmt = DB.prepareStatement(sql, get_TrxName());
pstmt.setInt(1, pAlloc.getC_Invoice_ID());
rs = pstmt.executeQuery();
if (rs.next()) {
if (documentSO != null) { // already set, compare with current
if (documentSO.booleanValue() != ("Y".equals(rs.getString(1)))) {
return false;
}
} else {
documentSO = new Boolean ("Y".equals(rs.getString(1)));
}
}
}
catch (Exception e)
{
log.log(Level.SEVERE, sql, e);
}
finally
{
DB.close(rs, pstmt);
rs = null;
pstmt = null;
}
}
}
}
// DocumentType
Boolean paymentSO = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
String sql = "SELECT IsSOTrx "
+ "FROM C_DocType "
+ "WHERE C_DocType_ID=?";
try
{
pstmt = DB.prepareStatement(sql, get_TrxName());
pstmt.setInt(1, getC_DocType_ID());
rs = pstmt.executeQuery();
if (rs.next())
paymentSO = new Boolean ("Y".equals(rs.getString(1)));
}
catch (Exception e)
{
log.log(Level.SEVERE, sql, e);
}
finally
{
DB.close(rs, pstmt);
rs = null;
pstmt = null;
}
// No Payment info
if (paymentSO == null)
return false;
setIsReceipt(paymentSO.booleanValue());
// We have an Invoice .. and it does not match
if (documentSO != null
&& documentSO.booleanValue() != paymentSO.booleanValue())
return false;
// OK
return true;
} // verifyDocType
/**
* Verify Payment Allocate is ignored (must not exists) if the payment header has charge/invoice/order
* @param pAllocs
* @return true if ok
*/
private boolean verifyPaymentAllocateVsHeader(MPaymentAllocate[] pAllocs) {
if (pAllocs.length > 0) {
if (getC_Charge_ID() > 0 || getC_Invoice_ID() > 0 || getC_Order_ID() > 0)
return false;
}
return true;
}
/**
* Verify Payment Allocate Sum must be equal to the Payment Amount
* @param pAllocs
* @return true if ok
*/
private boolean verifyPaymentAllocateSum(MPaymentAllocate[] pAllocs) {
BigDecimal sumPaymentAllocates = Env.ZERO;
if (pAllocs.length > 0) {
for (MPaymentAllocate pAlloc : pAllocs)
sumPaymentAllocates = sumPaymentAllocates.add(pAlloc.getAmount());
if (getPayAmt().compareTo(sumPaymentAllocates) != 0)
return false;
}
return true;
}
/**
* Get ISO Code of Currency
* @return Currency ISO
*/
public String getCurrencyISO()
{
return MCurrency.getISO_Code (getCtx(), getC_Currency_ID());
} // getCurrencyISO
/**
* Get Document Status
* @return Document Status Clear Text
*/
public String getDocStatusName()
{
return MRefList.getListName(getCtx(), 131, getDocStatus());
} // getDocStatusName
/**
* Get Name of Credit Card
* @return Name
*/
public String getCreditCardName()
{
return getCreditCardName(getCreditCardType());
} // getCreditCardName
/**
* Get Name of Credit Card
* @param CreditCardType credit card type
* @return Name
*/
public String getCreditCardName(String CreditCardType)
{
if (CreditCardType == null)
return "--";
else if (CREDITCARDTYPE_MasterCard.equals(CreditCardType))
return "MasterCard";
else if (CREDITCARDTYPE_Visa.equals(CreditCardType))
return "Visa";
else if (CREDITCARDTYPE_Amex.equals(CreditCardType))
return "Amex";
else if (CREDITCARDTYPE_ATM.equals(CreditCardType))
return "ATM";
else if (CREDITCARDTYPE_Diners.equals(CreditCardType))
return "Diners";
else if (CREDITCARDTYPE_Discover.equals(CreditCardType))
return "Discover";
else if (CREDITCARDTYPE_PurchaseCard.equals(CreditCardType))
return "PurchaseCard";
return "?" + CreditCardType + "?";
} // getCreditCardName
/**
* Add to Description
* @param description text
*/
public void addDescription (String description)
{
String desc = getDescription();
if (desc == null)
setDescription(description);
else
setDescription(desc + " | " + description);
} // addDescription
/**
* Get Pay Amt
* @param absolute if true the absolute amount (i.e. negative if payment)
* @return amount
*/
public BigDecimal getPayAmt (boolean absolute)
{
if (isReceipt())
return super.getPayAmt();
return super.getPayAmt().negate();
} // getPayAmt
/**
* Get Pay Amt in cents
* @return amount in cents
*/
public int getPayAmtInCents ()
{
BigDecimal bd = super.getPayAmt().multiply(Env.ONEHUNDRED);
return bd.intValue();
} // getPayAmtInCents
/**************************************************************************
* Process document
* @param processAction document action
* @return true if performed
*/
public boolean processIt (String processAction)
{
m_processMsg = null;
DocumentEngine engine = new DocumentEngine (this, getDocStatus());
return engine.processIt (processAction, getDocAction());
} // process
/** Process Message */
private String m_processMsg = null;
/** Just Prepared Flag */
private boolean m_justPrepared = false;
/**
* Unlock Document.
* @return true if success
*/
public boolean unlockIt()
{
log.info(toString());
setProcessing(false);
return true;
} // unlockIt
/**
* Invalidate Document
* @return true if success
*/
public boolean invalidateIt()
{
log.info(toString());
setDocAction(DOCACTION_Prepare);
return true;
} // invalidateIt
/**************************************************************************
* Prepare Document
* @return new status (In Progress or Invalid)
*/
public String prepareIt()
{
log.info(toString());
m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_BEFORE_PREPARE);
if (m_processMsg != null)
return DocAction.STATUS_Invalid;
if (! MPaySelectionCheck.deleteGeneratedDraft(getCtx(), getC_Payment_ID(), get_TrxName())) {
m_processMsg = "Could not delete draft generated payment selection lines";
return DocAction.STATUS_Invalid;
}
// Std Period open?
if (!MPeriod.isOpen(getCtx(), getDateAcct(),
isReceipt() ? X_C_DocType.DOCBASETYPE_ARReceipt : X_C_DocType.DOCBASETYPE_APPayment, getAD_Org_ID()))
{
m_processMsg = "@PeriodClosed@";
return DocAction.STATUS_Invalid;
}
// Unsuccessful Online Payment
if (isOnline() && !isApproved())
{
if (getR_Result() != null)
m_processMsg = "@OnlinePaymentFailed@";
else
m_processMsg = "@PaymentNotProcessed@";
return DocAction.STATUS_Invalid;
}
// Waiting Payment - Need to create Invoice & Shipment
if (getC_Order_ID() != 0 && getC_Invoice_ID() == 0)
{ // see WebOrder.process
MOrder order = new MOrder (getCtx(), getC_Order_ID(), get_TrxName());
if (DOCSTATUS_WaitingPayment.equals(order.getDocStatus()))
{
order.setC_Payment_ID(getC_Payment_ID());
order.setDocAction(X_C_Order.DOCACTION_WaitComplete);
order.set_TrxName(get_TrxName());
// added AdempiereException by zuhri
if (!order.processIt (X_C_Order.DOCACTION_WaitComplete))
throw new AdempiereException("Failed when processing document - " + order.getProcessMsg());
// end added
m_processMsg = order.getProcessMsg();
order.saveEx(get_TrxName());
// Set Invoice
MInvoice[] invoices = order.getInvoices();
int length = invoices.length;
if (length > 0) // get last invoice
setC_Invoice_ID (invoices[length-1].getC_Invoice_ID());
//
if (getC_Invoice_ID() == 0)
{
m_processMsg = "@NotFound@ @C_Invoice_ID@";
return DocAction.STATUS_Invalid;
}
} // WaitingPayment
}
MPaymentAllocate[] pAllocs = MPaymentAllocate.get(this);
// Consistency of Invoice / Document Type and IsReceipt
if (!verifyDocType(pAllocs))
{
m_processMsg = "@PaymentDocTypeInvoiceInconsistent@";
return DocAction.STATUS_Invalid;
}
// Payment Allocate is ignored if charge/invoice/order exists in header
if (!verifyPaymentAllocateVsHeader(pAllocs))
{
m_processMsg = "@PaymentAllocateIgnored@";
return DocAction.STATUS_Invalid;
}
// Payment Amount must be equal to sum of Allocate amounts
if (!verifyPaymentAllocateSum(pAllocs))
{
m_processMsg = "@PaymentAllocateSumInconsistent@";
return DocAction.STATUS_Invalid;
}
// Do not pay when Credit Stop/Hold
if (!isReceipt())
{
MBPartner bp = new MBPartner (getCtx(), getC_BPartner_ID(), get_TrxName());
if (X_C_BPartner.SOCREDITSTATUS_CreditStop.equals(bp.getSOCreditStatus()))
{
m_processMsg = "@BPartnerCreditStop@ - @TotalOpenBalance@="
+ bp.getTotalOpenBalance()
+ ", @SO_CreditLimit@=" + bp.getSO_CreditLimit();
return DocAction.STATUS_Invalid;
}
if (X_C_BPartner.SOCREDITSTATUS_CreditHold.equals(bp.getSOCreditStatus()))
{
m_processMsg = "@BPartnerCreditHold@ - @TotalOpenBalance@="
+ bp.getTotalOpenBalance()
+ ", @SO_CreditLimit@=" + bp.getSO_CreditLimit();
return DocAction.STATUS_Invalid;
}
}
m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_AFTER_PREPARE);
if (m_processMsg != null)
return DocAction.STATUS_Invalid;
m_justPrepared = true;
if (!DOCACTION_Complete.equals(getDocAction()))
setDocAction(DOCACTION_Complete);
return DocAction.STATUS_InProgress;
} // prepareIt
/**
* Approve Document
* @return true if success
*/
public boolean approveIt()
{
log.info(toString());
setIsApproved(true);
return true;
} // approveIt
/**
* Reject Approval
* @return true if success
*/
public boolean rejectIt()
{
log.info(toString());
setIsApproved(false);
return true;
} // rejectIt
/**************************************************************************
* Complete Document
* @return new status (Complete, In Progress, Invalid, Waiting ..)
*/
public String completeIt()
{
// Re-Check
if (!m_justPrepared)
{
String status = prepareIt();
if (!DocAction.STATUS_InProgress.equals(status))
return status;
}
m_processMsg = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_BEFORE_COMPLETE);
if (m_processMsg != null)
return DocAction.STATUS_Invalid;
// Implicit Approval
if (!isApproved())
approveIt();
log.info(toString());
// Charge Handling
// begin @emmie issue #17
if (getC_Charge_ID() != 0 && !get_ValueAsBoolean("EsRetencionIIBB"))
// end @emmie
{
setIsAllocated(true);
}
else
{
allocateIt(); // Create Allocation Records
testAllocation();
}
// Project update
if (getC_Project_ID() != 0)
{
// MProject project = new MProject(getCtx(), getC_Project_ID());
}
// Update BP for Prepayments
if (getC_BPartner_ID() != 0 && getC_Invoice_ID() == 0 && getC_Charge_ID() == 0 && MPaymentAllocate.get(this).length == 0)
{
MBPartner bp = new MBPartner (getCtx(), getC_BPartner_ID(), get_TrxName());
// Update total balance to include this payment
BigDecimal payAmt = MConversionRate.convertBase(getCtx(), getPayAmt(),
getC_Currency_ID(), getDateAcct(), getC_ConversionType_ID(), getAD_Client_ID(), getAD_Org_ID());
if (payAmt == null)
{
m_processMsg = "Could not convert C_Currency_ID=" + getC_Currency_ID()
+ " to base C_Currency_ID=" + MClient.get(Env.getCtx()).getC_Currency_ID();
return DocAction.STATUS_Invalid;
}
// Total Balance
BigDecimal newBalance = bp.getTotalOpenBalance(false);
if (newBalance == null)
newBalance = Env.ZERO;
if (isReceipt())
newBalance = newBalance.subtract(payAmt);
else
newBalance = newBalance.add(payAmt);
bp.setTotalOpenBalance(newBalance);
bp.setSOCreditStatus();
bp.saveEx();
}
// Counter Doc
MPayment counter = createCounterDoc();
if (counter != null)
m_processMsg += " @CounterDoc@: @C_Payment_ID@=" + counter.getDocumentNo();
/* @emmie - Cashbook is no longer needed in LAR
// @Trifon - CashPayments
//if ( getTenderType().equals("X") ) {
if ( isCashTrx() && !MSysConfig.getBooleanValue("CASH_AS_PAYMENT", true , getAD_Client_ID())) {
// Create Cash Book entry
if ( getC_CashBook_ID() <= 0 ) {
log.saveError("Error", Msg.parseTranslation(getCtx(), "@Mandatory@: @C_CashBook_ID@"));
m_processMsg = "@NoCashBook@";
return DocAction.STATUS_Invalid;
}
MCash cash = MCash.get (getCtx(), getAD_Org_ID(), getDateAcct(), getC_Currency_ID(), get_TrxName());
if (cash == null || cash.get_ID() == 0)
{
m_processMsg = "@NoCashBook@";
return DocAction.STATUS_Invalid;
}
MCashLine cl = new MCashLine( cash );
cl.setCashType( X_C_CashLine.CASHTYPE_GeneralReceipts );
cl.setDescription("Generated From Payment #" + getDocumentNo());
cl.setC_Currency_ID( this.getC_Currency_ID() );
cl.setC_Payment_ID( getC_Payment_ID() ); // Set Reference to payment.
StringBuffer info=new StringBuffer();
info.append("Cash journal ( ")
.append(cash.getDocumentNo()).append(" )");
m_processMsg = info.toString();
// Amount
BigDecimal amt = this.getPayAmt();
MDocType dt = MDocType.get(getCtx(), invoice.getC_DocType_ID());
if (MDocType.DOCBASETYPE_APInvoice.equals( dt.getDocBaseType() )
|| MDocType.DOCBASETYPE_ARCreditMemo.equals( dt.getDocBaseType() )
) {
amt = amt.negate();
}
cl.setAmount( amt );
//
cl.setDiscountAmt( Env.ZERO );
cl.setWriteOffAmt( Env.ZERO );
cl.setIsGenerated( true );
if (!cl.save(get_TrxName()))
{
m_processMsg = "Could not save Cash Journal Line";
return DocAction.STATUS_Invalid;
}
}
// End Trifon - CashPayments
End @emmie - Cashbook is no longer needed in LAR */
// User Validation
String valid = ModelValidationEngine.get().fireDocValidate(this, ModelValidator.TIMING_AFTER_COMPLETE);
if (valid != null)
{
m_processMsg = valid;
return DocAction.STATUS_Invalid;
}
// Set the definite document number after completed (if needed)
setDefiniteDocumentNo();
//
setProcessed(true);
setDocAction(DOCACTION_Close);
return DocAction.STATUS_Completed;
} // completeIt
/**
* Set the definite document number after completed
*/
private void setDefiniteDocumentNo() {
MDocType dt = MDocType.get(getCtx(), getC_DocType_ID());
if (dt.isOverwriteDateOnComplete()) {
setDateTrx(new Timestamp (System.currentTimeMillis()));
}
if (dt.isOverwriteSeqOnComplete()) {
String value = DB.getDocumentNo(getC_DocType_ID(), get_TrxName(), true, this);
if (value != null)
setDocumentNo(value);
}
}
/**
* Create Counter Document
* @return payment
*/
private MPayment createCounterDoc()
{
// Is this a counter doc ?
if (getRef_Payment_ID() != 0)
return null;
// Org Must be linked to BPartner
MOrg org = MOrg.get(getCtx(), getAD_Org_ID());
int counterC_BPartner_ID = org.getLinkedC_BPartner_ID(get_TrxName());
if (counterC_BPartner_ID == 0)
return null;
// Business Partner needs to be linked to Org
MBPartner bp = new MBPartner (getCtx(), getC_BPartner_ID(), get_TrxName());
int counterAD_Org_ID = bp.getAD_OrgBP_ID_Int();
if (counterAD_Org_ID == 0)
return null;
MBPartner counterBP = new MBPartner (getCtx(), counterC_BPartner_ID, get_TrxName());
// MOrgInfo counterOrgInfo = MOrgInfo.get(getCtx(), counterAD_Org_ID);
log.info("Counter BP=" + counterBP.getName());
// Document Type
int C_DocTypeTarget_ID = 0;
MDocTypeCounter counterDT = MDocTypeCounter.getCounterDocType(getCtx(), getC_DocType_ID());
if (counterDT != null)
{
log.fine(counterDT.toString());
if (!counterDT.isCreateCounter() || !counterDT.isValid())
return null;
C_DocTypeTarget_ID = counterDT.getCounter_C_DocType_ID();
}
else // indirect
{
C_DocTypeTarget_ID = MDocTypeCounter.getCounterDocType_ID(getCtx(), getC_DocType_ID());
log.fine("Indirect C_DocTypeTarget_ID=" + C_DocTypeTarget_ID);
if (C_DocTypeTarget_ID <= 0)
return null;
}
// Deep Copy
MPayment counter = new MPayment (getCtx(), 0, get_TrxName());
counter.setAD_Org_ID(counterAD_Org_ID);
counter.setC_BPartner_ID(counterBP.getC_BPartner_ID());
counter.setIsReceipt(!isReceipt());
counter.setC_DocType_ID(C_DocTypeTarget_ID);
counter.setTrxType(getTrxType());
counter.setTenderType(getTenderType());
//
counter.setPayAmt(getPayAmt());
counter.setDiscountAmt(getDiscountAmt());
counter.setTaxAmt(getTaxAmt());
counter.setWriteOffAmt(getWriteOffAmt());
counter.setIsOverUnderPayment (isOverUnderPayment());
counter.setOverUnderAmt(getOverUnderAmt());
counter.setC_Currency_ID(getC_Currency_ID());
counter.setC_ConversionType_ID(getC_ConversionType_ID());
//
counter.setDateTrx (getDateTrx());
counter.setDateAcct (getDateAcct());
counter.setRef_Payment_ID(getC_Payment_ID());
//
String sql = "SELECT C_BankAccount_ID FROM C_BankAccount "
+ "WHERE C_Currency_ID=? AND AD_Org_ID IN (0,?) AND IsActive='Y' "
+ "ORDER BY IsDefault DESC";
int C_BankAccount_ID = DB.getSQLValue(get_TrxName(), sql, getC_Currency_ID(), counterAD_Org_ID);
counter.setC_BankAccount_ID(C_BankAccount_ID);
// References
counter.setC_Activity_ID(getC_Activity_ID());
counter.setC_Campaign_ID(getC_Campaign_ID());
counter.setC_Project_ID(getC_Project_ID());
counter.setUser1_ID(getUser1_ID());
counter.setUser2_ID(getUser2_ID());
counter.saveEx(get_TrxName());
log.fine(counter.toString());
setRef_Payment_ID(counter.getC_Payment_ID());
// Document Action
if (counterDT != null)
{
if (counterDT.getDocAction() != null)
{
counter.setDocAction(counterDT.getDocAction());
// added AdempiereException by zuhri
if (!counter.processIt(counterDT.getDocAction()))
throw new AdempiereException("Failed when rocessing document - " + counter.getProcessMsg());
// end added
counter.saveEx(get_TrxName());
}
}
return counter;
} // createCounterDoc
/**
* Allocate It.
* Only call when there is NO allocation as it will create duplicates.
* If an invoice exists, it allocates that
* otherwise it allocates Payment Selection.
* @return true if allocated
*/
public boolean allocateIt()
{
// Create invoice Allocation - See also MCash.completeIt
if (getC_Invoice_ID() != 0)
{
return allocateInvoice();
}
// Invoices of a AP Payment Selection
if (allocatePaySelection())
return true;
if (getC_Order_ID() != 0)
return false;
// Allocate to multiple Payments based on entry
MPaymentAllocate[] pAllocs = MPaymentAllocate.get(this);
if (pAllocs.length == 0)
return false;
MAllocationHdr alloc = new MAllocationHdr(getCtx(), false,
getDateTrx(), getC_Currency_ID(),
Msg.translate(getCtx(), "C_Payment_ID") + ": " + getDocumentNo(),
get_TrxName());
alloc.setAD_Org_ID(getAD_Org_ID());
if (!alloc.save())
{
log.severe("P.Allocations not created");
return false;
}
// Lines
for (int i = 0; i < pAllocs.length; i++)
{
MPaymentAllocate pa = pAllocs[i];
MAllocationLine aLine = null;
if (isReceipt())
aLine = new MAllocationLine (alloc, pa.getAmount(),
pa.getDiscountAmt(), pa.getWriteOffAmt(), pa.getOverUnderAmt());
else
aLine = new MAllocationLine (alloc, pa.getAmount().negate(),
pa.getDiscountAmt().negate(), pa.getWriteOffAmt().negate(), pa.getOverUnderAmt().negate());
aLine.setDocInfo(pa.getC_BPartner_ID(), 0, pa.getC_Invoice_ID());
aLine.setPaymentInfo(getC_Payment_ID(), 0);
if (!aLine.save(get_TrxName()))
log.warning("P.Allocations - line not saved");
else
{
pa.setC_AllocationLine_ID(aLine.getC_AllocationLine_ID());
pa.saveEx();
}
}
// added AdempiereException by zuhri
if (!alloc.processIt(DocAction.ACTION_Complete))
throw new AdempiereException("Failed when processing document - " + alloc.getProcessMsg());
// end added
m_processMsg = "@C_AllocationHdr_ID@: " + alloc.getDocumentNo();
return alloc.save(get_TrxName());
} // allocateIt
/**
* Allocate single AP/AR Invoice
* @return true if allocated
*/
private boolean allocateInvoice()
{
// calculate actual allocation
BigDecimal allocationAmt = getPayAmt(); // underpayment
if (getOverUnderAmt().signum() < 0 && getPayAmt().signum() > 0)
allocationAmt = allocationAmt.add(getOverUnderAmt()); // overpayment (negative)
MAllocationHdr alloc = new MAllocationHdr(getCtx(), false,
getDateTrx(), getC_Currency_ID(),
Msg.translate(getCtx(), "C_Payment_ID") + ": " + getDocumentNo() + " [1]", get_TrxName());
alloc.setAD_Org_ID(getAD_Org_ID());
alloc.setDateAcct(getDateAcct()); // in case date acct is different from datetrx in payment
alloc.saveEx();
MAllocationLine aLine = null;
if (isReceipt())
aLine = new MAllocationLine (alloc, allocationAmt,
getDiscountAmt(), getWriteOffAmt(), getOverUnderAmt());
else
aLine = new MAllocationLine (alloc, allocationAmt.negate(),
getDiscountAmt().negate(), getWriteOffAmt().negate(), getOverUnderAmt().negate());
aLine.setDocInfo(getC_BPartner_ID(), 0, getC_Invoice_ID());
aLine.setC_Payment_ID(getC_Payment_ID());
aLine.saveEx(get_TrxName());
// added AdempiereException by zuhri
if (!alloc.processIt(DocAction.ACTION_Complete))
throw new AdempiereException("Failed when processing document - " + alloc.getProcessMsg());
// end added
alloc.saveEx(get_TrxName());
m_processMsg = "@C_AllocationHdr_ID@: " + alloc.getDocumentNo();
// Get Project from Invoice
int C_Project_ID = DB.getSQLValue(get_TrxName(),
"SELECT MAX(C_Project_ID) FROM C_Invoice WHERE C_Invoice_ID=?", getC_Invoice_ID());
if (C_Project_ID > 0 && getC_Project_ID() == 0)
setC_Project_ID(C_Project_ID);
else if (C_Project_ID > 0 && getC_Project_ID() > 0 && C_Project_ID != getC_Project_ID())
log.warning("Invoice C_Project_ID=" + C_Project_ID
+ " <> Payment C_Project_ID=" + getC_Project_ID());
return true;
} // allocateInvoice
/**
* Allocate Payment Selection
* @return true if allocated
*/
private boolean allocatePaySelection()
{
MAllocationHdr alloc = new MAllocationHdr(getCtx(), false,
getDateTrx(), getC_Currency_ID(),
Msg.translate(getCtx(), "C_Payment_ID") + ": " + getDocumentNo() + " [n]", get_TrxName());
alloc.setAD_Org_ID(getAD_Org_ID());
alloc.setDateAcct(getDateAcct()); // in case date acct is different from datetrx in payment
String sql = "SELECT psc.C_BPartner_ID, psl.C_Invoice_ID, psl.IsSOTrx, " // 1..3
+ " psl.PayAmt, psl.DiscountAmt, psl.DifferenceAmt, psl.OpenAmt "
+ "FROM C_PaySelectionLine psl"
+ " INNER JOIN C_PaySelectionCheck psc ON (psl.C_PaySelectionCheck_ID=psc.C_PaySelectionCheck_ID) "
+ "WHERE psc.C_Payment_ID=?";
PreparedStatement pstmt = null;
ResultSet rs = null;
try
{
pstmt = DB.prepareStatement(sql, get_TrxName());
pstmt.setInt(1, getC_Payment_ID());
rs = pstmt.executeQuery();
while (rs.next())
{
int C_BPartner_ID = rs.getInt(1);
int C_Invoice_ID = rs.getInt(2);
if (C_BPartner_ID == 0 && C_Invoice_ID == 0)
continue;
boolean isSOTrx = "Y".equals(rs.getString(3));
BigDecimal PayAmt = rs.getBigDecimal(4);
BigDecimal DiscountAmt = rs.getBigDecimal(5);
BigDecimal WriteOffAmt = Env.ZERO;
BigDecimal OpenAmt = rs.getBigDecimal(7);
BigDecimal OverUnderAmt = OpenAmt.subtract(PayAmt)
.subtract(DiscountAmt).subtract(WriteOffAmt);
//
if (alloc.get_ID() == 0 && !alloc.save(get_TrxName()))
{
log.log(Level.SEVERE, "Could not create Allocation Hdr");
rs.close();
pstmt.close();
return false;
}
MAllocationLine aLine = null;
if (isSOTrx)
aLine = new MAllocationLine (alloc, PayAmt,
DiscountAmt, WriteOffAmt, OverUnderAmt);
else
aLine = new MAllocationLine (alloc, PayAmt.negate(),
DiscountAmt.negate(), WriteOffAmt.negate(), OverUnderAmt.negate());
aLine.setDocInfo(C_BPartner_ID, 0, C_Invoice_ID);
aLine.setC_Payment_ID(getC_Payment_ID());
if (!aLine.save(get_TrxName()))
log.log(Level.SEVERE, "Could not create Allocation Line");
}
}
catch (Exception e)
{
log.log(Level.SEVERE, "allocatePaySelection", e);
}
finally
{
DB.close(rs, pstmt);
rs = null;
pstmt = null;
}
// Should start WF
boolean ok = true;
if (alloc.get_ID() == 0)
{
log.fine("No Allocation created - C_Payment_ID="
+ getC_Payment_ID());
ok = false;
}
else
{
// added Adempiere Exception by zuhri
if(alloc.processIt(DocAction.ACTION_Complete))
ok = alloc.save(get_TrxName());
else
throw new AdempiereException("Failed when processing document - " + alloc.getProcessMsg());
// end added by zuhri
m_processMsg = "@C_AllocationHdr_ID@: " + alloc.getDocumentNo();
}
return ok;
} // allocatePaySelection
/**
* De-allocate Payment.
* Unkink Invoices and Orders and delete Allocations
*/
private void deAllocate()
{
if (getC_Order_ID() != 0)
setC_Order_ID(0);
// if (getC_Invoice_ID() == 0)
// return;
// De-Allocate all
MAllocationHdr[] allocations = MAllocationHdr.getOfPayment(getCtx(),
getC_Payment_ID(), get_TrxName());
log.fine("#" + allocations.length);
for (int i = 0; i < allocations.length; i++)
{
allocations[i].set_TrxName(get_TrxName());
allocations[i].setDocAction(DocAction.ACTION_Reverse_Correct);
if (!allocations[i].processIt(DocAction.ACTION_Reverse_Correct))
throw new AdempiereException(allocations[i].getProcessMsg());
allocations[i].saveEx();
}
// Unlink (in case allocation did not get it)
if (getC_Invoice_ID() != 0)
{
// Invoice
String sql = "UPDATE C_Invoice "
+ "SET C_Payment_ID = NULL, IsPaid='N' "
+ "WHERE C_Invoice_ID=" + getC_Invoice_ID()
+ " AND C_Payment_ID=" + getC_Payment_ID();
int no = DB.executeUpdate(sql, get_TrxName());
if (no != 0)
log.fine("Unlink Invoice #" + no);
// Order
sql = "UPDATE C_Order o "
+ "SET C_Payment_ID = NULL "
+ "WHERE EXISTS (SELECT * FROM C_Invoice i "
+ "WHERE o.C_Order_ID=i.C_Order_ID AND i.C_Invoice_ID=" + getC_Invoice_ID() + ")"
+ " AND C_Payment_ID=" + getC_Payment_ID();
no = DB.executeUpdate(sql, get_TrxName());
if (no != 0)
log.fine("Unlink Order #" + no);
}
//
setC_Invoice_ID(0);
setIsAllocated(false);
} // deallocate
/**
* Void Document.
* @return true if success
*/
public boolean voidIt()
{
log.info(toString());
// Before Void
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_VOID);
if (m_processMsg != null)
return false;
if (DOCSTATUS_Closed.equals(getDocStatus())
|| DOCSTATUS_Reversed.equals(getDocStatus())
|| DOCSTATUS_Voided.equals(getDocStatus()))
{
m_processMsg = "Document Closed: " + getDocStatus();
setDocAction(DOCACTION_None);
return false;
}
// If on Bank Statement, don't void it - reverse it
if (getC_BankStatementLine_ID() > 0)
return reverseCorrectIt();
// Not Processed
if (DOCSTATUS_Drafted.equals(getDocStatus())
|| DOCSTATUS_Invalid.equals(getDocStatus())
|| DOCSTATUS_InProgress.equals(getDocStatus())
|| DOCSTATUS_Approved.equals(getDocStatus())
|| DOCSTATUS_NotApproved.equals(getDocStatus()) )
{
addDescription(Msg.getMsg(getCtx(), "Voided") + " (" + getPayAmt() + ")");
setPayAmt(Env.ZERO);
setDiscountAmt(Env.ZERO);
setWriteOffAmt(Env.ZERO);
setOverUnderAmt(Env.ZERO);
setIsAllocated(false);
// Unlink & De-Allocate
deAllocate();
}
else
return reverseCorrectIt();
//
// After Void
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_VOID);
if (m_processMsg != null)
return false;
setProcessed(true);
setDocAction(DOCACTION_None);
return true;
} // voidIt
/**
* Close Document.
* @return true if success
*/
public boolean closeIt()
{
log.info(toString());
// Before Close
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_CLOSE);
if (m_processMsg != null)
return false;
setDocAction(DOCACTION_None);
// After Close
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_CLOSE);
if (m_processMsg != null)
return false;
return true;
} // closeIt
/**
* Reverse Correction
* @return true if success
*/
public boolean reverseCorrectIt()
{
log.info(toString());
// Before reverseCorrect
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_REVERSECORRECT);
if (m_processMsg != null)
return false;
// Std Period open?
Timestamp dateAcct = getDateAcct();
if (!MPeriod.isOpen(getCtx(), dateAcct,
isReceipt() ? X_C_DocType.DOCBASETYPE_ARReceipt : X_C_DocType.DOCBASETYPE_APPayment, getAD_Org_ID()))
dateAcct = new Timestamp(System.currentTimeMillis());
// Auto Reconcile if not on Bank Statement
boolean reconciled = getC_BankStatementLine_ID() == 0; //AZ Goodwill
// Create Reversal
MPayment reversal = new MPayment (getCtx(), 0, get_TrxName());
copyValues(this, reversal);
reversal.setClientOrg(this);
reversal.setC_Order_ID(0);
reversal.setC_Invoice_ID(0);
reversal.setDateAcct(dateAcct);
//
reversal.setDocumentNo(getDocumentNo() + REVERSE_INDICATOR); // indicate reversals
reversal.setDocStatus(DOCSTATUS_Drafted);
reversal.setDocAction(DOCACTION_Complete);
//
reversal.setPayAmt(getPayAmt().negate());
reversal.setDiscountAmt(getDiscountAmt().negate());
reversal.setWriteOffAmt(getWriteOffAmt().negate());
reversal.setOverUnderAmt(getOverUnderAmt().negate());
//
reversal.setIsAllocated(true);
reversal.setIsReconciled(reconciled); // to put on bank statement
reversal.setIsOnline(false);
reversal.setIsApproved(true);
reversal.setR_PnRef(null);
reversal.setR_Result(null);
reversal.setR_RespMsg(null);
reversal.setR_AuthCode(null);
reversal.setR_Info(null);
reversal.setProcessing(false);
reversal.setOProcessing("N");
reversal.setProcessed(false);
reversal.setPosted(false);
reversal.setDescription(getDescription());
reversal.addDescription("{->" + getDocumentNo() + ")");
//FR [ 1948157 ]
reversal.setReversal_ID(getC_Payment_ID());
reversal.saveEx(get_TrxName());
// Post Reversal
if (!reversal.processIt(DocAction.ACTION_Complete))
{
m_processMsg = "Reversal ERROR: " + reversal.getProcessMsg();
return false;
}
reversal.closeIt();
reversal.setDocStatus(DOCSTATUS_Reversed);
reversal.setDocAction(DOCACTION_None);
reversal.saveEx(get_TrxName());
// Unlink & De-Allocate
deAllocate();
setIsReconciled (reconciled);
setIsAllocated (true); // the allocation below is overwritten
// Set Status
addDescription("(" + reversal.getDocumentNo() + "<-)");
setDocStatus(DOCSTATUS_Reversed);
setDocAction(DOCACTION_None);
setProcessed(true);
//FR [ 1948157 ]
setReversal_ID(reversal.getC_Payment_ID());
// Create automatic Allocation
MAllocationHdr alloc = new MAllocationHdr (getCtx(), false,
getDateTrx(), getC_Currency_ID(),
Msg.translate(getCtx(), "C_Payment_ID") + ": " + reversal.getDocumentNo(), get_TrxName());
alloc.setAD_Org_ID(getAD_Org_ID());
if (!alloc.save())
log.warning("Automatic allocation - hdr not saved");
else
{
// Original Allocation
MAllocationLine aLine = new MAllocationLine (alloc, getPayAmt(true),
Env.ZERO, Env.ZERO, Env.ZERO);
aLine.setDocInfo(getC_BPartner_ID(), 0, 0);
aLine.setPaymentInfo(getC_Payment_ID(), 0);
if (!aLine.save(get_TrxName()))
log.warning("Automatic allocation - line not saved");
// Reversal Allocation
aLine = new MAllocationLine (alloc, reversal.getPayAmt(true),
Env.ZERO, Env.ZERO, Env.ZERO);
aLine.setDocInfo(reversal.getC_BPartner_ID(), 0, 0);
aLine.setPaymentInfo(reversal.getC_Payment_ID(), 0);
if (!aLine.save(get_TrxName()))
log.warning("Automatic allocation - reversal line not saved");
}
// added AdempiereException by zuhri
if (!alloc.processIt(DocAction.ACTION_Complete))
throw new AdempiereException("Failed when processing document - " + alloc.getProcessMsg());
// end added
alloc.saveEx(get_TrxName());
//
StringBuffer info = new StringBuffer (reversal.getDocumentNo());
info.append(" - @C_AllocationHdr_ID@: ").append(alloc.getDocumentNo());
// Update BPartner
if (getC_BPartner_ID() != 0)
{
MBPartner bp = new MBPartner (getCtx(), getC_BPartner_ID(), get_TrxName());
bp.setTotalOpenBalance();
bp.saveEx(get_TrxName());
}
// After reverseCorrect
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_REVERSECORRECT);
if (m_processMsg != null)
return false;
m_processMsg = info.toString();
return true;
} // reverseCorrectionIt
/**
* Get Bank Statement Line of payment or 0
* @return id or 0
*/
private int getC_BankStatementLine_ID()
{
String sql = "SELECT C_BankStatementLine_ID FROM C_BankStatementLine WHERE C_Payment_ID=?";
int id = DB.getSQLValue(get_TrxName(), sql, getC_Payment_ID());
if (id < 0)
return 0;
return id;
} // getC_BankStatementLine_ID
/**
* Reverse Accrual - none
* @return true if success
*/
public boolean reverseAccrualIt()
{
log.info(toString());
// Before reverseAccrual
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_REVERSEACCRUAL);
if (m_processMsg != null)
return false;
// After reverseAccrual
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_REVERSEACCRUAL);
if (m_processMsg != null)
return false;
return false;
} // reverseAccrualIt
/**
* Re-activate
* @return true if success
*/
public boolean reActivateIt()
{
log.info(toString());
// Before reActivate
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_BEFORE_REACTIVATE);
if (m_processMsg != null)
return false;
if (! reverseCorrectIt())
return false;
// After reActivate
m_processMsg = ModelValidationEngine.get().fireDocValidate(this,ModelValidator.TIMING_AFTER_REACTIVATE);
if (m_processMsg != null)
return false;
return true;
} // reActivateIt
/**
* String Representation
* @return info
*/
public String toString ()
{
StringBuffer sb = new StringBuffer ("MPayment[");
sb.append(get_ID()).append("-").append(getDocumentNo())
.append(",Receipt=").append(isReceipt())
.append(",PayAmt=").append(getPayAmt())
.append(",Discount=").append(getDiscountAmt())
.append(",WriteOff=").append(getWriteOffAmt())
.append(",OverUnder=").append(getOverUnderAmt());
return sb.toString ();
} // toString
/**
* Get Document Info
* @return document info (untranslated)
*/
public String getDocumentInfo()
{
MDocType dt = MDocType.get(getCtx(), getC_DocType_ID());
return dt.getName() + " " + getDocumentNo();
} // getDocumentInfo
/**
* Create PDF
* @return File or null
*/
public File createPDF ()
{
try
{
File temp = File.createTempFile(get_TableName()+get_ID()+"_", ".pdf");
return createPDF (temp);
}
catch (Exception e)
{
log.severe("Could not create PDF - " + e.getMessage());
}
return null;
} // getPDF
/**
* Create PDF file
* @param file output file
* @return file if success
*/
public File createPDF (File file)
{
// ReportEngine re = ReportEngine.get (getCtx(), ReportEngine.PAYMENT, getC_Payment_ID());
// if (re == null)
return null;
// return re.getPDF(file);
} // createPDF
/*************************************************************************
* Get Summary
* @return Summary of Document
*/
public String getSummary()
{
StringBuffer sb = new StringBuffer();
sb.append(getDocumentNo());
// : Total Lines = 123.00 (#1)
sb.append(": ")
.append(Msg.translate(getCtx(),"PayAmt")).append("=").append(getPayAmt())
.append(",").append(Msg.translate(getCtx(),"WriteOffAmt")).append("=").append(getWriteOffAmt());
// - Description
if (getDescription() != null && getDescription().length() > 0)
sb.append(" - ").append(getDescription());
return sb.toString();
} // getSummary
/**
* Get Process Message
* @return clear text error message
*/
public String getProcessMsg()
{
return m_processMsg;
} // getProcessMsg
/**
* Get Document Owner (Responsible)
* @return AD_User_ID
*/
public int getDoc_User_ID()
{
return getCreatedBy();
} // getDoc_User_ID
/**
* Get Document Approval Amount
* @return amount payment(AP) or write-off(AR)
*/
public BigDecimal getApprovalAmt()
{
if (isReceipt())
return getWriteOffAmt();
return getPayAmt();
} // getApprovalAmt
} // MPayment