/// <summary>
        /// Updates GroupLocationHistorical for any group locations in groups that have data group history enabled
        /// </summary>
        /// <param name="context">The context.</param>
        public void UpdateGroupLocationHistorical(IJobExecutionContext context)
        {
            var rockContext = new RockContext();
            var groupLocationHistoricalService = new GroupLocationHistoricalService(rockContext);
            var groupLocationService           = new GroupLocationService(rockContext);

            var groupLocationsWithHistoryEnabledQuery = groupLocationService.Queryable().Where(a => a.Group.GroupType.EnableGroupHistory == true).AsNoTracking();
            var groupLocationsHistoricalCurrentQuery  = groupLocationHistoricalService.Queryable().Where(a => a.CurrentRowIndicator == true).AsNoTracking();

            // Mark GroupLocationHistorical Rows as History ( CurrentRowIndicator = false, etc ) if any of the tracked field values change
            var groupLocationHistoricalNoLongerCurrentQuery = groupLocationsHistoricalCurrentQuery.Join(
                groupLocationsWithHistoryEnabledQuery,
                glh => glh.GroupLocationId,
                gl => gl.Id, (glh, gl) => new
            {
                GroupLocation           = gl,
                GroupLocationHistorical = glh
            })
                                                              .Where(a =>
                                                                     a.GroupLocation.GroupId != a.GroupLocationHistorical.GroupId ||
                                                                     (a.GroupLocation.GroupLocationTypeValueId != a.GroupLocation.GroupLocationTypeValueId) ||
                                                                     (a.GroupLocation.GroupLocationTypeValueId.HasValue && a.GroupLocation.GroupLocationTypeValue.Value != a.GroupLocationHistorical.GroupLocationTypeName) ||
                                                                     a.GroupLocation.LocationId != a.GroupLocationHistorical.LocationId ||
                                                                     a.GroupLocation.Location.ModifiedDateTime != a.GroupLocationHistorical.LocationModifiedDateTime ||
                                                                     (a.GroupLocation.Schedules.Select(s => new { ScheduleId = s.Id, s.ModifiedDateTime }).Except(a.GroupLocationHistorical.GroupLocationHistoricalSchedules.Select(hs => new { hs.ScheduleId, ModifiedDateTime = hs.ScheduleModifiedDateTime }))).Any()
                                                                     );

            var effectiveExpireDateTime            = RockDateTime.Now;
            int groupLocationsLoggedToHistory      = 0;
            int groupLocationsSaveToHistoryCurrent = 0;

            if (groupLocationHistoricalNoLongerCurrentQuery.Any())
            {
                var groupLocationHistoricalNoLongerCurrent = groupLocationHistoricalNoLongerCurrentQuery.Select(a => a.GroupLocationHistorical).AsNoTracking();

                groupLocationsLoggedToHistory = rockContext.BulkUpdate(groupLocationHistoricalNoLongerCurrent, glh => new GroupLocationHistorical
                {
                    CurrentRowIndicator = false,
                    ExpireDateTime      = effectiveExpireDateTime
                });
            }

            // Insert Group Locations (that have a group with GroupType.EnableGroupHistory) that don't have a CurrentRowIndicator row yet ( or don't have a CurrentRowIndicator because it was stamped with CurrentRowIndicator=false )
            var groupLocationsToAddToHistoricalCurrentsQuery = groupLocationsWithHistoryEnabledQuery.Where(gl => !groupLocationsHistoricalCurrentQuery.Any(glh => glh.GroupLocationId == gl.Id));

            if (groupLocationsToAddToHistoricalCurrentsQuery.Any())
            {
                List <GroupLocationHistorical> groupLocationHistoricalCurrentsToInsert = groupLocationsToAddToHistoricalCurrentsQuery
                                                                                         .Include(a => a.GroupLocationTypeValue)
                                                                                         .Include(a => a.Location).ToList()
                                                                                         .Select(gl => GroupLocationHistorical.CreateCurrentRowFromGroupLocation(gl, effectiveExpireDateTime)).ToList();

                groupLocationsSaveToHistoryCurrent = groupLocationHistoricalCurrentsToInsert.Count();

                // get the current max GroupLocatiionHistorical.Id to help narrow down which ones were inserted
                int groupLocationHistoricalStartId = groupLocationHistoricalService.Queryable().Max(a => ( int? )a.Id) ?? 0;

                rockContext.BulkInsert(groupLocationHistoricalCurrentsToInsert);

                // since we used BulkInsert, we'll need to go back and get the Ids and the associated GroupLocation's Schedules for the GroupLocationHistorical records that we just inserted
                var insertedGroupLocationHistoricalIdsWithSchedules = groupLocationHistoricalService.Queryable()
                                                                      .Where(a => a.Id > groupLocationHistoricalStartId && a.GroupLocation.Schedules.Any()).ToList()
                                                                      .Select(a => new { GroupLocationHistoricalId = a.Id, a.GroupLocation.Schedules });

                List <GroupLocationHistoricalSchedule> groupLocationHistoricalScheduleCurrentsToInsert = new List <GroupLocationHistoricalSchedule>();
                foreach (var insertedGroupLocationHistoricalIdWithSchedules in insertedGroupLocationHistoricalIdsWithSchedules)
                {
                    foreach (Schedule schedule in insertedGroupLocationHistoricalIdWithSchedules.Schedules)
                    {
                        groupLocationHistoricalScheduleCurrentsToInsert.Add(new GroupLocationHistoricalSchedule
                        {
                            GroupLocationHistoricalId = insertedGroupLocationHistoricalIdWithSchedules.GroupLocationHistoricalId,
                            ScheduleId               = schedule.Id,
                            ScheduleName             = schedule.ToString(),
                            ScheduleModifiedDateTime = schedule.ModifiedDateTime
                        });
                    }
                }

                if (groupLocationHistoricalScheduleCurrentsToInsert.Any())
                {
                    rockContext.BulkInsert(groupLocationHistoricalScheduleCurrentsToInsert);
                }
            }

            if (groupLocationsLoggedToHistory > 0)
            {
                _jobStatusMessages.Add($"Logged {groupLocationsLoggedToHistory} {"group location history snapshot".PluralizeIf( groupLocationsLoggedToHistory != 0 )}");
            }

            if (groupLocationsSaveToHistoryCurrent > 0)
            {
                int newGroupLocationsAddedToHistory = groupLocationsSaveToHistoryCurrent - groupLocationsLoggedToHistory;
                if (newGroupLocationsAddedToHistory > 0)
                {
                    _jobStatusMessages.Add($"Added {newGroupLocationsAddedToHistory} new {"group location history snapshot".PluralizeIf( newGroupLocationsAddedToHistory != 0 )}");
                }
            }
        }
