IDEMPIERE-5471 Refactoring of Payment Selection and Payment Print/Exp… (#1554)

* IDEMPIERE-5471 Refactoring of Payment Selection and Payment Print/Export form

* IDEMPIERE-5471 Refactoring of Payment Selection and Payment Print/Export form

- merge patch from Carlos
This commit is contained in:
hengsin 2022-11-09 00:15:25 +08:00 committed by GitHub
parent c926c05d4e
commit 5b5a957d87
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 635 additions and 222 deletions

View File

@ -676,7 +676,7 @@ public class MPaySelectionCheck extends X_C_PaySelectionCheck
StringBuilder sb = new StringBuilder("MPaymentCheck[");
sb.append(get_ID()).append("-").append(getDocumentNo())
.append("-").append(getPayAmt())
.append(",PaymetRule=").append(getPaymentRule())
.append(",PaymentRule=").append(getPaymentRule())
.append(",Qty=").append(getQty())
.append("]");
return sb.toString();

View File

@ -374,7 +374,6 @@ public abstract class PO
public int hashCode()
{
assert false : "hashCode not designed";
return 42; // any arbitrary constant will do
}

View File

@ -1088,7 +1088,7 @@ public class MWorkflow extends X_AD_Workflow implements ImmutablePOSupport
ProcessInfo processInfo = new ProcessInfo (((DocAction)po).getDocumentInfo(),column.getAD_Process_ID(),po.get_Table_ID(),po.get_ID());
processInfo.setTransactionName(po.get_TrxName());
processInfo.setPO(po);
ServerProcessCtl.process(processInfo, Trx.get(processInfo.getTransactionName(), false));
ServerProcessCtl.process(processInfo, !Util.isEmpty(processInfo.getTransactionName(), true) ? Trx.get(processInfo.getTransactionName(), false) : null);
return processInfo;
}
} // MWorkflow_ID

View File

