diff --git a/base/src/org/adempiere/impexp/AbstractExcelExporter.java b/base/src/org/adempiere/impexp/AbstractExcelExporter.java new file mode 100644 index 0000000000..76bd640206 --- /dev/null +++ b/base/src/org/adempiere/impexp/AbstractExcelExporter.java @@ -0,0 +1,407 @@ +/****************************************************************************** + * Product: Adempiere ERP & CRM Smart Business Solution * + * Copyright (C) 2008 SC ARHIPAC SERVICE SRL. 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. * + *****************************************************************************/ +package org.adempiere.impexp; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.OutputStream; +import java.sql.Timestamp; +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.util.HashMap; +import java.util.Properties; +import java.util.logging.Level; + +import org.apache.poi.hssf.usermodel.HSSFCell; +import org.apache.poi.hssf.usermodel.HSSFCellStyle; +import org.apache.poi.hssf.usermodel.HSSFDataFormat; +import org.apache.poi.hssf.usermodel.HSSFFont; +import org.apache.poi.hssf.usermodel.HSSFFooter; +import org.apache.poi.hssf.usermodel.HSSFHeader; +import org.apache.poi.hssf.usermodel.HSSFPrintSetup; +import org.apache.poi.hssf.usermodel.HSSFRow; +import org.apache.poi.hssf.usermodel.HSSFSheet; +import org.apache.poi.hssf.usermodel.HSSFWorkbook; +import org.compiere.Adempiere; +import org.compiere.util.CLogMgt; +import org.compiere.util.CLogger; +import org.compiere.util.DisplayType; +import org.compiere.util.Env; +import org.compiere.util.Ini; +import org.compiere.util.Language; +import org.compiere.util.Util; + +/** + * Abstract MS Excel Format (xls) Exporter + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + */ +public abstract class AbstractExcelExporter +{ + protected abstract boolean isFunctionRow(); + protected abstract int getColumnCount(); + protected abstract int getRowCount(); + protected abstract void setCurrentRow(int row); + protected abstract boolean isColumnPrinted(int col); + protected abstract String getHeaderName(int col); + protected abstract int getDisplayType(int row, int col); + protected abstract Object getValueAt(int row, int col); + protected abstract boolean isPageBreak(int row, int col); + + /** Logger */ + protected CLogger log = CLogger.getCLogger(getClass()); + // + private HSSFWorkbook m_workbook; + private HSSFDataFormat m_dataFormat; + private HSSFFont m_fontHeader = null; + private HSSFFont m_fontDefault = null; + private Language m_lang = null; + private int m_sheetCount = 0; + /** Styles cache */ + private HashMap m_styles = new HashMap(); + + public AbstractExcelExporter() { + m_workbook = new HSSFWorkbook(); + m_dataFormat = m_workbook.createDataFormat(); + } + + protected Properties getCtx() { + return Env.getCtx(); + } + + private String fixString(String str) + { + // ms excel doesn't support UTF8 charset + return Util.stripDiacritics(str); + } + + protected Language getLanguage() { + if (m_lang == null) + m_lang = Env.getLanguage(getCtx()); + return m_lang; + } + + private HSSFFont getFont(boolean isHeader) { + HSSFFont font = null; + if (isHeader) { + if (m_fontHeader == null) { + m_fontHeader = m_workbook.createFont(); + m_fontHeader.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); + } + font = m_fontHeader; + } + else if (isFunctionRow()) { + font = m_workbook.createFont(); + font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); + font.setItalic(true); + } + else { + if (m_fontDefault == null) { + m_fontDefault = m_workbook.createFont(); + } + font = m_fontDefault; + } + return font; + } + + /** + * Get Excel number format string by given {@link NumberFormat} + * @param df number format + * @param isHighlightNegativeNumbers highlight negative numbers using RED color + * @return number excel format string + */ + private String getFormatString(NumberFormat df, boolean isHighlightNegativeNumbers) { + StringBuffer format = new StringBuffer(); + int integerDigitsMin = df.getMinimumIntegerDigits(); + int integerDigitsMax = df.getMaximumIntegerDigits(); + for (int i = 0; i < integerDigitsMax; i++) { + if (i < integerDigitsMin) + format.insert(0, "0"); + else + format.insert(0, "#"); + if (i == 2) { + format.insert(0, ","); + } + } + int fractionDigitsMin = df.getMinimumFractionDigits(); + int fractionDigitsMax = df.getMaximumFractionDigits(); + for (int i = 0; i < fractionDigitsMax; i++) { + if (i == 0) + format.append("."); + if (i < fractionDigitsMin) + format.append("0"); + else + format.append("#"); + } + if (isHighlightNegativeNumbers) { + String f = format.toString(); + format = new StringBuffer(f).append(";[RED]-").append(f); + } + // + if (CLogMgt.isLevelFinest()) log.finest("NumberFormat: "+format); + return format.toString(); + + } + + private HSSFCellStyle getStyle(int row, int col) { + int displayType = getDisplayType(row, col); + String key = "cell-"+col+"-"+displayType; + HSSFCellStyle cs = m_styles.get(key); + if (cs == null) { + boolean isHighlightNegativeNumbers = true; + cs = m_workbook.createCellStyle(); + HSSFFont font = getFont(false); + cs.setFont(font); + // Border + cs.setBorderLeft((short)1); + cs.setBorderTop((short)1); + cs.setBorderRight((short)1); + cs.setBorderBottom((short)1); + // + if (DisplayType.isDate(displayType)) { + cs.setDataFormat(m_dataFormat.getFormat("DD.MM.YYYY")); + } + else if (DisplayType.isNumeric(displayType)) { + DecimalFormat df = DisplayType.getNumberFormat(displayType, getLanguage()); + String format = getFormatString(df, isHighlightNegativeNumbers); + cs.setDataFormat(m_dataFormat.getFormat(format)); + } + m_styles.put(key, cs); + } + return cs; + } + + private HSSFCellStyle getHeaderStyle(int col) + { + String key = "header-"+col; + HSSFCellStyle cs_header = m_styles.get(key); + if (cs_header == null) { + HSSFFont font_header = getFont(true); + cs_header = m_workbook.createCellStyle(); + cs_header.setFont(font_header); + cs_header.setBorderLeft((short)2); + cs_header.setBorderTop((short)2); + cs_header.setBorderRight((short)2); + cs_header.setBorderBottom((short)2); + cs_header.setDataFormat(HSSFDataFormat.getBuiltinFormat("text")); + cs_header.setWrapText(true); + m_styles.put(key, cs_header); + } + return cs_header; + } + + private void fixColumnWidth(HSSFSheet sheet, int lastColumnIndex) + { + /* POI 3.0.1 * + for (short colnum = 0; colnum < lastColumnIndex; colnum++) { + sheet.autoSizeColumn(colnum); + } + /**/ + } + + private void closeTableSheet(HSSFSheet prevSheet, String prevSheetName, int colCount) + { + if (prevSheet == null) + return; + // + fixColumnWidth(prevSheet, colCount); + prevSheet.createFreezePane(1, 1); + if (!Util.isEmpty(prevSheetName, true) && m_sheetCount > 0) { + int prevSheetIndex = m_sheetCount - 1; + try { + m_workbook.setSheetName(prevSheetIndex, prevSheetName); + } + catch (Exception e) { + log.log(Level.WARNING, "Error setting sheet "+prevSheetIndex+" name to "+prevSheetName, e); + } + } + } + private HSSFSheet createTableSheet() + { + HSSFSheet sheet= m_workbook.createSheet(); + sheet.setFitToPage(true); + // Print Setup + HSSFPrintSetup ps = sheet.getPrintSetup(); + sheet.setAutobreaks(true); + ps.setFitWidth((short)1); + ps.setNoColor(true); + // Sheet Header + HSSFHeader header = sheet.getHeader(); + header.setRight(HSSFHeader.page()+ " / "+HSSFHeader.numPages()); + // Sheet Footer + HSSFFooter footer = sheet.getFooter(); + footer.setLeft(Adempiere.ADEMPIERE_R); + footer.setCenter(Env.getHeader(getCtx(), 0)); + Timestamp now = new Timestamp(System.currentTimeMillis()); + footer.setRight(DisplayType.getDateFormat(DisplayType.DateTime, getLanguage()).format(now)); + // Table Header + createTableHeader(sheet); + m_sheetCount++; + // + return sheet; + } + + private void createTableHeader(HSSFSheet sheet) + { + short colnumMax = 0; + + HSSFRow row = sheet.createRow(0); + // for all columns + short colnum = 0; + for (int col = 0; col < getColumnCount(); col++) + { + if (colnum > colnumMax) + colnumMax = colnum; + // + if (isColumnPrinted(col)) + { + HSSFCell cell = row.createCell(colnum); + // header row + HSSFCellStyle style = getHeaderStyle(col); + cell.setCellStyle(style); + String str = fixString(getHeaderName(col)); + /* POI 3.0.1 * + cell.setCellValue(new HSSFRichTextString(str)); + /* POI 2.0 */ + cell.setCellValue(str); + /**/ + colnum++; + } // printed + } // for all columns +// m_workbook.setRepeatingRowsAndColumns(m_sheetCount, 0, 0, 0, 0); + } + + /** + * Export to given stream + * @param out + * @throws Exception + */ + private void export(OutputStream out) + throws Exception + { + HSSFSheet sheet= createTableSheet(); + String sheetName = null; + // + short colnumMax = 0; + for (int rownum = 0, xls_rownum = 1; rownum < getRowCount(); rownum++, xls_rownum++) + { + setCurrentRow(rownum); + + boolean isPageBreak = false; + HSSFRow row = sheet.createRow(xls_rownum); + // for all columns + short colnum = 0; + for (int col = 0; col < getColumnCount(); col++) + { + if (colnum > colnumMax) + colnumMax = colnum; + // + if (isColumnPrinted(col)) + { + HSSFCell cell = row.createCell(colnum); + // line row + Object obj = getValueAt(rownum, col); + int displayType = getDisplayType(rownum, col); + if (obj == null) + ; + else if (DisplayType.isDate(displayType)) { + Timestamp value = (Timestamp)obj; + cell.setCellValue(value); + } + else if (DisplayType.isNumeric(displayType)) { + double value = 0; + if (obj instanceof Number) { + value = ((Number)obj).doubleValue(); + } + cell.setCellValue(value); + } + else if (DisplayType.YesNo == displayType) { + boolean value = false; + if (obj instanceof Boolean) + value = (Boolean)obj; + else + value = "Y".equals(obj); + cell.setCellValue(value); + } + else { + String value = fixString(obj.toString()); // formatted + /* POI 3.0.1 * + cell.setCellValue(new HSSFRichTextString(value)); + /* POI 2.0 */ + cell.setCellValue(value); + /**/ + } + // + HSSFCellStyle style = getStyle(rownum, col); + cell.setCellStyle(style); + // Page break + if (isPageBreak(rownum, col)) { + isPageBreak = true; + sheetName = fixString(cell.getStringCellValue()); + } + // + colnum++; + } // printed + } // for all columns + // + // Page Break + if (isPageBreak) { + closeTableSheet(sheet, sheetName, colnumMax); + sheet = createTableSheet(); + xls_rownum = 0; + isPageBreak = false; + } + } // for all rows + closeTableSheet(sheet, sheetName, colnumMax); + // + m_workbook.write(out); + out.close(); + // + // Workbook Info + if (CLogMgt.isLevelFine()) { + log.fine("Sheets #"+m_sheetCount); + log.fine("Styles used #"+m_styles.size()); + } + } + + /** + * Export to file + * @param file + * @param language reporting language + * @throws Exception + */ + public void export(File file, Language language) + throws Exception + { + export(file, language, true); + } + + /** + * Export to file + * @param file + * @param language reporting language + * @param autoOpen auto open file after generated + * @throws Exception + */ + public void export(File file, Language language, boolean autoOpen) + throws Exception + { + m_lang = language; + if (file == null) + file = File.createTempFile("Report_", ".xls"); + FileOutputStream out = new FileOutputStream(file); + export(out); + if (autoOpen && Ini.isClient()) + Env.startBrowser(file.toURI().toString()); + } +} diff --git a/base/src/org/adempiere/impexp/ArrayExcelExporter.java b/base/src/org/adempiere/impexp/ArrayExcelExporter.java new file mode 100644 index 0000000000..0416b9286b --- /dev/null +++ b/base/src/org/adempiere/impexp/ArrayExcelExporter.java @@ -0,0 +1,116 @@ +/****************************************************************************** + * Product: Adempiere ERP & CRM Smart Business Solution * + * Copyright (C) 2008 SC ARHIPAC SERVICE SRL. 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. * + *****************************************************************************/ +package org.adempiere.impexp; + +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Properties; + +import org.compiere.util.DisplayType; +import org.compiere.util.Msg; +import org.compiere.util.Util; + +/** + * Export excel from ArrayList of data + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + * + */ +public class ArrayExcelExporter extends AbstractExcelExporter { + private Properties m_ctx = null; + private ArrayList> m_data = null; + + public ArrayExcelExporter(Properties ctx, ArrayList> data) { + super(); + m_ctx = ctx; + m_data = data; + } + + @Override + public Properties getCtx() { + return m_ctx; + } + + @Override + protected int getColumnCount() { + return m_data.get(0).size(); + } + + @Override + protected int getDisplayType(int row, int col) { + ArrayList dataRow = m_data.get(row+1); + Object value = dataRow.get(col); + if (value == null) + ; + else if (value instanceof Timestamp) { + return DisplayType.Date; + // TODO: handle DateTime + } + else if (value instanceof Number) { + if (value instanceof Integer) { + return DisplayType.Integer; + } + else { + return DisplayType.Number; + } + } + else if (value instanceof Boolean) { + return DisplayType.YesNo; + } + else { + return DisplayType.String; + } + return -1; + } + + @Override + protected String getHeaderName(int col) { + Object o = m_data.get(0).get(col); + String name = o != null ? o.toString() : null; + String nameTrl = Msg.translate(getLanguage(), name); + if (Util.isEmpty(nameTrl)) + nameTrl = name; + return nameTrl; + } + + @Override + protected int getRowCount() { + return m_data.size() - 1; + } + + @Override + protected Object getValueAt(int row, int col) { + ArrayList dataRow = m_data.get(row+1); + Object value = dataRow.get(col); + return value; + } + + @Override + protected boolean isColumnPrinted(int col) { + return true; + } + + @Override + protected boolean isFunctionRow() { + return false; + } + + @Override + protected boolean isPageBreak(int row, int col) { + return false; + } + + @Override + protected void setCurrentRow(int row) { + } +} diff --git a/base/src/org/compiere/model/MAlert.java b/base/src/org/compiere/model/MAlert.java index 6a3e7e0531..448ec744d3 100644 --- a/base/src/org/compiere/model/MAlert.java +++ b/base/src/org/compiere/model/MAlert.java @@ -19,7 +19,9 @@ package org.compiere.model; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; +import java.util.Collection; import java.util.Properties; +import java.util.TreeSet; import java.util.logging.Level; import org.compiere.util.DB; @@ -29,6 +31,9 @@ import org.compiere.util.DB; * * @author Jorg Janke * @version $Id: MAlert.java,v 1.3 2006/07/30 00:51:05 jjanke Exp $ + * + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + *
  • FR [ 1894573 ] Alert Processor Improvements */ public class MAlert extends X_AD_Alert { @@ -195,6 +200,32 @@ public class MAlert extends X_AD_Alert return -1; } // getFirstAD_User_ID + /** + * @return unique list of recipient users + */ + public Collection getRecipientUsers() { + MAlertRecipient[] recipients = getRecipients(false); + TreeSet users = new TreeSet(); + for (int i = 0; i < recipients.length; i++) + { + MAlertRecipient recipient = recipients[i]; + if (recipient.getAD_User_ID() >= 0) // System == 0 + users.add(recipient.getAD_User_ID()); + if (recipient.getAD_Role_ID() >= 0) // SystemAdministrator == 0 + { + MUserRoles[] urs = MUserRoles.getOfRole(getCtx(), recipient.getAD_Role_ID()); + for (int j = 0; j < urs.length; j++) + { + MUserRoles ur = urs[j]; + if (!ur.isActive()) + continue; + users.add(ur.getAD_User_ID()); + } + } + } + return users; + } + /** * String Representation * @return info diff --git a/base/src/org/compiere/model/MClient.java b/base/src/org/compiere/model/MClient.java index 0dccb2f361..c685c8d57f 100644 --- a/base/src/org/compiere/model/MClient.java +++ b/base/src/org/compiere/model/MClient.java @@ -513,8 +513,25 @@ public class MClient extends X_AD_Client * @return true if sent */ public boolean sendEMail (int AD_User_ID, - String subject, String message, File attachment) + String subject, String message, File attachment) { + Collection attachments = new ArrayList(); + if (attachment != null) + attachments.add(attachment); + return sendEMailAttachments(AD_User_ID, subject, message, attachments); + } + + /** + * Send EMail from Request User - with trace + * @param AD_User_ID recipient + * @param subject subject + * @param message message + * @param attachment optional collection of attachments + * @return true if sent + */ + public boolean sendEMailAttachments (int AD_User_ID, + String subject, String message, Collection attachments) + { MUser to = MUser.get(getCtx(), AD_User_ID); String toEMail = to.getEMail(); if (toEMail == null || toEMail.length() == 0) @@ -525,8 +542,7 @@ public class MClient extends X_AD_Client EMail email = createEMail(null, to, subject, message); if (email == null) return false; - if (attachment != null) - email.addAttachment(attachment); + email.addAttachments(attachments); try { return sendEmailNow(null, to, email); diff --git a/base/src/org/compiere/util/DefaultContextProvider.java b/base/src/org/compiere/util/DefaultContextProvider.java index 49460e0f7a..6409739e4b 100644 --- a/base/src/org/compiere/util/DefaultContextProvider.java +++ b/base/src/org/compiere/util/DefaultContextProvider.java @@ -40,6 +40,7 @@ public class DefaultContextProvider implements ContextProvider { } public void showURL(String url) { + /* JAVA5 */ if (!Ini.isClient()) return; // OS command String cmd = "rundll32 url.dll,FileProtocolHandler "; @@ -77,7 +78,15 @@ public class DefaultContextProvider implements ContextProvider { s_log.severe(execute + " - " + e); } } - + /* JAVA6 * + try { + java.net.URI uri = new java.net.URI(url); + java.awt.Desktop.getDesktop().browse(uri); + } + catch (Exception e) { + s_log.warning(e.getLocalizedMessage()); + } + /**/ } } diff --git a/base/src/org/compiere/util/EMail.java b/base/src/org/compiere/util/EMail.java index a61ab9cbdd..4513749fad 100644 --- a/base/src/org/compiere/util/EMail.java +++ b/base/src/org/compiere/util/EMail.java @@ -725,6 +725,19 @@ public final class EMail implements Serializable m_attachments = new ArrayList(); m_attachments.add(file); } // addAttachment + + /** + * Add a collection of attachments + * @param files collection of files + */ + public void addAttachments(Collection files) + { + if (files == null || files.size() == 0) + return; + for (File f : files) { + addAttachment(f); + } + } /** * Add url based file Attachment diff --git a/looks/src/org/compiere/util/Util.java b/looks/src/org/compiere/util/Util.java index a390a83e69..43f38c769f 100644 --- a/looks/src/org/compiere/util/Util.java +++ b/looks/src/org/compiere/util/Util.java @@ -209,7 +209,23 @@ public class Util */ public static boolean isEmpty (String str) { - return (str == null || str.length() == 0); + return isEmpty(str, false); + } // isEmpty + + /** + * Is String Empty + * @param str string + * @param trimWhitespaces trim whitespaces + * @return true if >= 1 char + */ + public static boolean isEmpty (String str, boolean trimWhitespaces) + { + if (str == null) + return true; + if (trimWhitespaces) + return str.trim().length() == 0; + else + return str.length() == 0; } // isEmpty /************************************************************************** @@ -634,4 +650,28 @@ public class Util getIterator (aString, new AttributedCharacterIterator.Attribute[] {TextAttribute.UNDERLINE}); } // main + /** + * String diacritics from given string + * @param s original string + * @return string without diacritics + */ + public static String stripDiacritics(String s) { + /* JAVA5 behaviour */ + return s; + /* JAVA6 behaviour * + if (s == null) { + return s; + } + String normStr = java.text.Normalizer.normalize(s, java.text.Normalizer.Form.NFD); + + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < normStr.length(); i++) { + char ch = normStr.charAt(i); + if (ch < 255) + sb.append(ch); + } + return sb.toString(); + /* */ + } + } // Util diff --git a/migration/331b-trunk/104_FR1894573.sql b/migration/331b-trunk/104_FR1894573.sql new file mode 100644 index 0000000000..e10110f6ad --- /dev/null +++ b/migration/331b-trunk/104_FR1894573.sql @@ -0,0 +1,3 @@ +-- FR [ 1894573 ] Alert Processor Improvements +insert into AD_SysConfig (AD_SYSCONFIG_ID,AD_CLIENT_ID,AD_ORG_ID,CREATED,UPDATED,CREATEDBY,UPDATEDBY,ISACTIVE,NAME,VALUE,DESCRIPTION,ENTITYTYPE,CONFIGURATIONLEVEL) +values (50014,0,0,to_date('15-02-2008','DD-MM-RRRR'),to_date('15-02-2008','DD-MM-RRRR'),0,0,'Y','ALERT_SEND_ATTACHMENT_AS_XLS','Y','Send alert results as Excel attachments','D','C'); diff --git a/migration/331b-trunk/postgresql/104_FR1894573.sql b/migration/331b-trunk/postgresql/104_FR1894573.sql new file mode 100644 index 0000000000..de45be0b4c --- /dev/null +++ b/migration/331b-trunk/postgresql/104_FR1894573.sql @@ -0,0 +1,3 @@ +-- FR [ 1894573 ] Alert Processor Improvements +insert into AD_SysConfig (AD_SYSCONFIG_ID,AD_CLIENT_ID,AD_ORG_ID,CREATED,UPDATED,CREATEDBY,UPDATEDBY,ISACTIVE,NAME,VALUE,DESCRIPTION,ENTITYTYPE,CONFIGURATIONLEVEL) +values (50014,0,0,TO_TIMESTAMP('2008-02-15 00:00:00','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2008-02-15 00:00:00','YYYY-MM-DD HH24:MI:SS'),0,0,'Y','ALERT_SEND_ATTACHMENT_AS_XLS','Y','Send alert results as Excel attachments','D','C'); diff --git a/serverRoot/src/main/server/org/compiere/server/AlertProcessor.java b/serverRoot/src/main/server/org/compiere/server/AlertProcessor.java index 3686d3274e..d493f9c9b0 100644 --- a/serverRoot/src/main/server/org/compiere/server/AlertProcessor.java +++ b/serverRoot/src/main/server/org/compiere/server/AlertProcessor.java @@ -16,11 +16,32 @@ *****************************************************************************/ package org.compiere.server; -import java.sql.*; -import java.util.logging.*; -import org.compiere.*; -import org.compiere.model.*; -import org.compiere.util.*; +import java.io.File; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Collection; +import java.util.logging.Level; + +import org.adempiere.impexp.ArrayExcelExporter; +import org.compiere.Adempiere; +import org.compiere.model.MAlert; +import org.compiere.model.MAlertProcessor; +import org.compiere.model.MAlertProcessorLog; +import org.compiere.model.MAlertRule; +import org.compiere.model.MClient; +import org.compiere.model.MRole; +import org.compiere.model.MSysConfig; +import org.compiere.model.MUser; +import org.compiere.util.CLogger; +import org.compiere.util.DB; +import org.compiere.util.Env; +import org.compiere.util.Msg; +import org.compiere.util.TimeUtil; +import org.compiere.util.Trx; +import org.compiere.util.ValueNamePair; /** @@ -28,6 +49,9 @@ import org.compiere.util.*; * * @author Jorg Janke * @version $Id: AlertProcessor.java,v 1.4 2006/07/30 00:53:33 jjanke Exp $ + * + * @author Teo Sarca, SC ARHIPAC SERVICE SRL + *
  • FR [ 1894573 ] Alert Processor Improvements */ public class AlertProcessor extends AdempiereServer { @@ -101,11 +125,12 @@ public class AlertProcessor extends AdempiereServer // boolean valid = true; boolean processed = false; + ArrayList attachments = new ArrayList(); MAlertRule[] rules = alert.getRules(false); for (int i = 0; i < rules.length; i++) { if (i > 0) - message.append(Env.NL).append("================================").append(Env.NL); + message.append(Env.NL); String trxName = null; // assume r/o MAlertRule rule = rules[i]; @@ -147,7 +172,11 @@ public class AlertProcessor extends AdempiereServer try { - String text = listSqlSelect(sql, trxName); + String text = null; + if (MSysConfig.getBooleanValue("ALERT_SEND_ATTACHMENT_AS_XLS", true, Env.getAD_Client_ID(getCtx()))) + text = getExcelReport(rule, sql, trxName, attachments); + else + text = getPlainTextReport(rule, sql, trxName, attachments); if (text != null && text.length() > 0) { message.append(text); @@ -208,51 +237,120 @@ public class AlertProcessor extends AdempiereServer return true; } - // Send Message - int countMail = 0; - MAlertRecipient[] recipients = alert.getRecipients(false); - for (int i = 0; i < recipients.length; i++) - { - MAlertRecipient recipient = recipients[i]; - if (recipient.getAD_User_ID() >= 0) // System == 0 - if (m_client.sendEMail(recipient.getAD_User_ID(), - alert.getAlertSubject(), message.toString(), null)) - countMail++; - if (recipient.getAD_Role_ID() >= 0) // SystemAdministrator == 0 - { - MUserRoles[] urs = MUserRoles.getOfRole(getCtx(), recipient.getAD_Role_ID()); - for (int j = 0; j < urs.length; j++) - { - MUserRoles ur = urs[j]; - if (!ur.isActive()) - continue; - if (m_client.sendEMail (ur.getAD_User_ID(), - alert.getAlertSubject(), message.toString(), null)) - countMail++; - } - } - } + Collection users = alert.getRecipientUsers(); + int countMail = notifyUsers(users, alert.getAlertSubject(), message.toString(), attachments); m_summary.append(alert.getName()).append(" (EMails=").append(countMail).append(") - "); return valid; } // processAlert /** - * List Sql Select - * @param sql sql select - * @param trxName transaction - * @return list of rows & values - * @throws Exception + * Notify users + * @param users AD_User_ID list + * @param subject email subject + * @param message email message + * @param attachments + * @return how many email were sent */ - private String listSqlSelect (String sql, String trxName) throws Exception + private int notifyUsers(Collection users, String subject, String message, Collection attachments) { - StringBuffer result = new StringBuffer(); + int countMail = 0; + for (int user_id : users) { + MUser user = MUser.get(getCtx(), user_id); + if (user.isNotificationEMail()) { + if (m_client.sendEMailAttachments (user_id, subject, message, attachments)) + { + countMail++; + } + } + if (user.isNotificationNote()) { + // TODO: implement + } + } + return countMail; + } + + /** + * Get Alert Data + * @param sql + * @param trxName + * @return data + * @throws Exception + */ + private ArrayList> getData (String sql, String trxName) throws Exception + { + ArrayList> data = new ArrayList>(); PreparedStatement pstmt = null; + ResultSet rs = null; Exception error = null; try { pstmt = DB.prepareStatement (sql, trxName); - ResultSet rs = pstmt.executeQuery (); + rs = pstmt.executeQuery (); + ResultSetMetaData meta = rs.getMetaData(); + boolean isFirstRow = true; + while (rs.next ()) + { + ArrayList header = (isFirstRow ? new ArrayList() : null); + ArrayList row = new ArrayList(); + for (int col = 1; col <= meta.getColumnCount(); col++) + { + if (isFirstRow) { + String columnName = meta.getColumnLabel(col); + header.add(columnName); + } + Object o = rs.getObject(col); + row.add(o); + } // for all columns + if (isFirstRow) + data.add(header); + data.add(row); + isFirstRow = false; + } + } + catch (Throwable e) + { + log.log(Level.SEVERE, sql, e); + if (e instanceof Exception) + error = (Exception)e; + else + error = new Exception(e.getMessage(), e); + } + finally + { + DB.close(rs, pstmt); + rs = null; pstmt = null; + } + + // Error occured + if (error != null) + throw new Exception ("(" + sql + ") " + Env.NL + + error.getLocalizedMessage()); + + return data; + } // getData + + /** + * Get Plain Text Report (old functionality) + * @param rule (ignored) + * @param sql sql select + * @param trxName transaction + * @param attachments (ignored) + * @return list of rows & values + * @throws Exception + * @deprecated + */ + private String getPlainTextReport(MAlertRule rule, String sql, String trxName, Collection attachments) + throws Exception + { + StringBuffer result = new StringBuffer(); + PreparedStatement pstmt = null; + ResultSet rs = null; + Exception error = null; + try + { + pstmt = DB.prepareStatement (sql, trxName); + rs = pstmt.executeQuery (); ResultSetMetaData meta = rs.getMetaData(); while (rs.next ()) { @@ -266,9 +364,6 @@ public class AlertProcessor extends AdempiereServer } if (result.length() == 0) log.fine("No rows selected"); - rs.close (); - pstmt.close (); - pstmt = null; } catch (Throwable e) { @@ -280,7 +375,8 @@ public class AlertProcessor extends AdempiereServer } finally { - DB.close(pstmt); + DB.close(rs, pstmt); + rs = null; pstmt = null; } // Error occured @@ -289,9 +385,33 @@ public class AlertProcessor extends AdempiereServer + error.getLocalizedMessage()); return result.toString(); - } // listSqlSelect - - + } + + /** + * Get Excel Report + * @param rule + * @param sql + * @param trxName + * @param attachments + * @return summary message to be added into mail content + * @throws Exception + */ + private String getExcelReport(MAlertRule rule, String sql, String trxName, Collection attachments) + throws Exception + { + ArrayList> data = getData(sql, trxName); + if (data.size() <= 1) + return null; + // File + String filePrefix = "Alert_"; // TODO: add AD_AlertRule.FileName (maybe) + File file = File.createTempFile(filePrefix, ".xls"); + // + ArrayExcelExporter exporter = new ArrayExcelExporter(getCtx(), data); + exporter.export(file, null, false); + attachments.add(file); + String msg = rule.getName() + " (@SeeAttachment@ "+file.getName()+")"+Env.NL; + return Msg.parseTranslation(Env.getCtx(), msg); + } /** * Get Server Info