From f7f95937c760f5e30eae622a2a5192d3f295f6cd Mon Sep 17 00:00:00 2001 From: Diego Ruiz Date: Fri, 23 Aug 2019 20:57:20 +0200 Subject: [PATCH] IDEMPIERE-4034 - Payment Selection improvements/bugs --- .../oracle/201908232051_IDEMPIERE-4034.sql | 18 +++++ .../201908232051_IDEMPIERE-4034.sql | 15 ++++ .../process/PaySelectionCreateFrom.java | 80 ++++++++++++++----- .../org/compiere/apps/form/VPaySelect.java | 2 +- .../adempiere/webui/apps/form/WPaySelect.java | 20 +++-- .../src/org/compiere/apps/form/PaySelect.java | 34 +++++++- 6 files changed, 141 insertions(+), 28 deletions(-) create mode 100644 migration/i6.2/oracle/201908232051_IDEMPIERE-4034.sql create mode 100644 migration/i6.2/postgresql/201908232051_IDEMPIERE-4034.sql diff --git a/migration/i6.2/oracle/201908232051_IDEMPIERE-4034.sql b/migration/i6.2/oracle/201908232051_IDEMPIERE-4034.sql new file mode 100644 index 0000000000..b021f59a0c --- /dev/null +++ b/migration/i6.2/oracle/201908232051_IDEMPIERE-4034.sql @@ -0,0 +1,18 @@ +SET SQLBLANKLINES ON +SET DEFINE OFF + +-- IDEMPIERE-4034 - Payment Selection improvements/bugs +-- Aug 23, 2019, 7:04:12 PM CEST +INSERT INTO AD_Message (MsgType,MsgText,MsgTip,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('I','Only positive balance','',0,0,'Y',TO_DATE('2019-08-23 19:04:11','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2019-08-23 19:04:11','YYYY-MM-DD HH24:MI:SS'),100,200537,'PositiveBalance','D','9184dbfd-02c9-4881-9dad-c3a6b390da1e') +; + +-- Aug 23, 2019, 8:27:41 PM CEST +INSERT INTO AD_Element (AD_Element_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,ColumnName,Name,Description,PrintName,EntityType,AD_Element_UU) VALUES (203357,0,0,'Y',TO_DATE('2019-08-23 20:27:40','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2019-08-23 20:27:40','YYYY-MM-DD HH24:MI:SS'),100,'PositiveBalance','Only positive balance','Include only positive balance','Only positive balance','D','27848071-41b9-4a4f-ada2-aa536af547c7') +; + +-- Aug 23, 2019, 8:28:34 PM CEST +INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,Description,AD_Process_ID,SeqNo,AD_Reference_ID,IsRange,FieldLength,IsMandatory,DefaultValue,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted) VALUES (200281,0,0,'Y',TO_DATE('2019-08-23 20:28:34','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2019-08-23 20:28:34','YYYY-MM-DD HH24:MI:SS'),100,'Only positive balance','Include only positive balance',156,80,20,'N',0,'Y','N','PositiveBalance','Y','D',203357,'50f11422-1361-4d50-b6d3-bfe6770e43d3','N') +; + +SELECT register_migration_script('201908232051_IDEMPIERE-4034.sql') FROM dual +; diff --git a/migration/i6.2/postgresql/201908232051_IDEMPIERE-4034.sql b/migration/i6.2/postgresql/201908232051_IDEMPIERE-4034.sql new file mode 100644 index 0000000000..d522ddd161 --- /dev/null +++ b/migration/i6.2/postgresql/201908232051_IDEMPIERE-4034.sql @@ -0,0 +1,15 @@ +-- IDEMPIERE-4034 - Payment Selection improvements/bugs +-- Aug 23, 2019, 7:04:12 PM CEST +INSERT INTO AD_Message (MsgType,MsgText,MsgTip,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('I','Only positive balance','',0,0,'Y',TO_TIMESTAMP('2019-08-23 19:04:11','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2019-08-23 19:04:11','YYYY-MM-DD HH24:MI:SS'),100,200537,'PositiveBalance','D','9184dbfd-02c9-4881-9dad-c3a6b390da1e') +; + +-- Aug 23, 2019, 8:27:41 PM CEST +INSERT INTO AD_Element (AD_Element_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,ColumnName,Name,Description,PrintName,EntityType,AD_Element_UU) VALUES (203357,0,0,'Y',TO_TIMESTAMP('2019-08-23 20:27:40','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2019-08-23 20:27:40','YYYY-MM-DD HH24:MI:SS'),100,'PositiveBalance','Only positive balance','Include only positive balance','Only positive balance','D','27848071-41b9-4a4f-ada2-aa536af547c7') +; + +-- Aug 23, 2019, 8:28:34 PM CEST +INSERT INTO AD_Process_Para (AD_Process_Para_ID,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,Name,Description,AD_Process_ID,SeqNo,AD_Reference_ID,IsRange,FieldLength,IsMandatory,DefaultValue,ColumnName,IsCentrallyMaintained,EntityType,AD_Element_ID,AD_Process_Para_UU,IsEncrypted) VALUES (200281,0,0,'Y',TO_TIMESTAMP('2019-08-23 20:28:34','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2019-08-23 20:28:34','YYYY-MM-DD HH24:MI:SS'),100,'Only positive balance','Include only positive balance',156,80,20,'N',0,'Y','N','PositiveBalance','Y','D',203357,'50f11422-1361-4d50-b6d3-bfe6770e43d3','N') +; + +SELECT register_migration_script('201908232051_IDEMPIERE-4034.sql') FROM dual +; diff --git a/org.adempiere.base.process/src/org/compiere/process/PaySelectionCreateFrom.java b/org.adempiere.base.process/src/org/compiere/process/PaySelectionCreateFrom.java index f388ffbd6b..ac57be1f5d 100644 --- a/org.adempiere.base.process/src/org/compiere/process/PaySelectionCreateFrom.java +++ b/org.adempiere.base.process/src/org/compiere/process/PaySelectionCreateFrom.java @@ -56,7 +56,9 @@ public class PaySelectionCreateFrom extends SvrProcess private int p_C_BP_Group_ID = 0; /** Payment Selection */ private int p_C_PaySelection_ID = 0; - + /** Only positive balance */ + private boolean p_OnlyPositive = false; + private Timestamp p_DueDate = null; /** @@ -86,6 +88,8 @@ public class PaySelectionCreateFrom extends SvrProcess p_C_BP_Group_ID = para[i].getParameterAsInt(); else if (name.equals("DueDate")) p_DueDate = (Timestamp) para[i].getParameter(); + else if (name.equals("PositiveBalance")) + p_OnlyPositive = "Y".equals(para[i].getParameter()); else log.log(Level.SEVERE, "Unknown Parameter: " + name); } @@ -104,6 +108,7 @@ public class PaySelectionCreateFrom extends SvrProcess + ", IncludeInDispute=" + p_IncludeInDispute + ", MatchRequirement=" + p_MatchRequirement + ", PaymentRule=" + p_PaymentRule + + ", POsitiveBalancet=" + p_OnlyPositive + ", C_BP_Group_ID=" + p_C_BP_Group_ID + ", C_BPartner_ID=" + p_C_BPartner_ID); MPaySelection psel = new MPaySelection (getCtx(), p_C_PaySelection_ID, get_TrxName()); @@ -127,13 +132,15 @@ public class PaySelectionCreateFrom extends SvrProcess .append(" PaymentRule, IsSOTrx, ") // 4..5 .append(" currencyConvert(invoiceWriteOff(i.C_Invoice_ID) ") .append(",i.C_Currency_ID, ?,?,i.C_ConversionType_ID,i.AD_Client_ID,i.AD_Org_ID) AS WriteOffAmt ") // 6 ##p6/p7 Currency_To,PayDate - .append("FROM C_Invoice_v i WHERE "); + .append("FROM C_Invoice_v i "); + + StringBuilder sqlWhere = new StringBuilder("WHERE "); if (X_C_Order.PAYMENTRULE_DirectDebit.equals(p_PaymentRule)) - sql.append("IsSOTrx='Y'"); + sqlWhere.append("i.IsSOTrx='Y'"); else - sql.append("IsSOTrx='N'"); - sql.append(" AND IsPaid='N' AND DocStatus IN ('CO','CL')") - .append(" AND AD_Client_ID=?") // ##p8 + sqlWhere.append("i.IsSOTrx='N'"); + sqlWhere.append(" AND i.IsPaid='N' AND i.DocStatus IN ('CO','CL')") + .append(" AND i.AD_Client_ID=?") // ##p8 // Existing Payments - Will reselect Invoice if prepared but not paid .append(" AND NOT EXISTS (SELECT * FROM C_PaySelectionLine psl") .append(" INNER JOIN C_PaySelectionCheck psc ON (psl.C_PaySelectionCheck_ID=psc.C_PaySelectionCheck_ID)") @@ -144,42 +151,42 @@ public class PaySelectionCreateFrom extends SvrProcess .append(" AND i.C_Invoice_ID NOT IN (SELECT i.C_Invoice_ID FROM C_PaySelectionLine psl WHERE psl.C_PaySelection_ID=?)"); // ##p9 // Disputed if (!p_IncludeInDispute) - sql.append(" AND i.IsInDispute='N'"); + sqlWhere.append(" AND i.IsInDispute='N'"); // PaymentRule (optional) if (p_PaymentRule != null) - sql.append(" AND PaymentRule=?"); // ## + sqlWhere.append(" AND i.PaymentRule=?"); // ## // OnlyDiscount if (p_OnlyDiscount) { if (p_OnlyDue) - sql.append(" AND ("); + sqlWhere.append(" AND ("); else - sql.append(" AND "); - sql.append("invoiceDiscount(i.C_Invoice_ID,?,i.C_InvoicePaySchedule_ID) > 0"); // ## + sqlWhere.append(" AND "); + sqlWhere.append("invoiceDiscount(i.C_Invoice_ID,?,i.C_InvoicePaySchedule_ID) > 0"); // ## } // OnlyDue if (p_OnlyDue) { if (p_OnlyDiscount) - sql.append(" OR "); + sqlWhere.append(" OR "); else - sql.append(" AND "); + sqlWhere.append(" AND "); // sql.append("paymentTermDueDays(C_PaymentTerm_ID, DateInvoiced, ?) >= 0"); // ## - sql.append("i.DueDate<=?"); // ## + sqlWhere.append("i.DueDate<=?"); // ## if (p_OnlyDiscount) - sql.append(")"); + sqlWhere.append(")"); } // Business Partner if (p_C_BPartner_ID != 0) - sql.append(" AND C_BPartner_ID=?"); // ## + sqlWhere.append(" AND i.C_BPartner_ID=?"); // ## // Business Partner Group else if (p_C_BP_Group_ID != 0) - sql.append(" AND EXISTS (SELECT * FROM C_BPartner bp ") + sqlWhere.append(" AND EXISTS (SELECT * FROM C_BPartner bp ") .append("WHERE bp.C_BPartner_ID=i.C_BPartner_ID AND bp.C_BP_Group_ID=?)"); // ## // PO Matching Requirement if (p_MatchRequirement.equals("P") || p_MatchRequirement.equals("B")) { - sql.append(" AND EXISTS (SELECT * FROM C_InvoiceLine il ") + sqlWhere.append(" AND EXISTS (SELECT * FROM C_InvoiceLine il ") .append("WHERE i.C_Invoice_ID=il.C_Invoice_ID") .append(" AND QtyInvoiced=(SELECT SUM(Qty) FROM M_MatchPO m ") .append("WHERE il.C_InvoiceLine_ID=m.C_InvoiceLine_ID))"); @@ -187,12 +194,32 @@ public class PaySelectionCreateFrom extends SvrProcess // Receipt Matching Requirement if (p_MatchRequirement.equals("R") || p_MatchRequirement.equals("B")) { - sql.append(" AND EXISTS (SELECT * FROM C_InvoiceLine il ") + sqlWhere.append(" AND EXISTS (SELECT * FROM C_InvoiceLine il ") .append("WHERE i.C_Invoice_ID=il.C_Invoice_ID") .append(" AND QtyInvoiced=(SELECT SUM(Qty) FROM M_MatchInv m ") .append("WHERE il.C_InvoiceLine_ID=m.C_InvoiceLine_ID))"); } + // Include only business partners with positive balance + if (p_OnlyPositive) { + + String subWhereClause = sqlWhere.toString(); + subWhereClause = subWhereClause.replaceAll("\\bi\\b", "i1"); + subWhereClause = subWhereClause.replaceAll("\\bpsl\\b", "psl1"); + subWhereClause = subWhereClause.replaceAll("\\bpsc\\b", "psc1"); + subWhereClause = subWhereClause.replaceAll("\\bpmt\\b", "pmt1"); + subWhereClause = subWhereClause.replaceAll("\\bbp\\b", "bp1"); + subWhereClause = subWhereClause.replaceAll("\\bil\\b", "il1"); + + String onlyPositiveWhere = " AND i.c_bpartner_id NOT IN ( SELECT i1.C_BPartner_ID" + + " FROM C_Invoice_v i1 " + + subWhereClause.toString() + + " GROUP BY i1.C_BPartner_ID" + + " HAVING sum(invoiceOpen(i1.C_Invoice_ID, i1.C_InvoicePaySchedule_ID)) <= 0) "; + + sqlWhere.append(onlyPositiveWhere); + } + sql.append(sqlWhere.toString()); // int lines = 0; int C_CurrencyTo_ID = psel.getC_Currency_ID(); @@ -223,6 +250,21 @@ public class PaySelectionCreateFrom extends SvrProcess pstmt.setInt (index++, p_C_BPartner_ID); else if (p_C_BP_Group_ID != 0) pstmt.setInt (index++, p_C_BP_Group_ID); + + if (p_OnlyPositive) { + pstmt.setInt(index++, psel.getAD_Client_ID()); + pstmt.setInt(index++, p_C_PaySelection_ID); + if (p_PaymentRule != null) + pstmt.setString(index++, p_PaymentRule); + if (p_OnlyDiscount) + pstmt.setTimestamp(index++, psel.getPayDate()); + if (p_OnlyDue) + pstmt.setTimestamp(index++, p_DueDate); + if (p_C_BPartner_ID != 0) + pstmt.setInt (index++, p_C_BPartner_ID); + else if (p_C_BP_Group_ID != 0) + pstmt.setInt (index++, p_C_BP_Group_ID); + } // rs = pstmt.executeQuery (); while (rs.next ()) diff --git a/org.adempiere.ui.swing/src/org/compiere/apps/form/VPaySelect.java b/org.adempiere.ui.swing/src/org/compiere/apps/form/VPaySelect.java index 7135fb4829..3ab400e066 100644 --- a/org.adempiere.ui.swing/src/org/compiere/apps/form/VPaySelect.java +++ b/org.adempiere.ui.swing/src/org/compiere/apps/form/VPaySelect.java @@ -280,7 +280,7 @@ public class VPaySelect extends PaySelect implements FormPanel, ActionListener, KeyNamePair bpartner = (KeyNamePair)fieldBPartner.getSelectedItem(); KeyNamePair docType = (KeyNamePair)fieldDtype.getSelectedItem(); - loadTableInfo(bi, payDate, paymentRule, onlyDue.isSelected(), bpartner, docType, miniTable); + loadTableInfo(bi, payDate, paymentRule, onlyDue.isSelected(), false, bpartner, docType, miniTable); calculateSelection(); } // loadTableInfo diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/form/WPaySelect.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/form/WPaySelect.java index d61ddaa980..55317fd290 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/form/WPaySelect.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/apps/form/WPaySelect.java @@ -107,6 +107,7 @@ public class WPaySelect extends PaySelect private Label labelCurrency = new Label(); private Label labelBalance = new Label(); private Checkbox onlyDue = new Checkbox(); + private Checkbox onlyPositiveBalance = new Checkbox(); private Label labelBPartner = new Label(); private Listbox fieldBPartner = ListboxFactory.newDropdownListbox(); private Label dataStatus = new Label(); @@ -183,7 +184,10 @@ public class WPaySelect extends PaySelect onlyDue.addActionListener(this); fieldPayDate.addValueChangeListener(this); ZKUpdateUtil.setHflex(fieldPayDate.getComponent(), "1"); - + + onlyPositiveBalance.setText(Msg.getMsg(Env.getCtx(), "PositiveBalance")); + onlyPositiveBalance.addActionListener(this); + //IDEMPIERE-2657, pritesh shah bGenerate.setEnabled(false); bGenerate.addActionListener(this); @@ -250,12 +254,14 @@ public class WPaySelect extends PaySelect row = rows.newRow(); row.appendChild(labelDtype.rightAlign()); row.appendChild(fieldDtype); - row.appendChild(new Space()); - if (ClientInfo.minWidth(ClientInfo.MEDIUM_WIDTH)) - { - row.appendChild(new Space()); + if (ClientInfo.maxWidth(ClientInfo.MEDIUM_WIDTH-1)) + { row.appendChild(new Space()); + row = rows.newRow(); } + row.appendChild(new Space()); + row.appendChild(onlyPositiveBalance); + row.appendChild(new Space()); row = rows.newRow(); row.appendChild(labelPayDate.rightAlign()); @@ -367,7 +373,7 @@ public class WPaySelect extends PaySelect KeyNamePair bpartner = (KeyNamePair) fieldBPartner.getSelectedItem().getValue(); KeyNamePair docType = (KeyNamePair) fieldDtype.getSelectedItem().getValue(); - loadTableInfo(bi, payDate, paymentRule, onlyDue.isSelected(), bpartner, docType, miniTable); + loadTableInfo(bi, payDate, paymentRule, onlyDue.isSelected(), onlyPositiveBalance.isSelected(), bpartner, docType, miniTable); calculateSelection(); if (ClientInfo.maxHeight(ClientInfo.MEDIUM_HEIGHT-1)) @@ -407,7 +413,7 @@ public class WPaySelect extends PaySelect // Update Open Invoices else if (e.getTarget() == fieldBPartner || e.getTarget() == bRefresh || e.getTarget() == fieldDtype - || e.getTarget() == fieldPaymentRule || e.getTarget() == onlyDue) + || e.getTarget() == fieldPaymentRule || e.getTarget() == onlyDue || e.getTarget() == onlyPositiveBalance) loadTableInfo(); else if (DialogEvents.ON_WINDOW_CLOSE.equals(e.getName())) { diff --git a/org.adempiere.ui/src/org/compiere/apps/form/PaySelect.java b/org.adempiere.ui/src/org/compiere/apps/form/PaySelect.java index 2facbc40f3..e63ed406b5 100644 --- a/org.adempiere.ui/src/org/compiere/apps/form/PaySelect.java +++ b/org.adempiere.ui/src/org/compiere/apps/form/PaySelect.java @@ -241,6 +241,7 @@ public class PaySelect + " INNER JOIN C_PaymentTerm p ON (i.C_PaymentTerm_ID=p.C_PaymentTerm_ID)", // WHERE "i.IsSOTrx=? AND IsPaid='N'" + + " AND invoiceOpen(i.C_Invoice_ID, i.C_InvoicePaySchedule_ID) != 0" //Check that AmountDue <> 0 // Different Payment Selection + " AND NOT EXISTS (SELECT * FROM C_PaySelectionLine psl" + " INNER JOIN C_PaySelectionCheck psc ON (psl.C_PaySelectionCheck_ID=psc.C_PaySelectionCheck_ID)" @@ -301,7 +302,7 @@ public class PaySelect * Query and create TableInfo */ public void loadTableInfo(BankInfo bi, Timestamp payDate, ValueNamePair paymentRule, boolean onlyDue, - KeyNamePair bpartner, KeyNamePair docType, IMiniTable miniTable) + boolean onlyPositiveBalance, KeyNamePair bpartner, KeyNamePair docType, IMiniTable miniTable) { log.config(""); // not yet initialized @@ -329,6 +330,27 @@ public class PaySelect int c_doctype_id = dt.getKey(); if (c_doctype_id != 0) sql += " AND i.c_doctype_id =?"; + + if (onlyPositiveBalance) { + int innerindex = sql.indexOf("INNER"); + String subWhereClause = sql.substring(innerindex, sql.length()); + + //Replace original aliases with new aliases + subWhereClause = subWhereClause.replaceAll("\\bi\\b", "i1"); + subWhereClause = subWhereClause.replaceAll("\\bbp\\b", "bp1"); + subWhereClause = subWhereClause.replaceAll("\\bc\\b", "c1"); + subWhereClause = subWhereClause.replaceAll("\\bp\\b", "p1"); + subWhereClause = subWhereClause.replaceAll("\\bpsl\\b", "psl1"); + subWhereClause = subWhereClause.replaceAll("\\bpsc\\b", "psc1"); + subWhereClause = subWhereClause.replaceAll("\\bpmt\\b", "pmt1"); + + sql += " AND i.c_bpartner_id NOT IN ( SELECT i1.C_BPartner_ID" + + " FROM C_Invoice_v i1 " + + subWhereClause + + " GROUP BY i1.C_BPartner_ID" + + " HAVING sum(invoiceOpen(i1.C_Invoice_ID, i1.C_InvoicePaySchedule_ID)) <= 0) "; + } + sql += " ORDER BY 2,3"; if (log.isLoggable(Level.FINEST)) log.finest(sql + " - C_Currency_ID=" + bi.C_Currency_ID + ", C_BPartner_ID=" + C_BPartner_ID + ", C_doctype_id=" + c_doctype_id ); @@ -357,6 +379,16 @@ public class PaySelect pstmt.setInt(index++, C_BPartner_ID); if (c_doctype_id != 0) //Document type pstmt.setInt(index++, c_doctype_id ); + if (onlyPositiveBalance) { + pstmt.setString(index++, isSOTrx); // IsSOTrx + pstmt.setInt(index++, m_AD_Client_ID); // Client + if (onlyDue) + pstmt.setTimestamp(index++, payDate); + if (C_BPartner_ID != 0) + pstmt.setInt(index++, C_BPartner_ID); + if (c_doctype_id != 0) //Document type + pstmt.setInt(index++, c_doctype_id ); + } // rs = pstmt.executeQuery(); miniTable.loadTable(rs);