Overview

We recently started using the Steps feature of RockRMS to track folks who have completed one of our Vision Venues. What some churches call membership or core classes. Previously we were using Person Attributes to just track the date that folks finished a Vision Venue. This told us the last time they completed a specific one, but not the historical dates for the repeat attenders. Plus we were only getting the completion date - nothing else. Steps allows us to track much more with Step Attributes, Start/End Date, & Status.

Considerations

We wanted an easy way for our class administrators to handle the creation of Steps when they wrapped up each Vision Venue session. The Auto-Complete Data View on the Step Type wasn't really an option because we wanted more details on the Step and more control of the Start/End dates. We considered using the Launch Workflow from a Group Member grid - but this didn't allow us to easily get the parameters (StepType, Start/End dates, etc) we needed for creating the step. And because each workflow would run independently - there wasn't a great way to provide a single summary to the admin when the entire run finished.

The Parts

We use a combination of 1 Step Program with 5 Step Types, 2 internal webpages and 2 workflows for this whole process. The first webpage gives the admin an overview of the process, prompts for the needed parameters, displays a list of all folks that will be processed if they continue, and provides a link to the second webpage once all parameters are entered. The second webpage is just a workflow entry block for the first workflow. The first workflow is interactive. It confirms the parameters one last time as well as the total number of folks that will be processed. Upon confirmation it will launch the second workflow. The second workflow runs in the background and loops thru the folks to create Steps based on the parameters passed from the first. Once all folks are processed, a summary email is sent to the user.

The Nuts & Bolts

For the purposes of this recipe I will assume you know how to setup a Step Program and Step Types. You will need to make note of the StepProgramId and the StepTypeIds.

Webpage #1: Vision Venue - Wrap-Up

This page uses a Page Parameter Filter block to get parameters from the user, a couple of HTML block to describe the process and show confirmation of parameters selected, and a Dynamic Data block to provide confirmation of the people that will be processed.

Webpage1-Sample.png


Page settings

Webpage1-Settings.png


HTML Content block #1: "Overview of Process"

Webpage1-HTML1.png


Page Parameter Filter block

Webpage1-PageParameterFilter.png


Filter: Vision Venue Type

We chose to use a single-select instead of a StepType for this filter for a better end-user experience.

Webpage1-VisionVenueType.png


Filter: Last & First Attendance Dates

These 2 filters are both setup the same except for their name and key. They use SQL for the Values to populate options based on the Group selected.

Webpage1-AttendanceDates.png

{% assign grpGuid = 'Global' | PageParameter:'GroupGuid' %}
{% if grpGuid and grpGuid != '' %}
  {% assign grpId = grpGuid | GroupByGuid | Property:'Id' %}
{% else %}
  {% assign grpId = -1 %}
{% endif %}

DECLARE @GroupId AS INTEGER = {{ grpId }}

SELECT
    CONVERT (varchar, ao.[OccurrenceDate], 101) AS 'Value'
    , CONVERT (varchar, ao.[OccurrenceDate], 101) AS 'Text'
FROM
    [AttendanceOccurrence] ao
WHERE
    ao.[GroupId] = @GroupId
ORDER BY ao.[OccurrenceDate] DESC
        

Filter: Minimum Attendance For Credit

We chose to use a single-select instead of an integer for this filter so that the page would auto-refresh after selection without the user having to click the update button.

Webpage1-MinAttendance.png


HTML Content block #2: "Confirm Parameters & Continue"

Be sure to enable the Rock Entity Lava Command for this block.

<style>
  .settings {
      display: inline-block;
      margin-top: 10px;
      margin-bottom: 2px;
  }
  .table>thead>tr>th {
      background-color: #d1d1d1;
  }
</style>

{% assign groupGuid = 'Global' | PageParameter:'GroupGuid' %}
{% assign visionVenueType = 'Global' | PageParameter:'VisionVenueType' %}
{% assign campusGuid = 'Global' | PageParameter:'Campus' %}
{% assign lastAttendanceDate = 'Global' | PageParameter:'LastAttendanceDate' | AsDateTime %}
{% assign firstAttendanceDate = 'Global' | PageParameter:'FirstAttendanceDate' | AsDateTime %}
{% assign minimumAttendanceForCredit = 'Global' | PageParameter:'MinimumAttendanceForCredit' %}
{% assign haveRequiredParms = true %}

