/// <summary>
        /// Gets the expression.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="entityIdProperty">The entity identifier property.</param>
        /// <param name="selection"></param>
        /// <returns></returns>
        public override Expression GetExpression(RockContext context, MemberExpression entityIdProperty, string selection)
        {
            // transactions
            var transactionDetails = context.Set <FinancialTransactionDetail>();

            // t
            ParameterExpression transactionDetailParameter = Expression.Parameter(typeof(FinancialTransactionDetail), "t");

            // t.Transaction
            MemberExpression transactionProperty = Expression.Property(transactionDetailParameter, "Transaction");

            // t.Transaction.AuthorizedPersonAlias
            MemberExpression authorizedPersonAliasProperty = Expression.Property(transactionProperty, "AuthorizedPersonAlias");

            // t.Transaction.AuthorizedPersonAlias.PersonId
            MemberExpression authorizedPersonIdProperty = Expression.Property(authorizedPersonAliasProperty, "PersonId");

            // t.Transaction.AuthorizedPersonAlias.PersonId == Convert(p.Id)
            Expression whereClause = Expression.Equal(authorizedPersonIdProperty, Expression.Convert(entityIdProperty, typeof(int)));

            // t.Transaction.TransactionTypeValueId
            MemberExpression transactionTypeValueIdProperty = Expression.Property(transactionProperty, "TransactionTypeValueId");

            int transactionTypeContributionId = DefinedValueCache.Get(Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION.AsGuid()).Id;

            // t.Transaction.TransactionTypeValueId == transactionTypeContributionId
            whereClause = Expression.And(whereClause, Expression.Equal(transactionTypeValueIdProperty, Expression.Constant(transactionTypeContributionId)));

            // get the selected AccountId(s).  If there are any, limit to transactions that for that Account
            if (!string.IsNullOrWhiteSpace(selection))
            {
                // accountIds
                var selectedAccountGuidList = selection.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries).AsGuidList();
                var selectedAccountIdList   = new FinancialAccountService(context).GetByGuids(selectedAccountGuidList).Select(a => a.Id).ToList();

                if (selectedAccountIdList.Count() > 0)
                {
                    // t.AccountId
                    MemberExpression accountIdProperty = Expression.Property(transactionDetailParameter, "AccountId");

                    // accountIds.Contains(t.AccountId)
                    Expression selectedAccountIds = Expression.Constant(selectedAccountIdList);
                    Expression containsExpression = Expression.Call(selectedAccountIds, "Contains", new Type[] { }, accountIdProperty);

                    // t.authorizedPersonId == Convert(p.Id) && accountIds.Contains(t.AccountId)
                    whereClause = Expression.And(whereClause, containsExpression);
                }
            }

            // t => t.Transaction.AuthorizedPersonId == Convert(p.Id)
            var compare = new Expression[] {
                Expression.Constant(transactionDetails),
                Expression.Lambda <Func <FinancialTransactionDetail, bool> >(whereClause, new ParameterExpression[] { transactionDetailParameter })
            };

            // transactions.Where( t => t.Transaction.AuthorizedPersonId == Convert(p.Id)
            Expression whereExpression = Expression.Call(typeof(Queryable), "Where", new Type[] { typeof(FinancialTransactionDetail) }, compare);

            // t.Transaction.TransactionDateTime
            MemberExpression transactionDateTime = Expression.Property(transactionProperty, "SundayDate");

            // t => t.Transaction.transactionDateTime
            var transactionDate = Expression.Lambda <Func <FinancialTransactionDetail, DateTime?> >(transactionDateTime, new ParameterExpression[] { transactionDetailParameter });

            // transaction.Where( t => t.Transaction.AuthorizedPersonId == Convert(p.Id).Max( t => t.Transaction.transactionDateTime)
            string     methodName       = FirstOrLast == FirstLast.Last ? "Max" : "Min";
            Expression maxMinExpression = Expression.Call(typeof(Queryable), methodName, new Type[] { typeof(FinancialTransactionDetail), typeof(DateTime? ) }, whereExpression, transactionDate);

            return(maxMinExpression);
        }
        /// <summary>
        /// Gets the expression.
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="entityIdProperty">The entity identifier property.</param>
        /// <param name="selection"></param>
        /// <returns></returns>
        public override Expression GetExpression( RockContext context, MemberExpression entityIdProperty, string selection )
        {
            // transactions
            var transactionDetails = context.Set<FinancialTransactionDetail>();

            // t
            ParameterExpression transactionDetailParameter = Expression.Parameter( typeof( FinancialTransactionDetail ), "t" );

            // t.Transaction
            MemberExpression transactionProperty = Expression.Property( transactionDetailParameter, "Transaction" );

            // t.Transaction.AuthorizedPersonAlias
            MemberExpression authorizedPersonAliasProperty = Expression.Property( transactionProperty, "AuthorizedPersonAlias" );

            // t.Transaction.AuthorizedPersonAlias.PersonId
            MemberExpression authorizedPersonIdProperty = Expression.Property( authorizedPersonAliasProperty, "PersonId" );

            // t.Transaction.AuthorizedPersonAlias.PersonId == Convert(p.Id)
            Expression whereClause = Expression.Equal( authorizedPersonIdProperty, Expression.Convert( entityIdProperty, typeof( int ) ) );

            // t.Transaction.TransactionTypeValueId
            MemberExpression transactionTypeValueIdProperty = Expression.Property( transactionProperty, "TransactionTypeValueId" );

            int transactionTypeContributionId = Rock.Web.Cache.DefinedValueCache.Read( Rock.SystemGuid.DefinedValue.TRANSACTION_TYPE_CONTRIBUTION.AsGuid() ).Id;

            // t.Transaction.TransactionTypeValueId == transactionTypeContributionId
            whereClause = Expression.And( whereClause, Expression.Equal( transactionTypeValueIdProperty, Expression.Constant( transactionTypeContributionId ) ) );

            // get the selected AccountId(s).  If there are any, limit to transactions that for that Account
            if ( !string.IsNullOrWhiteSpace( selection ) )
            {
                // accountIds
                var selectedAccountGuidList = selection.Split( new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries ).AsGuidList();
                var selectedAccountIdList = new FinancialAccountService( context ).GetByGuids( selectedAccountGuidList ).Select( a => a.Id ).ToList();

                if ( selectedAccountIdList.Count() > 0 )
                {
                    // t.AccountId
                    MemberExpression accountIdProperty = Expression.Property( transactionDetailParameter, "AccountId" );

                    // accountIds.Contains(t.AccountId)
                    Expression selectedAccountIds = Expression.Constant( selectedAccountIdList );
                    Expression containsExpression = Expression.Call( selectedAccountIds, "Contains", new Type[] { }, accountIdProperty );

                    // t.authorizedPersonId == Convert(p.Id) && accountIds.Contains(t.AccountId)
                    whereClause = Expression.And( whereClause, containsExpression );
                }
            }

            // t => t.Transaction.AuthorizedPersonId == Convert(p.Id)
            var compare = new Expression[] {
                    Expression.Constant(transactionDetails),
                    Expression.Lambda<Func<FinancialTransactionDetail, bool>>( whereClause, new ParameterExpression[] { transactionDetailParameter } )
                };

            // transactions.Where( t => t.Transaction.AuthorizedPersonId == Convert(p.Id)
            Expression whereExpression = Expression.Call( typeof( Queryable ), "Where", new Type[] { typeof( FinancialTransactionDetail ) }, compare );

            // t.Transaction.TransactionDateTime
            MemberExpression transactionDateTime = Expression.Property( transactionProperty, "SundayDate" );

            // t => t.Transaction.transactionDateTime
            var transactionDate = Expression.Lambda<Func<FinancialTransactionDetail, DateTime?>>( transactionDateTime, new ParameterExpression[] { transactionDetailParameter } );

            // transaction.Where( t => t.Transaction.AuthorizedPersonId == Convert(p.Id).Max( t => t.Transaction.transactionDateTime)
            string methodName = FirstOrLast == FirstLast.Last ? "Max" : "Min";
            Expression maxMinExpression = Expression.Call( typeof( Queryable ), methodName, new Type[] { typeof( FinancialTransactionDetail ), typeof( DateTime? ) }, whereExpression, transactionDate );

            return maxMinExpression;
        }