@ -22,6 +22,7 @@ import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import org.adempiere.util.Callback;
@ -57,12 +58,6 @@ import org.compiere.apps.form.PayPrint;
import org.compiere.model.MLookup;
import org.compiere.model.MLookupFactory;
import org.compiere.model.MPaySelectionCheck;
import org.compiere.model.MPaymentBatch;
import org.compiere.print.MPrintFormat;
import org.compiere.print.ReportEngine;
import org.compiere.process.ProcessInfo;
import org.compiere.process.ServerProcessCtl;
import org.compiere.util.DB;
import org.compiere.util.DisplayType;
import org.compiere.util.Env;
import org.compiere.util.Msg;
@ -74,8 +69,6 @@ import org.zkoss.zul.Center;
import org.zkoss.zul.Filedownload;
import org.zkoss.zul.South;
import com.lowagie.text.pdf.PdfReader;
/**
* Payment Print and Export
*
@ -121,7 +114,7 @@ public class WPayPrint extends PayPrint implements IFormController, EventListene
}
} // WPayPrint
// Static Variables
// Instance Variables
protected Panel centerPanel = new Panel();
protected ConfirmPanel southPanel = new ConfirmPanel(true, false, false, false, false, false, false);
protected Grid centerLayout = GridFactory.newGridLayout();
@ -277,9 +270,9 @@ public class WPayPrint extends PayPrint implements IFormController, EventListene
* Action Listener
* @param e event
*/
@Override
public void onEvent(Event e)
{
// log.config( "VPayPrint.actionPerformed" + e.toString());
if (e.getTarget() == bCancel)
dispose();
else if (m_C_PaySelection_ID <= 0)
@ -293,18 +286,17 @@ public class WPayPrint extends PayPrint implements IFormController, EventListene
cmd_EFT();
else if (e.getTarget() == bPrint)
confirm_cmd_print();
} // actionPerformed
}
/**
* PaySelect changed - load Bank
* load pay selection details
*/
protected void loadPaySelectInfo()
{
log.info( "VPayPrint.loadPaySelectInfo");
if (m_C_PaySelection_ID <= 0)
return;
// load Banks from PaySelectLine
// load details from PaySelectLine
loadPaySelectInfo(m_C_PaySelection_ID);
fBank.setText(bank);
@ -319,7 +311,6 @@ public class WPayPrint extends PayPrint implements IFormController, EventListene
*/
protected void loadPaymentRule()
{
log.info("");
if (m_C_BankAccount_ID == -1)
return;
@ -370,7 +361,9 @@ public class WPayPrint extends PayPrint implements IFormController, EventListene
getPluginFeatures();
} // loadPaymentRuleInfo
/**
* load payment export class
*/
protected void getPluginFeatures()
{
if (m_C_PaySelection_ID!=0)
@ -473,7 +466,6 @@ public class WPayPrint extends PayPrint implements IFormController, EventListene
protected void cmd_EFT()
{
String PaymentRule = fPaymentRule.getSelectedItem().toValueNamePair().getValue();
log.info(PaymentRule);
if (!getChecks(PaymentRule))
return;
dispose();
@ -504,7 +496,6 @@ public class WPayPrint extends PayPrint implements IFormController, EventListene
protected void cmd_print()
{
String PaymentRule = fPaymentRule.getSelectedItem().toValueNamePair().getValue();
log.info(PaymentRule);
if (!getChecks(PaymentRule))
return;
@ -513,54 +504,16 @@ public class WPayPrint extends PayPrint implements IFormController, EventListene
if (log.isLoggable(Level.CONFIG)) log.config("DocumentNo=" + startDocumentNo);
// for all checks
List<File> pdfList = new ArrayList<File>();
int lastDocumentNo = startDocumentNo;
for (int i = 0; i < m_checks.length; i++)
{
MPaySelectionCheck check = m_checks[i];
// Set new Check Document No
check.setDocumentNo(String.valueOf(lastDocumentNo));
check.saveEx();
// Update BankAccountDoc
MPaySelectionCheck.confirmPrint(m_checks[i], m_batch);
// ReportCtrl will check BankAccountDoc for PrintFormat
ReportEngine re = ReportEngine.get(Env.getCtx(), ReportEngine.CHECK, check.get_ID(), m_WindowNo);
List<File> pdfList = null;
try
{
MPrintFormat format = re.getPrintFormat();
File pdfFile = null;
if (format.getJasperProcess_ID() > 0)
{
ProcessInfo pi = new ProcessInfo("", format.getJasperProcess_ID());
pi.setRecord_ID(check.get_ID());
pi.setIsBatch(true);
ServerProcessCtl.process(pi, null);
pdfFile = pi.getPDFReport();
}
else
{
pdfFile = File.createTempFile("WPayPrint", null);
re.getPDF(pdfFile);
}
if (pdfFile != null)
{
// increase the check document no by the number of pages of the generated pdf file
PdfReader document = new PdfReader(pdfFile.getAbsolutePath());
lastDocumentNo += document.getNumberOfPages();
pdfList.add(pdfFile);
}
pdfList = createCheckDocuments(startDocumentNo, PaymentRule);
}
catch (Exception e)
{
log.log(Level.SEVERE, e.getLocalizedMessage(), e);
return;
}
}
SimplePDFViewer chequeViewer = null;
try
@ -578,16 +531,6 @@ public class WPayPrint extends PayPrint implements IFormController, EventListene
}
final SimplePDFViewer chequeViewerRef = chequeViewer;
// Update Check Next Document No
if (startDocumentNo != lastDocumentNo)
{
StringBuilder sb = new StringBuilder();
sb.append("UPDATE C_BankAccountDoc SET CurrentNext=").append(lastDocumentNo)
.append(" WHERE C_BankAccount_ID=").append(m_C_BankAccount_ID)
.append(" AND PaymentRule='").append(PaymentRule).append("'");
DB.executeUpdate(sb.toString(), null);
}
Dialog.ask(m_WindowNo, "VPayPrintPrintRemittance", new Callback<Boolean>() {
@Override
@ -596,35 +539,7 @@ public class WPayPrint extends PayPrint implements IFormController, EventListene
SimplePDFViewer remitViewer = null;
if (result)
{
List<File> pdfList = new ArrayList<File>();
for (int i = 0; i < m_checks.length; i++)
{
MPaySelectionCheck check = m_checks[i];
ReportEngine re = ReportEngine.get(Env.getCtx(), ReportEngine.REMITTANCE, check.get_ID(), m_WindowNo);
try
{
MPrintFormat format = re.getPrintFormat();
if (format.getJasperProcess_ID() > 0)
{
ProcessInfo pi = new ProcessInfo("", format.getJasperProcess_ID());
pi.setRecord_ID(check.get_ID());
pi.setIsBatch(true);
ServerProcessCtl.process(pi, null);
pdfList.add(pi.getPDFReport());
}
else
{
File file = File.createTempFile("WPayPrint", null);
re.getPDF(file);
pdfList.add(file);
}
}
catch (Exception e)
{
log.log(Level.SEVERE, e.getLocalizedMessage(), e);
}
}
List<File> pdfList = createRemittanceDocuments();
try
{
@ -660,31 +575,18 @@ public class WPayPrint extends PayPrint implements IFormController, EventListene
*/
protected boolean getChecks(String PaymentRule)
{
// do we have values
if (m_C_PaySelection_ID <= 0 || m_C_BankAccount_ID == -1
|| fPaymentRule.getSelectedIndex() == -1 || fDocumentNo.getValue() == null)
AtomicReference<ValueNamePair> error = new AtomicReference<>();
boolean ok = getChecks(PaymentRule, fDocumentNo.getValue(), error, null);
if (!ok)
{
Dialog.error(m_WindowNo, "VPayPrintNoRecords",
"(" + Msg.translate(Env.getCtx(), "C_PaySelectionLine_ID") + "=0)");
return false;
if (error.get() != null)
Dialog.error(m_WindowNo, error.get().getValue(), error.get().getName());
}
if (log.isLoggable(Level.CONFIG)) log.config("C_PaySelection_ID=" + m_C_PaySelection_ID + ", PaymentRule=" + PaymentRule);
// get payment selection checks without check no assignment
m_checks = MPaySelectionCheck.get(m_C_PaySelection_ID, PaymentRule, null);
//
if (m_checks == null || m_checks.length == 0)
{
Dialog.error(m_WindowNo, "VPayPrintNoRecords",
"(" + Msg.translate(Env.getCtx(), "C_PaySelectionLine_ID") + " #0");
return false;
}
m_batch = MPaymentBatch.getForPaySelection (Env.getCtx(), m_C_PaySelection_ID, null);
return true;
return ok;
} // getChecks
@Override
public ADForm getForm() {
return form;
}

View File

@ -21,13 +21,11 @@ package org.adempiere.webui.apps.form;
import static org.compiere.model.SystemIDs.FORM_PAYMENT_PRINT_EXPORT;
import static org.compiere.model.SystemIDs.PROCESS_C_PAYSELECTION_CREATEPAYMENT;
import java.io.File;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.logging.Level;
import org.adempiere.util.Callback;
import org.adempiere.util.IProcessUI;
import org.adempiere.webui.ClientInfo;
import org.adempiere.webui.LayoutUtils;
import org.adempiere.webui.apps.AEnv;
@ -69,7 +67,6 @@ import org.compiere.util.KeyNamePair;
import org.compiere.util.Msg;
import org.compiere.util.ValueNamePair;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.SuspendNotAllowedException;
import org.zkoss.zk.ui.WrongValueException;
import org.zkoss.zk.ui.event.Event;
@ -96,12 +93,9 @@ import org.zkoss.zul.Space;
*/
@org.idempiere.ui.zk.annotation.Form(name = "org.compiere.apps.form.VPaySelect")
public class WPaySelect extends PaySelect
implements IFormController, EventListener<Event>, WTableModelListener, IProcessUI, ValueChangeListener
implements IFormController, EventListener<Event>, WTableModelListener, ValueChangeListener
{
/** @todo withholding */
protected CustomForm form = new CustomForm();
//
private Panel mainPanel = new Panel();
private Borderlayout mainLayout = new Borderlayout();
@ -130,7 +124,6 @@ public class WPaySelect extends PaySelect
private Listbox fieldDtype = ListboxFactory.newDropdownListbox();
private Panel southPanel;
private Checkbox chkOnePaymentPerInv = new Checkbox();
@SuppressWarnings("unused")
private ProcessInfo m_pi;
private boolean m_isLock;
private Hlayout statusBar = new Hlayout();
@ -155,10 +148,10 @@ public class WPaySelect extends PaySelect
{
log.log(Level.SEVERE, "", e);
}
} // init
}
/**
* Static Init
* Init UI component and layout
* @throws Exception
*/
private void zkInit() throws Exception
@ -371,7 +364,7 @@ public class WPaySelect extends PaySelect
} // loadBankInfo
/**
* Query and create TableInfo
* Load open documents
*/
protected void loadTableInfo()
{
@ -424,6 +417,7 @@ public class WPaySelect extends PaySelect
* ActionListener
* @param e event
*/
@Override
public void onEvent (Event e)
{
// Update Bank Info
@ -497,7 +491,7 @@ public class WPaySelect extends PaySelect
{
m_isOnePaymentPerInvoice = chkOnePaymentPerInv.isChecked();
}
} // actionPerformed
}
@Override
public void valueChange(ValueChangeEvent e) {
@ -513,7 +507,7 @@ public class WPaySelect extends PaySelect
{
if (e.getColumn() == 0)
calculateSelection();
} // valueChanged
}
/**
* Calculate selected rows.
@ -572,7 +566,6 @@ public class WPaySelect extends PaySelect
AD_Proces_ID, X_C_PaySelection.Table_ID, m_ps.getC_PaySelection_ID(), false);
if (dialog.isValid()) {
try {
//dialog.setWidth("500px");
dialog.setVisible(true);
dialog.setPage(form.getPage());
dialog.doHighlighted();
@ -634,54 +627,24 @@ public class WPaySelect extends PaySelect
this.dispose();
}
public void executeASync(ProcessInfo pi) {
}
/**
*
* @return true if UI is lock
*/
public boolean isUILocked() {
return m_isLock;
}
@Override
public ADForm getForm() {
return form;
}
@Override
public void statusUpdate(String message) {
/**
*
* @return {@link ProcessInfo}
*/
public ProcessInfo getProcessInfo() {
return m_pi;
}
@Override
public void ask(final String message, final Callback<Boolean> callback) {
Executions.schedule(form.getDesktop(), new EventListener<Event>() {
@Override
public void onEvent(Event event) throws Exception {
Dialog.ask(m_WindowNo, message, callback);
}
}, new Event("onAsk"));
}
@Override
public void download(File file) {
// TODO Auto-generated method stub
}
@Override
public void askForInput(final String message, final Callback<String> callback) {
Executions.schedule(form.getDesktop(), new EventListener<Event>() {
@Override
public void onEvent(Event event) throws Exception {
Dialog.askForInput(m_WindowNo, message, callback);
}
}, new Event("onAskForInput"));
}
@Override
public void askForSecretInput(final String message, final Callback<String> callback) {
Executions.schedule(form.getDesktop(), new EventListener<Event>() {
@Override
public void onEvent(Event event) throws Exception {
Dialog.askForSecretInput(m_WindowNo, message, callback);
}
}, new Event("onAskForInput"));
}
} // VPaySelect
}

View File

@ -459,7 +459,7 @@ public class WListbox extends Listbox implements IMiniTable, TableValueChangeLis
MRole.SQL_FULLYQUALIFIED,
MRole.SQL_RO);
logger.finest(finalSQL);
if (logger.isLoggable(Level.FINEST)) logger.finest(finalSQL);
return finalSQL;
}

View File

@ -33,3 +33,4 @@ Bundle-ClassPath: .,
lib/org-openide-util-lookup.jar
Automatic-Module-Name: org.adempiere.ui
Bundle-Vendor: iDempiere Community
Import-Package: com.lowagie.text.pdf

View File

@ -20,11 +20,14 @@ package org.compiere.apps.form;
import static org.compiere.model.SystemIDs.REFERENCE_PAYMENTRULE;
import java.io.File;
import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import org.adempiere.base.Core;
@ -32,38 +35,47 @@ import org.compiere.model.MLookupFactory;
import org.compiere.model.MLookupInfo;
import org.compiere.model.MPaySelectionCheck;
import org.compiere.model.MPaymentBatch;
import org.compiere.print.MPrintFormat;
import org.compiere.print.ReportEngine;
import org.compiere.process.ProcessInfo;
import org.compiere.process.ServerProcessCtl;
import org.compiere.util.CLogger;
import org.compiere.util.DB;
import org.compiere.util.Env;
import org.compiere.util.Language;
import org.compiere.util.Msg;
import org.compiere.util.PaymentExport;
import org.compiere.util.Util;
import org.compiere.util.ValueNamePair;
import com.lowagie.text.pdf.PdfReader;
public class PayPrint {
/** Window No */
public int m_WindowNo = 0;
protected int m_WindowNo = 0;
/** Used Bank Account */
public int m_C_BankAccount_ID = -1;
protected int m_C_BankAccount_ID = -1;
/** Export Class for Bank Account */
public String m_PaymentExportClass = null;
protected String m_PaymentExportClass = null;
/** Payment Selection */
public int m_C_PaySelection_ID = 0;
protected int m_C_PaySelection_ID = 0;
/** Payment Information */
public MPaySelectionCheck[] m_checks = null;
protected MPaySelectionCheck[] m_checks = null;
/** Payment Batch */
public MPaymentBatch m_batch = null;
protected MPaymentBatch m_batch = null;
/** Logger */
public static final CLogger log = CLogger.getCLogger(PayPrint.class);
protected static final CLogger log = CLogger.getCLogger(PayPrint.class);
public String bank;
public String currency;
public BigDecimal balance;
protected String bank;
protected String currency;
protected BigDecimal balance;
protected PaymentExport m_PaymentExport;
/**
* PaySelect changed - load Bank
* load pay selection details (bank info, balance and payment export class)
* @param C_PaySelection_ID
*/
public void loadPaySelectInfo(int C_PaySelection_ID)
{
@ -114,7 +126,9 @@ public class PayPrint {
} // loadPaySelectInfo
/**
* Bank changed - load PaymentRule
* load payment rules that's applicable to pay selection
* @param C_PaySelection_ID
* @return list of applicable payment rules
*/
public ArrayList<ValueNamePair> loadPaymentRule(int C_PaySelection_ID)
{
@ -159,14 +173,17 @@ public class PayPrint {
return data;
} // loadPaymentRule
public String noPayments;
public Integer documentNo;
public Double sumPayments;
public Integer printFormatId;
protected String noPayments;
protected Integer documentNo;
protected Double sumPayments;
protected Integer printFormatId;
/**
* PaymentRule changed - load DocumentNo, NoPayments,
* enable/disable EFT, Print
* @param C_PaySelection_ID
* @param PaymentRule
* @return error message (if any)
*/
public String loadPaymentRuleInfo(int C_PaySelection_ID, String PaymentRule)
{
@ -241,6 +258,11 @@ public class PayPrint {
return msg;
} // loadPaymentRuleInfo
/**
*
* @param err error message buffer
* @return 0 if loaded fine, -1 if failed to load
*/
protected int loadPaymentExportClass (StringBuffer err)
{
m_PaymentExport = null ;
@ -278,4 +300,136 @@ public class PayPrint {
}
return 0 ;
} // loadPaymentExportClass
/**
* Create PDF documents from pay selection check records
* @param startDocumentNo
* @param paymentRule
* @return list of PDF documents
* @throws Exception
*/
protected List<File> createCheckDocuments(int startDocumentNo, String paymentRule) throws Exception
{
// for all checks
List<File> pdfList = new ArrayList<File>();
int lastDocumentNo = startDocumentNo;
for (int i = 0; i < m_checks.length; i++)
{
MPaySelectionCheck check = m_checks[i];
// Set new Check Document No
check.setDocumentNo(String.valueOf(lastDocumentNo));
check.saveEx();
// Update BankAccountDoc
MPaySelectionCheck.confirmPrint(m_checks[i], m_batch);
// ReportCtrl will check BankAccountDoc for PrintFormat
ReportEngine re = ReportEngine.get(Env.getCtx(), ReportEngine.CHECK, check.get_ID(), m_WindowNo);
MPrintFormat format = re.getPrintFormat();
File pdfFile = null;
if (format.getJasperProcess_ID() > 0)
{
ProcessInfo pi = new ProcessInfo("", format.getJasperProcess_ID());
pi.setRecord_ID(check.get_ID());
pi.setIsBatch(true);
ServerProcessCtl.process(pi, null);
pdfFile = pi.getPDFReport();
}
else
{
pdfFile = File.createTempFile("WPayPrint", null);
re.getPDF(pdfFile);
}
if (pdfFile != null)
{
// increase the check document no by the number of pages of the generated pdf file
PdfReader document = new PdfReader(pdfFile.getAbsolutePath());
lastDocumentNo += document.getNumberOfPages();
pdfList.add(pdfFile);
}
}
// Update Check Next Document No
if (startDocumentNo != lastDocumentNo)
{
StringBuilder sb = new StringBuilder();
sb.append("UPDATE C_BankAccountDoc SET CurrentNext=").append(lastDocumentNo)
.append(" WHERE C_BankAccount_ID=").append(m_C_BankAccount_ID)
.append(" AND PaymentRule='").append(paymentRule).append("'");
DB.executeUpdate(sb.toString(), null);
}
return pdfList;
}
/**
* Create Remittance Documents (PDF) from pay selection check records
* @return list of Remittance documents
*/
protected List<File> createRemittanceDocuments()
{
List<File> pdfList = new ArrayList<File>();
for (int i = 0; i < m_checks.length; i++)
{
MPaySelectionCheck check = m_checks[i];
ReportEngine re = ReportEngine.get(Env.getCtx(), ReportEngine.REMITTANCE, check.get_ID(), m_WindowNo);
try
{
MPrintFormat format = re.getPrintFormat();
if (format.getJasperProcess_ID() > 0)
{
ProcessInfo pi = new ProcessInfo("", format.getJasperProcess_ID());
pi.setRecord_ID(check.get_ID());
pi.setIsBatch(true);
ServerProcessCtl.process(pi, null);
pdfList.add(pi.getPDFReport());
}
else
{
File file = File.createTempFile("WPayPrint", null);
re.getPDF(file);
pdfList.add(file);
}
}
catch (Exception e)
{
log.log(Level.SEVERE, e.getLocalizedMessage(), e);
}
}
return pdfList;
}
/**************************************************************************
* Get Checks
* @param PaymentRule Payment Rule
* @return true if payments were created
*/
protected boolean getChecks(String PaymentRule, BigDecimal startDocumentNo, AtomicReference<ValueNamePair> error, String trxName)
{
// do we have values
if (m_C_PaySelection_ID <= 0 || m_C_BankAccount_ID == -1
|| Util.isEmpty(PaymentRule, true) || startDocumentNo == null)
{
error.set(new ValueNamePair("VPayPrintNoRecords", "(" + Msg.translate(Env.getCtx(), "C_PaySelectionLine_ID") + " #0"));
return false;
}
if (log.isLoggable(Level.CONFIG)) log.config("C_PaySelection_ID=" + m_C_PaySelection_ID + ", PaymentRule=" + PaymentRule);
// get payment selection checks without check no assignment
m_checks = MPaySelectionCheck.get(m_C_PaySelection_ID, PaymentRule, trxName);
//
if (m_checks == null || m_checks.length == 0)
{
error.set(new ValueNamePair("VPayPrintNoRecords", "(" + Msg.translate(Env.getCtx(), "C_PaySelectionLine_ID") + " #0"));
return false;
}
m_batch = MPaymentBatch.getForPaySelection (Env.getCtx(), m_C_PaySelection_ID, null);
return true;
} // getChecks
}

View File

@ -49,30 +49,32 @@ import org.compiere.util.ValueNamePair;
public class PaySelect
{
/** @todo withholding */
/** Window No */
public int m_WindowNo = 0;
protected int m_WindowNo = 0;
/** Format */
public DecimalFormat m_format = DisplayType.getNumberFormat(DisplayType.Amount);
protected DecimalFormat m_format = DisplayType.getNumberFormat(DisplayType.Amount);
/** Bank Balance */
private BigDecimal m_bankBalance = Env.ZERO;
/** SQL for Query */
private String m_sql;
/** Number of selected rows */
public int m_noSelected = 0;
protected int m_noSelected = 0;
/** Client ID */
private int m_AD_Client_ID = 0;
/**/
public boolean m_isLocked = false;
protected boolean m_isLocked = false;
/** Payment Selection */
public MPaySelection m_ps = null;
protected MPaySelection m_ps = null;
/** one-To-one payment per invoice */
public boolean m_isOnePaymentPerInvoice = false;
protected boolean m_isOnePaymentPerInvoice = false;
/** Logger */
public static final CLogger log = CLogger.getCLogger(PaySelect.class);
protected static final CLogger log = CLogger.getCLogger(PaySelect.class);
/**
* Get list of active bank account with active C_BankAccountDoc records
* @return list of {@link BankInfo}
*/
public ArrayList<BankInfo> getBankAccountData()
{
ArrayList<BankInfo> data = new ArrayList<BankInfo>();
@ -119,6 +121,10 @@ public class PaySelect
return data;
}
/**
* Get list of business partners with open vendor invoice
* @return list of business partners
*/
public ArrayList<KeyNamePair> getBPartnerData()
{
ArrayList<KeyNamePair> data = new ArrayList<KeyNamePair>();
@ -161,6 +167,10 @@ public class PaySelect
return data;
}
/**
* Get document types for invoice and credit memo
* @return list of document types
*/
public ArrayList<KeyNamePair> getDocTypeData()
{
ArrayList<KeyNamePair> data = new ArrayList<KeyNamePair>();
@ -200,6 +210,10 @@ public class PaySelect
return data;
}
/**
* Setup {@link ColumnInfo}, From and Where clause
* @param miniTable
*/
public void prepareTable(IMiniTable miniTable)
{
Properties ctx = Env.getCtx();
@ -253,10 +267,12 @@ public class PaySelect
+ " AND i.DocStatus IN ('CO','CL')"
+ " AND i.AD_Client_ID=?", // additional where & order in loadTableInfo()
true, "i");
} // dynInit
} // prepareTable
/**
* Load Bank Info - Load Info from Bank Account and valid Documents (PaymentRule)
* Get payment rules that's applicable to bank account
* @param bi
* @return list of applicable payment rules
*/
public ArrayList<ValueNamePair> getPaymentRuleData(BankInfo bi)
{
@ -301,12 +317,19 @@ public class PaySelect
}
/**
* Query and create TableInfo
* Load open documents into miniTable
* @param bi
* @param payDate
* @param paymentRule
* @param onlyDue
* @param onlyPositiveBalance
* @param bpartner
* @param docType
* @param miniTable
*/
public void loadTableInfo(BankInfo bi, Timestamp payDate, ValueNamePair paymentRule, boolean onlyDue,
boolean onlyPositiveBalance, KeyNamePair bpartner, KeyNamePair docType, IMiniTable miniTable)
{
log.config("");
// not yet initialized
if (m_sql == null)
return;
@ -414,6 +437,8 @@ public class PaySelect
/**
* Calculate selected rows.
* - add up selected rows
* @param miniTable
* @return info message
*/
public String calculateSelection(IMiniTable miniTable)
{
@ -442,15 +467,16 @@ public class PaySelect
return info.toString();
} // calculateSelection
public Trx trx = null;
/**
* Generate PaySelection
* @param miniTable
* @param paymentRule
* @param payDate
* @param bi
* @return error message (if any)
*/
public String generatePaySelect(IMiniTable miniTable, ValueNamePair paymentRule, Timestamp payDate, BankInfo bi)
{
log.info("");
String trxName = null;
Trx trx = null;
try {
@ -510,11 +536,21 @@ public class PaySelect
trx.commit();
trx.close();
}
if (m_ps != null)
m_ps.set_TrxName(null);
}
return null;
} // generatePaySelect
/**
* Get balance of selected bank record (after call to {@link #getPaymentRuleData(BankInfo)})
* @return bank balance
*/
protected BigDecimal getBankBalance() {
return m_bankBalance;
}
/**************************************************************************
* Bank Account Info
*/
@ -538,12 +574,13 @@ public class PaySelect
Currency = newCurrency;
Balance = newBalance;
}
int C_BankAccount_ID;
int C_Currency_ID;
String Name;
public int C_BankAccount_ID;
public int C_Currency_ID;
public String Name;
public String Currency;
public BigDecimal Balance;
boolean Transfers;
public boolean Transfers;
/**
* to String

View File

@ -0,0 +1,334 @@
/***********************************************************************
* This file is part of iDempiere ERP Open Source *
* http://www.idempiere.org *
* *
* Copyright (C) Contributors *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License *
* as published by the Free Software Foundation; either version 2 *
* of the License, or (at your option) any later version. *
* *
* 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., 51 Franklin Street, Fifth Floor, Boston, *
* MA 02110-1301, USA. *
* *
* Contributors: *
* - hengsin *
**********************************************************************/
package org.idempiere.test.form;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.File;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicReference;
import org.compiere.apps.form.PayPrint;
import org.compiere.apps.form.PaySelect;
import org.compiere.apps.form.PaySelect.BankInfo;
import org.compiere.minigrid.IDColumn;
import org.compiere.model.MAllocationHdr;
import org.compiere.model.MAllocationLine;
import org.compiere.model.MBPartner;
import org.compiere.model.MInvoice;
import org.compiere.model.MInvoiceLine;
import org.compiere.model.MPInstance;
import org.compiere.model.MPInstancePara;
import org.compiere.model.MPaySelection;
import org.compiere.model.MPaySelectionCheck;
import org.compiere.model.MPaySelectionLine;
import org.compiere.model.MPayment;
import org.compiere.model.Query;
import org.compiere.model.SystemIDs;
import org.compiere.process.DocAction;
import org.compiere.process.ProcessInfo;
import org.compiere.process.ServerProcessCtl;
import org.compiere.util.DB;
import org.compiere.util.DisplayType;
import org.compiere.util.Env;
import org.compiere.util.KeyNamePair;
import org.compiere.util.TimeUtil;
import org.compiere.util.Util;
import org.compiere.util.ValueNamePair;
import org.compiere.wf.MWorkflow;
import org.idempiere.test.AbstractTestCase;
import org.idempiere.test.DictionaryIDs;
import org.idempiere.test.ui.MiniTableImpl;
import org.junit.jupiter.api.Test;
public class PaySelectFormTest extends AbstractTestCase {
public PaySelectFormTest() {
}
@Test
public void testPaySelect() {
MInvoice invoice = null;
MInvoiceLine line = null;
MPaySelection paySelection = null;
Optional<ValueNamePair> optionalPR = null;
try {
//create vendor invoice
invoice = new MInvoice(Env.getCtx(), 0, null);
MBPartner bp = MBPartner.get(Env.getCtx(), DictionaryIDs.C_BPartner.PATIO.id);
invoice.setBPartner(bp);
invoice.setIsSOTrx(false);
invoice.setC_DocTypeTarget_ID();
invoice.setC_Currency_ID(DictionaryIDs.C_Currency.USD.id);
invoice.setPaymentRule(MInvoice.PAYMENTRULE_Check);
invoice.setC_PaymentTerm_ID(DictionaryIDs.C_PaymentTerm.IMMEDIATE.id);
invoice.setDateAcct(TimeUtil.getDay(System.currentTimeMillis()));
invoice.setDateOrdered(invoice.getDateAcct());
invoice.saveEx();
line = new MInvoiceLine(invoice);
line.setC_Charge_ID(DictionaryIDs.C_Charge.COMMISSIONS.id);
line.setQty(new BigDecimal("1"));
line.setPrice(new BigDecimal("10"));
line.saveEx();
ProcessInfo info = MWorkflow.runDocumentActionWorkflow(invoice, DocAction.ACTION_Complete);
assertFalse(info.isError(), info.getSummary());
invoice.load(null);
assertEquals(DocAction.STATUS_Completed, invoice.getDocStatus());
PaySelectImpl form = new PaySelectImpl();
MInvoice finalInvoice = invoice;
ArrayList<BankInfo> bis = form.getBankAccountData();
assertTrue(bis.size() > 0, "Failed to retrieve bank account info");
Optional<BankInfo> optionalBI = bis.stream().filter(e -> e.C_Currency_ID == finalInvoice.getC_Currency_ID()).findFirst();
assertTrue(optionalBI.isPresent(), "Failed to locate bank account record for currency " + invoice.getC_Currency_ID());
ArrayList<KeyNamePair> bps = form.getBPartnerData();
assertTrue(bps.size() > 0, "Failed to retrieve business partner records with open invoice");
Optional<KeyNamePair> optionalBP = bps.stream().filter(e -> e.getKey() == finalInvoice.getC_BPartner_ID()).findFirst();
assertTrue(optionalBP.isPresent(), "Failed to find business partner for invoice");
ArrayList<KeyNamePair> docTypes = form.getDocTypeData();
assertTrue(docTypes.size() > 0, "Failed to retrieve document type records");
Optional<KeyNamePair> optionalDocType = docTypes.stream().filter(e -> e.getKey() == finalInvoice.getC_DocType_ID()).findFirst();
assertTrue(optionalDocType.isPresent(), "Failed to retrieve document type for invoice");
ArrayList<ValueNamePair> paymentRules = form.getPaymentRuleData(optionalBI.get());
assertTrue(paymentRules.size() > 0, "Failed to retrieve payment rule records");
optionalPR = paymentRules.stream().filter(e -> e.getValue().equals(finalInvoice.getPaymentRule())).findFirst();
assertTrue(optionalPR.isPresent(), "Failed to retrieve payment rule for invoice");
assertEquals(optionalBI.get().Balance.setScale(2, RoundingMode.HALF_EVEN), form.getBankBalance().setScale(2, RoundingMode.HALF_EVEN), "Unexpected bank balance");
form.loadTableInfo(optionalBI.get(), invoice.getDateInvoiced(), optionalPR.get(), true, true, optionalBP.get(), optionalDocType.get(), form.miniTable);
assertTrue(form.miniTable.getRowCount() > 0, "Failed to load open invoice documents");
BigDecimal balance = optionalBI.get().Balance;
for(int i = 0; i < form.miniTable.getRowCount(); i++) {
IDColumn id = (IDColumn) form.miniTable.getValueAt(i, 0);
if (id.getRecord_ID().intValue() == invoice.get_ID()) {
id.setSelected(true);
form.miniTable.setSelectedRow(i);
BigDecimal amt = (BigDecimal)form.miniTable.getValueAt(i, 9);
balance = balance.subtract(amt);
break;
}
}
assertEquals(0, form.miniTable.getSelectedRow(), "Invoice not in loaded open list");
DecimalFormat format = DisplayType.getNumberFormat(DisplayType.Amount);
String status = form.calculateSelection(form.miniTable);
BigDecimal expected = optionalBI.get().Balance.subtract(invoice.getGrandTotal());
String remaining = format.format(expected);
assertTrue(status.contains(remaining), "Unexpected status text");
assertEquals(expected.setScale(2, RoundingMode.HALF_EVEN), balance.setScale(2, RoundingMode.HALF_EVEN), "Unexpected balance after selection and calculation");
//create pay selection
String error = form.generatePaySelect(form.miniTable, optionalPR.get(), invoice.getDateInvoiced(), optionalBI.get());
assertTrue(Util.isEmpty(error, true), error);
assertNotNull(form.getPaySelection(), "Pay Selection Not Generated");
paySelection = form.getPaySelection();
//create pay selection check
int AD_Process_ID = SystemIDs.PROCESS_C_PAYSELECTION_CREATEPAYMENT;
MPInstance mpi = new MPInstance(Env.getCtx(), AD_Process_ID, 0);
mpi.setRecord_ID(paySelection.get_ID());
mpi.saveEx();
MPInstancePara para = new MPInstancePara(mpi, 10);
para.setParameter(MPaySelection.COLUMNNAME_IsOnePaymentPerInvoice, false);
para.saveEx();
ProcessInfo pi = new ProcessInfo("PROCESS_C_PAYSELECTION_CREATEPAYMENT", AD_Process_ID);
pi.setAD_PInstance_ID(mpi.get_ID());
pi.setAD_Client_ID(getAD_Client_ID());
pi.setAD_User_ID(getAD_User_ID());
pi.setTable_ID(MPaySelection.Table_ID);
pi.setRecord_ID(paySelection.get_ID());
ServerProcessCtl.process(pi, null);
assertFalse(pi.isError(), pi.getSummary());
MPaySelectionCheck[] pscs = MPaySelectionCheck.get(paySelection.get_ID(), optionalPR.get().getValue(), null);
assertTrue(pscs.length > 0, "MPaySelectionCheck not created");
//create payment
PayPrintImpl payPrint = new PayPrintImpl();
payPrint.loadPaySelectInfo(paySelection.getC_PaySelection_ID());
paymentRules = payPrint.loadPaymentRule(paySelection.getC_PaySelection_ID());
assertTrue(paymentRules.size() > 0, "Failed to load applicable payment rules for payment selection");
payPrint.loadPaymentRuleInfo(paySelection.get_ID(), optionalPR.get().getValue());
assertTrue(payPrint.getNextDocumentNo() > 0, "Unexpected next check/document number");
assertTrue(payPrint.getNumberOfPreparePayment() > 0, "Unexpected number of C_PaySelectionCheck record: " + payPrint.getNumberOfPreparePayment());
assertTrue(payPrint.getPayAmtSum() > 0, "Unexpected sum of pay amount: " + payPrint.getPayAmtSum());
assertTrue(payPrint.getPrintFormatId() > 0, "No print format");
try {
AtomicReference<ValueNamePair> errorRef = new AtomicReference<>();
errorRef.set(new ValueNamePair(null, null));
boolean loaded = payPrint.getChecks(optionalPR.get().getValue(), new BigDecimal(payPrint.getNextDocumentNo()), errorRef, null);
assertTrue(loaded, "Failed to load check selection records");
assertTrue(Util.isEmpty(errorRef.get().getValue()), errorRef.get().getValue() + " " + errorRef.get().getName() != null ? errorRef.get().getName() : "");
MPaySelectionCheck[] checks = payPrint.getSelectionChecks();
assertTrue(checks.length > 0, "Unexpected number of C_PaySelectionCheck records : " + checks.length);
//create payments
List<File> pdfs = payPrint.createCheckDocuments(payPrint.getNextDocumentNo(), optionalPR.get().getValue());
assertTrue(pdfs.size() > 0, "Failed to create check document");
for(MPaySelectionCheck psc : checks) {
psc.load(null);
assertTrue(psc.getC_Payment_ID() > 0, "Payment not created");
}
pdfs = payPrint.createRemittanceDocuments();
assertTrue(pdfs.size() > 0, "Failed to create remittance documents");
} catch (Exception e1) {
fail(e1);
}
} finally {
if (paySelection != null && paySelection.get_ID() > 0) {
MPaySelectionLine[] lines = paySelection.getLines(true);
for(MPaySelectionLine l : lines)
l.deleteEx(true);
if (optionalPR.get() != null) {
MPaySelectionCheck[] pscs = MPaySelectionCheck.get(paySelection.get_ID(), optionalPR.get().getValue(), null);
for(MPaySelectionCheck psc : pscs) {
int C_Payment_ID = psc.getC_Payment_ID();
psc.deleteEx(true);
if (C_Payment_ID > 0) {
MPayment payment = new MPayment(Env.getCtx(), C_Payment_ID, null);
if (payment.get_ID() != C_Payment_ID) continue;
Query query = new Query(Env.getCtx(), MAllocationLine.Table_Name, "C_Payment_ID=?", null);
List<MAllocationLine> list = query.setParameters(payment.get_ID()).list();
List<Integer> headers = new ArrayList<>();
for(MAllocationLine al : list) {
if (!headers.contains(al.getC_AllocationHdr_ID()))
headers.add(al.getC_AllocationHdr_ID());
al.deleteEx(true);
}
for(Integer i : headers) {
MAllocationHdr hdr = new MAllocationHdr(Env.getCtx(), i, null);
hdr.deleteEx(true);
}
DB.executeUpdateEx("UPDATE C_Invoice SET C_Payment_ID=NULL WHERE C_Payment_ID=?", new Object[] {payment.get_ID()}, null);
payment.deleteEx(true);
}
}
}
paySelection.deleteEx(true);
}
if (line != null && line.get_ID() > 0) {
line.deleteEx(true);
}
if (invoice != null && invoice.get_ID() > 0) {
Query query = new Query(Env.getCtx(), MAllocationLine.Table_Name, "C_Invoice_ID=?", null);
List<MAllocationLine> list = query.setParameters(invoice.get_ID()).list();
List<Integer> headers = new ArrayList<>();
for(MAllocationLine al : list) {
if (!headers.contains(al.getC_AllocationHdr_ID()))
headers.add(al.getC_AllocationHdr_ID());
al.deleteEx(true);
}
for(Integer i : headers) {
MAllocationHdr hdr = new MAllocationHdr(Env.getCtx(), i, null);
hdr.deleteEx(true);
}
invoice.deleteEx(true);
}
}
}
private class PaySelectImpl extends PaySelect {
MiniTableImpl miniTable = null;
protected PaySelectImpl() {
miniTable = new MiniTableImpl();
prepareTable(miniTable);
}
protected BigDecimal getBankBalance() {
return super.getBankBalance();
}
protected MPaySelection getPaySelection() {
return m_ps;
}
}
private class PayPrintImpl extends PayPrint {
protected int getNextDocumentNo() {
return documentNo != null ? documentNo.intValue() : 0;
}
protected int getNumberOfPreparePayment() {
return !Util.isEmpty(noPayments, true) ? Integer.parseInt(noPayments) : 0;
}
protected Double getPayAmtSum() {
return sumPayments;
}
protected int getPrintFormatId() {
return printFormatId;
}
@Override
protected List<File> createCheckDocuments(int startDocumentNo, String paymentRule) throws Exception {
return super.createCheckDocuments(startDocumentNo, paymentRule);
}
@Override
protected List<File> createRemittanceDocuments() {
return super.createRemittanceDocuments();
}
@Override
protected boolean getChecks(String PaymentRule, BigDecimal startDocumentNo,
AtomicReference<ValueNamePair> error, String trxName) {
return super.getChecks(PaymentRule, startDocumentNo, error, trxName);
}
protected MPaySelectionCheck[] getSelectionChecks() {
return m_checks;
}
@Override
public void loadPaySelectInfo(int C_PaySelection_ID) {
m_C_PaySelection_ID = C_PaySelection_ID;
super.loadPaySelectInfo(C_PaySelection_ID);
}
}
}

View File

@ -36,6 +36,7 @@ import java.util.Map;
import org.compiere.minigrid.ColumnInfo;
import org.compiere.minigrid.IDColumn;
import org.compiere.minigrid.IMiniTable;
import org.compiere.model.MRole;
import org.compiere.model.PO;
import org.compiere.util.KeyNamePair;
@ -101,14 +102,36 @@ public class MiniTableImpl implements IMiniTable {
m_layout = layout;
m_tableColumns.clear();
model.clear();
StringBuilder sql = new StringBuilder ("SELECT ");
for (int columnIndex = 0; columnIndex < layout.length; columnIndex++) {
// create sql
if (columnIndex > 0)
{
sql.append(", ");
}
sql.append(layout[columnIndex].getColSQL());
// adding ID column
if (layout[columnIndex].isKeyPairCol())
{
sql.append(",").append(layout[columnIndex].getKeyPairColSQL());
}
addColumn(layout[columnIndex].getColHeader(), layout[columnIndex].getColDescription(), layout[columnIndex].getAD_Reference_ID(), layout[columnIndex].getColClass());
if (layout[columnIndex].getColClass() == IDColumn.class)
{
m_keyColumnIndex = columnIndex;
}
}
return null;
sql.append( " FROM ").append(from);
sql.append(" WHERE ").append(where);
String finalSQL = MRole.getDefault().addAccessSQL(sql.toString(),
tableName,
MRole.SQL_FULLYQUALIFIED,
MRole.SQL_RO);
return finalSQL;
}
@Override