<h3>Verify Session Details & Submit For Processing</h3>
<p>Please verify these settings. Once you have selected all required settings - you will be given a link to proceed with processing.</p>
<fieldset class="well settings">
  <table id="settings" class="table table-striped table-condensed">
      <thead>
          <tr><th>Setting</th><th>Value</th></tr>
      </thead>
      <tbody>
          <tr>
              <td>Group</td>
              <td>
                  {% if groupGuid and groupGuid != '' %}
                      {{ groupGuid | GroupByGuid | Property:'Name' }}
                  {% else %}
                      <em>still needed</em>
                      {% assign haveRequiredParms = false %}
                  {% endif %}
              </td>
          </tr>
          <tr>
              <td>Vision Venue Type</td>
              <td>
                  {% if visionVenueType and visionVenueType != '' %}
                      {% case visionVenueType %}
                          {% when 1 %} Baptism
                          {% when 2 %} Explorations
                          {% when 3 %} G1 Course
                          {% when 4 %} Leadership U
                          {% when 5 %} Vision Dinner
                      {% endcase %}
                  {% else %}
                      <em>still needed</em>
                      {% assign haveRequiredParms = false %}
                  {% endif %}
              </td>
          </tr>
          <tr>
              <td>Campus</td>
              <td>
                  {% if campusGuid and campusGuid != '' %}
                      {% campus where:'Guid == "{{ campusGuid }}"' securityenabled:'false' %}
                          {{ campusItems | First | Property:'Name' }}
                      {% endcampus %}
                  {% else %}
                      <em>-</em>
                  {% endif %}
              </td>
          </tr>
          <tr>
              <td>Last Attendance Date</td>
              <td>
                  {% if lastAttendanceDate and lastAttendanceDate != '' %}
                      {{ lastAttendanceDate | Date:'ddd, MMM d, yyyy' }}
                  {% else %}
                      <em>still needed</em>
                      {% assign haveRequiredParms = false %}
                  {% endif %}
              </td>
          </tr>
          <tr>
              <td>First Attendance Date</td>
              <td>
                  {% if firstAttendanceDate and firstAttendanceDate != '' %}
                      {{ firstAttendanceDate | Date:'ddd, MMM d, yyyy' }}
                  {% else %}
                      <em>still needed</em>
                      {% assign haveRequiredParms = false %}
                  {% endif %}
              </td>
          </tr>
          {% if firstAttendanceDate > lastAttendanceDate %}
              {% assign haveRequiredParms = false %}
              <tr>
                  <td colspan='2'>
                      <div class="alert alert-danger" role="alert">
                          First Attendance Date MUST be before Last Attendance Date!!
                      </div>
                  </td>
              </tr>                        
          {% endif %}            
          <tr>
              <td>Minimum Attendance Needed for Credit</td>
              <td>
                  {% if minimumAttendanceForCredit and minimumAttendanceForCredit != '' %}
                      {{ minimumAttendanceForCredit }}
                  {% else %}
                      <em>still needed</em>
                      {% assign haveRequiredParms = false %}
                  {% endif %}
              </td>
          </tr>
      </tbody>
  </table>

  {% if haveRequiredParms == true %}
      <hr>
      <h4>When you are ready to continue to the next step   
      <a role="button" class="btn btn-default" href="/page/2084?Group={{ groupGuid }}&VisionVenueType={{ visionVenueType }}&Campus={{ campusGuid }}&LastAttendanceDate={{ lastAttendanceDate }}&FirstAttendanceDate={{ firstAttendanceDate }}&MinimumAttendanceForCredit={{ minimumAttendanceForCredit }}">Click Here</a></h4>
      <hr>
      <div class="alert alert-danger" role="alert">
          If you have already run thru this process with these exact settings in the past hour - PLEASE DO NOT RUN IT AGAIN. Wait until you get the email confirmation.
      </div>
  
  {% endif %}

