/// <summary> /// Saves the attribute value. /// </summary> /// <param name="context">The context.</param> /// <param name="key">The key.</param> /// <param name="value">The value.</param> private void SaveAttributeValue(RockContext context, string key, string value) { var attributeSvc = new AttributeService(context); var attribute = attributeSvc.GetGlobalAttribute(key); var attributeValueSvc = new AttributeValueService(context); var attributeValue = attributeValueSvc.GetByAttributeIdAndEntityId(attribute.Id, null); if (attributeValue == null && !String.IsNullOrWhiteSpace(value)) { attributeValue = new AttributeValue(); attributeValue.AttributeId = attribute.Id; attributeValue.EntityId = null; attributeValueSvc.Add(attributeValue); } if (attributeValue == null || value.Equals(attributeValue.Value)) { return; } if (String.IsNullOrWhiteSpace(value)) { attributeValueSvc.Delete(attributeValue); } else { attributeValue.Value = value; } context.SaveChanges(); }
void lvAttributeValues_ItemDeleting(object sender, ListViewDeleteEventArgs e) { var attributeValueService = new AttributeValueService(); var attributeValue = attributeValueService.Get(( int )e.Keys["Id"]); if (attributeValue != null) { attributeValueService.Delete(attributeValue, _currentPersonId); attributeValueService.Save(attributeValue, _currentPersonId); _model.LoadAttributes(); } BindData(); }
/// <summary> /// Deletes the attribute value. /// </summary> /// <param name="attributeValueGuid">The attribute value unique identifier.</param> public static void DeleteAttributeValue(Guid attributeValueGuid) { using (var rockContext = new RockContext()) { var attributeValueService = new AttributeValueService(rockContext); var attributeValue = attributeValueService.Get(attributeValueGuid); if (attributeValue == null) { return; } attributeValueService.Delete(attributeValue); rockContext.SaveChanges(); } }
/// <summary> /// Job that will run quick SQL queries on a schedule. /// /// 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; Guid?entryWorkflowType = dataMap.GetString("EraEntryWorkflow").AsGuidOrNull(); Guid?exitWorkflowType = dataMap.GetString("EraExitWorkflow").AsGuidOrNull(); bool updateVisitDates = dataMap.GetBooleanValue("SetVisitDates"); int commandTimeout = dataMap.GetString("CommandTimeout").AsIntegerOrNull() ?? 3600; // configuration // // giving int exitGivingCount = 1; // attendance int exitAttendanceCountShort = 1; int exitAttendanceCountLong = 8; // get era dataset from stored proc var resultContext = new RockContext(); var eraAttribute = AttributeCache.Get(SystemGuid.Attribute.PERSON_ERA_CURRENTLY_AN_ERA.AsGuid()); var eraStartAttribute = AttributeCache.Get(SystemGuid.Attribute.PERSON_ERA_START_DATE.AsGuid()); var eraEndAttribute = AttributeCache.Get(SystemGuid.Attribute.PERSON_ERA_END_DATE.AsGuid()); if (eraAttribute == null || eraStartAttribute == null || eraEndAttribute == null) { throw new Exception("Family analytic attributes could not be found"); } resultContext.Database.CommandTimeout = commandTimeout; context.UpdateLastStatusMessage("Getting Family Analytics Era Dataset..."); var results = resultContext.Database.SqlQuery <EraResult>("spCrm_FamilyAnalyticsEraDataset").ToList(); int personEntityTypeId = EntityTypeCache.Get("Rock.Model.Person").Id; int attributeEntityTypeId = EntityTypeCache.Get("Rock.Model.Attribute").Id; int eraAttributeId = eraAttribute.Id; int personAnalyticsCategoryId = CategoryCache.Get(SystemGuid.Category.HISTORY_PERSON_ANALYTICS.AsGuid()).Id; int progressPosition = 0; int progressTotal = results.Count; foreach (var result in results) { progressPosition++; // create new rock context for each family (https://weblog.west-wind.com/posts/2014/Dec/21/Gotcha-Entity-Framework-gets-slow-in-long-Iteration-Loops) RockContext updateContext = new RockContext(); updateContext.SourceOfChange = SOURCE_OF_CHANGE; updateContext.Database.CommandTimeout = commandTimeout; var attributeValueService = new AttributeValueService(updateContext); var historyService = new HistoryService(updateContext); // if era ensure it still meets requirements if (result.IsEra) { // This process will not remove eRA status from a single inactive family member if the family is considered eRA, even if the person record status is inactive. // It removes eRA status from all family members if the family no longer meets the eRA requirements. if (result.ExitGiftCountDuration < exitGivingCount && result.ExitAttendanceCountDurationShort < exitAttendanceCountShort && result.ExitAttendanceCountDurationLong < exitAttendanceCountLong) { // exit era (delete attribute value from each person in family) var family = new GroupService(updateContext).Queryable("Members, Members.Person").AsNoTracking().Where(m => m.Id == result.FamilyId).FirstOrDefault(); if (family != null) { foreach (var person in family.Members.Select(m => m.Person)) { // remove the era flag var eraAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraAttribute.Id && v.EntityId == person.Id).FirstOrDefault(); if (eraAttributeValue != null) { attributeValueService.Delete(eraAttributeValue); } // set end date var eraEndAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraEndAttribute.Id && v.EntityId == person.Id).FirstOrDefault(); if (eraEndAttributeValue == null) { eraEndAttributeValue = new AttributeValue(); eraEndAttributeValue.EntityId = person.Id; eraEndAttributeValue.AttributeId = eraEndAttribute.Id; attributeValueService.Add(eraEndAttributeValue); } eraEndAttributeValue.Value = RockDateTime.Now.ToString(); // add a history record if (personAnalyticsCategoryId != 0 && personEntityTypeId != 0 && attributeEntityTypeId != 0 && eraAttributeId != 0) { History historyRecord = new History(); historyService.Add(historyRecord); historyRecord.EntityTypeId = personEntityTypeId; historyRecord.EntityId = person.Id; historyRecord.CreatedDateTime = RockDateTime.Now; historyRecord.CreatedByPersonAliasId = person.PrimaryAliasId; historyRecord.Caption = "eRA"; historyRecord.Verb = "EXITED"; historyRecord.ChangeType = History.HistoryChangeType.Attribute.ConvertToString(); historyRecord.ValueName = "eRA"; historyRecord.NewValue = "Exited"; historyRecord.RelatedEntityTypeId = attributeEntityTypeId; historyRecord.RelatedEntityId = eraAttributeId; historyRecord.CategoryId = personAnalyticsCategoryId; historyRecord.SourceOfChange = SOURCE_OF_CHANGE; } updateContext.SaveChanges(); } // launch exit workflow if (exitWorkflowType.HasValue) { LaunchWorkflow(exitWorkflowType.Value, family); } } } } else { // entered era var family = new GroupService(updateContext).Queryable("Members").AsNoTracking().Where(m => m.Id == result.FamilyId).FirstOrDefault(); if (family != null) { // The stored procedure does not filter out inactive users because we want to exit the family from eRA if they are not active. // So check the status for each person here and do not add the person if they are inactive. If the system defined value for // an inactive person is not available then use "-1" as every record should pass != -1. int inactiveStatusId = DefinedValueCache.GetId(Rock.SystemGuid.DefinedValue.PERSON_RECORD_STATUS_INACTIVE.AsGuid()) ?? -1; var familyMembers = family.Members .Where(m => !m.Person.IsDeceased) .Where(m => m.Person.RecordStatusValueId != inactiveStatusId) .Select(m => m.Person); foreach (var person in familyMembers) { // set era attribute to true var eraAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraAttribute.Id && v.EntityId == person.Id).FirstOrDefault(); if (eraAttributeValue == null) { eraAttributeValue = new AttributeValue(); eraAttributeValue.EntityId = person.Id; eraAttributeValue.AttributeId = eraAttribute.Id; attributeValueService.Add(eraAttributeValue); } eraAttributeValue.Value = bool.TrueString; // add start date var eraStartAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraStartAttribute.Id && v.EntityId == person.Id).FirstOrDefault(); if (eraStartAttributeValue == null) { eraStartAttributeValue = new AttributeValue(); eraStartAttributeValue.EntityId = person.Id; eraStartAttributeValue.AttributeId = eraStartAttribute.Id; attributeValueService.Add(eraStartAttributeValue); } eraStartAttributeValue.Value = RockDateTime.Now.ToString(); // delete end date if it exists var eraEndAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraEndAttribute.Id && v.EntityId == person.Id).FirstOrDefault(); if (eraEndAttributeValue != null) { attributeValueService.Delete(eraEndAttributeValue); } // add a history record if (personAnalyticsCategoryId != 0 && personEntityTypeId != 0 && attributeEntityTypeId != 0 && eraAttributeId != 0) { History historyRecord = new History(); historyService.Add(historyRecord); historyRecord.EntityTypeId = personEntityTypeId; historyRecord.EntityId = person.Id; historyRecord.CreatedDateTime = RockDateTime.Now; historyRecord.CreatedByPersonAliasId = person.PrimaryAliasId; historyRecord.Caption = "eRA"; historyRecord.Verb = "ENTERED"; historyRecord.ChangeType = History.HistoryChangeType.Attribute.ConvertToString(); historyRecord.RelatedEntityTypeId = attributeEntityTypeId; historyRecord.RelatedEntityId = eraAttributeId; historyRecord.CategoryId = personAnalyticsCategoryId; historyRecord.SourceOfChange = SOURCE_OF_CHANGE; } updateContext.SaveChanges(); } // launch entry workflow if (entryWorkflowType.HasValue) { LaunchWorkflow(entryWorkflowType.Value, family); } } } // update stats context.UpdateLastStatusMessage($"Updating eRA {progressPosition} of {progressTotal}"); } // load giving attributes context.UpdateLastStatusMessage("Updating Giving..."); resultContext.Database.ExecuteSqlCommand("spCrm_FamilyAnalyticsGiving"); // load attendance attributes context.UpdateLastStatusMessage("Updating Attendance..."); resultContext.Database.ExecuteSqlCommand("spCrm_FamilyAnalyticsAttendance"); // process visit dates if (updateVisitDates) { context.UpdateLastStatusMessage("Updating Visit Dates..."); resultContext.Database.ExecuteSqlCommand("spCrm_FamilyAnalyticsUpdateVisitDates"); } context.UpdateLastStatusMessage(""); }
private bool UpdateSearchValueRecords(IJobExecutionContext context, int howManyToConvert, int commandTimeout) { bool anyRemaining = true; int howManyLeft = howManyToConvert; var attribute = AttributeCache.Get("8F528431-A438-4488-8DC3-CA42E66C1B37".AsGuid()); var searchTypeValue = DefinedValueCache.Get(SystemGuid.DefinedValue.PERSON_SEARCH_KEYS_ALTERNATE_ID.AsGuid()); if (attribute != null && searchTypeValue != null) { while (howManyLeft > 0) { using (var rockContext = new RockContext()) { var groupMemberService = new GroupMemberService(rockContext); var attributeValueService = new AttributeValueService(rockContext); var personSearchKeyService = new PersonSearchKeyService(rockContext); int take = howManyLeft < 100 ? howManyLeft : 100; var attributeValueRecords = attributeValueService .Queryable() .Where(v => v.AttributeId == attribute.Id && v.EntityId.HasValue) .OrderBy(v => v.Id) .Take(take) .ToList(); anyRemaining = attributeValueRecords.Count >= take; howManyLeft = anyRemaining ? howManyLeft - take : 0; foreach (var attributevalueRecord in attributeValueRecords) { var hoh = groupMemberService .Queryable() .Where(m => m.GroupId == attributevalueRecord.EntityId.Value) .HeadOfHousehold(); if (hoh != null && hoh.PrimaryAlias != null) { var keys = attributevalueRecord.Value.Split(new char[] { '|' }, StringSplitOptions.RemoveEmptyEntries); foreach (var key in keys) { var searchValue = new PersonSearchKey { PersonAliasId = hoh.PrimaryAlias.Id, SearchTypeValueId = searchTypeValue.Id, SearchValue = key }; personSearchKeyService.Add(searchValue); } } attributeValueService.Delete(attributevalueRecord); rockContext.SaveChanges(); } int numberMigrated = howManyToConvert - howManyLeft; var percentComplete = howManyToConvert > 0 ? (numberMigrated * 100.0) / howManyToConvert : 100.0; var statusMessage = $@"Progress: {numberMigrated} of {howManyToConvert} ({Math.Round( percentComplete, 1 )}%) Family Check-in Identifiers migrated to person search key values"; context.UpdateLastStatusMessage(statusMessage); rockContext.SaveChanges(disablePrePostProcessing: true); } } } return(anyRemaining); }
/// <summary> /// Job that will run quick SQL queries on a schedule. /// /// 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; Guid?entryWorkflowType = dataMap.GetString("EraEntryWorkflow").AsGuidOrNull(); Guid?exitWorkflowType = dataMap.GetString("EraExitWorkflow").AsGuidOrNull(); bool updateVisitDates = dataMap.GetBooleanValue("SetVisitDates"); var groupTypeList = dataMap.GetString("GroupTypes"); // configuration // // giving int exitGivingCount = 1; // attendance int exitAttendanceCountShort = 1; int exitAttendanceCountLong = 8; // get era dataset from stored proc var resultContext = new RockContext(); var eraAttribute = AttributeCache.Read(SystemGuid.Attribute.PERSON_ERA_CURRENTLY_AN_ERA.AsGuid()); var eraStartAttribute = AttributeCache.Read(SystemGuid.Attribute.PERSON_ERA_START_DATE.AsGuid()); var eraEndAttribute = AttributeCache.Read(SystemGuid.Attribute.PERSON_ERA_END_DATE.AsGuid()); resultContext.Database.CommandTimeout = 3600; var results = resultContext.Database.SqlQuery <EraResult>("spCrm_FamilyAnalyticsEraDataset").ToList(); int personEntityTypeId = EntityTypeCache.Read("Rock.Model.Person").Id; int attributeEntityTypeId = EntityTypeCache.Read("Rock.Model.Attribute").Id; int eraAttributeId = AttributeCache.Read(SystemGuid.Attribute.PERSON_ERA_CURRENTLY_AN_ERA.AsGuid()).Id; int personAnalyticsCategoryId = CategoryCache.Read(SystemGuid.Category.HISTORY_PERSON_ANALYTICS.AsGuid()).Id; foreach (var result in results) { // create new rock context for each family (https://weblog.west-wind.com/posts/2014/Dec/21/Gotcha-Entity-Framework-gets-slow-in-long-Iteration-Loops) RockContext updateContext = new RockContext(); var attributeValueService = new AttributeValueService(updateContext); var historyService = new HistoryService(updateContext); // if era ensure it still meets requirements if (result.IsEra) { if (result.ExitGiftCountDuration < exitGivingCount && result.ExitAttendanceCountDurationShort < exitAttendanceCountShort && result.ExitAttendanceCountDurationLong < exitAttendanceCountLong) { // exit era (delete attribute value from each person in family) var family = new GroupService(updateContext).Queryable("Members, Members.Person").AsNoTracking().Where(m => m.Id == result.FamilyId).FirstOrDefault(); if (family != null) { foreach (var person in family.Members.Select(m => m.Person)) { // remove the era flag var eraAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraAttribute.Id && v.EntityId == person.Id).FirstOrDefault(); if (eraAttributeValue != null) { attributeValueService.Delete(eraAttributeValue); } // set end date var eraEndAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraEndAttribute.Id && v.EntityId == person.Id).FirstOrDefault(); if (eraEndAttributeValue == null) { eraEndAttributeValue = new AttributeValue(); eraEndAttributeValue.EntityId = person.Id; eraEndAttributeValue.AttributeId = eraEndAttribute.Id; attributeValueService.Add(eraEndAttributeValue); } eraEndAttributeValue.Value = RockDateTime.Now.ToString(); // add a history record if (personAnalyticsCategoryId != 0 && personEntityTypeId != 0 && attributeEntityTypeId != 0 && eraAttributeId != 0) { History historyRecord = new History(); historyService.Add(historyRecord); historyRecord.EntityTypeId = personEntityTypeId; historyRecord.EntityId = person.Id; historyRecord.CreatedDateTime = RockDateTime.Now; historyRecord.CreatedByPersonAliasId = person.PrimaryAliasId; historyRecord.Caption = "eRA"; historyRecord.Summary = "Exited eRA Status"; historyRecord.Verb = "EXITED"; historyRecord.RelatedEntityTypeId = attributeEntityTypeId; historyRecord.RelatedEntityId = eraAttributeId; historyRecord.CategoryId = personAnalyticsCategoryId; } updateContext.SaveChanges(); } // launch exit workflow if (exitWorkflowType.HasValue) { LaunchWorkflow(exitWorkflowType.Value, family); } } } } else { // entered era var family = new GroupService(updateContext).Queryable("Members").AsNoTracking().Where(m => m.Id == result.FamilyId).FirstOrDefault(); if (family != null) { foreach (var person in family.Members.Where(m => !m.Person.IsDeceased).Select(m => m.Person)) { // set era attribute to true var eraAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraAttribute.Id && v.EntityId == person.Id).FirstOrDefault(); if (eraAttributeValue == null) { eraAttributeValue = new AttributeValue(); eraAttributeValue.EntityId = person.Id; eraAttributeValue.AttributeId = eraAttribute.Id; attributeValueService.Add(eraAttributeValue); } eraAttributeValue.Value = bool.TrueString; // add start date var eraStartAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraStartAttribute.Id && v.EntityId == person.Id).FirstOrDefault(); if (eraStartAttributeValue == null) { eraStartAttributeValue = new AttributeValue(); eraStartAttributeValue.EntityId = person.Id; eraStartAttributeValue.AttributeId = eraStartAttribute.Id; attributeValueService.Add(eraStartAttributeValue); } eraStartAttributeValue.Value = RockDateTime.Now.ToString(); // delete end date if it exists var eraEndAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraEndAttribute.Id && v.EntityId == person.Id).FirstOrDefault(); if (eraEndAttributeValue != null) { attributeValueService.Delete(eraEndAttributeValue); } // add a history record if (personAnalyticsCategoryId != 0 && personEntityTypeId != 0 && attributeEntityTypeId != 0 && eraAttributeId != 0) { History historyRecord = new History(); historyService.Add(historyRecord); historyRecord.EntityTypeId = personEntityTypeId; historyRecord.EntityId = person.Id; historyRecord.CreatedDateTime = RockDateTime.Now; historyRecord.CreatedByPersonAliasId = person.PrimaryAliasId; historyRecord.Caption = "eRA"; historyRecord.Summary = "Entered eRA Status"; historyRecord.Verb = "ENTERED"; historyRecord.RelatedEntityTypeId = attributeEntityTypeId; historyRecord.RelatedEntityId = eraAttributeId; historyRecord.CategoryId = personAnalyticsCategoryId; } updateContext.SaveChanges(); } // launch entry workflow if (entryWorkflowType.HasValue) { LaunchWorkflow(entryWorkflowType.Value, family); } } } // update stats } // load giving attributes resultContext.Database.ExecuteSqlCommand("spCrm_FamilyAnalyticsGiving"); // load attendance attributes resultContext.Database.ExecuteSqlCommand("spCrm_FamilyAnalyticsAttendance"); // process history for group types if (!string.IsNullOrWhiteSpace(groupTypeList)) { string[] groupTypeGuids = groupTypeList.Split(','); var inactiveRecordValue = DefinedValueCache.Read(SystemGuid.DefinedValue.PERSON_RECORD_STATUS_INACTIVE); var groupTypeEntityTypeId = EntityTypeCache.Read("Rock.Model.GroupType").Id; foreach (var groupTypeGuid in groupTypeGuids) { var groupType = GroupTypeCache.Read(groupTypeGuid.AsGuid()); if (groupType != null) { // if the person is in a group of that type and the last history record for that group type isn't START write a start RockContext rockContext = new RockContext(); // get history for this group type var historyRecords = new HistoryService(rockContext).Queryable() .Where(h => h.EntityTypeId == personEntityTypeId && h.RelatedEntityTypeId == groupTypeEntityTypeId && h.RelatedEntityId == groupType.Id ) .GroupBy(h => h.EntityId) .Select(g => g.OrderByDescending(h => h.CreatedDateTime).Select(h => new { h.EntityId, h.Verb }).FirstOrDefault()) .ToList(); // get group member information var groupMemberInfo = new GroupMemberService(rockContext).Queryable() .Where(m => m.Group.GroupTypeId == groupType.Id && m.GroupMemberStatus == GroupMemberStatus.Active && m.Group.IsActive //&& m.Person.RecordStatusValueId != inactiveRecordValue.Id ) .GroupBy(m => m.PersonId) .Select(g => g.OrderBy(m => m.CreatedDateTime).Select(m => new { m.PersonId, m.CreatedDateTime, PersonAliasId = m.Person.Aliases.Select(p => p.Id).FirstOrDefault() }).FirstOrDefault()) .ToList(); var needsStartDate = groupMemberInfo.Where(m => !historyRecords.Any(h => h.EntityId == m.PersonId && h.Verb == "STARTED")); foreach (var startItem in needsStartDate) { using (RockContext updateContext = new RockContext()) { var historyService = new HistoryService(updateContext); History history = new History(); historyService.Add(history); history.EntityTypeId = personEntityTypeId; history.EntityId = startItem.PersonId; history.RelatedEntityTypeId = groupTypeEntityTypeId; history.RelatedEntityId = groupType.Id; history.Caption = groupType.Name; history.Summary = "Started Membership in Group Of Type"; history.Verb = "STARTED"; history.CreatedDateTime = startItem.CreatedDateTime; history.CreatedByPersonAliasId = startItem.PersonAliasId; history.CategoryId = personAnalyticsCategoryId; updateContext.SaveChanges(); } } var needsStoppedDate = historyRecords.Where(h => h.Verb == "STARTED" && !groupMemberInfo.Any(m => m.PersonId == h.EntityId)); foreach (var stopItem in needsStoppedDate) { using (RockContext updateContext = new RockContext()) { var person = new PersonService(updateContext).Get(stopItem.EntityId); if (person != null) { var historyService = new HistoryService(updateContext); History history = new History(); historyService.Add(history); history.EntityTypeId = personEntityTypeId; history.EntityId = person.Id; history.RelatedEntityTypeId = groupTypeEntityTypeId; history.RelatedEntityId = groupType.Id; history.Caption = groupType.Name; history.Summary = "Stopped Membership in Group Of Type"; history.Verb = "STOPPED"; history.CreatedDateTime = RockDateTime.Now; history.CreatedByPersonAliasId = person.PrimaryAliasId; history.CategoryId = personAnalyticsCategoryId; updateContext.SaveChanges(); } } } } } } // process visit dates if (updateVisitDates) { resultContext.Database.ExecuteSqlCommand("spCrm_FamilyAnalyticsUpdateVisitDates"); } }
void lvAttributeValues_ItemDeleting( object sender, ListViewDeleteEventArgs e ) { var attributeValueService = new AttributeValueService(); var attributeValue = attributeValueService.Get( ( int )e.Keys["Id"] ); if ( attributeValue != null ) { attributeValueService.Delete( attributeValue, _currentPersonId ); attributeValueService.Save( attributeValue, _currentPersonId ); Rock.Attribute.Helper.LoadAttributes( _model ); } BindData(); }
/// <summary> /// Job that will run quick SQL queries on a schedule. /// /// 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; Guid?entryWorkflowType = dataMap.GetString("EraEntryWorkflow").AsGuidOrNull(); Guid?exitWorkflowType = dataMap.GetString("EraExitWorkflow").AsGuidOrNull(); bool updateVisitDates = dataMap.GetBooleanValue("SetVisitDates"); int commandTimeout = dataMap.GetString("CommandTimeout").AsIntegerOrNull() ?? 3600; // configuration // // giving int exitGivingCount = 1; // attendance int exitAttendanceCountShort = 1; int exitAttendanceCountLong = 8; // get era dataset from stored proc var resultContext = new RockContext(); var eraAttribute = AttributeCache.Get(SystemGuid.Attribute.PERSON_ERA_CURRENTLY_AN_ERA.AsGuid()); var eraStartAttribute = AttributeCache.Get(SystemGuid.Attribute.PERSON_ERA_START_DATE.AsGuid()); var eraEndAttribute = AttributeCache.Get(SystemGuid.Attribute.PERSON_ERA_END_DATE.AsGuid()); if (eraAttribute == null || eraStartAttribute == null || eraEndAttribute == null) { throw new Exception("Family analytic attributes could not be found"); } resultContext.Database.CommandTimeout = commandTimeout; var results = resultContext.Database.SqlQuery <EraResult>("spCrm_FamilyAnalyticsEraDataset").ToList(); int personEntityTypeId = EntityTypeCache.Get("Rock.Model.Person").Id; int attributeEntityTypeId = EntityTypeCache.Get("Rock.Model.Attribute").Id; int eraAttributeId = eraAttribute.Id; int personAnalyticsCategoryId = CategoryCache.Get(SystemGuid.Category.HISTORY_PERSON_ANALYTICS.AsGuid()).Id; foreach (var result in results) { // create new rock context for each family (https://weblog.west-wind.com/posts/2014/Dec/21/Gotcha-Entity-Framework-gets-slow-in-long-Iteration-Loops) RockContext updateContext = new RockContext(); updateContext.SourceOfChange = SOURCE_OF_CHANGE; updateContext.Database.CommandTimeout = commandTimeout; var attributeValueService = new AttributeValueService(updateContext); var historyService = new HistoryService(updateContext); // if era ensure it still meets requirements if (result.IsEra) { if (result.ExitGiftCountDuration < exitGivingCount && result.ExitAttendanceCountDurationShort < exitAttendanceCountShort && result.ExitAttendanceCountDurationLong < exitAttendanceCountLong) { // exit era (delete attribute value from each person in family) var family = new GroupService(updateContext).Queryable("Members, Members.Person").AsNoTracking().Where(m => m.Id == result.FamilyId).FirstOrDefault(); if (family != null) { foreach (var person in family.Members.Select(m => m.Person)) { // remove the era flag var eraAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraAttribute.Id && v.EntityId == person.Id).FirstOrDefault(); if (eraAttributeValue != null) { attributeValueService.Delete(eraAttributeValue); } // set end date var eraEndAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraEndAttribute.Id && v.EntityId == person.Id).FirstOrDefault(); if (eraEndAttributeValue == null) { eraEndAttributeValue = new AttributeValue(); eraEndAttributeValue.EntityId = person.Id; eraEndAttributeValue.AttributeId = eraEndAttribute.Id; attributeValueService.Add(eraEndAttributeValue); } eraEndAttributeValue.Value = RockDateTime.Now.ToString(); // add a history record if (personAnalyticsCategoryId != 0 && personEntityTypeId != 0 && attributeEntityTypeId != 0 && eraAttributeId != 0) { History historyRecord = new History(); historyService.Add(historyRecord); historyRecord.EntityTypeId = personEntityTypeId; historyRecord.EntityId = person.Id; historyRecord.CreatedDateTime = RockDateTime.Now; historyRecord.CreatedByPersonAliasId = person.PrimaryAliasId; historyRecord.Caption = "eRA"; historyRecord.Verb = "EXITED"; historyRecord.ChangeType = History.HistoryChangeType.Attribute.ConvertToString(); historyRecord.ValueName = "eRA"; historyRecord.NewValue = "Exited"; historyRecord.RelatedEntityTypeId = attributeEntityTypeId; historyRecord.RelatedEntityId = eraAttributeId; historyRecord.CategoryId = personAnalyticsCategoryId; historyRecord.SourceOfChange = SOURCE_OF_CHANGE; } updateContext.SaveChanges(); } // launch exit workflow if (exitWorkflowType.HasValue) { LaunchWorkflow(exitWorkflowType.Value, family); } } } } else { // entered era var family = new GroupService(updateContext).Queryable("Members").AsNoTracking().Where(m => m.Id == result.FamilyId).FirstOrDefault(); if (family != null) { foreach (var person in family.Members.Where(m => !m.Person.IsDeceased).Select(m => m.Person)) { // set era attribute to true var eraAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraAttribute.Id && v.EntityId == person.Id).FirstOrDefault(); if (eraAttributeValue == null) { eraAttributeValue = new AttributeValue(); eraAttributeValue.EntityId = person.Id; eraAttributeValue.AttributeId = eraAttribute.Id; attributeValueService.Add(eraAttributeValue); } eraAttributeValue.Value = bool.TrueString; // add start date var eraStartAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraStartAttribute.Id && v.EntityId == person.Id).FirstOrDefault(); if (eraStartAttributeValue == null) { eraStartAttributeValue = new AttributeValue(); eraStartAttributeValue.EntityId = person.Id; eraStartAttributeValue.AttributeId = eraStartAttribute.Id; attributeValueService.Add(eraStartAttributeValue); } eraStartAttributeValue.Value = RockDateTime.Now.ToString(); // delete end date if it exists var eraEndAttributeValue = attributeValueService.Queryable().Where(v => v.AttributeId == eraEndAttribute.Id && v.EntityId == person.Id).FirstOrDefault(); if (eraEndAttributeValue != null) { attributeValueService.Delete(eraEndAttributeValue); } // add a history record if (personAnalyticsCategoryId != 0 && personEntityTypeId != 0 && attributeEntityTypeId != 0 && eraAttributeId != 0) { History historyRecord = new History(); historyService.Add(historyRecord); historyRecord.EntityTypeId = personEntityTypeId; historyRecord.EntityId = person.Id; historyRecord.CreatedDateTime = RockDateTime.Now; historyRecord.CreatedByPersonAliasId = person.PrimaryAliasId; historyRecord.Caption = "eRA"; historyRecord.Verb = "ENTERED"; historyRecord.ChangeType = History.HistoryChangeType.Attribute.ConvertToString(); historyRecord.RelatedEntityTypeId = attributeEntityTypeId; historyRecord.RelatedEntityId = eraAttributeId; historyRecord.CategoryId = personAnalyticsCategoryId; historyRecord.SourceOfChange = SOURCE_OF_CHANGE; } updateContext.SaveChanges(); } // launch entry workflow if (entryWorkflowType.HasValue) { LaunchWorkflow(entryWorkflowType.Value, family); } } } // update stats } // load giving attributes resultContext.Database.ExecuteSqlCommand("spCrm_FamilyAnalyticsGiving"); // load attendance attributes resultContext.Database.ExecuteSqlCommand("spCrm_FamilyAnalyticsAttendance"); // process visit dates if (updateVisitDates) { resultContext.Database.ExecuteSqlCommand("spCrm_FamilyAnalyticsUpdateVisitDates"); } }