/////////////////////////////////////////////////////////// // ClientNotifyEvent.cs // Implementation of Class ClientNotifyEvent // CSLA type: Editable Root // Created on: 10-December-2008 // Object design: John // Coded: 10-December-2008 /////////////////////////////////////////////////////////// using System; using System.Data; using CSLA.Data; using GZTW.Data; using CSLA; using System.Runtime.Serialization.Formatters.Binary; using System.IO; using System.Collections.Generic; //using Chilkat; using System.Text; using System.Text.RegularExpressions; //case 53 namespace GZTW.AyaNova.BLL { /// /// ClientNotifyEvent object /// Insert and manage client notification events /// /// [Serializable] public class ClientNotifyEvent : BusinessBase { #pragma warning disable 1591 #region Attributes private Guid mID; private SmartDate mCreated; private SmartDate mModified; private Guid mCreator; private Guid mModifier; private Guid mClientID = Guid.Empty; private SmartDate mDeliverAfter; private byte[] mContent=null; private int mObjectSize; #endregion #region Constructor /// /// Private constructor to prevent direct instantiation /// private ClientNotifyEvent() { //New ID mID = Guid.NewGuid(); //Set record history to defaults mCreated = new SmartDate(DBUtil.CurrentWorkingDateTime); mModified = new SmartDate(); mCreator = Guid.Empty; mModifier = Guid.Empty; //case 1163 mDeliverAfter = new SmartDate(DBUtil.CurrentWorkingDateTime - TimeSpan.FromSeconds(30));//deliver after 30 seconds ago just in case ClientID = Guid.Empty; mObjectSize = 0; } #endregion #region Business properties /// /// Internal Unique GUID value of ClientNotifyEvent record in database /// public Guid ID { get { return mID; } } /// /// Get created date /// /// /// public string Created { get { return mCreated.ToString(); } } /// /// Get modified date /// /// /// public string Modified { get { return mModified.ToString(); } } /// /// Get user record ID of person who created this record /// /// /// public Guid Creator { get { return mCreator; } } /// /// Get user ID of person who modified this record /// /// /// public Guid Modifier { get { return mModifier; } } /// /// AyaNova object ID /// public Guid ClientID { get { return mClientID; } set { if (mClientID != value) { mClientID = value; BrokenRules.Assert("ClientID", "Error.Object.RequiredFieldEmpty,ClientNotifyEvent.Label.ClientID", "ClientID", value == Guid.Empty); MarkDirty(); } } } /// /// Deliver after date, used only /// for follow up client notifications /// public DateTime DeliverAfter { get { return mDeliverAfter.Date; } set { mDeliverAfter.Date = value; } } /// /// Get the MIME content /// /// public string GetContentAsString { get { return Encoding.Unicode.GetString(mContent); } } public System.IO.MemoryStream GetContent() { //if (mContent.Length == mObjectSize)//it's not compressed so just return it return new System.IO.MemoryStream(mContent); // else//it *is* compressed so decompress and return // return new System.IO.MemoryStream(AyaBizUtils.Decompress(mContent)); } /// /// Set the content based on string /// /// public void SetContent(string sContent) { using (MemoryStream ms = new MemoryStream(System.Text.Encoding.Unicode.GetBytes(sContent))) { SetContent(ms); } } public void SetContent(System.IO.Stream mStream) { mObjectSize = (int)mStream.Length; mStream.Position = 0; byte[] bData = new byte[mStream.Length]; mStream.Read(bData, 0, (int)mStream.Length); mContent = bData;//just store, compression not needed here //mContent = AyaBizUtils.Compress(bData); ////did it compress smaller? ////don't want to store uncompressible files that are actually larger after compression //if (mContent.Length >= mObjectSize) //{ // //yup, it's bigger compressed, so store the uncompressed version instead // mContent = bData; //} MarkDirty(); } /// /// Byte array set content /// /// public void SetContent(byte[] bData) { mObjectSize = (int)bData.LongLength; //mStream.Position = 0; //byte[] bData = new byte[mStream.Length]; //mStream.Read(bData, 0, (int)mStream.Length); // mContent = AyaBizUtils.Compress(bData); //did it compress smaller? //don't want to store uncompressible files that are actually larger after compression //if (mContent.Length >= mObjectSize) //{ //yup, it's bigger compressed, so store the uncompressed version instead mContent = bData; //} MarkDirty(); } /// /// Throw an error when a read only user /// tries to set a property /// (this should normally never be called unless someone is using the developer api since the UI /// should prevent it from happening initially) /// private void ThrowSetError() { throw new System.Security.SecurityException ( string.Format ( LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToChange"), LocalizedTextTable.GetLocalizedTextDirect("O.ClientNotifyEvent") ) ); } #endregion #region System.object overrides public override string ToString() { return "ClientNotifyEvent" + mID.ToString(); } /// /// public override bool Equals(Object obj) { if (obj == null || GetType() != obj.GetType()) return false; ClientNotifyEvent c = (ClientNotifyEvent)obj; return mID == c.mID; } public override int GetHashCode() { return ("ClientNotifyEvent" + mID).GetHashCode(); } #endregion #region Static methods /// /// Overload /// /// /// /// /// /// /// /// /// /// /// internal static void ProcessEvent(ClientNotifyEventType type, Guid ClientID, Guid WorkorderStatusID, string wonumber, string contact, string cref, string csrdetails, Guid WorkorderID, string wosummary, string csrtitle) { ProcessEvent(type, ClientID, WorkorderStatusID, wonumber, contact, cref, csrdetails, WorkorderID, wosummary, csrtitle, WorkorderQuoteStatusTypes.NotSet); } /// /// Generate a new client notification if appropriate /// /// /// /// /// /// /// /// /// /// /// /// internal static void ProcessEvent(ClientNotifyEventType type, Guid ClientID, Guid WorkorderStatusID, string wonumber, string contact, string cref, string csrdetails, Guid WorkorderID,string wosummary, string csrtitle, WorkorderQuoteStatusTypes quoteStatus) { ClientList cl = ClientList.GetListForSingleItem(ClientID); if (cl.Count < 1) return; if (!cl[0].LT_Client_Label_Notification) return; if (string.IsNullOrEmpty(cl[0].LT_Client_Label_Email)) return; Region r = Region.GetItem(cl[0].LT_O_Region.Value); if (!r.ClientNotification) return; string sTemplate = ""; //case 1151 Guid gAttachReportID = Guid.Empty; switch (type) { case ClientNotifyEventType.CSRAccepted: { if (!r.NotifyCSRAccepted) return; sTemplate = r.NotifyCSRMSG; } break; case ClientNotifyEventType.CSRRejected: { if (!r.NotifyCSRRejected) return; sTemplate = r.NotifyCSRRejectMSG; } break; case ClientNotifyEventType.NewWorkorder: { if (!r.NotifyNewWO) return; sTemplate = r.NotifyNewWOMSG; } break; case ClientNotifyEventType.WorkorderClosed: { if (!r.NotifyWOClosed) return; sTemplate = r.NotifyWOClosedMSG; //added for case 1151 if (r.NotifyWOClosedAttachWO) gAttachReportID = r.NotifyWOClosedRPT; } break; case ClientNotifyEventType.WorkorderFollowUp: { if (!r.NotifyWOFollowUp) return; sTemplate = r.NotifyWOFollowUpMSG; } break; case ClientNotifyEventType.WorkorderStatusSet: { //if (!r.NotifyWOStatus) return; //if (WorkorderStatusID == Guid.Empty || WorkorderStatusID != r.NotifyWOStatusID) return; //sTemplate = r.NotifyWOStatMSG; //case 1151 if (WorkorderStatusID == Guid.Empty) return; System.Text.StringBuilder stb = new StringBuilder(); foreach (RegionWoStatusNotifyItem rwsni in r.WoStatusNotifyItems) { if (rwsni.Active && rwsni.NotifyWOStatusID == WorkorderStatusID) { sTemplate=rwsni.NotifyWOStatMSG; gAttachReportID = rwsni.WoReportID; break; } } } break; //case 1499 case ClientNotifyEventType.QuoteStatusSet: { if (!r.NotifyQuoteStatus) return; if (r.NotifyQuoteStatusType != quoteStatus) return; sTemplate = r.NotifyQuoteStatMSG; if (r.NotifyQuoteStatusRPT!=Guid.Empty) gAttachReportID = r.NotifyQuoteStatusRPT; } break; } if(string.IsNullOrEmpty(sTemplate)) return; #region Template processing WorkorderStatusPickList statpick = WorkorderStatusPickList.GetList(); //fill in template //Match all keywords and substitute queried data for them MatchCollection matches = Regex.Matches(sTemplate, @"\[(.|\n)*?\]", RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled); foreach (Match KeyMatch in matches) { switch (KeyMatch.Value) { case "[WorkorderService.Label.ServiceNumber]": sTemplate=sTemplate.Replace(KeyMatch.Value, wonumber); break; case "[O.WorkorderStatus]": if (statpick.Contains(WorkorderStatusID)) sTemplate = sTemplate.Replace(KeyMatch.Value, statpick[WorkorderStatusID].Name); else sTemplate = sTemplate.Replace(KeyMatch.Value, ""); break; case "[Workorder.Label.CustomerContactName]": sTemplate = sTemplate.Replace(KeyMatch.Value, contact); break; case "[Workorder.Label.CustomerReferenceNumber]": sTemplate = sTemplate.Replace(KeyMatch.Value, cref); break; case "[Region.Label.WBIUrl]": sTemplate = sTemplate.Replace(KeyMatch.Value, r.WBIUrl); break; case "[Client.Label.Name]": sTemplate = sTemplate.Replace(KeyMatch.Value, cl[0].LT_O_Client.Display); break; case "[ClientServiceRequest.Label.Details]": sTemplate = sTemplate.Replace(KeyMatch.Value, csrdetails); break; case "[Workorder.Label.Summary]": sTemplate = sTemplate.Replace(KeyMatch.Value, wosummary); break; case "[ClientServiceRequest.Label.Title]": sTemplate = sTemplate.Replace(KeyMatch.Value, csrtitle); break; //case 1499 case "[WorkorderQuote.Label.QuoteNumber]": sTemplate = sTemplate.Replace(KeyMatch.Value, wonumber); break; } } #endregion template if(string.IsNullOrEmpty(sTemplate)) return; //subject line first line or first 100 characters of template string sSubject=""; //Let's get the default 100 characters or less first if (sTemplate.Length < 101) sSubject = sTemplate; else sSubject = sTemplate.Substring(0, 100); //fine tune if there is a return or linefeed within the bounds of reason int n = sTemplate.IndexOfAny(new char[] { '\n', '\r' }); if (n != -1 && n<102 && n > 2) { sSubject = sTemplate.Substring(0, n);//case 1984 was n-1 } //generate email System.Text.StringBuilder sb = new StringBuilder(); sb.Append("CLIENTNOTIFYEVENT|"); //Email email = new Email(); // email.UnlockComponent("SAyanovaMAILQ_46WCmUg3lQ1i"); // email.Mailer = "AyaNova service management software licensed to " + AyaBizUtils.REGTO; //email.Body = sTemplate; sb.Append(sTemplate); sb.Append("|"); //email.Subject = sSubject; sb.Append(sSubject); sb.Append("|"); //email.AddTo("", cl[0].LT_Client_Label_Email); sb.Append(cl[0].LT_Client_Label_Email); sb.Append("|"); //email.From = r.ReplyToEmail; sb.Append(r.ReplyToEmail); //ATTACH REPORT? //case 1151 modified to add status change, b4 was only on closed //indicate which wo to attach and which report to use //(saves looking it up later) if (gAttachReportID!=Guid.Empty) { //put in delimiter for previous item sb.Append("|"); //email.AddHeaderField("WorkorderID", WorkorderID.ToString()); sb.Append(WorkorderID.ToString()); sb.Append("|"); //email.AddHeaderField("ReportID", r.NotifyWOClosedRPT.ToString()); sb.Append(gAttachReportID.ToString()); } ClientNotifyEvent cn = ClientNotifyEvent.NewItem(); cn.ClientID = ClientID; if (type == ClientNotifyEventType.WorkorderFollowUp) cn.DeliverAfter += TimeSpan.FromDays(r.NotifyWOFollowUpDays); cn.SetContent(sb.ToString()); cn.Save(); } /// /// Create new ClientNotifyEvent /// /// Empty ClientNotifyEvent object public static ClientNotifyEvent NewItem() { ClientNotifyEvent c; //if (AyaBizUtils.Right("Object.ClientNotifyEvent") > (int)SecurityLevelTypes.ReadOnly) //{ c = new ClientNotifyEvent(); return c; //} //else // throw new System.Security.SecurityException( // string.Format( // LocalizedTextTable.GetLocalizedTextDirect("Error.Security.NotAuthorizedToCreate"), // LocalizedTextTable.GetLocalizedTextDirect("O.ClientNotifyEvent"))); } /// /// Fetch existing ClientNotifyEvent /// /// ClientNotifyEvent /// ClientNotifyEvent Guid public static ClientNotifyEvent GetItem(Guid ID) { return (ClientNotifyEvent)DataPortal.Fetch(new Criteria(ID,Guid.Empty)); } /// /// Delete ClientNotifyEvent /// /// ClientNotifyEvent applicationID public static void DeleteItem(Guid ID) { DataPortal.Delete(new Criteria(ID, Guid.Empty)); } /// /// Delete all events for a specified client /// used when saving a client record that has it's send notifications /// unchecked and when deleting a client /// /// Client ID public static void DeleteAllNotifyEventsForClient(Guid ClientID) { DataPortal.Delete(new Criteria(Guid.Empty, ClientID)); } #endregion #region DAL DATA ACCESS #region Fetch /// /// protected override void DataPortal_Fetch(object Criteria) { Criteria crit = (Criteria)Criteria; SafeDataReader dr = null; try { dr = DBUtil.GetReaderFromSQLString("SELECT * FROM aClientNotifyEvent WHERE aID=@ID;", crit.ID); if (!dr.Read()) DBUtil.ThrowFetchError("ClientNotifyEvent ID: " + crit.ID.ToString()); //Standard fields mID = dr.GetGuid("aID"); mCreated = DBUtil.ToLocal(dr.GetSmartDate("aCreated")); mModified = DBUtil.ToLocal(dr.GetSmartDate("aModified")); mDeliverAfter = DBUtil.ToLocal(dr.GetSmartDate("ADELIVERAFTER")); mCreator = dr.GetGuid("aCreator"); mModifier = dr.GetGuid("aModifier"); //ClientNotifyEvent fields mObjectSize = dr.GetInt32("AOBJECTSIZE"); ClientID = dr.GetGuid("aClientID"); //allocate a place to store it mContent = new Byte[mObjectSize]; //retrieve the (compressed) bytes dr.GetBytes("AOBJECT", 0, mContent, 0, mContent.Length); if(dr!=null) dr.Close(); } finally { if (dr != null) dr.Close(); } MarkOld(); } #endregion fetch #region Update /// /// Called by DataPortal to delete/add/update data into the database /// protected override void DataPortal_Update() { //-------------------------- //case 3827 //Remove any entries deliverafter older than 7 days DBCommandWrapper cmTrim = DBUtil.GetCommandFromSQL( "DELETE FROM aClientNotifyEvent " + "WHERE (aDeliverAfter < @SEVENDAYSAGO)" ); cmTrim.AddInParameter("@SEVENDAYSAGO", DbType.DateTime, DBUtil.ToUTC(DBUtil.CurrentWorkingDateTime.AddDays(-7))); DBUtil.DB.ExecuteNonQuery(cmTrim); //------------------------ // If not a new record, check if record was modified //by another user since original retrieval: if (!IsNew) DBUtil.CheckSafeToUpdate(this.mModified.Date, this.mID, "aClientNotifyEvent"); #region Delete if (IsDeleted) { throw new System.NotSupportedException("ClientNotifyEvent->Update->Delete: not supported for this object, call the static/shared ClientNotifyEvent.DeleteItem() method instead"); } #endregion #region Add / Update //get modification time temporarily, if update succeeds then //set to this time System.DateTime dtModified = DBUtil.CurrentWorkingDateTime; DBCommandWrapper cm = null; if (IsNew)//Add or update? cm = DBUtil.GetCommandFromSQL( "INSERT INTO aClientNotifyEvent (aID, aCreated,aModified,aCreator,aModifier, " + "aClientID, aDeliverAfter, AOBJECT,AOBJECTSIZE) " + "VALUES (@ID,@Created,@Modified,@CurrentUserID,@CurrentUserID, " + "@ClientID, @DeliverAfter, @OBJECT,@OBJECTSIZE)" ); else cm = DBUtil.GetCommandFromSQL( "UPDATE aClientNotifyEvent SET aID=@ID, " + "aModified=@Modified,aModifier=@CurrentUserID, " + "aClientID=@ClientID, " + "aDeliverAfter=@DeliverAfter, " + "AOBJECT=@OBJECT, AOBJECTSIZE=@OBJECTSIZE " + "WHERE aID=@ID" ); //ClientNotifyEvent fields cm.AddInParameter("@ID", DbType.Guid, mID); cm.AddInParameter("@ClientID", DbType.Guid, mClientID); cm.AddInParameter("@DeliverAfter", DbType.DateTime, DBUtil.ToUTC(mDeliverAfter.Date)); cm.AddInParameter("@OBJECT", DbType.Object, mContent); cm.AddInParameter("@OBJECTSIZE", DbType.Int32, mContent.GetLength(0)); //Standard fields cm.AddInParameter("@CurrentUserID", DbType.Guid, CurrentUserID); cm.AddInParameter("@Created", DbType.DateTime, DBUtil.ToUTC(mCreated).DBValue); cm.AddInParameter("@Modified", DbType.DateTime, DBUtil.ToUTC(dtModified)); using (IDbConnection connection = DBUtil.DB.GetConnection()) { connection.Open(); IDbTransaction transaction = connection.BeginTransaction(); try { DBUtil.DB.ExecuteNonQuery(cm, transaction); MarkOld();//db is now synched with object // Commit the transaction transaction.Commit(); } catch { // Rollback transaction transaction.Rollback(); throw; } finally { connection.Close(); } //Successful update so //change modification time to match this.mModified.Date = dtModified; } #endregion } #endregion update #region Delete /// /// Remove a ClientNotifyEvent record /// /// protected override void DataPortal_Delete(object Criteria) { Criteria crit = (Criteria)Criteria; DBCommandWrapper cmDelete = null; //Delete *all* events for a client if (crit.ClientID != Guid.Empty) { cmDelete = DBUtil.GetCommandFromSQL("DELETE FROM aClientNotifyEvent WHERE aClientID = @ID"); cmDelete.AddInParameter("@ID", DbType.Guid, crit.ClientID); } else { //Delete object cmDelete = DBUtil.GetCommandFromSQL("DELETE FROM aClientNotifyEvent WHERE aID = @ID;"); cmDelete.AddInParameter("@ID", DbType.Guid, crit.ID); } using (IDbConnection connection = DBUtil.DB.GetConnection()) { connection.Open(); IDbTransaction transaction = connection.BeginTransaction(); try { DBUtil.DB.ExecuteNonQuery(cmDelete, transaction); // Commit the transaction transaction.Commit(); } catch { // Rollback transaction transaction.Rollback(); throw; } finally { connection.Close(); } } } #endregion delete #endregion #region Override IsValid / IsDirty public override bool IsValid { get { return base.IsValid ; } } public override bool IsDirty { get { return base.IsDirty ; } } #endregion #region criteria /// /// Criteria for identifying existing object /// [Serializable] private class Criteria { public Guid ID; public Guid ClientID; public Criteria(Guid _ID, Guid _ClientID) { ID = _ID; ClientID = _ClientID; } } #endregion }//end ClientNotifyEvent #region Notification events public enum ClientNotifyEventType : int { CSRAccepted=1, CSRRejected=2, NewWorkorder=3, WorkorderStatusSet=4, WorkorderClosed=5, WorkorderFollowUp=6, QuoteStatusSet=7//case 1499 } #endregion #pragma warning restore 1591 }//end namespace GZTW.AyaNova.BLL