</fieldset>

<hr>
        

Dynamic Data Block

Webpage1-DynamicData.png

SELECT  p.[Id]
      , p.[LastName]
      , p.[FirstName]
      , COUNT(ao.[OccurrenceDate]) AS 'AttendanceCount'
      , CASE
          WHEN COUNT(ao.[OccurrenceDate]) >= @MinimumAttendanceForCredit THEN 'Completed'
          WHEN COUNT(ao.[OccurrenceDate]) > 0 THEN 'Started'
          ELSE 'Registered'
        END AS 'AttendanceStatus'
FROM  [AttendanceOccurrence] ao
INNER JOIN [Attendance] a on a.[OccurrenceId] = ao.[Id]
INNER JOIN [PersonAlias] pa on pa.[Id] = a.[PersonAliasId]
INNER JOIN [Person] p on p.[Id] = pa.[PersonId]
INNER JOIN [Group] g on g.[Id] = ao.[GroupId]
WHERE g.[Guid] = @GroupGuid
AND   ao.[OccurrenceDate] BETWEEN @FirstAttendanceDate AND @LastAttendanceDate
AND   a.[DidAttend] = 'true'
AND   p.[IsDeceased] = 'false'
GROUP BY p.[Id], p.[LastName], p.[FirstName]
ORDER BY p.[LastName], p.[FirstName]    
        

Webpage #2: Vision Venue - Wrap-Up (processing)

This is a really basic page with just a workflow entry block.

Webpage2-Sample.png


Page settings

Webpage2-Settings.png


Workflow Entry block

Webpage2-WFEntry.png


Workflow #1: Vision Venue - Wrap Up - Part 1

Overview

This workflow is interactive and verifies the parameters and affected number of people with the user one last time before calling the second workflow to create the steps.

Workflow1-Overview.png


Workflow Attributes

Create each workflow attribute shown in the overview. The only one that needs additional details is the Vision Venue Type [Single-Select]:

Workflow1-Attribute2.png


Activity #1: Start: Verify Required Settings

This activity determines if all required parameters were passed into the workflow or not.

WF1-Activity1.png


Action #1: Check for Required Settings
Lava Run action - saves result to activity attribute "All Settings Provided"
{% assign group = Workflow | Attribute:'Group' %}
{% assign visionVenueType = Workflow | Attribute:'VisionVenueType','RawValue' %}
{% assign lastAttendanceDate = Workflow | Attribute:'LastAttendanceDate' | Date:'ddd, MMM d, yyyy' %}
{% assign firstAttendanceDate = Workflow | Attribute:'FirstAttendanceDate' | Date:'ddd, MMM d, yyyy' %}
{% assign minimumAttendanceForCredit = Workflow | Attribute:'MinimumAttendanceForCredit' %}

{% if group == empty or visionVenueType == empty or lastAttendanceDate == empty or firstAttendanceDate == empty or minimumAttendanceForCredit == emtpy %}
No
{% else %}
Yes
{% endif %}
        

Action #2: ACTIVATE: ERROR: Missing Required Settings
Activate Activity action - starts "ERROR: Missing Required Settings" activity if AllSettingsProvided is NOT Yes

WF1-Activity1-Action2.png


Action #3: ACTIVATE: Begin Processing
Activate Activity action - starts "Begin Processing" activity if AllSettingsProvided is Yes

WF1-Activity1-Action3.png


Activity #2: Begin Processing

This activity gets a total count of people to be processed based on parameters. Errors if count is 0. If count > 0 - asks user if they wish to proceed.

WF1-Activity2.png


Action #1: Determine PersonCount for Settings
Lava Run action - SQL command enabled - outputs to workflow attribute "PersonCount"
{% assign groupId = Workflow | Attribute:'Group','Id' %}
{% assign firstAttendanceDate = Workflow | Attribute:'FirstAttendanceDate' | Date:'yyyy-MM-dd' %}
{% assign lastAttendanceDate = Workflow | Attribute:'LastAttendanceDate' | Date:'yyyy-MM-dd' %}

