/// <summary> /// Sets the system communication. /// </summary> /// <returns>JobPreviewInfo.</returns> private SystemCommunicationPreviewInfo SetSystemCommunication() { var previewInfo = new SystemCommunicationPreviewInfo(); var systemCommunicationGuid = GetAttributeValue(AttributeKey.SystemCommunication).AsGuid(); if (!systemCommunicationGuid.IsEmpty()) { previewInfo.ParameterSettingType = SystemCommunicationPreviewInfo.ParameterSettingTypeEnum.BlockSetting; ViewState[ViewStateKey.SystemCommunicationGuid] = systemCommunicationGuid; } else { previewInfo.ParameterSettingType = SystemCommunicationPreviewInfo.ParameterSettingTypeEnum.QueryStringParameter; var systemCommunicationId = PageParameter(PageParameterKey.SystemCommunicationId).AsInteger(); if (systemCommunicationId > 0) { var systemCommunicationService = new SystemCommunicationService(new RockContext()); var systemCommunication = systemCommunicationService.Get(systemCommunicationId); if (systemCommunication != null) { systemCommunicationGuid = systemCommunication.Guid; ViewState[ViewStateKey.SystemCommunicationGuid] = systemCommunicationGuid; } } } HasSystemCommunication = ViewState[ViewStateKey.SystemCommunicationGuid].ToStringSafe().Length > 0; return(previewInfo); }
/// <summary> /// Gets the <see cref="SystemCommunication"/> for a <see cref="GroupType"/>. /// </summary> /// <param name="groupType">The <see cref="GroupType"/>.</param> /// <param name="systemCommunicationService">The <see cref="SystemCommunicationService"/>.</param> /// <returns>A <see cref="SystemCommunication"/> if one is set on the <see cref="GroupType"/>, otherwise null.</returns> private SystemCommunication GetGroupTypeRsvpReminder(GroupType groupType, SystemCommunicationService systemCommunicationService) { SystemCommunication groupTypeReminder = null; if (groupType.RSVPReminderSystemCommunicationId.HasValue) { groupTypeReminder = systemCommunicationService.Get(groupType.RSVPReminderSystemCommunicationId.Value); } return(groupTypeReminder); }
private SystemCommunication GetSystemCommunication() { var systemCommunicationGuid = ViewState[ViewStateKey.SystemCommunicationGuid].ToStringSafe().AsGuid(); if (systemCommunicationGuid != Guid.Empty) { var communicationService = new SystemCommunicationService(new RockContext()); return(communicationService.Get(systemCommunicationGuid)); } return(null); }
/// <summary> /// Handles the Delete event of the gEmailTemplates control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="RowEventArgs" /> instance containing the event data.</param> protected void gEmailTemplates_Delete(object sender, RowEventArgs e) { var rockContext = new RockContext(); SystemCommunicationService emailTemplateService = new SystemCommunicationService(rockContext); SystemCommunication emailTemplate = emailTemplateService.Get(e.RowKeyId); if (emailTemplate != null) { emailTemplateService.Delete(emailTemplate); rockContext.SaveChanges(); } BindGrid(); }
/// <summary> /// Job that will sync groups. /// /// Called by the <see cref="IScheduler" /> when a /// <see cref="ITrigger" /> fires that is associated with /// the <see cref="IJob" />. /// </summary> public virtual void Execute(IJobExecutionContext context) { JobDataMap dataMap = context.JobDetail.JobDataMap; try { int notificationsSent = 0; int errorsEncountered = 0; int pendingMembersCount = 0; // get groups set to sync RockContext rockContext = new RockContext(); Guid?groupTypeGuid = dataMap.GetString("GroupType").AsGuidOrNull(); Guid?systemEmailGuid = dataMap.GetString("NotificationEmail").AsGuidOrNull(); Guid?groupRoleFilterGuid = dataMap.GetString("GroupRoleFilter").AsGuidOrNull(); int? pendingAge = dataMap.GetString("PendingAge").AsIntegerOrNull(); bool includePreviouslyNotificed = dataMap.GetString("IncludePreviouslyNotified").AsBoolean(); // get system email var emailService = new SystemCommunicationService(rockContext); SystemCommunication systemEmail = null; if (!systemEmailGuid.HasValue || systemEmailGuid == Guid.Empty) { context.Result = "Job failed. Unable to find System Email"; throw new Exception("No system email found."); } systemEmail = emailService.Get(systemEmailGuid.Value); // get group members if (!groupTypeGuid.HasValue || groupTypeGuid == Guid.Empty) { context.Result = "Job failed. Unable to find group type"; throw new Exception("No group type found"); } var qry = new GroupMemberService(rockContext).Queryable("Person, Group, Group.Members.GroupRole") .Where(m => m.Group.GroupType.Guid == groupTypeGuid.Value && m.GroupMemberStatus == GroupMemberStatus.Pending); if (!includePreviouslyNotificed) { qry = qry.Where(m => m.IsNotified == false); } if (groupRoleFilterGuid.HasValue) { qry = qry.Where(m => m.GroupRole.Guid == groupRoleFilterGuid.Value); } if (pendingAge.HasValue && pendingAge.Value > 0) { var ageDate = RockDateTime.Now.AddDays(pendingAge.Value * -1); qry = qry.Where(m => m.ModifiedDateTime > ageDate); } var pendingGroupMembers = qry.ToList(); var groups = pendingGroupMembers.GroupBy(m => m.Group); var errorList = new List <string>(); foreach (var groupKey in groups) { var group = groupKey.Key; // get list of pending people var qryPendingIndividuals = group.Members.Where(m => m.GroupMemberStatus == GroupMemberStatus.Pending); if (!includePreviouslyNotificed) { qryPendingIndividuals = qryPendingIndividuals.Where(m => m.IsNotified == false); } if (groupRoleFilterGuid.HasValue) { qryPendingIndividuals = qryPendingIndividuals.Where(m => m.GroupRole.Guid == groupRoleFilterGuid.Value); } var pendingIndividuals = qryPendingIndividuals.Select(m => m.Person).ToList(); if (!pendingIndividuals.Any()) { continue; } // get list of leaders var groupLeaders = group.Members.Where(m => m.GroupRole.IsLeader == true && m.Person != null && m.Person.Email != null && m.Person.Email != string.Empty); if (!groupLeaders.Any()) { errorList.Add("Unable to send emails to members in group " + group.Name + " because there is no group leader"); continue; } var recipients = new List <RockEmailMessageRecipient>(); foreach (var leader in groupLeaders) { // create merge object var mergeFields = new Dictionary <string, object>(); mergeFields.Add("PendingIndividuals", pendingIndividuals); mergeFields.Add("Group", group); mergeFields.Add("ParentGroup", group.ParentGroup); mergeFields.Add("Person", leader.Person); recipients.Add(new RockEmailMessageRecipient(leader.Person, mergeFields)); } var errorMessages = new List <string>(); var emailMessage = new RockEmailMessage(systemEmail.Guid); emailMessage.SetRecipients(recipients); var sendSuccess = emailMessage.Send(out errorMessages); errorsEncountered += errorMessages.Count; errorList.AddRange(errorMessages); // be conservative: only mark as notified if we are sure the email didn't fail if (sendSuccess == false) { continue; } notificationsSent += recipients.Count(); // mark pending members as notified as we go in case the job fails var notifiedPersonIds = pendingIndividuals.Select(p => p.Id); foreach (var pendingGroupMember in pendingGroupMembers.Where(m => m.IsNotified == false && m.GroupId == group.Id && notifiedPersonIds.Contains(m.PersonId))) { pendingGroupMember.IsNotified = true; pendingMembersCount++; } rockContext.SaveChanges(); } context.Result = string.Format("Sent {0} emails to leaders for {1} pending individuals. {2} errors encountered.", notificationsSent, pendingMembersCount, errorsEncountered); if (errorList.Any()) { StringBuilder sb = new StringBuilder(); sb.AppendLine(); sb.Append("Errors in GroupLeaderPendingNotificationJob: "); errorList.ForEach(e => { sb.AppendLine(); sb.Append(e); }); string errors = sb.ToString(); context.Result += errors; throw new Exception(errors); } } catch (Exception ex) { HttpContext context2 = HttpContext.Current; ExceptionLogService.LogException(ex, context2); throw; } }
/// <summary> /// Executes this instance. /// </summary> /// <param name="message"></param> public override void Execute(Message message) { using (var rockContext = new RockContext()) { // Load the alert and alert type var financialTransactionAlertService = new FinancialTransactionAlertService(rockContext); var alert = financialTransactionAlertService.Queryable() .AsNoTracking() .Include(a => a.FinancialTransactionAlertType) .FirstOrDefault(a => a.Id == message.FinancialTransactionAlertId); var alertType = alert?.FinancialTransactionAlertType; // If the alert or alert type are no longer in the database, then there is nothing that can be done if (alertType == null) { return; } // Get the person that this alert was generated for. Several of the items below use this var personAliasService = new PersonAliasService(rockContext); var person = personAliasService.Queryable() .AsNoTracking() .Where(pa => pa.Id == alert.PersonAliasId) .Select(pa => pa.Person) .FirstOrDefault(); // Generate the merge objects for the lava templates used in the items below var isoDate = alert.AlertDateTime.ToISO8601DateString(); var alertsPageId = PageCache.Get(SystemGuid.Page.GIVING_ALERTS).Id; var relativeAlertLink = $"page/{alertsPageId}?StartDate={isoDate}&EndDate={isoDate}&AlertTypeId={alertType.Id}"; var mergeObjects = new Dictionary <string, object> { { nameof(FinancialTransactionAlert), alert }, { nameof(FinancialTransactionAlertType), alertType }, { nameof(Person), person }, { "RelativeAlertLink", relativeAlertLink } }; // Launch workflow if configured if (alertType.WorkflowTypeId.HasValue) { var workflowAttributeValues = new Dictionary <string, string>(); workflowAttributeValues.Add(nameof(FinancialTransactionAlert), alert.Guid.ToString()); workflowAttributeValues.Add(nameof(FinancialTransactionAlertType), alertType.Guid.ToString()); workflowAttributeValues.Add(nameof(Person), person.Guid.ToString()); alert.LaunchWorkflow(alertType.WorkflowTypeId, string.Empty, workflowAttributeValues, null); } // Add the person to a connection opportunity if configured if (alertType.ConnectionOpportunityId.HasValue) { var connectionOpportunityService = new ConnectionOpportunityService(rockContext); var statuses = connectionOpportunityService.Queryable() .AsNoTracking() .Where(co => co.Id == alertType.ConnectionOpportunityId) .SelectMany(co => co.ConnectionType.ConnectionStatuses) .Where(cs => cs.IsActive) .ToList() .OrderBy(cs => cs.Order); var status = statuses.FirstOrDefault(cs => cs.IsDefault) ?? statuses.FirstOrDefault(); if (status != null) { var connectionRequestService = new ConnectionRequestService(rockContext); var request = new ConnectionRequest { ConnectionOpportunityId = alertType.ConnectionOpportunityId.Value, PersonAliasId = alert.PersonAliasId, ConnectionStatusId = status.Id }; if (alert.TransactionId.HasValue) { request.LoadAttributes(); request.SetAttributeValue("FinancialTransactionId", alert.TransactionId.Value.ToString()); } connectionRequestService.Add(request); } } // Send a bus event if configured if (alertType.SendBusEvent) { new TransactionWasAlertedMessage { FinancialTransactionAlertId = alert.Id }.Publish(); } // Send a communication if configured if (alertType.SystemCommunicationId.HasValue) { var systemCommunicationService = new SystemCommunicationService(rockContext); var systemCommunication = systemCommunicationService.Get(alertType.SystemCommunicationId.Value); if (person != null && systemCommunication != null) { CommunicationHelper.SendMessage(person, ( int )person.CommunicationPreference, systemCommunication, mergeObjects); } } // Send a communication to account followers if an Account Participant System Communication and Account is specified // for this alert type if (alertType.AccountParticipantSystemCommunicationId.HasValue && alertType.FinancialAccountId.HasValue) { var systemCommunicationService = new SystemCommunicationService(rockContext); var financialAccountService = new FinancialAccountService(rockContext); var accountParticipantSystemCommunication = systemCommunicationService.Get(alertType.AccountParticipantSystemCommunicationId.Value); if (accountParticipantSystemCommunication != null) { var accountFollowers = financialAccountService .GetAccountParticipants(alertType.FinancialAccountId.Value, RelatedEntityPurposeKey.FinancialAccountGivingAlert) .Select(a => a.Person); foreach (var accountFollower in accountFollowers) { CommunicationHelper.SendMessage(accountFollower, ( int )accountFollower.CommunicationPreference, accountParticipantSystemCommunication, mergeObjects); } } } // Send a notification to a group if configured if (alertType.AlertSummaryNotificationGroupId.HasValue) { var systemEmailGuid = SystemGuid.SystemCommunication.FINANCIAL_TRANSACTION_ALERT_NOTIFICATION_SUMMARY.AsGuid(); var systemCommunicationService = new SystemCommunicationService(rockContext); var systemCommunication = systemCommunicationService.Get(systemEmailGuid); CommunicationHelper.SendMessage(alertType.AlertSummaryNotificationGroupId.Value, systemCommunication, mergeObjects); } rockContext.SaveChanges(); } }
/// <summary> /// Executes the specified context. /// </summary> /// <param name="context">The context.</param> public void Execute(IJobExecutionContext context) { var rockContext = new RockContext(); var personService = new PersonService(rockContext); JobDataMap dataMap = context.JobDetail.JobDataMap; Guid? systemEmailGuid = dataMap.GetString("BirthdayEmail").AsGuidOrNull(); var emailService = new SystemCommunicationService(rockContext); SystemCommunication systemEmail = null; if (systemEmailGuid.HasValue) { systemEmail = emailService.Get(systemEmailGuid.Value); } if (systemEmail == null) { // no email specified, so nothing to do return; } var activeStatusGuid = Rock.SystemGuid.DefinedValue.PERSON_RECORD_STATUS_ACTIVE.AsGuid(); // only include alive people that have record status of Active var personQry = personService.Queryable(false, false).Where(a => a.RecordStatusValue.Guid == activeStatusGuid && a.IsDeceased == false); var ageRange = (dataMap.GetString("AgeRange") ?? string.Empty).Split(','); if (ageRange.Length == 2) { int?minimumAge = ageRange[0].AsIntegerOrNull(); int?maximumAge = ageRange[1].AsIntegerOrNull(); personQry = personQry.WhereAgeRange(minimumAge, maximumAge, true); } // only include people whose birthday is today (which can be determined from the computed DaysUntilBirthday column) personQry = personQry.Where(a => a.DaysUntilBirthday.HasValue && a.DaysUntilBirthday == 0); var connectionStatusGuids = (dataMap.GetString("ConnectionStatuses") ?? string.Empty).Split(',').AsGuidList(); if (connectionStatusGuids.Any()) { personQry = personQry.Where(a => connectionStatusGuids.Contains(a.ConnectionStatusValue.Guid)); } // only include people that have an email address and want an email personQry = personQry.Where(a => (a.Email != null) && (a.Email != string.Empty) && (a.EmailPreference != EmailPreference.DoNotEmail) && (a.IsEmailActive)); var recipients = new List <RockEmailMessageRecipient>(); var personList = personQry.AsNoTracking().ToList(); foreach (var person in personList) { var mergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields(null); mergeFields.Add("Person", person); recipients.Add(new RockEmailMessageRecipient(person, mergeFields)); } var emailMessage = new RockEmailMessage(systemEmail.Guid); emailMessage.SetRecipients(recipients); var errors = new List <string>(); emailMessage.Send(out errors); context.Result = string.Format("{0} birthday emails sent", recipients.Count()); if (errors.Any()) { StringBuilder sb = new StringBuilder(); sb.AppendLine(); sb.Append(string.Format("{0} Errors: ", errors.Count())); errors.ForEach(e => { sb.AppendLine(); sb.Append(e); }); string errorMessage = sb.ToString(); context.Result += errorMessage; var exception = new Exception(errorMessage); HttpContext context2 = HttpContext.Current; ExceptionLogService.LogException(exception, context2); throw exception; } }
/// <summary> /// Shows the edit. /// </summary> /// <param name="emailTemplateId">The email template id.</param> protected void ShowEdit(int emailTemplateId) { var globalAttributes = GlobalAttributesCache.Get(); string globalFromName = globalAttributes.GetValue("OrganizationName"); tbFromName.Help = string.Format("If a From Name value is not entered the 'Organization Name' Global Attribute value of '{0}' will be used when this template is sent. <small><span class='tip tip-lava'></span></small>", globalFromName); string globalFrom = globalAttributes.GetValue("OrganizationEmail"); tbFrom.Help = string.Format("If a From Address value is not entered the 'Organization Email' Global Attribute value of '{0}' will be used when this template is sent. <small><span class='tip tip-lava'></span></small>", globalFrom); tbTo.Help = "You can specify multiple email addresses by separating them with a comma."; SystemCommunicationService emailTemplateService = new SystemCommunicationService(new RockContext()); SystemCommunication emailTemplate = emailTemplateService.Get(emailTemplateId); bool showMessagePreview = false; var pushCommunication = new CommunicationDetails(); if (emailTemplate != null) { pdAuditDetails.Visible = true; pdAuditDetails.SetEntity(emailTemplate, ResolveRockUrl("~")); lActionTitle.Text = ActionTitle.Edit(SystemCommunication.FriendlyTypeName).FormatAsHtmlTitle(); hfEmailTemplateId.Value = emailTemplate.Id.ToString(); cbIsActive.Checked = emailTemplate.IsActive.GetValueOrDefault(); cpCategory.SetValue(emailTemplate.CategoryId); tbTitle.Text = emailTemplate.Title; tbFromName.Text = emailTemplate.FromName; tbFrom.Text = emailTemplate.From; tbTo.Text = emailTemplate.To; tbCc.Text = emailTemplate.Cc; tbBcc.Text = emailTemplate.Bcc; tbSubject.Text = emailTemplate.Subject; ceEmailTemplate.Text = emailTemplate.Body; pushCommunication = new CommunicationDetails { PushData = emailTemplate.PushData, PushImageBinaryFileId = emailTemplate.PushImageBinaryFileId, PushMessage = emailTemplate.PushMessage, PushTitle = emailTemplate.PushTitle, PushOpenMessage = emailTemplate.PushOpenMessage, PushOpenAction = emailTemplate.PushOpenAction }; nbTemplateHelp.InnerHtml = CommunicationTemplateHelper.GetTemplateHelp(false); kvlMergeFields.Value = emailTemplate.LavaFields.Select(a => string.Format("{0}^{1}", a.Key, a.Value)).ToList().AsDelimited("|"); hfShowAdditionalFields.Value = (!string.IsNullOrEmpty(emailTemplate.Cc) || !string.IsNullOrEmpty(emailTemplate.Bcc)).ToTrueFalse().ToLower(); cbCssInliningEnabled.Checked = emailTemplate.CssInliningEnabled; showMessagePreview = true; } else { pdAuditDetails.Visible = false; lActionTitle.Text = ActionTitle.Add(SystemCommunication.FriendlyTypeName).FormatAsHtmlTitle(); hfEmailTemplateId.Value = 0.ToString(); cbIsActive.Checked = true; cpCategory.SetValue(( int? )null); tbTitle.Text = string.Empty; tbFromName.Text = string.Empty; tbFrom.Text = string.Empty; tbTo.Text = string.Empty; tbCc.Text = string.Empty; tbBcc.Text = string.Empty; tbSubject.Text = string.Empty; ceEmailTemplate.Text = string.Empty; } var pushNotificationControl = phPushNotification.Controls[0] as PushNotification; if (pushNotificationControl != null) { pushNotificationControl.SetFromCommunication(pushCommunication); } SetEmailMessagePreviewModeEnabled(showMessagePreview); LoadDropDowns(); // SMS Fields mfpSMSMessage.MergeFields.Clear(); mfpSMSMessage.MergeFields.Add("GlobalAttribute"); mfpSMSMessage.MergeFields.Add("Rock.Model.Person"); if (emailTemplate != null) { dvpSMSFrom.SetValue(emailTemplate.SMSFromDefinedValueId); tbSMSTextMessage.Text = emailTemplate.SMSMessage; } }
/// <summary> /// Handles the Click event of the btnSave control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="EventArgs" /> instance containing the event data.</param> protected void btnSave_Click(object sender, EventArgs e) { var rockContext = new RockContext(); SystemCommunicationService emailTemplateService = new SystemCommunicationService(rockContext); SystemCommunication emailTemplate; int emailTemplateId = int.Parse(hfEmailTemplateId.Value); if (emailTemplateId == 0) { emailTemplate = new SystemCommunication(); emailTemplateService.Add(emailTemplate); } else { emailTemplate = emailTemplateService.Get(emailTemplateId); } emailTemplate.IsActive = cbIsActive.Checked; emailTemplate.CategoryId = cpCategory.SelectedValueAsInt(); emailTemplate.Title = tbTitle.Text; emailTemplate.FromName = tbFromName.Text; emailTemplate.From = tbFrom.Text; emailTemplate.To = tbTo.Text; emailTemplate.Cc = tbCc.Text; emailTemplate.Bcc = tbBcc.Text; emailTemplate.Subject = tbSubject.Text; emailTemplate.Body = ceEmailTemplate.Text; emailTemplate.LavaFields = kvlMergeFields.Value.AsDictionaryOrNull(); emailTemplate.CssInliningEnabled = cbCssInliningEnabled.Checked; emailTemplate.SMSFromDefinedValueId = dvpSMSFrom.SelectedValue.AsIntegerOrNull(); emailTemplate.SMSMessage = tbSMSTextMessage.Text; var pushCommunication = new CommunicationDetails(); var pushNotificationControl = phPushNotification.Controls[0] as PushNotification; if (pushNotificationControl != null) { pushNotificationControl.UpdateCommunication(pushCommunication); } emailTemplate.PushData = pushCommunication.PushData; emailTemplate.PushImageBinaryFileId = pushCommunication.PushImageBinaryFileId; emailTemplate.PushMessage = pushCommunication.PushMessage; emailTemplate.PushOpenAction = pushCommunication.PushOpenAction; emailTemplate.PushOpenMessage = pushCommunication.PushOpenMessage; emailTemplate.PushTitle = pushCommunication.PushTitle; if (!emailTemplate.IsValid) { // If CodeEditor is hidden, we need to manually add the Required error message or it will not be shown. if (string.IsNullOrWhiteSpace(ceEmailTemplate.Text) && !ceEmailTemplate.Visible) { var customValidator = new CustomValidator(); customValidator.ValidationGroup = ceEmailTemplate.ValidationGroup; customValidator.ControlToValidate = ceEmailTemplate.ID; customValidator.ErrorMessage = "Email Message Body is required."; customValidator.IsValid = false; Page.Validators.Add(customValidator); } // Controls will render the error messages return; } rockContext.SaveChanges(); NavigateToParentPage(); }
/// <summary> /// Private method called by Execute() to process the job. /// </summary> private void ProcessJob(IJobExecutionContext context) { JobDataMap dataMap = context.JobDetail.JobDataMap; int notificationsSent = 0; int errorsEncountered = 0; int absentMembersCount = 0; int sendFailed = 0; // get groups set to sync RockContext rockContext = new RockContext(); Guid?groupTypeGuid = dataMap.GetString(AttributeKey.GroupType).AsGuidOrNull(); Guid?systemEmailGuid = dataMap.GetString(AttributeKey.NotificationEmail).AsGuidOrNull(); Guid?groupRoleFilterGuid = dataMap.GetString(AttributeKey.GroupRoleFilter).AsGuidOrNull(); int minimumAbsences = dataMap.GetString(AttributeKey.MinimumAbsences).AsInteger(); // get system email var emailService = new SystemCommunicationService(rockContext); SystemCommunication systemEmail = null; if (!systemEmailGuid.HasValue || systemEmailGuid == Guid.Empty) { context.Result = "Job failed. Unable to find System Email"; throw new Exception("No system email found."); } if (minimumAbsences == default(int)) { context.Result = "Job failed. The is no minimum absense count entered."; throw new Exception("No minimum absense count found."); } systemEmail = emailService.Get(systemEmailGuid.Value); // get group members if (!groupTypeGuid.HasValue || groupTypeGuid == Guid.Empty) { context.Result = "Job failed. Unable to find group type"; throw new Exception("No group type found."); } var groupMemberQry = new GroupMemberService(rockContext).Queryable("Group, Group.Members.GroupRole") .Where(m => m.Group.GroupType.Guid == groupTypeGuid.Value); if (groupRoleFilterGuid.HasValue) { groupMemberQry = groupMemberQry.Where(m => m.GroupRole.Guid == groupRoleFilterGuid.Value); } var groupMembers = groupMemberQry.GroupBy(m => m.Group); var errorList = new List <string>(); foreach (var groupGroupMember in groupMembers) { var group = groupGroupMember.Key; var filteredPersons = groupGroupMember.Select(a => a.PersonId); // get list of leaders var groupLeaders = group.Members.Where(m => m.GroupRole.IsLeader == true && m.Person != null && m.Person.Email != null && m.Person.Email != string.Empty); if (!groupLeaders.Any()) { errorList.Add("Unable to send emails to members in group " + group.Name + " because there is no group leader"); continue; } // Get all the occurrences for this group var occurrences = new AttendanceOccurrenceService(rockContext) .Queryable("Attendees.PersonAlias.Person") .Where(a => a.DidNotOccur.HasValue && !a.DidNotOccur.Value && a.GroupId == group.Id) .OrderByDescending(a => a.OccurrenceDate) .Take(minimumAbsences) .ToList(); if (occurrences.Count == minimumAbsences) { var absentPersons = occurrences .SelectMany(a => a.Attendees) .Where(a => a.DidAttend.HasValue && !a.DidAttend.Value && filteredPersons.Contains(a.PersonAlias.PersonId)) .GroupBy(a => a.PersonAlias.Person) .Where(a => a.Count() == minimumAbsences) .Select(a => a.Key) .ToList(); if (absentPersons.Count > 0) { var recipients = new List <RockEmailMessageRecipient>(); foreach (var leader in groupLeaders) { // create merge object var mergeFields = new Dictionary <string, object>(); mergeFields.Add("AbsentMembers", absentPersons); mergeFields.Add("Group", group); mergeFields.Add("Person", leader.Person); recipients.Add(new RockEmailMessageRecipient(leader.Person, mergeFields)); } var errorMessages = new List <string>(); var emailMessage = new RockEmailMessage(systemEmail.Guid); emailMessage.SetRecipients(recipients); var sendSuccess = emailMessage.Send(out errorMessages); if (!sendSuccess) { sendFailed++; } errorsEncountered += errorMessages.Count; errorList.AddRange(errorMessages); // be conservative: only mark as notified if we are sure the email didn't fail if (errorMessages.Any()) { continue; } absentMembersCount += absentPersons.Count; notificationsSent += recipients.Count(); } } } context.Result = string.Format("Sent {0} emails to leaders for {1} absent members. {2} errors encountered. {3} times Send reported a fail.", notificationsSent, absentMembersCount, errorsEncountered, sendFailed); if (errorList.Any()) { StringBuilder sb = new StringBuilder(); sb.AppendLine(); sb.Append("Errors in GroupLeaderAbsenceNotifications: "); errorList.ForEach(e => { sb.AppendLine(); sb.Append(e); }); string errors = sb.ToString(); context.Result += errors; throw new Exception(errors); } }
/// <summary> /// Starts the refund process. /// </summary> private void StartRefunds() { long totalMilliseconds = 0; var importTask = new Task(() => { // wait a little so the browser can render and start listening to events System.Threading.Thread.Sleep(1000); _hubContext.Clients.All.showButtons(this.SignalRNotificationKey, false); Stopwatch stopwatch = Stopwatch.StartNew(); List <int> registrationTemplateIds = rtpRegistrationTemplate.ItemIds.AsIntegerList(); registrationTemplateIds.RemoveAll(i => i.Equals(0)); RockContext rockContext = new RockContext(); SystemCommunicationService systemCommunicationService = new SystemCommunicationService(rockContext); if (pnlRegistration.Visible && registrationTemplateIds.Count > 0) { List <int> registrationInstanceIds = new List <int>(); if (ddlRegistrationInstance.SelectedValueAsId().HasValue&& ddlRegistrationInstance.SelectedValueAsId() > 0) { registrationInstanceIds.Add(ddlRegistrationInstance.SelectedValueAsId().Value); } else { RegistrationTemplateService registrationTemplateService = new RegistrationTemplateService(rockContext); var templates = registrationTemplateService.GetByIds(rtpRegistrationTemplate.ItemIds.AsIntegerList()); int registrationCount = templates.SelectMany(t => t.Instances).SelectMany(i => i.Registrations).Count(); registrationInstanceIds.AddRange(templates.SelectMany(t => t.Instances).OrderBy(i => i.Name).Select(i => i.Id)); } RegistrationInstanceService registrationInstanceService = new RegistrationInstanceService(rockContext); // Load the registration instance and then iterate through all registrations. var registrations = registrationInstanceService.Queryable().Where(ri => registrationInstanceIds.Contains(ri.Id)).SelectMany(ri => ri.Registrations); int j = 1; foreach (Registration registration in registrations) { bool issuedRefund = false; OnProgress("Processing registration refund " + j + " of " + registrations.Count()); foreach (var payment in registration.GetPayments(rockContext)) { issuedRefund = issueRefund(payment.Transaction, "Registration", registration.FirstName + " " + registration.LastName); } j++; // Send an email if applicable if (issuedRefund && !string.IsNullOrWhiteSpace(registration.ConfirmationEmail) && ddlSystemCommunication.SelectedValueAsInt().HasValue&& ddlSystemCommunication.SelectedValueAsInt() > 0) { var mergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields(this.RockPage); mergeFields.Add("Registration", registration); SystemCommunication systemCommunication = systemCommunicationService.Get(ddlSystemCommunication.SelectedValueAsInt().Value); var emailMessage = new RockEmailMessage(systemCommunication); emailMessage.AdditionalMergeFields = mergeFields; emailMessage.AddRecipient(RockEmailMessageRecipient.CreateAnonymous(registration.ConfirmationEmail, mergeFields)); emailMessage.CreateCommunicationRecord = true; emailMessage.Send(); } } } if (pnlTransactionCodes.Visible && tbTransactionCodes.Text.Length > 0) { var codes = tbTransactionCodes.Text.SplitDelimitedValues(); FinancialTransactionService financialTransactionService = new FinancialTransactionService(rockContext); var transactions = financialTransactionService.Queryable().Where(ft => codes.Contains(ft.TransactionCode)); int j = 0; foreach (var transaction in transactions) { OnProgress("Processing transaction refund " + j + " of " + transactions.Count()); var issuedRefund = issueRefund(transaction, "Transaction", transaction.AuthorizedPersonAlias != null ? transaction.AuthorizedPersonAlias.Person.FullName : "Unknown"); // Send an email if applicable if (issuedRefund && transaction.AuthorizedPersonAlias != null && !string.IsNullOrWhiteSpace(transaction.AuthorizedPersonAlias.Person.Email) && ddlSystemCommunication.SelectedValueAsInt().HasValue&& ddlSystemCommunication.SelectedValueAsInt() > 0) { var mergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields(this.RockPage); mergeFields.Add("Transaction", transaction); SystemCommunication systemCommunication = systemCommunicationService.Get(ddlSystemCommunication.SelectedValueAsInt().Value); var emailMessage = new RockEmailMessage(systemCommunication); emailMessage.AdditionalMergeFields = mergeFields; emailMessage.FromEmail = ebEmail.Text; emailMessage.AddRecipient(new RockEmailMessageRecipient(transaction.AuthorizedPersonAlias.Person, mergeFields)); emailMessage.CreateCommunicationRecord = true; emailMessage.Send(); } } } stopwatch.Stop(); totalMilliseconds = stopwatch.ElapsedMilliseconds; _hubContext.Clients.All.showButtons(this.SignalRNotificationKey, true); }); importTask.ContinueWith((t) => { if (t.IsFaulted) { foreach (var exception in t.Exception.InnerExceptions) { LogException(exception); } OnProgress("ERROR: " + t.Exception.Message); } else { OnProgress(string.Format("{0} Complete: [{1}ms]", "All refunds have been issued.", totalMilliseconds)); } }); importTask.Start(); }
/// <summary> /// Sends the expired credit card notices. /// </summary> /// <param name="context">The context.</param> /// <returns></returns> /// <exception cref="Exception">Expiring credit card email is missing.</exception> private SendExpiredCreditCardNoticesResult SendExpiredCreditCardNotices(IJobExecutionContext context) { var dataMap = context.JobDetail.JobDataMap; var rockContext = new RockContext(); // Get the details for the email that we'll be sending out. Guid?systemEmailGuid = dataMap.GetString(AttributeKey.ExpiringCreditCardEmail).AsGuidOrNull(); SystemCommunication systemCommunication = null; if (systemEmailGuid.HasValue) { var systemCommunicationService = new SystemCommunicationService(rockContext); systemCommunication = systemCommunicationService.Get(systemEmailGuid.Value); } if (systemCommunication == null) { throw new Exception("Expiring credit card email is missing."); } // Fetch the configured Workflow once if one was set, we'll use it later. Guid?workflowGuid = dataMap.GetString(AttributeKey.Workflow).AsGuidOrNull(); WorkflowTypeCache workflowType = null; WorkflowService workflowService = new WorkflowService(rockContext); if (workflowGuid != null) { workflowType = WorkflowTypeCache.Get(workflowGuid.Value); } var financialScheduledTransactionQuery = new FinancialScheduledTransactionService(rockContext).Queryable() .Where(t => t.IsActive && t.FinancialPaymentDetail.ExpirationMonthEncrypted != null && (t.EndDate == null || t.EndDate > DateTime.Now)) .AsNoTracking(); List <ScheduledTransactionInfo> scheduledTransactionInfoList = financialScheduledTransactionQuery.Select(a => new ScheduledTransactionInfo { Id = a.Id, FinancialPaymentDetail = a.FinancialPaymentDetail, AuthorizedPersonAliasGuid = a.AuthorizedPersonAlias.Guid, Person = a.AuthorizedPersonAlias.Person }).ToList(); // Get the current month and year DateTime now = DateTime.Now; int currentMonth = now.Month; int currentYYYY = now.Year; // get the common merge fields once, so we don't have to keep calling it for every person, then create a new mergeFields for each person, starting with a copy of the common merge fields var commonMergeFields = Rock.Lava.LavaHelper.GetCommonMergeFields(null); var result = new SendExpiredCreditCardNoticesResult { ExaminedCount = scheduledTransactionInfoList.Count() }; foreach (ScheduledTransactionInfo scheduledTransactionInfo in scheduledTransactionInfoList.OrderByDescending(a => a.Id)) { int?expirationMonth = scheduledTransactionInfo.FinancialPaymentDetail.ExpirationMonth; int?expirationYYYY = scheduledTransactionInfo.FinancialPaymentDetail.ExpirationYear; if (!expirationMonth.HasValue || !expirationMonth.HasValue) { continue; } int warningYear = expirationYYYY.Value; int warningMonth = expirationMonth.Value - 1; if (warningMonth == 0) { warningYear -= 1; warningMonth = 12; } if ((warningYear == currentYYYY) && (warningMonth == currentMonth)) { string maskedCardNumber = string.Empty; if (!string.IsNullOrEmpty(scheduledTransactionInfo.FinancialPaymentDetail.AccountNumberMasked) && scheduledTransactionInfo.FinancialPaymentDetail.AccountNumberMasked.Length >= 4) { maskedCardNumber = scheduledTransactionInfo.FinancialPaymentDetail.AccountNumberMasked.Substring(scheduledTransactionInfo.FinancialPaymentDetail.AccountNumberMasked.Length - 4); } string expirationDateMMYYFormatted = scheduledTransactionInfo.FinancialPaymentDetail?.ExpirationDate; var recipients = new List <RockEmailMessageRecipient>(); var person = scheduledTransactionInfo.Person; if (!person.IsEmailActive || person.Email.IsNullOrWhiteSpace() || person.EmailPreference == EmailPreference.DoNotEmail) { continue; } // make a mergeFields for this person, starting with copy of the commonFieldFields var mergeFields = new Dictionary <string, object>(commonMergeFields); mergeFields.Add("Person", person); mergeFields.Add("Card", maskedCardNumber); mergeFields.Add("Expiring", expirationDateMMYYFormatted); recipients.Add(new RockEmailMessageRecipient(person, mergeFields)); var emailMessage = new RockEmailMessage(systemCommunication); emailMessage.SetRecipients(recipients); emailMessage.Send(out List <string> emailErrors); if (emailErrors.Any()) { var errorLines = new StringBuilder(); errorLines.AppendLine(string.Empty); foreach (string error in emailErrors) { errorLines.AppendLine(error); } // Provide better identifying context in case the errors are too vague. var exception = new Exception($"Unable to send email (Person ID = {person.Id}).{errorLines}"); result.EmailSendExceptions.Add(exception); } else { result.NoticesSentCount++; } // Start workflow for this person if (workflowType != null) { Dictionary <string, string> attributes = new Dictionary <string, string>(); attributes.Add("Person", scheduledTransactionInfo.AuthorizedPersonAliasGuid.ToString()); attributes.Add("Card", maskedCardNumber); attributes.Add("Expiring", expirationDateMMYYFormatted); attributes.Add("FinancialScheduledTransactionId", scheduledTransactionInfo.Id.ToString()); StartWorkflow(workflowService, workflowType, attributes, $"{person.FullName} (scheduled transaction Id: {scheduledTransactionInfo.Id})"); } } } return(result); }