diff --git a/migration/i1.0c-release/oracle/20130724102515_IDEMPIERE-1187.sql b/migration/i1.0c-release/oracle/20130724102515_IDEMPIERE-1187.sql
new file mode 100644
index 0000000000..b07f6644de
--- /dev/null
+++ b/migration/i1.0c-release/oracle/20130724102515_IDEMPIERE-1187.sql
@@ -0,0 +1,32 @@
+-- Jul 24, 2013 10:16:11 AM COT
+-- IDEMPIERE-1187 in make menu window, when select "Summary Level", field "Window" still display
+UPDATE AD_Field SET DisplayLogic='@Action@=W & @IsSummary@=N',Updated=TO_DATE('2013-07-24 10:16:11','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=206
+;
+
+-- Jul 24, 2013 10:16:35 AM COT
+-- IDEMPIERE-1187 in make menu window, when select "Summary Level", field "Window" still display
+UPDATE AD_Field SET DisplayLogic='@Action@=X & @IsSummary@=N',Updated=TO_DATE('2013-07-24 10:16:35','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=3612
+;
+
+-- Jul 24, 2013 10:16:48 AM COT
+-- IDEMPIERE-1187 in make menu window, when select "Summary Level", field "Window" still display
+UPDATE AD_Field SET DisplayLogic='@Action@=I & @IsSummary@=N',Updated=TO_DATE('2013-07-24 10:16:48','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201638
+;
+
+-- Jul 24, 2013 10:17:27 AM COT
+-- IDEMPIERE-1187 in make menu window, when select "Summary Level", field "Window" still display
+UPDATE AD_Field SET DisplayLogic='@Action@=P | @Action@=R & @IsSummary@=N',Updated=TO_DATE('2013-07-24 10:17:27','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=2576
+;
+
+-- Jul 24, 2013 10:17:53 AM COT
+-- IDEMPIERE-1187 in make menu window, when select "Summary Level", field "Window" still display
+UPDATE AD_Field SET DisplayLogic='@Action@=T & @IsSummary@=N',Updated=TO_DATE('2013-07-24 10:17:53','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=208
+;
+
+-- Jul 24, 2013 10:18:05 AM COT
+-- IDEMPIERE-1187 in make menu window, when select "Summary Level", field "Window" still display
+UPDATE AD_Field SET DisplayLogic='@Action@=F & @IsSummary@=N',Updated=TO_DATE('2013-07-24 10:18:05','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=207
+;
+
+SELECT register_migration_script('20130724102515_IDEMPIERE-1187.sql') FROM dual
+;
diff --git a/migration/i1.0c-release/oracle/201307301144_IDEMPIERE-840.sql b/migration/i1.0c-release/oracle/201307301144_IDEMPIERE-840.sql
new file mode 100644
index 0000000000..2032a4f8a4
--- /dev/null
+++ b/migration/i1.0c-release/oracle/201307301144_IDEMPIERE-840.sql
@@ -0,0 +1,7 @@
+-- Jul 30, 2013 11:49:17 AM SGT
+-- IDEMPIERE-840 Improvement to Request model class
+UPDATE AD_ModelValidator SET IsActive='N',Updated=TO_DATE('2013-07-30 11:49:17','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_ModelValidator_ID=200003
+;
+
+SELECT register_migration_script('201307301144_IDEMPIERE-840.sql') FROM dual
+;
\ No newline at end of file
diff --git a/migration/i1.0c-release/postgresql/20130724102515_IDEMPIERE-1187.sql b/migration/i1.0c-release/postgresql/20130724102515_IDEMPIERE-1187.sql
new file mode 100644
index 0000000000..9ed5ce99fe
--- /dev/null
+++ b/migration/i1.0c-release/postgresql/20130724102515_IDEMPIERE-1187.sql
@@ -0,0 +1,32 @@
+-- Jul 24, 2013 10:16:11 AM COT
+-- IDEMPIERE-1187 in make menu window, when select "Summary Level", field "Window" still display
+UPDATE AD_Field SET DisplayLogic='@Action@=W & @IsSummary@=N',Updated=TO_TIMESTAMP('2013-07-24 10:16:11','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=206
+;
+
+-- Jul 24, 2013 10:16:35 AM COT
+-- IDEMPIERE-1187 in make menu window, when select "Summary Level", field "Window" still display
+UPDATE AD_Field SET DisplayLogic='@Action@=X & @IsSummary@=N',Updated=TO_TIMESTAMP('2013-07-24 10:16:35','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=3612
+;
+
+-- Jul 24, 2013 10:16:48 AM COT
+-- IDEMPIERE-1187 in make menu window, when select "Summary Level", field "Window" still display
+UPDATE AD_Field SET DisplayLogic='@Action@=I & @IsSummary@=N',Updated=TO_TIMESTAMP('2013-07-24 10:16:48','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=201638
+;
+
+-- Jul 24, 2013 10:17:27 AM COT
+-- IDEMPIERE-1187 in make menu window, when select "Summary Level", field "Window" still display
+UPDATE AD_Field SET DisplayLogic='@Action@=P | @Action@=R & @IsSummary@=N',Updated=TO_TIMESTAMP('2013-07-24 10:17:27','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=2576
+;
+
+-- Jul 24, 2013 10:17:53 AM COT
+-- IDEMPIERE-1187 in make menu window, when select "Summary Level", field "Window" still display
+UPDATE AD_Field SET DisplayLogic='@Action@=T & @IsSummary@=N',Updated=TO_TIMESTAMP('2013-07-24 10:17:53','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=208
+;
+
+-- Jul 24, 2013 10:18:05 AM COT
+-- IDEMPIERE-1187 in make menu window, when select "Summary Level", field "Window" still display
+UPDATE AD_Field SET DisplayLogic='@Action@=F & @IsSummary@=N',Updated=TO_TIMESTAMP('2013-07-24 10:18:05','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Field_ID=207
+;
+
+SELECT register_migration_script('20130724102515_IDEMPIERE-1187.sql') FROM dual
+;
\ No newline at end of file
diff --git a/migration/i1.0c-release/postgresql/201307301144_IDEMPIERE-840.sql b/migration/i1.0c-release/postgresql/201307301144_IDEMPIERE-840.sql
new file mode 100644
index 0000000000..c61018980b
--- /dev/null
+++ b/migration/i1.0c-release/postgresql/201307301144_IDEMPIERE-840.sql
@@ -0,0 +1,7 @@
+-- Jul 30, 2013 11:49:17 AM SGT
+-- IDEMPIERE-840 Improvement to Request model class
+UPDATE AD_ModelValidator SET IsActive='N',Updated=TO_TIMESTAMP('2013-07-30 11:49:17','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_ModelValidator_ID=200003
+;
+
+SELECT register_migration_script('201307301144_IDEMPIERE-840.sql') FROM dual
+;
\ No newline at end of file
diff --git a/org.adempiere.base/OSGI-INF/requesteventhandler.xml b/org.adempiere.base/OSGI-INF/requesteventhandler.xml
new file mode 100644
index 0000000000..25987bc891
--- /dev/null
+++ b/org.adempiere.base/OSGI-INF/requesteventhandler.xml
@@ -0,0 +1,6 @@
+
+
+
+ e.base.event.RequestSendEMailEventHandler"/>
+
+
diff --git a/org.adempiere.base/build.properties b/org.adempiere.base/build.properties
index e8a0395fc2..a8eb848631 100644
--- a/org.adempiere.base/build.properties
+++ b/org.adempiere.base/build.properties
@@ -28,6 +28,7 @@ bin.includes = META-INF/,\
OSGI-INF/defaultshipmentprocessorfactory.xml,\
OSGI-INF/defaultpaymentprocessorfactory.xml,\
OSGI-INF/broadcastutil.xml,\
+ OSGI-INF/requesteventhandler.xml,\
schema/
output.base.jar = build/
src.includes = schema/
diff --git a/org.adempiere.base/src/org/adempiere/base/event/IEventTopics.java b/org.adempiere.base/src/org/adempiere/base/event/IEventTopics.java
index cd372aaf2b..990590cead 100644
--- a/org.adempiere.base/src/org/adempiere/base/event/IEventTopics.java
+++ b/org.adempiere.base/src/org/adempiere/base/event/IEventTopics.java
@@ -92,5 +92,7 @@ public interface IEventTopics {
public static final String PREF_AFTER_LOAD = "adempiere/pref/afterLoad";
public static final String BROADCAST_MESSAGE = "idempiere/broadcastMsg";
+
+ public static final String REQUEST_SEND_EMAIL = "idempiere/requestSendEMail";
}
diff --git a/org.adempiere.base/src/org/adempiere/base/event/RequestEventHandler.java b/org.adempiere.base/src/org/adempiere/base/event/RequestEventHandler.java
new file mode 100644
index 0000000000..bcba0ac4bf
--- /dev/null
+++ b/org.adempiere.base/src/org/adempiere/base/event/RequestEventHandler.java
@@ -0,0 +1,407 @@
+/******************************************************************************
+ * Copyright (C) 2013 Nur Yasmin *
+ * Copyright (C) 2013 Trek Global
+ * 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.base.event;
+
+import static org.compiere.model.SystemIDs.MESSAGE_REQUESTUPDATE;
+
+import java.io.File;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.logging.Level;
+
+import org.adempiere.exceptions.DBException;
+import org.compiere.model.I_R_Request;
+import org.compiere.model.MClient;
+import org.compiere.model.MNote;
+import org.compiere.model.MRequest;
+import org.compiere.model.MRequestAction;
+import org.compiere.model.MRequestUpdate;
+import org.compiere.model.MUser;
+import org.compiere.model.PO;
+import org.compiere.model.X_AD_User;
+import org.compiere.model.X_R_Request;
+import org.compiere.util.CLogger;
+import org.compiere.util.DB;
+import org.compiere.util.Env;
+import org.compiere.util.Msg;
+import org.osgi.service.event.Event;
+
+/**
+ * Request event handler
+ * @author Nur Yasmin
+ *
+ */
+public class RequestEventHandler extends AbstractEventHandler
+{
+ private static CLogger s_log = CLogger.getCLogger (RequestEventHandler.class);
+
+ @Override
+ protected void doHandleEvent(Event event)
+ {
+ String topic = event.getTopic();
+ if (topic.equals(IEventTopics.REQUEST_SEND_EMAIL))
+ {
+ RequestSendEMailEventData eventData = (RequestSendEMailEventData) event.getProperty(EventManager.EVENT_DATA);
+ if (!eventData.getClient().sendEMail(eventData.getFrom(), eventData.getTo(), eventData.getSubject(), eventData.getMessage(), eventData.getAttachment()))
+ {
+ int AD_Message_ID = MESSAGE_REQUESTUPDATE;
+ MNote note = new MNote(Env.getCtx(), AD_Message_ID, eventData.getTo().getAD_User_ID(),
+ X_R_Request.Table_ID, eventData.getRequestID(),
+ eventData.getSubject(), eventData.getMessage(), null);
+ note.save();
+ }
+ }
+ else if (topic.equals(IEventTopics.PO_BEFORE_NEW) || topic.equals(IEventTopics.PO_BEFORE_CHANGE)
+ || topic.equals(IEventTopics.PO_AFTER_NEW) || topic.equals(IEventTopics.PO_AFTER_CHANGE))
+ {
+ PO po = getPO(event);
+ if (po.get_TableName().equals(I_R_Request.Table_Name))
+ {
+ MRequest r = (MRequest) po;
+ if (topic.equals(IEventTopics.PO_BEFORE_NEW) || topic.equals(IEventTopics.PO_BEFORE_CHANGE))
+ beforeSaveRequest(r, topic.equals(IEventTopics.PO_BEFORE_NEW));
+ else if (topic.equals(IEventTopics.PO_AFTER_NEW) || topic.equals(IEventTopics.PO_AFTER_CHANGE))
+ afterSaveRequest(r, topic.equals(IEventTopics.PO_AFTER_NEW));
+ }
+ }
+ }
+
+ @Override
+ protected void initialize()
+ {
+ registerEvent(IEventTopics.REQUEST_SEND_EMAIL);
+ registerTableEvent(IEventTopics.PO_BEFORE_NEW, I_R_Request.Table_Name);
+ registerTableEvent(IEventTopics.PO_BEFORE_CHANGE, I_R_Request.Table_Name);
+ registerTableEvent(IEventTopics.PO_AFTER_NEW, I_R_Request.Table_Name);
+ registerTableEvent(IEventTopics.PO_AFTER_CHANGE, I_R_Request.Table_Name);
+ }
+
+ public static String beforeSaveRequest(MRequest r, boolean newRecord)
+ {
+ // New
+ if (newRecord)
+ return null;
+
+ // Change Log
+ r.setIsChanged(false);
+ ArrayList sendInfo = new ArrayList();
+ MRequestAction ra = new MRequestAction(r, false);
+ //
+ if (checkChange(r, ra, "R_RequestType_ID"))
+ sendInfo.add("R_RequestType_ID");
+ if (checkChange(r, ra, "R_Group_ID"))
+ sendInfo.add("R_Group_ID");
+ if (checkChange(r, ra, "R_Category_ID"))
+ sendInfo.add("R_Category_ID");
+ if (checkChange(r, ra, "R_Status_ID"))
+ sendInfo.add("R_Status_ID");
+ if (checkChange(r, ra, "R_Resolution_ID"))
+ sendInfo.add("R_Resolution_ID");
+ //
+ if (checkChange(r, ra, "SalesRep_ID"))
+ {
+ // Sender
+ int AD_User_ID = Env.getContextAsInt(r.getCtx(), "#AD_User_ID");
+ if (AD_User_ID == 0)
+ AD_User_ID = r.getUpdatedBy();
+ // Old
+ Object oo = r.get_ValueOld("SalesRep_ID");
+ int oldSalesRep_ID = 0;
+ if (oo instanceof Integer)
+ oldSalesRep_ID = ((Integer)oo).intValue();
+ if (oldSalesRep_ID != 0)
+ {
+ // RequestActionTransfer - Request {0} was transfered by {1} from {2} to {3}
+ Object[] args = new Object[] {r.getDocumentNo(),
+ MUser.getNameOfUser(AD_User_ID),
+ MUser.getNameOfUser(oldSalesRep_ID),
+ MUser.getNameOfUser(r.getSalesRep_ID())
+ };
+ String msg = Msg.getMsg(r.getCtx(), "RequestActionTransfer", args);
+ r.addToResult(msg);
+ sendInfo.add("SalesRep_ID");
+ }
+ }
+ checkChange(r, ra, "AD_Role_ID");
+ //
+ checkChange(r, ra, "Priority");
+ if (checkChange(r, ra, "PriorityUser"))
+ sendInfo.add("PriorityUser");
+ if (checkChange(r, ra, "IsEscalated"))
+ sendInfo.add("IsEscalated");
+ //
+ checkChange(r, ra, "ConfidentialType");
+ checkChange(r, ra, "Summary");
+ checkChange(r, ra, "IsSelfService");
+ checkChange(r, ra, "C_BPartner_ID");
+ checkChange(r, ra, "AD_User_ID");
+ checkChange(r, ra, "C_Project_ID");
+ checkChange(r, ra, "A_Asset_ID");
+ checkChange(r, ra, "C_Order_ID");
+ checkChange(r, ra, "C_Invoice_ID");
+ checkChange(r, ra, "M_Product_ID");
+ checkChange(r, ra, "C_Payment_ID");
+ checkChange(r, ra, "M_InOut_ID");
+ checkChange(r, ra, "M_RMA_ID");
+ // checkChange(ra, "C_Campaign_ID");
+ // checkChange(ra, "RequestAmt");
+ checkChange(r, ra, "IsInvoiced");
+ checkChange(r, ra, "C_Activity_ID");
+ checkChange(r, ra, "DateNextAction");
+ checkChange(r, ra, "M_ProductSpent_ID");
+ checkChange(r, ra, "QtySpent");
+ checkChange(r, ra, "QtyInvoiced");
+ checkChange(r, ra, "StartDate");
+ checkChange(r, ra, "CloseDate");
+ checkChange(r, ra, "TaskStatus");
+ checkChange(r, ra, "DateStartPlan");
+ checkChange(r, ra, "DateCompletePlan");
+ //
+ if (r.is_Changed())
+ ra.saveEx();
+
+ // Current Info
+ MRequestUpdate update = new MRequestUpdate(r);
+ if (update.isNewInfo())
+ update.saveEx();
+ else
+ update = null;
+ //
+ if (update != null || sendInfo.size() > 0)
+ {
+ // Note that calling the notifications from beforeSave is causing the
+ // new interested are not notified if the RV_RequestUpdates view changes
+ // this is, when changed the sales rep (solved in sendNotices)
+ // or when changed the request category or group or contact (unsolved - the old ones are notified)
+ sendNotices(r, sendInfo);
+
+ // Update
+ r.setDateLastAction(r.getUpdated());
+ r.setLastResult(r.getResult());
+ r.setDueType();
+ // Reset
+ r.setConfidentialTypeEntry (r.getConfidentialType());
+ // r.setStartDate(null); //red1 - bug [ 1743159 ] Requests - Start Date is not retained.
+ r.setEndTime(null);
+ r.setR_StandardResponse_ID(0);
+ r.setR_MailText_ID(0);
+ r.setResult(null);
+ // globalqss - these fields must be cleared (waiting to open bug in sf)
+ // r.setM_ProductSpent_ID(0);
+ // r.setQtySpent(null);
+ // r.setQtyInvoiced(null);
+ }
+
+ return null;
+ }
+
+ public static String afterSaveRequest(MRequest r, boolean newRecord)
+ {
+ // Initial Mail
+ if (newRecord)
+ sendNotices(r, new ArrayList());
+
+ return null;
+ }
+
+ /**
+ * Check for changes
+ * @param ra request action
+ * @param columnName column
+ * @return true if changes
+ */
+ public static boolean checkChange (MRequest r, MRequestAction ra, String columnName)
+ {
+ if (r.is_ValueChanged(columnName))
+ {
+ Object value = r.get_ValueOld(columnName);
+ if (value == null)
+ ra.addNullColumn(columnName);
+ else
+ ra.set_ValueNoCheck(columnName, value);
+ r.setIsChanged(true);
+ return true;
+ }
+ return false;
+ } // checkChange
+
+ /**
+ * Send Update EMail/Notices
+ * @param list list of changes
+ */
+ public static void sendNotices(MRequest r, ArrayList list)
+ {
+ // Subject
+ String subject = Msg.translate(r.getCtx(), "R_Request_ID")
+ + " " + Msg.getMsg(r.getCtx(), "Updated") + ": " + r.getDocumentNo();
+ // Message
+ StringBuilder message = new StringBuilder();
+ // UpdatedBy: Joe
+ int UpdatedBy = Env.getAD_User_ID(r.getCtx());
+ MUser from = MUser.get(r.getCtx(), UpdatedBy);
+ if (from != null)
+ message.append(Msg.translate(r.getCtx(), "UpdatedBy")).append(": ")
+ .append(from.getName());
+ // LastAction/Created: ...
+ if (r.getDateLastAction() != null)
+ message.append("\n").append(Msg.translate(r.getCtx(), "DateLastAction"))
+ .append(": ").append(r.getDateLastAction());
+ else
+ message.append("\n").append(Msg.translate(r.getCtx(), "Created"))
+ .append(": ").append(r.getCreated());
+ // Changes
+ for (int i = 0; i < list.size(); i++)
+ {
+ String columnName = (String)list.get(i);
+ message.append("\n").append(Msg.getElement(r.getCtx(), columnName))
+ .append(": ").append(r.get_DisplayValue(columnName, false))
+ .append(" -> ").append(r.get_DisplayValue(columnName, true));
+ }
+ // NextAction
+ if (r.getDateNextAction() != null)
+ message.append("\n").append(Msg.translate(r.getCtx(), "DateNextAction"))
+ .append(": ").append(r.getDateNextAction());
+ message.append(MRequest.SEPARATOR)
+ .append(r.getSummary());
+ if (r.getResult() != null)
+ message.append("\n----------\n").append(r.getResult());
+ message.append(getMailTrailer(r, null));
+ File pdf = r.createPDF();
+ if (s_log.isLoggable(Level.FINER)) s_log.finer(message.toString());
+
+ // Prepare sending Notice/Mail
+ MClient client = MClient.get(r.getCtx());
+ // Reset from if external
+ if (from.getEMailUser() == null || from.getEMailUserPW() == null)
+ from = null;
+ //
+ ArrayList userList = new ArrayList();
+ final String sql = "SELECT u.AD_User_ID, u.NotificationType, u.EMail, u.Name, MAX(r.AD_Role_ID) "
+ + "FROM RV_RequestUpdates_Only ru"
+ + " INNER JOIN AD_User u ON (ru.AD_User_ID=u.AD_User_ID OR u.AD_User_ID=?)"
+ + " LEFT OUTER JOIN AD_User_Roles r ON (u.AD_User_ID=r.AD_User_ID) "
+ + "WHERE ru.R_Request_ID=? "
+ + "GROUP BY u.AD_User_ID, u.NotificationType, u.EMail, u.Name";
+ PreparedStatement pstmt = null;
+ ResultSet rs = null;
+ try
+ {
+ pstmt = DB.prepareStatement (sql, r.get_TrxName());
+ pstmt.setInt (1, r.getSalesRep_ID());
+ pstmt.setInt (2, r.getR_Request_ID());
+ rs = pstmt.executeQuery ();
+ while (rs.next ())
+ {
+ int AD_User_ID = rs.getInt(1);
+ String NotificationType = rs.getString(2);
+ if (NotificationType == null)
+ NotificationType = X_AD_User.NOTIFICATIONTYPE_EMail;
+ String email = rs.getString(3);
+ String Name = rs.getString(4);
+ // Role
+ int AD_Role_ID = rs.getInt(5);
+ if (rs.wasNull())
+ AD_Role_ID = -1;
+
+ // Don't send mail to oneself
+ // if (AD_User_ID == UpdatedBy)
+ // continue;
+
+ // No confidential to externals
+ if (AD_Role_ID == -1
+ && (r.getConfidentialTypeEntry().equals(MRequest.CONFIDENTIALTYPE_Internal)
+ || r.getConfidentialTypeEntry().equals(MRequest.CONFIDENTIALTYPE_PrivateInformation)))
+ continue;
+
+ if (X_AD_User.NOTIFICATIONTYPE_None.equals(NotificationType))
+ {
+ if (s_log.isLoggable(Level.CONFIG)) s_log.config("Opt out: " + Name);
+ continue;
+ }
+ if ((X_AD_User.NOTIFICATIONTYPE_EMail.equals(NotificationType)
+ || X_AD_User.NOTIFICATIONTYPE_EMailPlusNotice.equals(NotificationType))
+ && (email == null || email.length() == 0))
+ {
+ if (AD_Role_ID >= 0)
+ NotificationType = X_AD_User.NOTIFICATIONTYPE_Notice;
+ else
+ {
+ if (s_log.isLoggable(Level.CONFIG)) s_log.config("No EMail: " + Name);
+ continue;
+ }
+ }
+ if (X_AD_User.NOTIFICATIONTYPE_Notice.equals(NotificationType)
+ && AD_Role_ID >= 0)
+ {
+ if (s_log.isLoggable(Level.CONFIG)) s_log.config("No internal User: " + Name);
+ continue;
+ }
+
+ // Check duplicate receivers
+ Integer ii = new Integer (AD_User_ID);
+ if (userList.contains(ii))
+ continue;
+ userList.add(ii);
+ //
+ MUser to = MUser.get (r.getCtx(), AD_User_ID);
+ // Send Mail
+ if (X_AD_User.NOTIFICATIONTYPE_EMail.equals(NotificationType)
+ || X_AD_User.NOTIFICATIONTYPE_EMailPlusNotice.equals(NotificationType))
+ {
+ RequestSendEMailEventData eventData = new RequestSendEMailEventData(client, from, to, subject, message.toString(), pdf, r.getR_Request_ID());
+ Event event = EventManager.newEvent(IEventTopics.REQUEST_SEND_EMAIL, eventData);
+ EventManager.getInstance().postEvent(event);
+ }
+ // Send Note
+ if (X_AD_User.NOTIFICATIONTYPE_Notice.equals(NotificationType)
+ || X_AD_User.NOTIFICATIONTYPE_EMailPlusNotice.equals(NotificationType))
+ {
+ int AD_Message_ID = MESSAGE_REQUESTUPDATE;
+ MNote note = new MNote(r.getCtx(), AD_Message_ID, AD_User_ID,
+ X_R_Request.Table_ID, r.getR_Request_ID(),
+ subject, message.toString(), r.get_TrxName());
+ note.save();
+ }
+ }
+ }
+ catch (SQLException e)
+ {
+ throw new DBException(e, sql);
+ }
+ finally
+ {
+ DB.close(rs, pstmt);
+ rs = null; pstmt = null;
+ }
+ } // sendNotice
+
+ /**************************************************************************
+ * Get MailID
+ * @param serverAddress server address
+ * @return Mail Trailer
+ */
+ public static String getMailTrailer(MRequest r, String serverAddress)
+ {
+ StringBuffer sb = new StringBuffer("\n").append(MRequest.SEPARATOR)
+ .append(Msg.translate(r.getCtx(), "R_Request_ID"))
+ .append(": ").append(r.getDocumentNo())
+ .append(" ").append(r.getMailTag())
+ .append("\nSent by AdempiereMail");
+ if (serverAddress != null)
+ sb.append(" from ").append(serverAddress);
+ return sb.toString();
+ } // getMailTrailer
+}
diff --git a/org.adempiere.base/src/org/compiere/model/RequestValidator.java b/org.adempiere.base/src/org/compiere/model/RequestValidator.java
index 260283b2f4..bca5aaa40d 100644
--- a/org.adempiere.base/src/org/compiere/model/RequestValidator.java
+++ b/org.adempiere.base/src/org/compiere/model/RequestValidator.java
@@ -14,36 +14,14 @@
package org.compiere.model;
-import static org.compiere.model.SystemIDs.MESSAGE_REQUESTUPDATE;
-
-import java.io.File;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.logging.Level;
-
-import org.adempiere.base.event.EventManager;
-import org.adempiere.base.event.RequestSendEMailEventData;
-import org.adempiere.exceptions.DBException;
-import org.compiere.util.CLogger;
-import org.compiere.util.DB;
-import org.compiere.util.Env;
-import org.compiere.util.Msg;
-import org.osgi.service.event.Event;
-import org.osgi.service.event.EventHandler;
/**
*
* @author Elaine
*
*/
-public class RequestValidator implements ModelValidator, EventHandler
+public class RequestValidator implements ModelValidator
{
- public static final String ON_REQUEST_SEND_EMAIL_TOPIC = "onRequestSendEMail";
-
- private static CLogger s_log = CLogger.getCLogger (RequestValidator.class);
-
private int m_AD_Client_ID;
@Override
@@ -51,10 +29,6 @@ public class RequestValidator implements ModelValidator, EventHandler
{
if (client != null)
m_AD_Client_ID = client.getAD_Client_ID();
- engine.addModelChange(I_R_Request.Table_Name, this);
-
- if (EventManager.getInstance() != null)
- EventManager.getInstance().register(ON_REQUEST_SEND_EMAIL_TOPIC, this);
}
@Override
@@ -72,14 +46,6 @@ public class RequestValidator implements ModelValidator, EventHandler
@Override
public String modelChange(PO po, int type) throws Exception
{
- if (po instanceof MRequest )
- {
- MRequest r = (MRequest) po;
- if (type == TYPE_BEFORE_NEW || type == TYPE_BEFORE_CHANGE)
- beforeSaveRequest(r, type == TYPE_BEFORE_NEW);
- else if (type == TYPE_AFTER_NEW || type == TYPE_AFTER_CHANGE)
- afterSaveRequest(r, type == TYPE_AFTER_NEW);
- }
return null;
}
@@ -88,336 +54,4 @@ public class RequestValidator implements ModelValidator, EventHandler
{
return null;
}
-
- public static String beforeSaveRequest(MRequest r, boolean newRecord)
- {
- // New
- if (newRecord)
- return null;
-
- // Change Log
- r.setIsChanged(false);
- ArrayList sendInfo = new ArrayList();
- MRequestAction ra = new MRequestAction(r, false);
- //
- if (checkChange(r, ra, "R_RequestType_ID"))
- sendInfo.add("R_RequestType_ID");
- if (checkChange(r, ra, "R_Group_ID"))
- sendInfo.add("R_Group_ID");
- if (checkChange(r, ra, "R_Category_ID"))
- sendInfo.add("R_Category_ID");
- if (checkChange(r, ra, "R_Status_ID"))
- sendInfo.add("R_Status_ID");
- if (checkChange(r, ra, "R_Resolution_ID"))
- sendInfo.add("R_Resolution_ID");
- //
- if (checkChange(r, ra, "SalesRep_ID"))
- {
- // Sender
- int AD_User_ID = Env.getContextAsInt(r.getCtx(), "#AD_User_ID");
- if (AD_User_ID == 0)
- AD_User_ID = r.getUpdatedBy();
- // Old
- Object oo = r.get_ValueOld("SalesRep_ID");
- int oldSalesRep_ID = 0;
- if (oo instanceof Integer)
- oldSalesRep_ID = ((Integer)oo).intValue();
- if (oldSalesRep_ID != 0)
- {
- // RequestActionTransfer - Request {0} was transfered by {1} from {2} to {3}
- Object[] args = new Object[] {r.getDocumentNo(),
- MUser.getNameOfUser(AD_User_ID),
- MUser.getNameOfUser(oldSalesRep_ID),
- MUser.getNameOfUser(r.getSalesRep_ID())
- };
- String msg = Msg.getMsg(r.getCtx(), "RequestActionTransfer", args);
- r.addToResult(msg);
- sendInfo.add("SalesRep_ID");
- }
- }
- checkChange(r, ra, "AD_Role_ID");
- //
- checkChange(r, ra, "Priority");
- if (checkChange(r, ra, "PriorityUser"))
- sendInfo.add("PriorityUser");
- if (checkChange(r, ra, "IsEscalated"))
- sendInfo.add("IsEscalated");
- //
- checkChange(r, ra, "ConfidentialType");
- checkChange(r, ra, "Summary");
- checkChange(r, ra, "IsSelfService");
- checkChange(r, ra, "C_BPartner_ID");
- checkChange(r, ra, "AD_User_ID");
- checkChange(r, ra, "C_Project_ID");
- checkChange(r, ra, "A_Asset_ID");
- checkChange(r, ra, "C_Order_ID");
- checkChange(r, ra, "C_Invoice_ID");
- checkChange(r, ra, "M_Product_ID");
- checkChange(r, ra, "C_Payment_ID");
- checkChange(r, ra, "M_InOut_ID");
- checkChange(r, ra, "M_RMA_ID");
- // checkChange(ra, "C_Campaign_ID");
- // checkChange(ra, "RequestAmt");
- checkChange(r, ra, "IsInvoiced");
- checkChange(r, ra, "C_Activity_ID");
- checkChange(r, ra, "DateNextAction");
- checkChange(r, ra, "M_ProductSpent_ID");
- checkChange(r, ra, "QtySpent");
- checkChange(r, ra, "QtyInvoiced");
- checkChange(r, ra, "StartDate");
- checkChange(r, ra, "CloseDate");
- checkChange(r, ra, "TaskStatus");
- checkChange(r, ra, "DateStartPlan");
- checkChange(r, ra, "DateCompletePlan");
- //
- if (r.is_Changed())
- ra.saveEx();
-
- // Current Info
- MRequestUpdate update = new MRequestUpdate(r);
- if (update.isNewInfo())
- update.saveEx();
- else
- update = null;
- //
- if (update != null || sendInfo.size() > 0)
- {
- // Note that calling the notifications from beforeSave is causing the
- // new interested are not notified if the RV_RequestUpdates view changes
- // this is, when changed the sales rep (solved in sendNotices)
- // or when changed the request category or group or contact (unsolved - the old ones are notified)
- sendNotices(r, sendInfo);
-
- // Update
- r.setDateLastAction(r.getUpdated());
- r.setLastResult(r.getResult());
- r.setDueType();
- // Reset
- r.setConfidentialTypeEntry (r.getConfidentialType());
- // r.setStartDate(null); //red1 - bug [ 1743159 ] Requests - Start Date is not retained.
- r.setEndTime(null);
- r.setR_StandardResponse_ID(0);
- r.setR_MailText_ID(0);
- r.setResult(null);
- // globalqss - these fields must be cleared (waiting to open bug in sf)
- // r.setM_ProductSpent_ID(0);
- // r.setQtySpent(null);
- // r.setQtyInvoiced(null);
- }
-
- return null;
- }
-
- public static String afterSaveRequest(MRequest r, boolean newRecord)
- {
- // Initial Mail
- if (newRecord)
- sendNotices(r, new ArrayList());
-
- return null;
- }
-
- /**
- * Check for changes
- * @param ra request action
- * @param columnName column
- * @return true if changes
- */
- public static boolean checkChange (MRequest r, MRequestAction ra, String columnName)
- {
- if (r.is_ValueChanged(columnName))
- {
- Object value = r.get_ValueOld(columnName);
- if (value == null)
- ra.addNullColumn(columnName);
- else
- ra.set_ValueNoCheck(columnName, value);
- r.setIsChanged(true);
- return true;
- }
- return false;
- } // checkChange
-
- /**
- * Send Update EMail/Notices
- * @param list list of changes
- */
- public static void sendNotices(MRequest r, ArrayList list)
- {
- // Subject
- String subject = Msg.translate(r.getCtx(), "R_Request_ID")
- + " " + Msg.getMsg(r.getCtx(), "Updated") + ": " + r.getDocumentNo();
- // Message
- StringBuilder message = new StringBuilder();
- // UpdatedBy: Joe
- int UpdatedBy = Env.getAD_User_ID(r.getCtx());
- MUser from = MUser.get(r.getCtx(), UpdatedBy);
- if (from != null)
- message.append(Msg.translate(r.getCtx(), "UpdatedBy")).append(": ")
- .append(from.getName());
- // LastAction/Created: ...
- if (r.getDateLastAction() != null)
- message.append("\n").append(Msg.translate(r.getCtx(), "DateLastAction"))
- .append(": ").append(r.getDateLastAction());
- else
- message.append("\n").append(Msg.translate(r.getCtx(), "Created"))
- .append(": ").append(r.getCreated());
- // Changes
- for (int i = 0; i < list.size(); i++)
- {
- String columnName = (String)list.get(i);
- message.append("\n").append(Msg.getElement(r.getCtx(), columnName))
- .append(": ").append(r.get_DisplayValue(columnName, false))
- .append(" -> ").append(r.get_DisplayValue(columnName, true));
- }
- // NextAction
- if (r.getDateNextAction() != null)
- message.append("\n").append(Msg.translate(r.getCtx(), "DateNextAction"))
- .append(": ").append(r.getDateNextAction());
- message.append(MRequest.SEPARATOR)
- .append(r.getSummary());
- if (r.getResult() != null)
- message.append("\n----------\n").append(r.getResult());
- message.append(getMailTrailer(r, null));
- File pdf = r.createPDF();
- if (s_log.isLoggable(Level.FINER)) s_log.finer(message.toString());
-
- // Prepare sending Notice/Mail
- MClient client = MClient.get(r.getCtx());
- // Reset from if external
- if (from.getEMailUser() == null || from.getEMailUserPW() == null)
- from = null;
- //
- ArrayList userList = new ArrayList();
- final String sql = "SELECT u.AD_User_ID, u.NotificationType, u.EMail, u.Name, MAX(r.AD_Role_ID) "
- + "FROM RV_RequestUpdates_Only ru"
- + " INNER JOIN AD_User u ON (ru.AD_User_ID=u.AD_User_ID OR u.AD_User_ID=?)"
- + " LEFT OUTER JOIN AD_User_Roles r ON (u.AD_User_ID=r.AD_User_ID) "
- + "WHERE ru.R_Request_ID=? "
- + "GROUP BY u.AD_User_ID, u.NotificationType, u.EMail, u.Name";
- PreparedStatement pstmt = null;
- ResultSet rs = null;
- try
- {
- pstmt = DB.prepareStatement (sql, r.get_TrxName());
- pstmt.setInt (1, r.getSalesRep_ID());
- pstmt.setInt (2, r.getR_Request_ID());
- rs = pstmt.executeQuery ();
- while (rs.next ())
- {
- int AD_User_ID = rs.getInt(1);
- String NotificationType = rs.getString(2);
- if (NotificationType == null)
- NotificationType = X_AD_User.NOTIFICATIONTYPE_EMail;
- String email = rs.getString(3);
- String Name = rs.getString(4);
- // Role
- int AD_Role_ID = rs.getInt(5);
- if (rs.wasNull())
- AD_Role_ID = -1;
-
- // Don't send mail to oneself
- // if (AD_User_ID == UpdatedBy)
- // continue;
-
- // No confidential to externals
- if (AD_Role_ID == -1
- && (r.getConfidentialTypeEntry().equals(MRequest.CONFIDENTIALTYPE_Internal)
- || r.getConfidentialTypeEntry().equals(MRequest.CONFIDENTIALTYPE_PrivateInformation)))
- continue;
-
- if (X_AD_User.NOTIFICATIONTYPE_None.equals(NotificationType))
- {
- if (s_log.isLoggable(Level.CONFIG)) s_log.config("Opt out: " + Name);
- continue;
- }
- if ((X_AD_User.NOTIFICATIONTYPE_EMail.equals(NotificationType)
- || X_AD_User.NOTIFICATIONTYPE_EMailPlusNotice.equals(NotificationType))
- && (email == null || email.length() == 0))
- {
- if (AD_Role_ID >= 0)
- NotificationType = X_AD_User.NOTIFICATIONTYPE_Notice;
- else
- {
- if (s_log.isLoggable(Level.CONFIG)) s_log.config("No EMail: " + Name);
- continue;
- }
- }
- if (X_AD_User.NOTIFICATIONTYPE_Notice.equals(NotificationType)
- && AD_Role_ID >= 0)
- {
- if (s_log.isLoggable(Level.CONFIG)) s_log.config("No internal User: " + Name);
- continue;
- }
-
- // Check duplicate receivers
- Integer ii = new Integer (AD_User_ID);
- if (userList.contains(ii))
- continue;
- userList.add(ii);
- //
- MUser to = MUser.get (r.getCtx(), AD_User_ID);
- // Send Mail
- if (X_AD_User.NOTIFICATIONTYPE_EMail.equals(NotificationType)
- || X_AD_User.NOTIFICATIONTYPE_EMailPlusNotice.equals(NotificationType))
- {
- RequestSendEMailEventData eventData = new RequestSendEMailEventData(client, from, to, subject, message.toString(), pdf, r.getR_Request_ID());
- Event event = EventManager.newEvent(ON_REQUEST_SEND_EMAIL_TOPIC, eventData);
- EventManager.getInstance().postEvent(event);
- }
- // Send Note
- if (X_AD_User.NOTIFICATIONTYPE_Notice.equals(NotificationType)
- || X_AD_User.NOTIFICATIONTYPE_EMailPlusNotice.equals(NotificationType))
- {
- int AD_Message_ID = MESSAGE_REQUESTUPDATE;
- MNote note = new MNote(r.getCtx(), AD_Message_ID, AD_User_ID,
- X_R_Request.Table_ID, r.getR_Request_ID(),
- subject, message.toString(), r.get_TrxName());
- note.save();
- }
- }
- }
- catch (SQLException e)
- {
- throw new DBException(e, sql);
- }
- finally
- {
- DB.close(rs, pstmt);
- rs = null; pstmt = null;
- }
- } // sendNotice
-
- /**************************************************************************
- * Get MailID
- * @param serverAddress server address
- * @return Mail Trailer
- */
- public static String getMailTrailer(MRequest r, String serverAddress)
- {
- StringBuffer sb = new StringBuffer("\n").append(MRequest.SEPARATOR)
- .append(Msg.translate(r.getCtx(), "R_Request_ID"))
- .append(": ").append(r.getDocumentNo())
- .append(" ").append(r.getMailTag())
- .append("\nSent by AdempiereMail");
- if (serverAddress != null)
- sb.append(" from ").append(serverAddress);
- return sb.toString();
- } // getMailTrailer
-
- @Override
- public void handleEvent(Event event) {
- if (event.getTopic() == ON_REQUEST_SEND_EMAIL_TOPIC)
- {
- RequestSendEMailEventData eventData = (RequestSendEMailEventData) event.getProperty(EventManager.EVENT_DATA);
- if (!eventData.getClient().sendEMail(eventData.getFrom(), eventData.getTo(), eventData.getSubject(), eventData.getMessage(), eventData.getAttachment()))
- {
- int AD_Message_ID = MESSAGE_REQUESTUPDATE;
- MNote note = new MNote(Env.getCtx(), AD_Message_ID, eventData.getTo().getAD_User_ID(),
- X_R_Request.Table_ID, eventData.getRequestID(),
- eventData.getSubject(), eventData.getMessage(), null);
- note.save();
- }
- }
- }
}