{% sql GroupId:'{{ groupId }}' FirstDate:'{{ firstAttendanceDate }}' LastDate:'{{ lastAttendanceDate}}' %}
    SELECT
        p.[Id] AS 'PersonId'
    FROM
        [AttendanceOccurrence] ao
        INNER JOIN [Attendance] a on a.[OccurrenceId] = ao.[Id]
        INNER JOIN [PersonAlias] pa on pa.[Id] = a.[PersonAliasId]
        INNER JOIN [Person] p on p.[Id] = pa.[PersonId]
    WHERE
        ao.[GroupId] = @GroupId
    AND ao.[OccurrenceDate] BETWEEN @FirstDate AND @LastDate
    AND a.[DidAttend] = 'true'
    AND p.[IsDeceased] = 'false'
    GROUP BY
        p.[Id]
{% endsql %}

{{ results | Size }}        
        

Action #2: ACTIVATE: ERROR: No people for settings [If PersonCount < 1]

WF1-Activity2-Action2.png


Action #3: FORM: Confirm settings & present warnings
While this is a user entry form - we're not accepting input from the user. We are only using it to confirm the parameters that were passed to the workflow and the number of people that will be included based on those parameters. Because of this we make sure of the Form Header & Form Footer fields.

WF1-Activity2-Action3-Top.png

Form Header
{% assign group = Workflow | Attribute:'Group' %}
{% assign visionVenueType = Workflow | Attribute:'VisionVenueType' %}
{% assign campusName = Workflow | Attribute:'Campus','Name' %}
{% assign lastAttendanceDate = Workflow | Attribute:'LastAttendanceDate' | Date:'ddd, MMM d, yyyy' %}
{% assign firstAttendanceDate = Workflow | Attribute:'FirstAttendanceDate' | Date:'ddd, MMM d, yyyy' %}
{% assign minimumAttendanceForCredit = Workflow | Attribute:'MinimumAttendanceForCredit' %}

<fieldset class="well settings">
    <table id="settings" class="table table-striped table-condensed">
        <thead>
            <tr><th>Setting</th><th>Value</th></tr>
        </thead>
        <tbody>
            <tr><td>Group</td><td>{{ group }}</td></tr>
            <tr><td>Vision Venue Type</td><td>{{ visionVenueType }}</td></tr>
            <tr><td>Campus</td><td>{{ campusName }}</td></tr>
            <tr><td>Last Attendance Date</td><td>{{ lastAttendanceDate | Date:'ddd, MMM d, yyyy' }}</td></tr>
            <tr><td>First Attendance Date</td><td>{{ firstAttendanceDate | Date:'ddd, MMM d, yyyy' }}</td></tr>
            <tr><td>Minimum Attendance Needed for Credit</td><td>{{ minimumAttendanceForCredit }}</td></tr>
        </tbody>
    </table>
</fieldset>
        
Form Footer
{% assign personCount = Workflow | Attribute:'PersonCount' | AsInteger %}
<p>Based on these settings, {{ personCount }} people will be processed.</p>
{% if personCount > 50 %}
    <div class="alert alert-info" role="alert">
        Because there are more than 50 people to process - this will need to run in the background. You will receive an email when it has finished.
        <br>
        NOTE: This can take upto an hour. If you do not have results after an hour - please email webhelp@thecrossing.church.
    </div>
{% endif %}
<h4>Do you wish to proceed using these settings?</h4>
        

WF1-Activity2-Action3-Bottom.png


Action #4: ACTIVATE: Launch WF #2 [IF UserEntry = YES]
Activate Activity action - starts "Launch WF #2" activity if UserEntry is Yes

WF1-Activity2-Action4.png


Action #5: Complete Activity
Activity Complete action - we do this for the case when the user elected not to continue - and returned to the previous page - to ensure the activity completes.

Activity #3: Launch WF #2

This activity gets the current person so we can notify them when the process completes, launches workflow #2, displays a confirmation email, and completes the workflow.

