IDEMPIERE-5621 - Dashboard Report ignore if parameter is mandatory or not (#1714)

* IDEMPIERE-5621 - Dashboard Report ignore if parameter is mandatory or not

* IDEMPIERE-5621 - small fixes

* IDEMPIERE-5621 - missing javadoc for new methods

* IDEMPIERE-5621 - move scripts, list empty para, update css
This commit is contained in:
Peter Takács 2023-03-16 05:01:40 +01:00 committed by GitHub
parent c170c59f47
commit b7b9a4d476
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 186 additions and 28 deletions

View File

@ -0,0 +1,23 @@
-- IDEMPIERE-5621
SELECT register_migration_script('202303101443_IDEMPIERE-5621.sql') FROM dual;
SET SQLBLANKLINES ON
SET DEFINE OFF
-- Mar 10, 2023, 2:43:41 PM CET
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 ('E','Fill mandatory parameters!','Mandatory parameters should be filled in the Process Parameter field of the Dashboard Content.',0,0,'Y',TO_TIMESTAMP('2023-03-10 14:43:41','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-03-10 14:43:41','YYYY-MM-DD HH24:MI:SS'),100,200824,'FillMandatoryParametersDashboard','D','e490d702-11b5-40e8-bea9-0221ae6ae3c9')
;
-- Mar 15, 2023, 2:23:02 PM CET
UPDATE AD_Message SET MsgText='Fill mandatory parameters: {0}',Updated=TO_TIMESTAMP('2023-03-15 14:23:02','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Message_ID=200824
;
-- Mar 15, 2023, 2:27:16 PM CET
UPDATE AD_Message SET MsgText='Fill mandatory parameters: {0}<br>
Mandatory parameters should be filled in the Process Parameter field of the Dashboard Content.', MsgTip=NULL,Updated=TO_TIMESTAMP('2023-03-15 14:27:16','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Message_ID=200824
;
-- Mar 15, 2023, 2:29:00 PM CET
UPDATE AD_Message SET MsgText='Fill mandatory parameters: {0}; Mandatory parameters should be filled in the Process Parameter field of the Dashboard Content.',Updated=TO_TIMESTAMP('2023-03-15 14:29:00','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Message_ID=200824
;

View File

@ -0,0 +1,20 @@
-- IDEMPIERE-5621
SELECT register_migration_script('202303101443_IDEMPIERE-5621.sql') FROM dual;
-- Mar 10, 2023, 2:43:41 PM CET
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 ('E','Fill mandatory parameters!','Mandatory parameters should be filled in the Process Parameter field of the Dashboard Content.',0,0,'Y',TO_TIMESTAMP('2023-03-10 14:43:41','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2023-03-10 14:43:41','YYYY-MM-DD HH24:MI:SS'),100,200824,'FillMandatoryParametersDashboard','D','e490d702-11b5-40e8-bea9-0221ae6ae3c9')
;
-- Mar 15, 2023, 2:23:02 PM CET
UPDATE AD_Message SET MsgText='Fill mandatory parameters: {0}',Updated=TO_TIMESTAMP('2023-03-15 14:23:02','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Message_ID=200824
;
-- Mar 15, 2023, 2:27:16 PM CET
UPDATE AD_Message SET MsgText='Fill mandatory parameters: {0}<br>
Mandatory parameters should be filled in the Process Parameter field of the Dashboard Content.', MsgTip=NULL,Updated=TO_TIMESTAMP('2023-03-15 14:27:16','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Message_ID=200824
;
-- Mar 15, 2023, 2:29:00 PM CET
UPDATE AD_Message SET MsgText='Fill mandatory parameters: {0}; Mandatory parameters should be filled in the Process Parameter field of the Dashboard Content.',Updated=TO_TIMESTAMP('2023-03-15 14:29:00','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Message_ID=200824
;

View File

@ -5,10 +5,15 @@ package org.compiere.model;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Properties; import java.util.Properties;
import org.adempiere.exceptions.AdempiereException;
import org.compiere.util.Env; import org.compiere.util.Env;
import org.compiere.util.Msg;
import org.compiere.util.Util;
/** /**
* @author teo_sarca * @author teo_sarca
@ -172,4 +177,61 @@ public class MDashboardContent extends X_PA_DashboardContent
return (I_AD_Menu)MTable.get(getCtx(), I_AD_Menu.Table_Name) return (I_AD_Menu)MTable.get(getCtx(), I_AD_Menu.Table_Name)
.getPO(getAD_Menu_ID(), get_TrxName()); .getPO(getAD_Menu_ID(), get_TrxName());
} }
/**
* Parse Process Parameters
* @param parameters
* @return HashMap<String parameterName, String value>
*/
public static Map<String, String> parseProcessParameters(String parameters) {
Map<String, String> paramMap = new HashMap<String, String>();
if (parameters != null && parameters.trim().length() > 0) {
String[] params = parameters.split("[,]");
for (String s : params)
{
int pos = s.indexOf("=");
String key = s.substring(0, pos);
String value = s.substring(pos + 1);
paramMap.put(key, value);
}
}
return paramMap;
}
/**
* Parse all Process Parameters that are mandatory and not set
* @return String of comma separated parameter names
*/
public String getEmptyMandatoryProcessPara() {
StringBuilder emptyPara = new StringBuilder();
int processID = getAD_Process_ID();
if(processID > 0) {
MProcess process = MProcess.get(processID);
Map<String, String> paramMap = parseProcessParameters(getProcessParameters());
for(MProcessPara processPara : process.getParameters()) {
if(processPara.isMandatory() && Util.isEmpty(paramMap.get(processPara.getColumnName()), true)) {
if(!Util.isEmpty(emptyPara.toString(), true))
emptyPara.append(", ");
emptyPara.append(processPara.getColumnName());
}
}
}
return emptyPara.toString();
}
/*
* Before Save
* @param newRecord new
* @return
*/
protected boolean beforeSave (boolean newRecord) {
// all mandatory process parameters need to be set
if(getAD_Process_ID() > 0) {
String emptyPara = getEmptyMandatoryProcessPara();
if(!Util.isEmpty(emptyPara)) {
throw new AdempiereException(Msg.getMsg(getCtx(), "FillMandatoryParametersDashboard", new Object[] {emptyPara}));
}
}
return true;
}
} }

View File

@ -57,6 +57,6 @@ Copyright (C) 2007 Ashley G Ramdass (ADempiere WebUI).
<!-- this js module doesn't actually exists and it is here for default theme version --> <!-- this js module doesn't actually exists and it is here for default theme version -->
<!-- since loading of js module is on demand, it doesn't cause any error as long as you don't try to load it --> <!-- since loading of js module is on demand, it doesn't cause any error as long as you don't try to load it -->
<javascript-module name="idempiere.theme.default" version="202302211500" /> <javascript-module name="idempiere.theme.default" version="202303151445" />
</language> </language>

View File

@ -787,23 +787,27 @@ public class DashboardController implements EventListener<Event> {
Iframe iframe = new Iframe(); Iframe iframe = new Iframe();
iframe.setSclass("dashboard-report-iframe"); iframe.setSclass("dashboard-report-iframe");
iframe.setStyle("flex-grow: 1;"); iframe.setStyle("flex-grow: 1;");
layout.appendChild(iframe);
iframe.setContent(generateReport(AD_Process_ID, dashboardContent.getAD_PrintFormat_ID(), processParameters, appDesktop, contextPath)); iframe.setContent(generateReport(AD_Process_ID, dashboardContent.getAD_PrintFormat_ID(), processParameters, appDesktop, contextPath));
if(iframe.getContent() != null)
layout.appendChild(iframe);
else
layout.appendChild(createFillMandatoryLabel(dashboardContent));
Toolbar toolbar = new Toolbar(); Toolbar toolbar = new Toolbar();
layout.appendChild(toolbar); layout.appendChild(toolbar);
btn.setLabel(Msg.getMsg(Env.getCtx(), "OpenRunDialog")); btn.setLabel(Msg.getMsg(Env.getCtx(), "OpenRunDialog"));
toolbar.appendChild(btn); toolbar.appendChild(btn);
btn = new ToolBarButton(); if(iframe.getContent() != null) {
btn.setAttribute("AD_Process_ID", AD_Process_ID); btn = new ToolBarButton();
btn.setAttribute("ProcessParameters", processParameters); btn.setAttribute("AD_Process_ID", AD_Process_ID);
btn.setAttribute("AD_PrintFormat_ID", dashboardContent.getAD_PrintFormat_ID()); btn.setAttribute("ProcessParameters", processParameters);
btn.addEventListener(Events.ON_CLICK, this); btn.setAttribute("AD_PrintFormat_ID", dashboardContent.getAD_PrintFormat_ID());
btn.setLabel(Msg.getMsg(Env.getCtx(), "ViewReportInNewTab")); btn.addEventListener(Events.ON_CLICK, this);
toolbar.appendChild(new Separator("vertical")); btn.setLabel(Msg.getMsg(Env.getCtx(), "ViewReportInNewTab"));
toolbar.appendChild(btn); toolbar.appendChild(new Separator("vertical"));
toolbar.appendChild(btn);
}
btn = new ToolBarButton(); btn = new ToolBarButton();
if (ThemeManager.isUseFontIconForImage()) { if (ThemeManager.isUseFontIconForImage()) {
btn.setIconSclass("z-icon-Refresh"); btn.setIconSclass("z-icon-Refresh");
@ -1153,6 +1157,21 @@ public class DashboardController implements EventListener<Event> {
} }
} }
/**
* Create Fill Mandatory Process Parameters error label for the reports in dashboard
* @return Div
*/
private Div createFillMandatoryLabel(MDashboardContent dc) {
Div wrapper = new Div();
wrapper.setSclass("fill-mandatory-process-para-wrapper");
Div msgText = new Div();
msgText.appendChild(new Text(Msg.getMsg(Env.getCtx(), "FillMandatoryParametersDashboard", new Object[] {dc.getEmptyMandatoryProcessPara()})));
LayoutUtils.addSclass("fill-mandatory-process-para-text", msgText);
wrapper.appendChild(msgText);
return wrapper;
}
private void createDashboardPreference(int AD_User_ID, int AD_Role_ID) private void createDashboardPreference(int AD_User_ID, int AD_Role_ID)
{ {
MDashboardContent[] dcs = MDashboardContentAccess.get(Env.getCtx(),AD_Role_ID, AD_User_ID, null); MDashboardContent[] dcs = MDashboardContentAccess.get(Env.getCtx(),AD_Role_ID, AD_User_ID, null);
@ -1462,7 +1481,8 @@ public class DashboardController implements EventListener<Event> {
pInstance.setIsProcessing(true); pInstance.setIsProcessing(true);
pInstance.saveEx(); pInstance.saveEx();
try { try {
fillParameter(pInstance, parameters); if(!fillParameter(pInstance, parameters))
return null;
// //
ProcessInfo pi = new ProcessInfo (process.getName(), process.getAD_Process_ID(), ProcessInfo pi = new ProcessInfo (process.getName(), process.getAD_Process_ID(),
AD_Table_ID, Record_ID); AD_Table_ID, Record_ID);
@ -1488,7 +1508,8 @@ public class DashboardController implements EventListener<Event> {
private AMedia generateReport(int AD_Process_ID, int AD_PrintFormat_ID, String parameters, IDesktop appDesktop, String contextPath) throws Exception { private AMedia generateReport(int AD_Process_ID, int AD_PrintFormat_ID, String parameters, IDesktop appDesktop, String contextPath) throws Exception {
ReportEngine re = runReport(AD_Process_ID, AD_PrintFormat_ID, parameters); ReportEngine re = runReport(AD_Process_ID, AD_PrintFormat_ID, parameters);
if(re == null)
return null;
File file = FileUtil.createTempFile(re.getName(), ".html"); File file = FileUtil.createTempFile(re.getName(), ".html");
re.createHTML(file, false, AEnv.getLanguage(Env.getCtx()), new HTMLExtension(contextPath, "rp", re.createHTML(file, false, AEnv.getLanguage(Env.getCtx()), new HTMLExtension(contextPath, "rp",
appDesktop.getComponent().getUuid(), String.valueOf(AD_Process_ID))); appDesktop.getComponent().getUuid(), String.valueOf(AD_Process_ID)));
@ -1500,28 +1521,32 @@ public class DashboardController implements EventListener<Event> {
new ZkReportViewerProvider().openViewer(re); new ZkReportViewerProvider().openViewer(re);
} }
private void fillParameter(MPInstance pInstance, String parameters) { /**
* Fill Parameters
* @param pInstance
* @param parameters
* @return true if the parameters were filled successfully
*/
private boolean fillParameter(MPInstance pInstance, String parameters) {
MProcessPara[] processParams = pInstance.getProcessParameters();
if (parameters != null && parameters.trim().length() > 0) { if (parameters != null && parameters.trim().length() > 0) {
Map<String, String> paramMap = new HashMap<String, String>(); Map<String, String> paramMap = MDashboardContent.parseProcessParameters(parameters);
String[] params = parameters.split("[,]");
for (String s : params)
{
int pos = s.indexOf("=");
String key = s.substring(0, pos);
String value = s.substring(pos + 1);
paramMap.put(key, value);
}
MProcessPara[] processParams = pInstance.getProcessParameters();
for (int pi = 0; pi < processParams.length; pi++) for (int pi = 0; pi < processParams.length; pi++)
{ {
MPInstancePara iPara = new MPInstancePara (pInstance, processParams[pi].getSeqNo()); MPInstancePara iPara = new MPInstancePara (pInstance, processParams[pi].getSeqNo());
iPara.setParameterName(processParams[pi].getColumnName()); iPara.setParameterName(processParams[pi].getColumnName());
iPara.setInfo(processParams[pi].getName()); iPara.setInfo(processParams[pi].getName());
MProcessPara sPara = processParams[pi];
String variable = paramMap.get(iPara.getParameterName()); String variable = paramMap.get(iPara.getParameterName());
if (Util.isEmpty(variable)) if (Util.isEmpty(variable, true)) {
continue; if(sPara.isMandatory())
return false; // empty mandatory parameter
else
continue;
}
boolean isTo = false; boolean isTo = false;
@ -1572,7 +1597,12 @@ public class DashboardController implements EventListener<Event> {
// No Value // No Value
if (value == null) if (value == null)
{ {
continue; if(sPara.isMandatory()) {
return false; // empty mandatory parameter
}
else {
continue;
}
} }
if( DisplayType.isText(iPara.getDisplayType()) if( DisplayType.isText(iPara.getDisplayType())
&& Util.isEmpty(String.valueOf(value))) { && Util.isEmpty(String.valueOf(value))) {
@ -1646,7 +1676,15 @@ public class DashboardController implements EventListener<Event> {
isTo = true; isTo = true;
} }
} }
} }
else {
for(MProcessPara processPara : processParams) {
if(processPara.isMandatory()) {
return false; // empty mandatory parameter
}
}
}
return true;
} }
private String getDisplay(MPInstance i, MPInstancePara ip, int id) { private String getDisplay(MPInstance i, MPInstancePara ip, int id) {

View File

@ -345,3 +345,18 @@
padding: 5px; padding: 5px;
cursor: default; cursor: default;
} }
.fill-mandatory-process-para-wrapper {
padding: 11px;
display: flex;
flex-direction: column;
max-width: 500px;
}
.fill-mandatory-process-para-text {
background: #C62223;
color: white;
padding: 10px;
border-radius: 5px;
opacity: 90%;
}