/// <summary> /// Rolls back a CMO message. /// </summary> /// <param name="message">The <see cref="CmoMessage"/> to roll back.</param> private static void RollBack(CmoMessage message) { if (message != null) { for (int i = 0; i < Properties.Settings.Default.MaxCleanupRetryCount; i++) { message.Reload(); if (message.Delete()) { return; } } } }
/// <summary> /// Posts a CMO message for viewing by C-Access accounts and . /// </summary> /// <param name="candidateID">The CFIS ID of the candidate recipient of the message to post.</param> /// <param name="messageID">The ID of the message to post.</param> /// <param name="version">The version of the message to post.</param> /// <param name="notify">true if posted message notifications should be sent; otherwise, false.</param> /// <returns>true if the message was succesfully posted; otherwise, false.</returns> /// <remarks>For Post Election Audit messages, posting will fail if the CFIS dates were unsuccessfully updated, the post election audit workflow would be disrupted, or a response was already received.</remarks> public bool PostCmoMessage(string candidateID, int messageID, byte[] version, bool notify) { CmoMessage message = GetCmoMessage(candidateID, messageID); if (message != null) { if (!message.IsPosted) { if (RequiresPostElectionDateUpdate(message)) { // check for post election audit workflow violation AuditReportBase pear = null; if (message.IsInitialDocumentationRequest) { pear = GetInitialDocumentationRequest(candidateID, message.ElectionCycle, false); } else if (message.IsIdrInadequateResponseLetter) { pear = GetIdrInadequateEvent(candidateID, message.ElectionCycle, false); } else if (message.IsDraftAuditReport) { pear = GetDraftAuditReport(candidateID, message.ElectionCycle, false); } if (pear != null && (pear.ResponseReceived || !HasValidPostElectionRequestType(message, pear.IsSecondRequest))) { return(false); } // update CFIS dates for post election audit messages if (!UpdatePostElectionDates(message)) { return(false); } } using (Data.CmoEntities context = new Data.CmoEntities()) { var ret = context.CmoPostMessage(candidateID, messageID, version).FirstOrDefault(); if (ret.HasValue && ret.Value > 0) { // secure all attachments if ((CmoRepository.Repository != null) && message.HasAttachment) { CmoRepository.Repository.LockDown(message); } message.Reload(); // send notification if (notify) { // BUGFIX #60: To prevent timeout of long-running email notification operations, failed recipient notification // will be included in the internal carbon-copy, and sending will be executed asynchronously. Func <CmoMessage, LoadCandidateEventHandler, IEnumerable <CPUser>, bool> notifyAsync = CmoPostedMessageNotice.SendFor; notifyAsync.BeginInvoke(message, this.GetCandidate, null, null, null); } return(true); } } } } return(false); }
/// <summary> /// Directly posts a letter to C-Access as a CMO message. /// </summary> /// <param name="electionCycle">The election cycle context of the letter.</param> /// <param name="candidateID">The ID of the candidate receipient of the letter.</param> /// <param name="creator">The network username of the user posting the letter.</param> /// <param name="title">The letter subject.</param> /// <param name="body">The letter body.</param> /// <param name="receiptEmail">The e-mail address for the recipient of open receipt e-mails if desired; otherwise, null to decline open receipts for this letter.</param> /// <param name="categoryID">The letter category ID.</param> /// <param name="notify">Indicates whether to generate an e-mail notification to the campaign's C-Access accounts upon post.</param> /// <param name="addAttachment">The delegate method to use for adding the attachment.</param> /// <param name="addPayment">The delegate method to use for adding a payment run to the message.</param> /// <param name="addTolling">The delegate method to use for adding tolling details to the message.</param> /// <param name="addStatementReview">The delegate method to use for adding a statement review to the message.</param> /// <param name="addPostElection">The delegate method to use for adding a DAR/FAR to the message.</param> /// <returns>The ID of the message if succesfully posted; otherwise, a negative value representing an error code.</returns> private int PostLetter(string electionCycle, string candidateID, string creator, string title, string body, string receiptEmail, byte categoryID, bool notify, Func <CmoMessage, bool> addAttachment = null, Func <CmoMessage, bool> addPayment = null, Func <CmoMessage, bool> addTolling = null, Func <CmoMessage, bool> addStatementReview = null, Func <CmoMessage, bool> addPostElection = null) { CmoMessage message = CmoMessage.Add(candidateID, electionCycle, title, body, creator, GetEmail(creator, receiptEmail), categoryID); if (message == null) { return(Convert.ToInt32(CmoServiceError.MessageAddFailure)); } bool success = false; try { // set category-specific properties if (addPayment != null) { if (!addPayment(message)) { return(Convert.ToInt32(CmoServiceError.PaymentRunFailure)); } } if (addTolling != null) { if (!addTolling(message)) { return(Convert.ToInt32(CmoServiceError.TollingFailure)); } } if (addStatementReview != null) { if (!addStatementReview(message)) { return(Convert.ToInt32(CmoServiceError.StatementNumberFailure)); } } if (addPostElection != null) { if (!addPostElection(message)) { return(Convert.ToInt32(CmoServiceError.PostElectionRequestTypeFailure)); } } if (addAttachment == null || !addAttachment(message)) { return(Convert.ToInt32(CmoServiceError.AttachmentFailure)); } // post message if (message.Reload()) { return((success = message.Post() != null) ? message.ID : Convert.ToInt32(CmoServiceError.MessagePostFailure)); } return(Convert.ToInt32(CmoServiceError.MessageGeneralFailure)); } finally { if (!success) { RollBack(message); } } }