WF1-Activity3-Overview.png


Action #1: Get CurrentPerson
Attribute Set to Current Person action

WF1-Activity3-Action1.png


Action #2: Launch WF #2
Activate Workflow action

WF1-Activity3-Action2.png


Action #3: Display message
Workflow Entry Show HTML action

WF1-Activity3-Action3.png


Action #4: Complete workflow
Workflow Complete action

Activity #4: ERROR: Missing Required Settings

This activity displays an message to the user and completes the workflow.
Action #1: Display message
Workflow Entry Show HTML action

WF1-Activity4-Action1.png


Action #2: Complete workflow
Workflow Complete action

Activity #5: ERROR: No people for settings

This activity displays an message to the user and completes the workflow.
Action #1: Display message
Workflow Entry Show HTML action

WF1-Activity5-Action1.png


Action #2: Complete workflow
Workflow Complete action

Activity #6: Delete Abandoned Workflow

This is our cleanup activity. It will delay for 1 hour - then delete the workflow.
Action #1: Delay 1 hour
Delay action
Action #2: Delete workflow
Workflow Delete action

Workflow #2: Vision Venue - Wrap Up - Part 2

This workflow is NOT interactive and should only be called from workflow #1. Also - its processing interval should be set to 1 minute.

Overview

Workflow2-Overview.png


Workflow Attributes

WF2-Attributes.png


Activity #1: Begin Processing

This activity does all our prep work: building list of people to process based on inputs, determining step type to process, and kicking off the processing loop.
Action #1: Build PersonAttendanceList
Lava Run action - SQL command enabled - outputs to workflow attribute "PersonAttendanceList"
NOTE: This will be a comma-delimited list - that is made up of pipe-delimited (|) PersonId and AttendanceCount. The LOOP activity will parse these back out.
{% assign groupId = Workflow | Attribute:'Group','Id' %}
{% assign firstAttendanceDate = Workflow | Attribute:'FirstAttendanceDate' | Date:'yyyy-MM-dd' %}
{% assign lastAttendanceDate = Workflow | Attribute:'LastAttendanceDate' | Date:'yyyy-MM-dd' %}

{% sql GroupId:'{{ groupId }}' FirstDate:'{{ firstAttendanceDate }}' LastDate:'{{ lastAttendanceDate}}' %}
    SELECT
        p.[Id] AS 'PersonId'
        , COUNT(ao.[OccurrenceDate]) AS 'AttendanceCount'
    FROM
        [AttendanceOccurrence] ao
        INNER JOIN [Attendance] a on a.[OccurrenceId] = ao.[Id]
        INNER JOIN [PersonAlias] pa on pa.[Id] = a.[PersonAliasId]
        INNER JOIN [Person] p on p.[Id] = pa.[PersonId]
    WHERE
        ao.[GroupId] = @GroupId
    AND ao.[OccurrenceDate] BETWEEN @FirstDate AND @LastDate
    AND a.[DidAttend] = 'true'
    AND p.[IsDeceased] = 'false'
    GROUP BY
        p.[Id]
{% endsql %}

{% capture list %}
{% for item in results %}
    {{- item.PersonId -}}|{{- item.AttendanceCount -}}{% unless forloop.last %},{% endunless %}
{% endfor %}
{% endcapture %}
{{- list | Trim | StripNewlines -}}
        

Action #2: Determine Step Type Id
Lava Run action - outputs to workflow attribute "Step Type Id"
NOTE: You will need to update this with your own Step Type Ids
{% assign visionVenueType = Workflow | Attribute:'VisionVenueType','RawValue' %}

{% comment %}
return Step Type Id based on VisionVenueType
1 - 13 - Baptism
2 - 10 - Explorations
3 - 9 - G1 Course
4 - 11 - Leadership U
5 - 8 - Vision Dinner
{% endcomment %}

{% case visionVenueType %}
    {% when 1 %}13
    {% when 2 %}10
    {% when 3 %}9
    {% when 4 %}11
    {% when 5 %}8
{% endcase %}
        