Exemple #2
0
        /// <summary>
        /// Handles the Click event of the lbSave 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 lbSave_Click(object sender, EventArgs e)
        {
            var rockContext = new RockContext();

            var    personService = new PersonService(rockContext);
            Person business      = null;

            if (int.Parse(hfBusinessId.Value) != 0)
            {
                business = personService.Get(int.Parse(hfBusinessId.Value));
            }

            if (business == null)
            {
                business = new Person();
                personService.Add(business);
                tbBusinessName.Text = tbBusinessName.Text.FixCase();
            }

            // Business Name
            business.LastName = tbBusinessName.Text;

            // Phone Number
            var businessPhoneTypeId = new DefinedValueService(rockContext).GetByGuid(new Guid(Rock.SystemGuid.DefinedValue.PERSON_PHONE_TYPE_WORK)).Id;

            var phoneNumber = business.PhoneNumbers.FirstOrDefault(n => n.NumberTypeValueId == businessPhoneTypeId);

            if (!string.IsNullOrWhiteSpace(PhoneNumber.CleanNumber(pnbPhone.Number)))
            {
                if (phoneNumber == null)
                {
                    phoneNumber = new PhoneNumber {
                        NumberTypeValueId = businessPhoneTypeId
                    };
                    business.PhoneNumbers.Add(phoneNumber);
                }
                phoneNumber.CountryCode        = PhoneNumber.CleanNumber(pnbPhone.CountryCode);
                phoneNumber.Number             = PhoneNumber.CleanNumber(pnbPhone.Number);
                phoneNumber.IsMessagingEnabled = cbSms.Checked;
                phoneNumber.IsUnlisted         = cbUnlisted.Checked;
            }
            else
            {
                if (phoneNumber != null)
                {
                    business.PhoneNumbers.Remove(phoneNumber);
                    new PhoneNumberService(rockContext).Delete(phoneNumber);
                }
            }

            // Record Type - this is always "business". it will never change.
            business.RecordTypeValueId = DefinedValueCache.Get(Rock.SystemGuid.DefinedValue.PERSON_RECORD_TYPE_BUSINESS.AsGuid()).Id;

            // Record Status
            business.RecordStatusValueId = dvpRecordStatus.SelectedValueAsInt();;

            // Record Status Reason
            int?newRecordStatusReasonId = null;

            if (business.RecordStatusValueId.HasValue && business.RecordStatusValueId.Value == DefinedValueCache.Get(new Guid(Rock.SystemGuid.DefinedValue.PERSON_RECORD_STATUS_INACTIVE)).Id)
            {
                newRecordStatusReasonId = dvpReason.SelectedValueAsInt();
            }
            business.RecordStatusReasonValueId = newRecordStatusReasonId;

            // Email
            business.IsEmailActive   = true;
            business.Email           = tbEmail.Text.Trim();
            business.EmailPreference = rblEmailPreference.SelectedValue.ConvertToEnum <EmailPreference>();

            avcEditAttributes.GetEditValues(business);

            if (!business.IsValid)
            {
                // Controls will render the error messages
                return;
            }

            rockContext.WrapTransaction(() =>
            {
                rockContext.SaveChanges();

                // Add/Update Family Group
                var familyGroupType = GroupTypeCache.GetFamilyGroupType();
                int adultRoleId     = familyGroupType.Roles
                                      .Where(r => r.Guid.Equals(Rock.SystemGuid.GroupRole.GROUPROLE_FAMILY_MEMBER_ADULT.AsGuid()))
                                      .Select(r => r.Id)
                                      .FirstOrDefault();
                var adultFamilyMember = UpdateGroupMember(business.Id, familyGroupType, business.LastName + " Business", ddlCampus.SelectedValueAsInt(), adultRoleId, rockContext);
                business.GivingGroup  = adultFamilyMember.Group;

                // Add/Update Known Relationship Group Type
                var knownRelationshipGroupType   = GroupTypeCache.Get(Rock.SystemGuid.GroupType.GROUPTYPE_KNOWN_RELATIONSHIPS.AsGuid());
                int knownRelationshipOwnerRoleId = knownRelationshipGroupType.Roles
                                                   .Where(r => r.Guid.Equals(Rock.SystemGuid.GroupRole.GROUPROLE_KNOWN_RELATIONSHIPS_OWNER.AsGuid()))
                                                   .Select(r => r.Id)
                                                   .FirstOrDefault();
                var knownRelationshipOwner = UpdateGroupMember(business.Id, knownRelationshipGroupType, "Known Relationship", null, knownRelationshipOwnerRoleId, rockContext);

                // Add/Update Implied Relationship Group Type
                var impliedRelationshipGroupType   = GroupTypeCache.Get(Rock.SystemGuid.GroupType.GROUPTYPE_PEER_NETWORK.AsGuid());
                int impliedRelationshipOwnerRoleId = impliedRelationshipGroupType.Roles
                                                     .Where(r => r.Guid.Equals(Rock.SystemGuid.GroupRole.GROUPROLE_PEER_NETWORK_OWNER.AsGuid()))
                                                     .Select(r => r.Id)
                                                     .FirstOrDefault();
                var impliedRelationshipOwner = UpdateGroupMember(business.Id, impliedRelationshipGroupType, "Implied Relationship", null, impliedRelationshipOwnerRoleId, rockContext);

                rockContext.SaveChanges();

                // Location
                int workLocationTypeId = DefinedValueCache.Get(Rock.SystemGuid.DefinedValue.GROUP_LOCATION_TYPE_WORK).Id;

                var groupLocationService = new GroupLocationService(rockContext);
                var workLocation         = groupLocationService.Queryable("Location")
                                           .Where(gl =>
                                                  gl.GroupId == adultFamilyMember.Group.Id &&
                                                  gl.GroupLocationTypeValueId == workLocationTypeId)
                                           .FirstOrDefault();

                if (string.IsNullOrWhiteSpace(acAddress.Street1))
                {
                    if (workLocation != null)
                    {
                        if (cbSaveFormerAddressAsPreviousAddress.Checked)
                        {
                            GroupLocationHistorical.CreateCurrentRowFromGroupLocation(workLocation, RockDateTime.Now);
                        }

                        groupLocationService.Delete(workLocation);
                    }
                }
                else
                {
                    var newLocation = new LocationService(rockContext).Get(acAddress.Street1, acAddress.Street2, acAddress.City, acAddress.State, acAddress.PostalCode, acAddress.Country);
                    if (workLocation == null)
                    {
                        workLocation = new GroupLocation();
                        groupLocationService.Add(workLocation);
                        workLocation.GroupId = adultFamilyMember.Group.Id;
                        workLocation.GroupLocationTypeValueId = workLocationTypeId;
                    }
                    else
                    {
                        // Save this to history if the box is checked and the new info is different than the current one.
                        if (cbSaveFormerAddressAsPreviousAddress.Checked && newLocation.Id != workLocation.Location.Id)
                        {
                            new GroupLocationHistoricalService(rockContext).Add(GroupLocationHistorical.CreateCurrentRowFromGroupLocation(workLocation, RockDateTime.Now));
                        }
                    }

                    workLocation.Location          = newLocation;
                    workLocation.IsMailingLocation = true;
                }

                rockContext.SaveChanges();

                hfBusinessId.Value = business.Id.ToString();
            });

            /* Ethan Drotning 2022-01-11
             * Need save the PersonSearchKeys outside of the transaction since the DB might not have READ_COMMITTED_SNAPSHOT enabled.
             */

            // PersonSearchKey
            var personSearchKeyService = new PersonSearchKeyService(rockContext);
            var validSearchTypes       = GetValidSearchKeyTypes();
            var databaseSearchKeys     = personSearchKeyService.Queryable().Where(a => a.PersonAlias.PersonId == business.Id && validSearchTypes.Contains(a.SearchTypeValue.Guid)).ToList();

            foreach (var deletedSearchKey in databaseSearchKeys.Where(a => !PersonSearchKeysState.Any(p => p.Guid == a.Guid)))
            {
                personSearchKeyService.Delete(deletedSearchKey);
            }

            foreach (var personSearchKey in PersonSearchKeysState.Where(a => !databaseSearchKeys.Any(d => d.Guid == a.Guid)))
            {
                personSearchKey.PersonAliasId = business.PrimaryAliasId.Value;
                personSearchKeyService.Add(personSearchKey);
            }

            rockContext.SaveChanges();

            business.SaveAttributeValues();

            var queryParams = new Dictionary <string, string>
            {
                { "BusinessId", hfBusinessId.Value }
            };

            NavigateToCurrentPage(queryParams);
        }