示例#1
0
        private void LaunchWorkflow(RockContext rockContext, ConnectionWorkflow connectionWorkflow, string name)
        {
            var workflowType = Web.Cache.WorkflowTypeCache.Read(connectionWorkflow.WorkflowTypeId.Value);

            if (workflowType != null && (workflowType.IsActive ?? true))
            {
                ConnectionRequestActivity connectionRequestActivity = null;
                if (ConnectionRequestActivityGuid.HasValue)
                {
                    connectionRequestActivity = new ConnectionRequestActivityService(rockContext).Get(ConnectionRequestActivityGuid.Value);
                    var workflow = Rock.Model.Workflow.Activate(workflowType, name);

                    List <string> workflowErrors;
                    new WorkflowService(rockContext).Process(workflow, connectionRequestActivity, out workflowErrors);
                    if (workflow.Id != 0)
                    {
                        ConnectionRequestWorkflow connectionRequestWorkflow = new ConnectionRequestWorkflow();
                        connectionRequestWorkflow.ConnectionRequestId  = connectionRequestActivity.ConnectionRequestId;
                        connectionRequestWorkflow.WorkflowId           = workflow.Id;
                        connectionRequestWorkflow.ConnectionWorkflowId = connectionWorkflow.Id;
                        connectionRequestWorkflow.TriggerType          = connectionWorkflow.TriggerType;
                        connectionRequestWorkflow.TriggerQualifier     = connectionWorkflow.QualifierValue;
                        new ConnectionRequestWorkflowService(rockContext).Add(connectionRequestWorkflow);
                        rockContext.SaveChanges();
                    }
                }
            }
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="ConnectionRequestActivityChangeTransaction"/> class.
 /// </summary>
 /// <param name="connectionRequestActivity">The connectionRequestActivity.</param>
 public ConnectionRequestActivityChangeTransaction(ConnectionRequestActivity connectionRequestActivity)
 {
     if (connectionRequestActivity != null)
     {
         ConnectionRequestActivityGuid = connectionRequestActivity.Guid;
         ConnectionRequestId           = connectionRequestActivity.ConnectionRequestId;
         ConnectionOpportunityId       = connectionRequestActivity.ConnectionOpportunityId;
         ConnectionActivityTypeId      = connectionRequestActivity.ConnectionActivityTypeId;
     }
 }
示例#3
0
        /// <summary>
        /// Executes the specified workflow.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="action">The action.</param>
        /// <param name="entity">The entity.</param>
        /// <param name="errorMessages">The error messages.</param>
        /// <returns></returns>
        public override bool Execute(RockContext rockContext, WorkflowAction action, Object entity, out List <string> errorMessages)
        {
            errorMessages = new List <string>();

            // Get the connection request
            ConnectionRequest request     = null;
            Guid connectionRequestGuid    = action.GetWorklowAttributeValue(GetAttributeValue(action, "ConnectionRequestAttribute").AsGuid()).AsGuid();
            var  connectionRequestService = new ConnectionRequestService(rockContext);

            request = connectionRequestService.Get(connectionRequestGuid);
            if (request == null)
            {
                errorMessages.Add("Invalid Connection Request Attribute or Value!");
                return(false);
            }

            // Get the opportunity
            ConnectionOpportunity opportunity = null;
            Guid opportunityTypeGuid          = action.GetWorklowAttributeValue(GetAttributeValue(action, "ConnectionOpportunityAttribute").AsGuid()).AsGuid();

            opportunity = new ConnectionOpportunityService(rockContext).Get(opportunityTypeGuid);
            if (opportunity == null)
            {
                errorMessages.Add("Invalid Connection Opportunity Attribute or Value!");
                return(false);
            }

            // Get the transfer note
            string note = GetAttributeValue(action, "TransferNote", true);

            if (request != null && opportunity != null)
            {
                request.ConnectionOpportunityId = opportunity.Id;

                var guid = Rock.SystemGuid.ConnectionActivityType.TRANSFERRED.AsGuid();
                var transferredActivityId = new ConnectionActivityTypeService(rockContext)
                                            .Queryable()
                                            .Where(t => t.Guid == guid)
                                            .Select(t => t.Id)
                                            .FirstOrDefault();

                ConnectionRequestActivity connectionRequestActivity = new ConnectionRequestActivity();
                connectionRequestActivity.ConnectionRequestId      = request.Id;
                connectionRequestActivity.ConnectionOpportunityId  = opportunity.Id;
                connectionRequestActivity.ConnectionActivityTypeId = transferredActivityId;
                connectionRequestActivity.Note = note;
                new ConnectionRequestActivityService(rockContext).Add(connectionRequestActivity);

                rockContext.SaveChanges();
            }

            return(true);
        }
        /// <summary>
        /// Returns the field's current value(s)
        /// </summary>
        /// <param name="parentControl">The parent control.</param>
        /// <param name="value">Information about the value</param>
        /// <param name="configurationValues">The configuration values.</param>
        /// <param name="condensed">Flag indicating if the value should be condensed (i.e. for use in a grid column)</param>
        /// <returns></returns>
        public override string FormatValue(Control parentControl, string value, Dictionary <string, ConfigurationValue> configurationValues, bool condensed)
        {
            string formattedValue = value;

            ConnectionRequestActivity connectionRequestActivity = null;

            using (var rockContext = new RockContext())
            {
                Guid?guid = value.AsGuidOrNull();
                if (guid.HasValue)
                {
                    connectionRequestActivity = new ConnectionRequestActivityService(rockContext).GetNoTracking(guid.Value);
                }

                if (connectionRequestActivity != null &&
                    connectionRequestActivity.Note != null)
                {
                    formattedValue = connectionRequestActivity.Note;
                }
            }

            return(base.FormatValue(parentControl, formattedValue, configurationValues, condensed));
        }
示例#5
0
        /// <summary>
        /// Assigns the connection requests from the SelectedCampaign's entity set.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="selectedCampaignItem">The selected campaign item.</param>
        /// <param name="numberOfRequestsRemaining">The number of requests remaining.</param>
        /// <param name="connectorPerson">The connector person.</param>
        private static void AssignConnectionRequestsFromEntitySet(RockContext rockContext, CampaignItem selectedCampaignItem, ref int numberOfRequestsRemaining, Person connectorPerson)
        {
            var opportunityService            = new ConnectionOpportunityService(rockContext);
            ConnectionOpportunity opportunity = opportunityService.Get(selectedCampaignItem.OpportunityGuid);

            if (opportunity == null || !opportunity.IsActive)
            {
                return;
            }

            int?defaultStatusId = opportunity.ConnectionType.ConnectionStatuses
                                  .Where(s => s.IsDefault)
                                  .Select(s => ( int? )s.Id)
                                  .FirstOrDefault();

            // If opportunity doesn't have a default status, something is wrong
            if (defaultStatusId == null)
            {
                return;
            }

            var connectorCampusIds = GetConnectorCampusIds(selectedCampaignItem, connectorPerson);

            var connectionRequestService         = new ConnectionRequestService(rockContext);
            var connectionRequestActivityService = new ConnectionRequestActivityService(rockContext);

            // get previous connections for the connector that have the same campus of the connector, or if the person's campus or connector person's campus is null
            var previousConnectedPersonIdsForCurrentPerson = connectionRequestService.Queryable()
                                                             .Where(a => a.ConnectionOpportunityId == opportunity.Id)
                                                             .Where(a => a.ConnectorPersonAlias.PersonId == connectorPerson.Id)
                                                             .Where(a => (a.CampusId == null) || connectorCampusIds.Any(connectorCampusId => connectorCampusId == null || a.CampusId.Value == connectorCampusId))
                                                             .Select(a => a.PersonAlias.PersonId).Distinct().ToList();

            var entitySetId          = CampaignConnectionHelper.GetEntitySet(selectedCampaignItem);
            var entitySetItemService = new EntitySetItemService(rockContext);
            var entitySetItemList    = entitySetItemService.Queryable().Where(a => a.EntitySetId == entitySetId).OrderBy(a => a.Order).Select(a => new
            {
                PersonId        = a.EntityId,
                EntityItemOrder = a.Order
            }).ToList();

            if (selectedCampaignItem.PreferPreviousConnector)
            {
                // sort them by any where the current person was assigned to this person before
                entitySetItemList = entitySetItemList
                                    .OrderBy(a => previousConnectedPersonIdsForCurrentPerson.Any(x => x == a.PersonId))
                                    .ThenBy(a => a.EntityItemOrder).ToList();
            }
            else
            {
                entitySetItemList = entitySetItemList.OrderBy(a => a.EntityItemOrder).ToList();
            }

            var personService = new PersonService(rockContext);

            // get the last connection datetime.
            var lastConnectionDateTime = RockDateTime.Now.AddDays(-selectedCampaignItem.DaysBetweenConnection);

            // if DaysBetweenConnection is 0 then check for connection request for any time period.
            if (selectedCampaignItem.DaysBetweenConnection == default(int))
            {
                lastConnectionDateTime = DateTime.MinValue;
            }

            foreach (var entitySetItem in entitySetItemList)
            {
                var entitySetPerson = personService.Get(entitySetItem.PersonId);
                if (entitySetPerson == null)
                {
                    continue;
                }

                var entitySetPersonPrimaryCampusId = entitySetPerson.PrimaryCampusId;

                bool validCampus = IsValidCampus(connectorCampusIds, entitySetPersonPrimaryCampusId);
                if (!validCampus)
                {
                    continue;
                }

                // double check that they haven't already been added
                bool personAlreadyHasConnectionRequest = PersonAlreadyHasConnectionRequest(opportunity.Id, rockContext, lastConnectionDateTime, entitySetPerson.Id);

                if (personAlreadyHasConnectionRequest)
                {
                    continue;
                }

                var connectionRequest = new ConnectionRequest();
                connectionRequest.ConnectionOpportunityId = opportunity.Id;

                /*
                 *  3/30/2020 - NA
                 *
                 *  When setting the connection request's Requester, we have to use the PrimaryAlias
                 *  to set the connectionRequest.PersonAlias property because the ConnectionRequestChangeTransaction
                 *  https://github.com/SparkabilityGroup/Rock/blob/a556a9285b7fdfe5594441286242f4feaa5847f2/Rock/Transactions/ConnectionRequestChangeTransaction.cs#L123
                 *  (which handles triggered workflows) expects it.  Also, it needs to be tracked by
                 *  the current rockContext... hence the change from GetAsNoTracking() to just Get() above:
                 *  var entitySetPerson = personService.Get( entitySetItem.PersonId );
                 *
                 *  In other words, this will not work correctly:
                 *  connectionRequest.PersonAliasId = entitySetPerson.PrimaryAliasId.Value;
                 *
                 *  Reason: This plug-in cannot change Rock core assembly code.
                 */

                connectionRequest.PersonAlias            = entitySetPerson.PrimaryAlias;
                connectionRequest.ConnectionState        = ConnectionState.Active;
                connectionRequest.ConnectorPersonAliasId = connectorPerson.PrimaryAliasId;
                connectionRequest.CampusId           = entitySetPersonPrimaryCampusId;
                connectionRequest.ConnectionStatusId = defaultStatusId.Value;

                if (selectedCampaignItem.RequestCommentsLavaTemplate.IsNotNullOrWhiteSpace())
                {
                    var mergeFields = new Dictionary <string, object>();
                    mergeFields.Add("Person", entitySetPerson);
                    mergeFields.Add("Family", entitySetPerson.GetFamily());
                    connectionRequest.Comments = selectedCampaignItem.RequestCommentsLavaTemplate.ResolveMergeFields(mergeFields);
                }

                connectionRequestService.Add(connectionRequest);

                var connectionActivityTypeAssignedGuid = Rock.SystemGuid.ConnectionActivityType.ASSIGNED.AsGuid();
                int?assignedActivityId = new ConnectionActivityTypeService(rockContext).GetId(connectionActivityTypeAssignedGuid);
                if (assignedActivityId.HasValue)
                {
                    var connectionRequestActivity = new ConnectionRequestActivity();
                    connectionRequestActivity.ConnectionRequest        = connectionRequest;
                    connectionRequestActivity.ConnectionOpportunityId  = connectionRequest.ConnectionOpportunityId;
                    connectionRequestActivity.ConnectionActivityTypeId = assignedActivityId.Value;
                    connectionRequestActivity.ConnectorPersonAliasId   = connectorPerson.PrimaryAliasId;
                    connectionRequestActivityService.Add(connectionRequestActivity);
                }

                numberOfRequestsRemaining--;
                if (numberOfRequestsRemaining <= 0)
                {
                    break;
                }
            }
        }
示例#6
0
        /// <summary>
        /// Adds connection request(s) for the specified connectorPerson
        /// </summary>
        /// <param name="selectedCampaignItem">The selected campaign item.</param>
        /// <param name="connectorPerson">The connector person.</param>
        /// <param name="numberOfRequests">The number of requests.</param>
        /// <param name="numberOfRequestsRemaining">The number of requests remaining.</param>
        public static void AddConnectionRequestsForPerson(CampaignItem selectedCampaignItem, Person connectorPerson, int numberOfRequests, out int numberOfRequestsRemaining)
        {
            var rockContext = new RockContext();

            numberOfRequestsRemaining = numberOfRequests;

            /* To assign requests, do the following in this order
             * - a) Get current connectionRequest records that don't have a connector and have a connection state of Active or a pastdue FutureFollowUp.
             * - b) If that runs out, get persons from the EntitySet of the selectedCampaignConnectionItem
             * - If there aren't enough from 'a' or 'b'
             */

            IQueryable <ConnectionRequest> connectionRequestsWithoutConnectorQuery = GetConnectionRequestsWithoutConnectorQuery(rockContext, selectedCampaignItem, connectorPerson);

            numberOfRequestsRemaining = numberOfRequests;
            var connectionRequestsWithoutConnectorList = connectionRequestsWithoutConnectorQuery
                                                         .OrderBy(a => a.CreatedDateTime)
                                                         .ToList();

            int connectorPersonAliasId = connectorPerson.PrimaryAliasId.Value;

            var connectionActivityTypeAssignedGuid = Rock.SystemGuid.ConnectionActivityType.ASSIGNED.AsGuid();
            int?assignedActivityId = new ConnectionActivityTypeService(rockContext).GetId(connectionActivityTypeAssignedGuid);
            var connectionRequestActivityService = new ConnectionRequestActivityService(rockContext);

            foreach (var connectionRequest in connectionRequestsWithoutConnectorList)
            {
                connectionRequest.ConnectorPersonAliasId = connectorPersonAliasId;
                if (selectedCampaignItem.RequestCommentsLavaTemplate.IsNotNullOrWhiteSpace() && connectionRequest.Comments.IsNullOrWhiteSpace())
                {
                    var mergeFields = new Dictionary <string, object>();
                    mergeFields.Add("Person", connectionRequest.PersonAlias.Person);
                    mergeFields.Add("Family", connectionRequest.PersonAlias.Person.GetFamily());
                    connectionRequest.Comments = selectedCampaignItem.RequestCommentsLavaTemplate.ResolveMergeFields(mergeFields);
                }

                /*
                 *  4/1/2020 - NA
                 *
                 *  You cannot attached the connectorPerson.PrimaryAlias to the connectionRequest.ConnectorPersonAlias
                 *  because they are tracked by two different contexts.  Therefore this will not work:
                 *  connectionRequest.ConnectorPersonAlias = connectorPerson.PrimaryAlias;
                 */

                if (assignedActivityId.HasValue)
                {
                    var connectionRequestActivity = new ConnectionRequestActivity();
                    connectionRequestActivity.ConnectionRequestId      = connectionRequest.Id;
                    connectionRequestActivity.ConnectionOpportunityId  = connectionRequest.ConnectionOpportunityId;
                    connectionRequestActivity.ConnectionActivityTypeId = assignedActivityId.Value;
                    connectionRequestActivity.ConnectorPersonAliasId   = connectorPersonAliasId;
                    connectionRequestActivityService.Add(connectionRequestActivity);
                }

                numberOfRequestsRemaining--;
                if (numberOfRequestsRemaining <= 0)
                {
                    break;
                }
            }

            rockContext.SaveChanges();

            if (numberOfRequestsRemaining == 0)
            {
                // we were able to assign enough from connectionRequestsWithoutConnectorList, so save those changes and return
                return;
            }

            lock ( addConnectionRequestsLockObject )
            {
                AssignConnectionRequestsFromEntitySet(rockContext, selectedCampaignItem, ref numberOfRequestsRemaining, connectorPerson);
                rockContext.SaveChanges();
            }
        }
        /// <summary>
        /// Handles the Click event of the lbConnect 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 lbConnect_Click( object sender, EventArgs e )
        {
            using ( var rockContext = new RockContext() )
            {
                var connectionRequestService = new ConnectionRequestService( rockContext );
                var groupMemberService = new GroupMemberService( rockContext );
                var connectionActivityTypeService = new ConnectionActivityTypeService( rockContext );
                var connectionRequestActivityService = new ConnectionRequestActivityService( rockContext );
                var connectionRequest = connectionRequestService.Get( hfConnectionRequestId.ValueAsInt() );

                if ( connectionRequest != null &&
                    connectionRequest.PersonAlias != null &&
                    connectionRequest.ConnectionOpportunity != null )
                {
                    bool okToConnect = true;

                    GroupMember groupMember = null;

                    // Only do group member placement if the request has an assigned placement group, role, and status
                    if ( connectionRequest.AssignedGroupId.HasValue &&
                        connectionRequest.AssignedGroupMemberRoleId.HasValue &&
                        connectionRequest.AssignedGroupMemberStatus.HasValue )
                    {
                        var group = new GroupService( rockContext ).Get( connectionRequest.AssignedGroupId.Value );
                        if ( group != null )
                        {
                            // Only attempt the add if person does not already exist in group with same role
                            groupMember = groupMemberService.GetByGroupIdAndPersonIdAndGroupRoleId( connectionRequest.AssignedGroupId.Value,
                                connectionRequest.PersonAlias.PersonId, connectionRequest.AssignedGroupMemberRoleId.Value );
                            if ( groupMember == null )
                            {
                                groupMember = new GroupMember();
                                groupMember.PersonId = connectionRequest.PersonAlias.PersonId;
                                groupMember.GroupId = connectionRequest.AssignedGroupId.Value;
                                groupMember.GroupRoleId = connectionRequest.AssignedGroupMemberRoleId.Value;
                                groupMember.GroupMemberStatus = connectionRequest.AssignedGroupMemberStatus.Value;

                                foreach ( ListItem item in cblManualRequirements.Items )
                                {
                                    if ( !item.Selected && group.MustMeetRequirementsToAddMember.HasValue && group.MustMeetRequirementsToAddMember.Value )
                                    {
                                        okToConnect = false;
                                        nbRequirementsErrors.Text = "Group Requirements have not been met. Please verify all of the requirements.";
                                        nbRequirementsErrors.Visible = true;
                                        break;
                                    }
                                    else
                                    {
                                        groupMember.GroupMemberRequirements.Add( new GroupMemberRequirement
                                        {
                                            GroupRequirementId = item.Value.AsInteger(),
                                            RequirementMetDateTime = RockDateTime.Now,
                                            LastRequirementCheckDateTime = RockDateTime.Now
                                        } );
                                    }
                                }

                                if ( okToConnect )
                                {
                                    groupMemberService.Add( groupMember );
                                    if ( !string.IsNullOrWhiteSpace( connectionRequest.AssignedGroupMemberAttributeValues ) )
                                    {
                                        var savedValues = JsonConvert.DeserializeObject<Dictionary<string, string>>( connectionRequest.AssignedGroupMemberAttributeValues );
                                        if ( savedValues != null )
                                        {
                                            groupMember.LoadAttributes();
                                            foreach ( var item in savedValues )
                                            {
                                                groupMember.SetAttributeValue( item.Key, item.Value );
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    if ( okToConnect )
                    {
                        // ... but always record the connection activity and change the state to connected.
                        var guid = Rock.SystemGuid.ConnectionActivityType.CONNECTED.AsGuid();
                        var connectedActivityId = connectionActivityTypeService.Queryable()
                            .Where( t => t.Guid == guid )
                            .Select( t => t.Id )
                            .FirstOrDefault();
                        if ( connectedActivityId > 0 )
                        {
                            var connectionRequestActivity = new ConnectionRequestActivity();
                            connectionRequestActivity.ConnectionRequestId = connectionRequest.Id;
                            connectionRequestActivity.ConnectionOpportunityId = connectionRequest.ConnectionOpportunityId;
                            connectionRequestActivity.ConnectionActivityTypeId = connectedActivityId;
                            connectionRequestActivity.ConnectorPersonAliasId = CurrentPersonAliasId;
                            connectionRequestActivityService.Add( connectionRequestActivity );
                        }

                        connectionRequest.ConnectionState = ConnectionState.Connected;

                        rockContext.SaveChanges();
                        if ( groupMember != null && !string.IsNullOrWhiteSpace( connectionRequest.AssignedGroupMemberAttributeValues ) )
                        {
                            groupMember.SaveAttributeValues( rockContext );
                        }

                        ShowDetail( connectionRequest.Id, connectionRequest.ConnectionOpportunityId );
                    }
                }
            }
        }
        /// <summary>
        /// Handles the Click event of the btnTransferSave 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 btnTransferSave_Click( object sender, EventArgs e )
        {
            using ( var rockContext = new RockContext() )
            {
                var connectionRequestService = new ConnectionRequestService( rockContext );
                var connectionActivityTypeService = new ConnectionActivityTypeService( rockContext );
                var connectionRequestActivityService = new ConnectionRequestActivityService( rockContext );

                var connectionRequest = connectionRequestService.Get( hfConnectionRequestId.ValueAsInt() );
                if ( connectionRequest != null )
                {
                    int? newOpportunityId = ddlTransferOpportunity.SelectedValueAsId();
                    int? newStatusId = ddlTransferStatus.SelectedValueAsId();

                    var guid = Rock.SystemGuid.ConnectionActivityType.TRANSFERRED.AsGuid();
                    var transferredActivityId = connectionActivityTypeService.Queryable()
                        .Where( t => t.Guid == guid )
                        .Select( t => t.Id )
                        .FirstOrDefault();

                    if ( newOpportunityId.HasValue && newStatusId.HasValue && transferredActivityId > 0 )
                    {
                        ConnectionRequestActivity connectionRequestActivity = new ConnectionRequestActivity();
                        connectionRequestActivity.ConnectionRequestId = connectionRequest.Id;
                        connectionRequestActivity.ConnectionOpportunityId = newOpportunityId.Value;
                        connectionRequestActivity.ConnectionActivityTypeId = transferredActivityId;
                        connectionRequestActivity.Note = tbTransferNote.Text;
                        connectionRequestActivityService.Add( connectionRequestActivity );

                        connectionRequest.ConnectionOpportunityId = newOpportunityId.Value;
                        connectionRequest.ConnectionStatusId = newStatusId.Value;
                        connectionRequest.AssignedGroupId = null;
                        connectionRequest.AssignedGroupMemberRoleId = null;
                        connectionRequest.AssignedGroupMemberStatus = null;

                        if ( cbClearConnector.Checked )
                        {
                            connectionRequest.ConnectorPersonAliasId = null;
                        }

                        rockContext.SaveChanges();

                        pnlReadDetails.Visible = true;
                        wpConnectionRequestActivities.Visible = true;
                        wpConnectionRequestWorkflow.Visible = true;
                        pnlTransferDetails.Visible = false;

                        ShowDetail( connectionRequest.Id, connectionRequest.ConnectionOpportunityId );
                    }
                }
            }
        }
        /// <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 )
        {
            if ( ! ppRequestor.PersonAliasId.HasValue )
            {
                ShowErrorMessage( "Incomplete", "You must select a person to save a request." );
                return;
            }

            if ( Page.IsValid )
            {
                using ( var rockContext = new RockContext() )
                {
                    ConnectionRequestService connectionRequestService = new ConnectionRequestService( rockContext );
                    ConnectionRequest connectionRequest = null;

                    int connectionRequestId = hfConnectionRequestId.ValueAsInt();

                    // if adding a new connection request
                    if ( connectionRequestId.Equals( 0 ) )
                    {
                        connectionRequest = new ConnectionRequest();
                        connectionRequest.ConnectionOpportunityId = hfConnectionOpportunityId.ValueAsInt();
                        if ( ddlCampus.SelectedValueAsId().HasValue )
                        {
                            SetUserPreference( CAMPUS_SETTING, ddlCampus.SelectedValueAsId().Value.ToString() );
                        }
                    }
                    else
                    {
                        // load existing connection request
                        connectionRequest = connectionRequestService.Get( connectionRequestId );
                    }

                    var personAliasService = new PersonAliasService( rockContext );

                    int? oldConnectorPersonAliasId = connectionRequest.ConnectorPersonAliasId;
                    int? newConnectorPersonId = ddlConnectorEdit.SelectedValueAsId();
                    int? newConnectorPersonAliasId = newConnectorPersonId.HasValue ? personAliasService.GetPrimaryAliasId( newConnectorPersonId.Value ) : (int?)null;

                    connectionRequest.ConnectorPersonAliasId = newConnectorPersonAliasId;
                    connectionRequest.PersonAlias = personAliasService.Get( ppRequestor.PersonAliasId.Value );
                    connectionRequest.ConnectionState = rblState.SelectedValueAsEnum<ConnectionState>();
                    connectionRequest.ConnectionStatusId = rblStatus.SelectedValueAsId().Value;

                    if ( ddlCampus.SelectedValueAsId().HasValue )
                    {
                        connectionRequest.CampusId = ddlCampus.SelectedValueAsId().Value;
                    }

                    connectionRequest.AssignedGroupId = ddlPlacementGroup.SelectedValueAsId();
                    connectionRequest.AssignedGroupMemberRoleId = ddlPlacementGroupRole.SelectedValueAsInt();
                    connectionRequest.AssignedGroupMemberStatus = ddlPlacementGroupStatus.SelectedValueAsEnumOrNull<GroupMemberStatus>();
                    connectionRequest.AssignedGroupMemberAttributeValues = GetGroupMemberAttributeValues();

                    connectionRequest.Comments = tbComments.Text.ScrubHtmlAndConvertCrLfToBr();
                    connectionRequest.FollowupDate = dpFollowUp.SelectedDate;

                    if ( !Page.IsValid )
                    {
                        return;
                    }

                    // if the connectionRequest IsValue is false, and the UI controls didn't report any errors, it is probably
                    // because the custom rules of ConnectionRequest didn't pass.
                    // So, make sure a message is displayed in the validation summary.
                    cvConnectionRequest.IsValid = connectionRequest.IsValid;

                    if ( !cvConnectionRequest.IsValid )
                    {
                        cvConnectionRequest.ErrorMessage = connectionRequest.ValidationResults.Select( a => a.ErrorMessage ).ToList().AsDelimited( "<br />" );
                        return;
                    }

                    if ( connectionRequest.Id.Equals( 0 ) )
                    {
                        connectionRequestService.Add( connectionRequest );
                    }

                    rockContext.SaveChanges();

                    if ( newConnectorPersonAliasId.HasValue && !newConnectorPersonAliasId.Equals( oldConnectorPersonAliasId ) )
                    {
                        var guid = Rock.SystemGuid.ConnectionActivityType.ASSIGNED.AsGuid();
                        var assignedActivityId = new ConnectionActivityTypeService( rockContext ).Queryable()
                            .Where( t => t.Guid == guid )
                            .Select( t => t.Id )
                            .FirstOrDefault();
                        if ( assignedActivityId > 0 )
                        {
                            var connectionRequestActivityService = new ConnectionRequestActivityService( rockContext );
                            var connectionRequestActivity = new ConnectionRequestActivity();
                            connectionRequestActivity.ConnectionRequestId = connectionRequest.Id;
                            connectionRequestActivity.ConnectionOpportunityId = connectionRequest.ConnectionOpportunityId;
                            connectionRequestActivity.ConnectionActivityTypeId = assignedActivityId;
                            connectionRequestActivity.ConnectorPersonAliasId = newConnectorPersonAliasId;
                            connectionRequestActivityService.Add( connectionRequestActivity );
                            rockContext.SaveChanges();
                        }
                    }

                    var qryParams = new Dictionary<string, string>();
                    qryParams["ConnectionRequestId"] = connectionRequest.Id.ToString();
                    qryParams["ConnectionOpportunityId"] = connectionRequest.ConnectionOpportunityId.ToString();

                    NavigateToPage( RockPage.Guid, qryParams );
                }
            }
        }
示例#10
0
        /// <summary>
        /// Trigger Future Followup Workflow
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="futureFollowupDateWorkflows">The future follow-up date workflows.</param>
        /// <returns></returns>
        private string TriggerFutureFollowupWorkFlow(IJobExecutionContext context, List <ConnectionWorkflow> futureFollowupDateWorkflows)
        {
            try
            {
                JobDataMap dataMap = context.JobDetail.JobDataMap;

                context.UpdateLastStatusMessage($"Processing future follow-up workFlows.");

                int recordsUpdated   = 0;
                int triggerWorkflow  = 0;
                int recordsWithError = 0;

                var rockContext = new RockContext();

                DateTime midnightToday = RockDateTime.Today.AddDays(1);

                var connectionRequestService   = new ConnectionRequestService(rockContext);
                var eligibleConnectionRequests = connectionRequestService
                                                 .Queryable("ConnectionRequestWorkflows")
                                                 .AsNoTracking()
                                                 .Where(c => c.ConnectionState == ConnectionState.FutureFollowUp &&
                                                        c.FollowupDate.HasValue &&
                                                        c.FollowupDate < midnightToday)
                                                 .ToList();

                foreach (var connectionRequest in eligibleConnectionRequests)
                {
                    try
                    {
                        using (var updateRockContext = new RockContext())
                        {
                            // increase the timeout just in case.
                            updateRockContext.Database.CommandTimeout = 180;
                            updateRockContext.SourceOfChange          = SOURCE_OF_CHANGE;
                            var connectionOpportunity = connectionRequest.ConnectionOpportunity;
                            if (connectionOpportunity != null)
                            {
                                var opportunityWorkflows = futureFollowupDateWorkflows
                                                           .Where(w =>
                                                                  (w.ConnectionOpportunityId.HasValue && w.ConnectionOpportunityId.Value == connectionOpportunity.Id) ||
                                                                  (w.ConnectionTypeId.HasValue && w.ConnectionTypeId.Value == connectionOpportunity.ConnectionTypeId));

                                foreach (var connectionWorkflow in opportunityWorkflows)
                                {
                                    LaunchWorkflow(updateRockContext, connectionRequest, connectionWorkflow, ConnectionWorkflowTriggerType.FutureFollowupDateReached.ConvertToString());
                                    triggerWorkflow += 1;
                                }

                                updateRockContext.ConnectionRequests.Attach(connectionRequest);
                                connectionRequest.ConnectionState = ConnectionState.Active;

                                var guid = Rock.SystemGuid.ConnectionActivityType.FUTURE_FOLLOWUP_COMPLETE.AsGuid();
                                var futureFollowupCompleteActivityId = new ConnectionActivityTypeService(rockContext)
                                                                       .Queryable()
                                                                       .Where(t => t.Guid == guid)
                                                                       .Select(t => t.Id)
                                                                       .FirstOrDefault();

                                ConnectionRequestActivity connectionRequestActivity = new ConnectionRequestActivity();
                                connectionRequestActivity.ConnectionRequestId      = connectionRequest.Id;
                                connectionRequestActivity.ConnectionOpportunityId  = connectionRequest.ConnectionOpportunityId;
                                connectionRequestActivity.ConnectionActivityTypeId = futureFollowupCompleteActivityId;
                                new ConnectionRequestActivityService(updateRockContext).Add(connectionRequestActivity);
                                updateRockContext.SaveChanges();
                                recordsUpdated += 1;
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        // Log exception and keep on trucking.
                        ExceptionLogService.LogException(new Exception($"Exception occurred trying to trigger future followup workFlow:{connectionRequest.Id}.", ex), _httpContext);
                        recordsWithError += 1;
                    }
                }

                // Format the result message
                string result = $"{recordsUpdated:N0} connection request records triggered {triggerWorkflow} workflows.";
                if (recordsWithError > 0)
                {
                    result += $"{recordsWithError:N0} records logged an exception.";
                }

                return(result);
            }
            catch (Exception ex)
            {
                // Log exception and return the exception messages.
                ExceptionLogService.LogException(ex, _httpContext);

                return(ex.Messages().AsDelimited("; "));
            }
        }
        /// <summary>
        /// Handles the Click event of the lbConnect 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 lbConnect_Click( object sender, EventArgs e )
        {
            using ( var rockContext = new RockContext() )
            {
                var connectionRequestService = new ConnectionRequestService( rockContext );
                var groupMemberService = new GroupMemberService( rockContext );
                var connectionActivityTypeService = new ConnectionActivityTypeService( rockContext );
                var connectionRequestActivityService = new ConnectionRequestActivityService( rockContext );
                var connectionRequest = connectionRequestService.Get( hfConnectionRequestId.ValueAsInt() );

                if ( connectionRequest != null &&
                    connectionRequest.PersonAlias != null &&
                    connectionRequest.ConnectionOpportunity != null )
                {

                    // Only do group member placement if the request has an assigned placement group
                    if ( connectionRequest.ConnectionOpportunity.GroupMemberRoleId.HasValue &&
                        connectionRequest.AssignedGroupId.HasValue )
                    {
                        // Only attempt the add if person does not already exist in group with same role
                        var groupMember = groupMemberService.GetByGroupIdAndPersonIdAndGroupRoleId( connectionRequest.AssignedGroupId.Value,
                            connectionRequest.PersonAlias.PersonId, connectionRequest.ConnectionOpportunity.GroupMemberRoleId.Value );
                        if ( groupMember == null )
                        {
                            groupMember = new GroupMember();
                            groupMember.PersonId = connectionRequest.PersonAlias.PersonId;
                            groupMember.GroupRoleId = connectionRequest.ConnectionOpportunity.GroupMemberRoleId.Value;
                            groupMember.GroupMemberStatus = connectionRequest.ConnectionOpportunity.GroupMemberStatus;
                            groupMember.GroupId = connectionRequest.AssignedGroupId.Value;
                            groupMemberService.Add( groupMember );
                        }
                    }

                    // ... but always record the connection activity and change the state to connected.
                    var guid = Rock.SystemGuid.ConnectionActivityType.CONNECTED.AsGuid();
                    var connectedActivityId = connectionActivityTypeService.Queryable()
                        .Where( t => t.Guid == guid )
                        .Select( t => t.Id )
                        .FirstOrDefault();
                    if ( connectedActivityId > 0 )
                    {
                        var connectionRequestActivity = new ConnectionRequestActivity();
                        connectionRequestActivity.ConnectionRequestId = connectionRequest.Id;
                        connectionRequestActivity.ConnectionOpportunityId = connectionRequest.ConnectionOpportunityId;
                        connectionRequestActivity.ConnectionActivityTypeId = connectedActivityId;
                        connectionRequestActivity.ConnectorPersonAliasId = CurrentPersonAliasId;
                        connectionRequestActivityService.Add( connectionRequestActivity );
                    }

                    connectionRequest.ConnectionState = ConnectionState.Connected;

                    rockContext.SaveChanges();
                    ShowDetail( connectionRequest.Id, connectionRequest.ConnectionOpportunityId );
                }
            }
        }
示例#12
0
        /// <summary>
        /// Executes the specified workflow.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="action">The action.</param>
        /// <param name="entity">The entity.</param>
        /// <param name="errorMessages">The error messages.</param>
        /// <returns></returns>
        public override bool Execute( RockContext rockContext, WorkflowAction action, Object entity, out List<string> errorMessages )
        {
            errorMessages = new List<string>();

            // Get the connection request
            ConnectionRequest request = null;
            Guid connectionRequestGuid = action.GetWorklowAttributeValue( GetAttributeValue( action, "ConnectionRequestAttribute" ).AsGuid() ).AsGuid();
            var connectionRequestService = new ConnectionRequestService( rockContext );
            request = connectionRequestService.Get( connectionRequestGuid );
            if ( request == null )
            {
                errorMessages.Add( "Invalid Connection Request Attribute or Value!" );
                return false;
            }

            // Get the opportunity
            ConnectionOpportunity opportunity = null;
            Guid opportunityTypeGuid = action.GetWorklowAttributeValue( GetAttributeValue( action, "ConnectionOpportunityAttribute" ).AsGuid() ).AsGuid();
            opportunity = new ConnectionOpportunityService( rockContext ).Get( opportunityTypeGuid );
            if ( opportunity == null )
            {
                errorMessages.Add( "Invalid Connection Opportunity Attribute or Value!" );
                return false;
            }

            // Get the tranfer note
            string note = GetAttributeValue( action, "TransferNote", true );

            if ( request != null && opportunity != null )
            {
                request.ConnectionOpportunityId = opportunity.Id;

                var guid = Rock.SystemGuid.ConnectionActivityType.TRANSFERRED.AsGuid();
                var transferredActivityId = new ConnectionActivityTypeService( rockContext )
                    .Queryable()
                    .Where( t => t.Guid == guid )
                    .Select( t => t.Id )
                    .FirstOrDefault();

                ConnectionRequestActivity connectionRequestActivity = new ConnectionRequestActivity();
                connectionRequestActivity.ConnectionRequestId = request.Id;
                connectionRequestActivity.ConnectionOpportunityId = opportunity.Id;
                connectionRequestActivity.ConnectionActivityTypeId = transferredActivityId;
                connectionRequestActivity.Note = note;
                new ConnectionRequestActivityService( rockContext ).Add( connectionRequestActivity );

                rockContext.SaveChanges();
            }

            return true;
        }
示例#13
0
        /// <summary>
        /// Add Connection Request to Context
        /// </summary>
        /// <param name="entityItemPersonAlias">The entity set item person alias.</param>
        /// <param name="requestCommentsLavaTemplate">The connection opportunity.</param>
        /// <param name="connectionOpportunityId">The connection opportunity indentifier.</param>
        /// <param name="connectionStatusId">The connection status identifier.</param>
        /// <param name="connectorPersonAliasId">The connector person alias indentifier.</param>
        /// <param name="rockContext">The rock context.</param>
        /// <returns></returns>
        private void CreateConnectionRequest(PersonAlias entityItemPersonAlias, string requestCommentsLavaTemplate, int connectionOpportunityId, int?connectionStatusId, int?connectorPersonAliasId, RockContext rockContext)
        {
            var defaultCampus = entityItemPersonAlias.Person.GetCampus();

            using (var insertRockContext = new RockContext())
            {
                try
                {
                    /*
                     *  3/30/2020 - NA
                     *
                     *  When setting the connection request's Requester, we have to use the PrimaryAlias
                     *  to set the connectionRequest.PersonAlias property because the ConnectionRequestChangeTransaction
                     *  https://github.com/SparkabilityGroup/Rock/blob/a556a9285b7fdfe5594441286242f4feaa5847f2/Rock/Transactions/ConnectionRequestChangeTransaction.cs#L123
                     *  (which handles triggered workflows) expects it.  Also, it needs to be tracked by
                     *  the current rockContext...
                     *
                     *  In other words, this will not work correctly:
                     *  PersonAliasId = personAlias.Id,
                     *
                     *  Reason: This plug-in cannot change Rock core assembly code.
                     */

                    var personPrimaryAlias = new PersonAliasService(insertRockContext).GetPrimaryAlias(entityItemPersonAlias.PersonId);
                    var connectionRequestActivityService = new ConnectionRequestActivityService(insertRockContext);
                    var insertConnectionRequestService   = new ConnectionRequestService(insertRockContext);

                    var connectionRequest = new ConnectionRequest()
                    {
                        ConnectionOpportunityId = connectionOpportunityId,
                        PersonAlias             = personPrimaryAlias,
                        ConnectionState         = ConnectionState.Active,
                        ConnectorPersonAliasId  = connectorPersonAliasId,
                        CampusId           = defaultCampus?.Id,
                        ConnectionStatusId = connectionStatusId.Value,
                    };

                    if (requestCommentsLavaTemplate.IsNotNullOrWhiteSpace())
                    {
                        var mergeFields = new Dictionary <string, object>();
                        mergeFields.Add("Person", entityItemPersonAlias.Person);
                        mergeFields.Add("Family", entityItemPersonAlias.Person.GetFamily());
                        connectionRequest.Comments = requestCommentsLavaTemplate.ResolveMergeFields(mergeFields);
                    }

                    insertConnectionRequestService.Add(connectionRequest);

                    if (connectorPersonAliasId.HasValue)
                    {
                        var connectionActivityTypeAssignedGuid = Rock.SystemGuid.ConnectionActivityType.ASSIGNED.AsGuid();
                        int?assignedActivityId = new ConnectionActivityTypeService(rockContext).GetId(connectionActivityTypeAssignedGuid);
                        if (assignedActivityId.HasValue)
                        {
                            var connectionRequestActivity = new ConnectionRequestActivity();
                            connectionRequestActivity.ConnectionRequest        = connectionRequest;
                            connectionRequestActivity.ConnectionOpportunityId  = connectionRequest.ConnectionOpportunityId;
                            connectionRequestActivity.ConnectionActivityTypeId = assignedActivityId.Value;
                            connectionRequestActivity.ConnectorPersonAliasId   = connectorPersonAliasId;
                            connectionRequestActivityService.Add(connectionRequestActivity);
                        }
                    }

                    insertRockContext.SaveChanges();
                }
                catch (Exception ex)
                {
                    // Log exception and keep on trucking.
                    var exception = new Exception($"Exception occurred trying to create connection request:{entityItemPersonAlias.Id}.", ex);
                    createConnectionRequestExceptions.Add(exception);
                    ExceptionLogService.LogException(exception, null);
                }
            }
        }
        /// <summary>
        /// Executes the specified workflow.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="action">The action.</param>
        /// <param name="entity">The entity.</param>
        /// <param name="errorMessages">The error messages.</param>
        /// <returns></returns>
        public override bool Execute(RockContext rockContext, WorkflowAction action, Object entity, out List <string> errorMessages)
        {
            errorMessages = new List <string>();
            var mergeFields = GetMergeFields(action);

            // Get the connection request
            ConnectionRequest connectionRequest = null;
            Guid connectionRequestGuid          = action.GetWorklowAttributeValue(GetAttributeValue(action, "ConnectionRequestAttribute").AsGuid()).AsGuid();

            connectionRequest = new ConnectionRequestService(rockContext).Get(connectionRequestGuid);
            if (connectionRequest == null)
            {
                errorMessages.Add("Invalid Connection Request Attribute or Value!");
                return(false);
            }

            // Get the connector
            int? personAliasId       = null;
            Guid?personAttributeGuid = GetAttributeValue(action, "PersonAttribute").AsGuidOrNull();

            if (personAttributeGuid.HasValue)
            {
                Guid?personAliasGuid = action.GetWorklowAttributeValue(personAttributeGuid.Value).AsGuidOrNull();
                if (personAliasGuid.HasValue)
                {
                    var personAlias = new PersonAliasService(rockContext).Get(personAliasGuid.Value);
                    if (personAlias != null)
                    {
                        personAliasId = personAlias.Id;
                    }
                }
                else
                {
                    errorMessages.Add("Invalid Person Attribute or Value!");
                    return(false);
                }
            }

            // Set the connector to the connection
            if (!connectionRequest.ConnectorPersonAliasId.HasValue || !GetAttributeValue(action, "Ignore").AsBoolean())
            {
                int?oldConnectorPersonAliasId = connectionRequest.ConnectorPersonAliasId;
                int?newConnectorPersonAliasId = personAliasId;

                connectionRequest.ConnectorPersonAliasId = newConnectorPersonAliasId;
                rockContext.SaveChanges();

                if (newConnectorPersonAliasId.HasValue && !newConnectorPersonAliasId.Equals(oldConnectorPersonAliasId))
                {
                    var guid = Rock.SystemGuid.ConnectionActivityType.ASSIGNED.AsGuid();
                    var assignedActivityId = new ConnectionActivityTypeService(rockContext).Queryable()
                                             .Where(t => t.Guid == guid)
                                             .Select(t => t.Id)
                                             .FirstOrDefault();
                    if (assignedActivityId > 0)
                    {
                        var connectionRequestActivityService = new ConnectionRequestActivityService(rockContext);
                        var connectionRequestActivity        = new ConnectionRequestActivity();
                        connectionRequestActivity.ConnectionRequestId      = connectionRequest.Id;
                        connectionRequestActivity.ConnectionOpportunityId  = connectionRequest.ConnectionOpportunityId;
                        connectionRequestActivity.ConnectionActivityTypeId = assignedActivityId;
                        connectionRequestActivity.ConnectorPersonAliasId   = newConnectorPersonAliasId;
                        connectionRequestActivityService.Add(connectionRequestActivity);
                        rockContext.SaveChanges();
                    }
                }
            }

            return(true);
        }
示例#15
0
        /// <summary>
        /// Creates the connection requests.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="campaignItem">The campaign item.</param>
        /// <returns></returns>
        private int CreateConnectionRequests(IJobExecutionContext context, CampaignItem campaignItem)
        {
            context.UpdateLastStatusMessage($"Processing create connection requests for {campaignItem.Name}");

            // Skip creating connection requests if set to "AsNeeded" and DailyLimitAssigned is 0 or null
            if (campaignItem.CreateConnectionRequestOption == CreateConnectionRequestOptions.AsNeeded &&
                (campaignItem.DailyLimitAssigned <= 0 || campaignItem.DailyLimitAssigned == null))
            {
                return(0);
            }

            int recordsProcessed = 0;

            var rockContext = new RockContext();
            var connectionOpportunityService = new ConnectionOpportunityService(rockContext);
            var personAliasService           = new PersonAliasService(rockContext);
            var connectionRequestService     = new ConnectionRequestService(rockContext);

            var connectionOpportunity = connectionOpportunityService.Get(campaignItem.OpportunityGuid);

            if (connectionOpportunity == null)
            {
                return(0);
            }

            // get cutoff for the last connection datetime.
            var lastConnectionDateTime = RockDateTime.Now.AddDays(-campaignItem.DaysBetweenConnection);

            // if DaysBetweenConnection is 0 then check for connection request for any time period.
            if (campaignItem.DaysBetweenConnection == default(int))
            {
                lastConnectionDateTime = DateTime.MinValue;
            }

            var entitySetItemService = new EntitySetItemService(rockContext);

            var entitySetItemsQry = entitySetItemService
                                    .Queryable()
                                    .Where(a => a.EntitySetId == campaignItem.EntitySetId)
                                    .OrderBy(a => a.Order);

            bool autoAssignment     = false;
            var  eligibleConnectors = new List <ConnectionConnector>();

            if (campaignItem.CreateConnectionRequestOption == CreateConnectionRequestOptions.AsNeeded &&
                campaignItem.DailyLimitAssigned.HasValue &&
                campaignItem.DailyLimitAssigned != default(int))
            {
                autoAssignment     = true;
                eligibleConnectors = GetEligibleConnectorWithLimit(connectionOpportunity.Id, rockContext, campaignItem.DailyLimitAssigned.Value);
            }

            int?connectionStatusId = connectionOpportunity.ConnectionType.ConnectionStatuses
                                     .Where(s => s.IsDefault)
                                     .Select(s => ( int? )s.Id)
                                     .FirstOrDefault();

            // If opportunity doesn't have a default status, something is wrong
            if (connectionStatusId == null)
            {
                ExceptionLogService.LogException(new Exception($"Unable to determine default connection status for {connectionOpportunity.Name} while processing campaigns", null));
                return(0);
            }

            var dayofWeek         = RockDateTime.Now.DayOfWeek;
            var entitySetItemList = entitySetItemsQry.ToList();

            foreach (var entitySetItem in entitySetItemList)
            {
                var personAlias            = personAliasService.GetPrimaryAlias(entitySetItem.EntityId);
                var defaultCampus          = personAlias.Person.GetCampus();
                int?connectorPersonAliasId = null;
                if (autoAssignment)
                {
                    int?connectorPersonId = null;
                    if (campaignItem.PreferPreviousConnector)
                    {
                        var personIds = eligibleConnectors
                                        .Where(a => a.Limit - a.Current > 0 &&
                                               (!a.DaysOfWeek.Any() || a.DaysOfWeek.Contains(dayofWeek)) &&
                                               (!a.CampusId.HasValue || (a.CampusId.HasValue && defaultCampus != null && defaultCampus.Id == a.CampusId.Value)))
                                        .Select(a => a.PersonId)
                                        .ToList();

                        if (personIds.Any())
                        {
                            var person = connectionRequestService
                                         .Queryable()
                                         .Where(a => a.ConnectionOpportunityId == connectionOpportunity.Id &&
                                                a.PersonAlias.PersonId == personAlias.PersonId &&
                                                a.ConnectionState == ConnectionState.Connected &&
                                                a.ConnectorPersonAliasId.HasValue &&
                                                personIds.Contains(a.ConnectorPersonAlias.PersonId))
                                         .Select(a => a.ConnectorPersonAlias.Person)
                                         .FirstOrDefault();

                            if (person != null)
                            {
                                connectorPersonId = person.Id;
                            }
                        }
                    }

                    if (!connectorPersonId.HasValue)
                    {
                        var eligibleConnector = eligibleConnectors
                                                .Where(a => a.Limit - a.Current > 0 &&
                                                       (!a.DaysOfWeek.Any() || a.DaysOfWeek.Contains(dayofWeek)) &&
                                                       (!a.CampusId.HasValue || (a.CampusId.HasValue && defaultCampus != null && defaultCampus.Id == a.CampusId.Value)))
                                                .OrderBy(a => a.Current)     // order from least assigned to most assigned
                                                .ThenBy(x => Guid.NewGuid()) // and then randomize
                                                .FirstOrDefault();

                        if (eligibleConnector != null)
                        {
                            connectorPersonId = eligibleConnector.PersonId;
                        }
                    }

                    if (!connectorPersonId.HasValue)
                    {
                        continue;
                    }

                    foreach (var connectionConnector in eligibleConnectors.Where(a => a.PersonId == connectorPersonId.Value))
                    {
                        connectorPersonAliasId       = connectionConnector.PersonAliasId;
                        connectionConnector.Current += 1;
                    }
                }

                using (var insertRockContext = new RockContext())
                {
                    try
                    {
                        /*
                         *  3/30/2020 - NA
                         *
                         *  When setting the connection request's Requester, we have to use the PrimaryAlias
                         *  to set the connectionRequest.PersonAlias property because the ConnectionRequestChangeTransaction
                         *  https://github.com/SparkabilityGroup/Rock/blob/a556a9285b7fdfe5594441286242f4feaa5847f2/Rock/Transactions/ConnectionRequestChangeTransaction.cs#L123
                         *  (which handles triggered workflows) expects it.  Also, it needs to be tracked by
                         *  the current rockContext...
                         *
                         *  In other words, this will not work correctly:
                         *  PersonAliasId = personAlias.Id,
                         *
                         *  Reason: This plug-in cannot change Rock core assembly code.
                         */

                        var personPrimaryAlias = new PersonAliasService(insertRockContext).GetPrimaryAlias(entitySetItem.EntityId);
                        var connectionRequestActivityService = new ConnectionRequestActivityService(insertRockContext);
                        var insertConnectionRequestService   = new ConnectionRequestService(insertRockContext);

                        // double check that they haven't already been added
                        var personAlreadyHasConnectionRequest = CampaignConnectionHelper.PersonAlreadyHasConnectionRequest(connectionOpportunity.Id, rockContext, lastConnectionDateTime, entitySetItem.EntityId);

                        if (personAlreadyHasConnectionRequest)
                        {
                            continue;
                        }

                        var connectionRequest = new ConnectionRequest()
                        {
                            ConnectionOpportunityId = connectionOpportunity.Id,
                            PersonAlias             = personPrimaryAlias,
                            ConnectionState         = ConnectionState.Active,
                            ConnectorPersonAliasId  = connectorPersonAliasId,
                            CampusId           = defaultCampus?.Id,
                            ConnectionStatusId = connectionStatusId.Value,
                        };

                        if (campaignItem.RequestCommentsLavaTemplate.IsNotNullOrWhiteSpace())
                        {
                            var mergeFields = new Dictionary <string, object>();
                            mergeFields.Add("Person", personAlias.Person);
                            mergeFields.Add("Family", personAlias.Person.GetFamily());
                            connectionRequest.Comments = campaignItem.RequestCommentsLavaTemplate.ResolveMergeFields(mergeFields);
                        }

                        insertConnectionRequestService.Add(connectionRequest);

                        if (connectorPersonAliasId.HasValue)
                        {
                            var connectionActivityTypeAssignedGuid = Rock.SystemGuid.ConnectionActivityType.ASSIGNED.AsGuid();
                            int?assignedActivityId = new ConnectionActivityTypeService(rockContext).GetId(connectionActivityTypeAssignedGuid);
                            if (assignedActivityId.HasValue)
                            {
                                var connectionRequestActivity = new ConnectionRequestActivity();
                                connectionRequestActivity.ConnectionRequest        = connectionRequest;
                                connectionRequestActivity.ConnectionOpportunityId  = connectionRequest.ConnectionOpportunityId;
                                connectionRequestActivity.ConnectionActivityTypeId = assignedActivityId.Value;
                                connectionRequestActivity.ConnectorPersonAliasId   = connectorPersonAliasId;
                                connectionRequestActivityService.Add(connectionRequestActivity);
                            }
                        }

                        insertRockContext.SaveChanges();
                    }
                    catch (Exception ex)
                    {
                        // Log exception and keep on trucking.
                        var exception = new Exception($"Exception occurred trying to create connection request:{personAlias.Id}.", ex);
                        createConnectionRequestExceptions.Add(exception);
                        ExceptionLogService.LogException(exception, null);
                    }
                }

                recordsProcessed += 1;
            }

            return(recordsProcessed);
        }
        /// <summary>
        /// Handles the Click event of the btnAddConnectionRequestActivity 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 btnAddConnectionRequestActivity_Click( object sender, EventArgs e )
        {
            using ( var rockContext = new RockContext() )
            {
                var connectionRequestService = new ConnectionRequestService( rockContext );
                var connectionRequestActivityService = new ConnectionRequestActivityService( rockContext );
                var personAliasService = new PersonAliasService( rockContext );

                var connectionRequest = connectionRequestService.Get( hfConnectionRequestId.ValueAsInt() );
                if ( connectionRequest != null )
                {
                    int? activityTypeId = ddlActivity.SelectedValueAsId();
                    int? personAliasId = personAliasService.GetPrimaryAliasId( ddlActivityConnector.SelectedValueAsId() ?? 0 );
                    if ( activityTypeId.HasValue && personAliasId.HasValue )
                    {

                        ConnectionRequestActivity connectionRequestActivity = null;
                        Guid? guid = hfAddConnectionRequestActivityGuid.Value.AsGuidOrNull();
                        if ( guid.HasValue )
                        {
                            connectionRequestActivity = connectionRequestActivityService.Get( guid.Value );
                        }
                        if ( connectionRequestActivity == null )
                        {
                            connectionRequestActivity = new ConnectionRequestActivity();
                            connectionRequestActivity.ConnectionRequestId = connectionRequest.Id;
                            connectionRequestActivity.ConnectionOpportunityId = connectionRequest.ConnectionOpportunityId;
                            connectionRequestActivityService.Add( connectionRequestActivity );
                        }

                        connectionRequestActivity.ConnectionActivityTypeId = activityTypeId.Value;
                        connectionRequestActivity.ConnectorPersonAliasId = personAliasId.Value;
                        connectionRequestActivity.Note = tbNote.Text;

                        rockContext.SaveChanges();

                        BindConnectionRequestActivitiesGrid( connectionRequest, rockContext );
                        HideDialog();
                    }
                }
            }
        }
        /// <summary>
        /// Executes the specified workflow.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="action">The action.</param>
        /// <param name="entity">The entity.</param>
        /// <param name="errorMessages">The error messages.</param>
        /// <returns></returns>
        public override bool Execute(RockContext rockContext, WorkflowAction action, Object entity, out List <string> errorMessages)
        {
            errorMessages = new List <string>();
            var mergeFields = GetMergeFields(action);

            // Get the connection request
            ConnectionRequest request  = null;
            Guid connectionRequestGuid = action.GetWorklowAttributeValue(GetAttributeValue(action, "ConnectionRequestAttribute").AsGuid()).AsGuid();

            request = new ConnectionRequestService(rockContext).Get(connectionRequestGuid);
            if (request == null)
            {
                errorMessages.Add("Invalid Connection Request Attribute or Value!");
                return(false);
            }

            // Get the activity type
            ConnectionActivityType activityType = null;
            Guid activityTypeGuid = action.GetWorklowAttributeValue(GetAttributeValue(action, "ConnectionActivityTypeAttribute").AsGuid()).AsGuid();

            activityType = new ConnectionActivityTypeService(rockContext).Get(activityTypeGuid);
            if (activityType == null)
            {
                errorMessages.Add("Invalid Connection Activity Type Attribute or Value!");
                return(false);
            }

            // Get the note
            string noteValue = GetAttributeValue(action, "Note", true);
            string note      = string.Empty;
            Guid?  noteGuid  = noteValue.AsGuidOrNull();

            if (noteGuid.HasValue)
            {
                var attribute = AttributeCache.Read(noteGuid.Value, rockContext);
                if (attribute != null)
                {
                    note = action.GetWorklowAttributeValue(noteGuid.Value);
                }
            }
            else
            {
                note = noteValue;
            }

            // Get the connector
            int? personAliasId       = null;
            Guid?personAttributeGuid = GetAttributeValue(action, "PersonAttribute").AsGuidOrNull();

            if (personAttributeGuid.HasValue)
            {
                Guid?personAliasGuid = action.GetWorklowAttributeValue(personAttributeGuid.Value).AsGuidOrNull();
                if (personAliasGuid.HasValue)
                {
                    var personAlias = new PersonAliasService(rockContext).Get(personAliasGuid.Value);
                    if (personAlias != null)
                    {
                        personAliasId = personAlias.Id;
                    }
                }
            }

            // Add the activity
            var activity = new ConnectionRequestActivity();

            activity.ConnectionRequestId      = request.Id;
            activity.ConnectionActivityTypeId = activityType.Id;
            activity.ConnectionOpportunityId  = request.ConnectionOpportunityId;
            activity.ConnectorPersonAliasId   = personAliasId;
            activity.Note = note.ResolveMergeFields(mergeFields);
            new ConnectionRequestActivityService(rockContext).Add(activity);
            rockContext.SaveChanges();

            return(true);
        }
        /// <summary>
        /// Executes the specified workflow.
        /// </summary>
        /// <param name="rockContext">The rock context.</param>
        /// <param name="action">The action.</param>
        /// <param name="entity">The entity.</param>
        /// <param name="errorMessages">The error messages.</param>
        /// <returns></returns>
        public override bool Execute( RockContext rockContext, WorkflowAction action, Object entity, out List<string> errorMessages )
        {
            errorMessages = new List<string>();
            var mergeFields = GetMergeFields( action );

            // Get the connection request
            ConnectionRequest request = null;
            Guid connectionRequestGuid = action.GetWorklowAttributeValue(GetAttributeValue( action, "ConnectionRequestAttribute" ).AsGuid()).AsGuid();
            request = new ConnectionRequestService( rockContext ).Get( connectionRequestGuid );
            if ( request == null )
            {
                errorMessages.Add( "Invalid Connection Request Attribute or Value!" );
                return false;
            }

            // Get the activity type
            ConnectionActivityType activityType = null;
            Guid activityTypeGuid = action.GetWorklowAttributeValue( GetAttributeValue( action, "ConnectionActivityTypeAttribute" ).AsGuid() ).AsGuid();
            activityType = new ConnectionActivityTypeService( rockContext ).Get( activityTypeGuid );
            if ( activityType == null )
            {
                errorMessages.Add( "Invalid Connection Activity Type Attribute or Value!" );
                return false;
            }

            // Get the note
            string noteValue = GetAttributeValue( action, "Note", true );
            string note = string.Empty;
            Guid? noteGuid = noteValue.AsGuidOrNull();
            if ( noteGuid.HasValue )
            {
                var attribute = AttributeCache.Read( noteGuid.Value, rockContext );
                if ( attribute != null )
                {
                    note  = action.GetWorklowAttributeValue( noteGuid.Value );
                }
            }
            else
            {
                note = noteValue;
            }

            // Get the connector
            int? personAliasId = null;
            Guid? personAttributeGuid = GetAttributeValue( action, "PersonAttribute" ).AsGuidOrNull();
            if ( personAttributeGuid.HasValue )
            {
                Guid? personAliasGuid = action.GetWorklowAttributeValue( personAttributeGuid.Value ).AsGuidOrNull();
                if ( personAliasGuid.HasValue )
                {
                    var personAlias = new PersonAliasService( rockContext ).Get( personAliasGuid.Value );
                    if ( personAlias != null )
                    {
                        personAliasId = personAlias.Id;
                    }
                }
            }

            // Add the activity
            var activity = new ConnectionRequestActivity();
            activity.ConnectionRequestId = request.Id;
            activity.ConnectionActivityTypeId = activityType.Id;
            activity.ConnectionOpportunityId = request.ConnectionOpportunityId;
            activity.ConnectorPersonAliasId = personAliasId;
            activity.Note = note.ResolveMergeFields( mergeFields );
            new ConnectionRequestActivityService( rockContext ).Add( activity );
            rockContext.SaveChanges();

            return true;
        }