Action #3: Determine Step Type
Lava Run action - Rock Entity command enabled - outputs to workflow attribute "Step Type"
{% assign stepTypeId = Workflow | Attribute:'StepTypeId' %}
{% steptype id:'{{ stepTypeId }}' %}
    {{ steptype.StepProgram.Guid }}|{{ steptype.Guid }}
{% endsteptype %}
        

Action #4: Calc MaxIndex
Lava Run action - outputs to workflow attribute "Max Index"
{% assign list = Workflow | Attribute:'PersonAttendanceList' %}
{% if list != '' %}
    {{ list | Split:',' | Size }}
{% else %}
    0
{% endif %}                
        

Action #5: ACTIVATE: ERROR: No people for parameters [IF MaxIndex < 1]
Activate Activity action - starts "ERROR: No people for parameters" activity if MaxIndex < 0

WF2-Activity1-Action5.png


Action #6: Delay 1 minute [IF MaxIndex > 50]
Disclaimer - really not sure why we had to do this ... but workflow #1 would time out waiting for this workflow if we didn't add this delay.

WF2-Activity1-Action6.png


Action #7: ACTIVATE: LOOP: Process PersonAttendance
Activate Activity action - starts "LOOP: Process PersonAttendance" activity

WF2-Activity1-Action7.png


Action #8: Complete Activity
Activity Complete action - since we had prior actions that were filtered - do this to ensure the activity completes.

Activity #2: LOOP: Process PersonAttendance

This is the LOOP activity. It will run once for every person on the list that was build in activity #1 ... plus one last time to stop the loop processing. For each person it will determine the status the person earned based on their attendance, look for an existing step for the person and either create a step or update the one found as needed incrementing the appropriate counter, then loop to the next person. Once the list is exhausted, it will start the wrap up activity.

WF2-Activity2-Attributes.png


Action #1: ACTIVATE: FINISH: Final Processing & Message [IF CurrentIndex <= MaxIndex]
Activate Activity action - starts "FINISH: Final Processing & Message" activity if CurrentIndex <= MaxIndex

WF2-Activity2-Action1.png


Action #2: Get PersonAttendance from List
Lava Run action - outputs to activity attribute "PersonAttendance"
NOTE: The PersonAttendance is that pipe-delimited (|) PersonId and AttendanceCount from above
{% assign array = Workflow | Attribute:'PersonAttendanceList' | Split:',' %}
{% assign maxIndex = Workflow | Attribute:'MaxIndex' %}
{% if maxIndex == '1' %}
    {{- array -}}
{% else %}
    {% assign currentIndex = Workflow | Attribute:'CurrentIndex' %}
    {{- array | Index:currentIndex -}}
{% endif %}
        

Action #3: Get Person
Lava Run action - outputs to activity attribute "Person"
{% assign personId = Activity | Attribute:'PersonAttendance' | Split:'|' | First %}
{% assign personObj = personId | PersonById %}
{{ personObj.PrimaryAlias.Guid }}
        

Action #4: Get AttendanceCount
Attribute Set Value action

WF2-Activity2-Action4.png


Action #5: Increment CurrentIndex
Attribute Set Value action

WF2-Activity2-Action5.png


Action #6: Determine Step Status Id
Lava Run action - outputs to activity attribute "Step Status Id"
{% assign minAttend = Workflow | Attribute:'MinimumAttendanceForCredit' %}
{% assign attendCnt = Activity | Attribute:'AttendanceCount' %}
{% if attendCnt >= minAttend %}
    {{ Workflow | Attribute:'StepStatusId-Completed' }}
{% else %}
    {{ Workflow | Attribute:'StepStatusId-Started' }}
{% endif %}
        

Action #7: Determine Step Status
Lava Run action - outputs to activity attribute "Step Status"
{% assign minAttend = Workflow | Attribute:'MinimumAttendanceForCredit' %}
{% assign attendCnt = Activity | Attribute:'AttendanceCount' %}
{% if attendCnt >= minAttend %}
    {{ Workflow | Attribute:'StepStatus-Completed','RawValue' }}
{% else %}
    {{ Workflow | Attribute:'StepStatus-Started','RawValue' }}
{% endif %}
        

Action #8: Find Existing Step
Lava Run action - outputs to activity attribute "Step"
NOTE: This used our StepProgramId of '3' - you will need to update this with your own StepProgramId.
{% assign prsnObj = Activity | Attribute:'Person','Object' %}
{% assign stepTypeId = Workflow | Attribute:'StepToCreate' %}
{% assign startDt = Workflow | Attribute:'FirstAttendanceDate' | Date:'yyyy-MM-dd' %}
{% assign endDt = Workflow | Attribute:'LastAttendanceDate' | Date:'yyyy-MM-dd' %}
{% assign campusId = Workflow | Attribute:'Campus','Id' %}

{% assign steps = prsnObj | Steps:'3','',stepTypeId %}
{% for step in steps %}
    {% assign stepStartDt = step.StartDateTime | Date:'yyyy-MM-dd' %}
    {% assign stepEndDt = step.EndDateTime | Date:'yyyy-MM-dd' %}
    {% if stepStartDt == startDt and stepEndDt == endDt %}
        {% if step.CampusId == campusId or campusId == empty %}
            {{ step.Guid }}
            {% break %}
        {% endif %}
    {% endif %}
{% endfor %}
        

Action #9: Change Step Action to Updated [IF STEP FOUND]
Attribute Set Value action

WF2-Activity2-Action9.png


Action #10: Create Step for Person [IF STEP NOT FOUND]
Step Add action

WF2-Activity2-Action10.png


Action #11: Update Step Completed Date [IF STATUS IS COMPLETED]
Entity Property Set action

WF2-Activity2-Action11.png


Action #12: Update Step Status [IF ACTION IS UPDATED]
Entity Property Set action

WF2-Activity2-Action12.png


Action #13: Update Step Attribute 'SessionsAttended' [IF MinAttend > 1]
Entity Attribute Set action

WF2-Activity2-Action13.png


Action #14: Increment StepsCreatedCount [IF ACTION IS CREATED]
Attribute Set Value action

WF2-Activity2-Action14.png


Action #15: Increment StepsUpdatedCount [IF ACTION IS UPDATED]
Attribute Set Value action

WF2-Activity2-Action15.png


Action #16: ACTIVATE: LOOP: Process PersonAttendance
Activate Activity action

WF2-Activity2-Action16.png


Activity #3: FINISH: Final Process & Message

This is the wrap-up activity. It will be activated once the list of people has been processed. It will email the person who kicked off the processing with final counts and complete the workflow.
Action #1: EMAIL: final message
Email Send action - sent to CurrentPerson that was passed to this workflow
For body of message:
{% assign groupName = Workflow | Attribute:'Group','Name' %}
{% assign visionVenueType = Workflow | Attribute:'VisionVenueType' %}
{% assign campusName = Workflow | Attribute:'Campus','Name' %}
{% assign lastAttendanceDate = Workflow | Attribute:'LastAttendanceDate' | Date:'ddd, MMM d, yyyy' %}
{% assign firstAttendanceDate = Workflow | Attribute:'FirstAttendanceDate' | Date:'ddd, MMM d, yyyy' %}
{% assign minimumAttendanceForCredit = Workflow | Attribute:'MinimumAttendanceForCredit' %}

<fieldset class="well settings">
    <table id="settings" class="table table-striped table-condensed">
        <thead>
            <tr><th>Setting</th><th>Value</th></tr>
        </thead>
        <tbody>
            <tr>
                <td>Group</td>
                <td>{{ groupName }}</td>
            </tr>
            <tr>
                <td>Vision Venue Type</td>
                <td>{{ visionVenueType }}</td>
            </tr>
            <tr>
                <td>Campus</td>
                <td>{{ campusName }}</td>
            </tr>
            <tr>
                <td>Last Attendance Date</td>
                <td>{{ lastAttendanceDate | Date:'ddd, MMM d, yyyy' }}</td>
            </tr>
            <tr>
                <td>First Attendance Date</td>
                <td>{{ firstAttendanceDate | Date:'ddd, MMM d, yyyy' }}</td>
            </tr>
            <tr>
                <td>Minimum Attendance Needed for Credit</td>
                <td>{{ minimumAttendanceForCredit }}</td>
            </tr>
        </tbody>
    </table>
</fieldset>
<hr>
<fieldset class="well results">
    <h4>SUCCESS!</h4>
    <table id="results" class="table table-striped table-condensed">
        <thead><tr><th colspan='3'>Here are the final counts:</th></tr></thead>
        <tbody>
            <tr>
                <td colspan='2'>Total People Processed</td>
                <td>{{ Workflow | Attribute:'MaxIndex' }}</td>
            </tr>
        </tbody>
        <thead>
            <tr><th colspan='3'>Steps</th></tr>
        </thead>
        <tbody>
            <tr>
                <td></td>
                <td>Created</td>
                <td>{{ Workflow | Attribute:'StepsCreatedCount' }}</td>
            </tr>
            <tr>
                <td></td>
                <td>Updated</td>
                <td>{{ Workflow | Attribute:'StepsUpdatedCount' }}</td>
            </tr>
        </tbody>
    </table>
</fieldset>
<br>
        

Action #2: Complete workflow
Workflow Complete action

Activity #4: ERROR: No People

Action #1: EMAIL: No People
Email Send action - sent to CurrentPerson that was passed to this workflow
For body of message:
<div class="alert alert-warning" role="alert">
    <h4 class="alert-heading">No people found for the supplied parameters!</h4>
    <p>
        Please confirm the parameters and try again.
    </p>
</div>

{% assign groupName = Workflow | Attribute:'Group','Name' %}
{% assign visionVenueType = Workflow | Attribute:'VisionVenueType' %}
{% assign campusName = Workflow | Attribute:'Campus','Name' %}
{% assign lastAttendanceDate = Workflow | Attribute:'LastAttendanceDate' | Date:'ddd, MMM d, yyyy' %}
{% assign firstAttendanceDate = Workflow | Attribute:'FirstAttendanceDate' | Date:'ddd, MMM d, yyyy' %}
{% assign minimumAttendanceForCredit = Workflow | Attribute:'MinimumAttendanceForCredit' %}

<fieldset class="well settings">
    <table id="settings" class="table table-striped table-condensed">
        <thead>
            <tr><th>Setting</th><th>Value</th></tr>
        </thead>
        <tbody>
            <tr>
                <td>Group</td>
                <td>{{ groupName }}</td>
            </tr>
            <tr>
                <td>Vision Venue Type</td>
                <td>{{ visionVenueType }}</td>
            </tr>
            <tr>
                <td>Campus</td>
                <td>{{ campusName }}</td>
            </tr>
            <tr>
                <td>Last Attendance Date</td>
                <td>{{ lastAttendanceDate | Date:'ddd, MMM d, yyyy' }}</td>
            </tr>
            <tr>
                <td>First Attendance Date</td>
                <td>{{ firstAttendanceDate | Date:'ddd, MMM d, yyyy' }}</td>
            </tr>
            <tr>
                <td>Minimum Attendance Needed for Credit</td>
                <td>{{ minimumAttendanceForCredit }}</td>
            </tr>
        </tbody>
    </table>
</fieldset>
        

Action #2: Complete workflow
Workflow Complete action

Final Thoughts

First - congratulations for making it all the way to the end. This turned out to be a much longer one than I originally anticipated.

I indicated that this recipe requires Rock v1.13.x or higher. This is primarily because of the Lava filter "Steps" used in the Lava action that looks for an existing step for the person. If you remove this filter and go with an entity command instead, then I believe you only have to be at Rock v1.10 or 1.11. I cannot confirm this as this was all developed under Rock v1.13.

If you aren't super comfortable or familiar with loop processing in workflows - BlueBoxMoon has a great plug-in "Workflow Stimpack" that includes a workflow action called "For Each" which handles all the loop processing for you.