Archive for the ‘ Uncategorized ’ Category

Refactoring and Improving…Fixing Roll-Up Summaries

After I posted this: http://wp.me/p1xleL-1w, Daniel Llewellyn (@Kenji776) commented that this could also be done using sub-queries. I recognized immediately that I he was right and my code was not as efficient as it could be. I finally found some time to refactor and what resulted is simpler and more efficient code.

The biggest change to the previous post is selecting the opportunities in a sub-select while querying the accounts:

select Id, Name, Total_Number_of_Opportunities__c,
Num_of_Won_Opportunities__c, Num_of_Closed_Opportunities__c,
(select Id, IsWon, IsClosed from Opportunities)
from Account where Id IN :accountIdSet

The main idea to take away from this is that we are selecting the accounts and ALL of the associated opportunities in a single select statement rather than selecting accounts, then selecting Opportunities. Also beyond reducing the number of SOQL to just one, we also eliminate the need to create a map of Account Ids to lists of opportunities.

I also want to point out that in the sub-select query we are querying “from Opportunities” not  “from Opportunity”. By querying Opportunities we are telling Salesforce.com to pull from just the opportunities tied to each account (and to group them by each account). For custom objects you will need to determine the child relationship name and then query that. For example, if you have a lookup field from the “Part” object to the “Car” object the Child Relationship Name (found on the lookup field detail) might be “Parts”. This means if you wanted to select all carss and the associated parts your query might look like this:

List<Car> carList = [select Id, Name, (select Id, Name from Parts__r) from Car];
for(Car c : carList){
  for(Part p : c.Parts__r){
    ...do stuff here...
  }
}

While this doesn’t greatly increase the  speed of a single opportunity update , imagine doing a bulk update all of your opportunities where you have an average of 25 opportunities per account. Since we no longer create a mapping of every account to its opportunities we greatly reduce the number of script statements need to get the job done.

So here is the updated code to perform roll-up summaries (And yes, I know this can be done using roll-up summary fields, but since I posted this example already, I am sticking with it.):

trigger updateAccountOpportunityCounts on Opportunity (after insert, after update, after delete, after undelete) {

    /*Create a Set to hold Acct Ids of opps in triger
      and a List to hold accts which will be updated*/
    Set<Id> accountIdSet = new Set<Id>();
    List<Account> accountUpdateList = new List<Account>();

    /*Create ths set of Account IDs.
      If this is a delete trigger, pull them the trigger.old,
      otherwise from trigger.new*/
    if(Trigger.isDelete)
        for(Opportunity o : trigger.old)
            accountIdSet.add(o.AccountId);
    else
        for(Opportunity o : trigger.new)
            accountIdSet.add(o.AccountId);

    /*Query for all of the accounts assoicated with the
      opportunities in the trigger using the above created set of Ids*/
    List<Account> acctOpptyList = [select Id, Name, Total_Number_of_Opportunities__c,
    			Num_of_Won_Opportunities__c, Num_of_Closed_Opportunities__c,
                (select Id, IsWon, IsClosed from Opportunities)
                from Account where Id IN :accountIdSet];

	/*loop through all of the accounts in the map and get
	  the counts for total number of opps,
	  count of closed and count of won opps.*/
    for(Account a : acctOpptyList){
        //initialize our counters
        Integer wonOpps = 0;
        Integer closedOpps = 0;

        //loop through the associated opportunities and count up the opportunities
        for(Opportunity o : a.Opportunities){
            if(o.IsClosed){
            	closedOpps++;
            	/*can't be won without being closed, reduce script statements
            	  by checking this inside IsClosed check*/
            	if(o.IsWon) wonOpps++;
            }
        }

        //set the counts
        a.Total_Number_of_Opportunities__c = a.Opportunities.size();
        a.Num_of_Won_Opportunities__c = wonOpps;
        a.Num_of_Closed_Opportunities__c = closedOpps;

        //add the account to the update list
        accountUpdateList.add(a);
    }

    //update all of the accounts if the list isn't empty
	if(!accountUpdateList.IsEmpty()) update accountUpdateList;
}

Creating Rollup Summaries for Standard to Standard Objects

Update: @hammnick pointed out that you can in fact do this using roll-up summaries. I swear I checked this before hand and it wasn’t working. Regardless, I will keep this post up as I think it provides a useful learning tool. This would be more useful in a situation where you do not have a Master-Detail relationship and still want to gather counts. I am glad I didn’t spend too much time in this!

I was reading through @nikpanter‘s blog a little while ago and came across this post about learning Apex: http://www.xlerate.ca/nik/?p=165. In that post Nik mentioned writing a trigger to count the number of opportunities tied to an account as well as the number of won and number of closed opportunities. I reached out to Nik and confirmed that he hadn’t written this trigger and then proceeded to write it myself.

Since we are keeping track of opportunity counts on the account, we need to remember to update the account whenever an opportunity is inserted, updated, deleted or undeleted. We can calculate the stats after each of these actions are done so this will be an ‘After’ trigger for each of those events on the opportunity object.

We will need three custom fields on the Account to hold the values. I created the following fields:

  • Total # of Opportunities (Total_Number_of_Opportunities__c)
  • # of Closed Opportunities (Num_of_Closed_Opportunities__c)
  • # of Won Opportunities (Num_of_Won_Opportunities__c)
My approach was to first get all of the accounts tied to the opportunities in the trigger.  Once I had those, I could then query for ALL of the opportunities tied to each of those accounts and then count up each of our stats. I added the accounts to a map with a list of the opportunities so that we could check the size of each list tied to an opportunity in order to get the opportunity stats.
Since this is a trigger it will only take effect once an action is taken on an opportunity. You will want to perform an update on all of your opportunities to prompt the update of the account stats. You can use the data loader to export just the Id of all opportunities and then use that file to ‘update’ the opportunities, causing the trigger to fire and your accounts to be updated.
Trigger
trigger updateAccountOpportunityCounts on Opportunity (after insert, after update, after delete, after undelete) {

    ////////////////////////////////////////////////////
    //Set up Map, a Set and a List
    //Map will hold accounts and all opportunities tied to it
    //Set will hold Ids of accounts for the opportunities in the trigger
    //List to hold accounts which we will be updating
    ////////////////////////////////////////////////////
    Map<Account, List<Opportunity>> totalCountMap = new Map<Account, List<Opportunity>>();
    Set<Id> accountIdSet = new Set<Id>();
    List<Account> accountUpdateList = new List<Account>();

    ////////////////////////////////////////////////////
    //Create the set of Account IDs.
    //If this is a delete trigger, pull them the trigger.old, otherwise from trigger.new
    ////////////////////////////////////////////////////
    if(Trigger.isDelete)
        for(Opportunity o : trigger.old)
            accountIdSet.add(o.AccountId);
    else
        for(Opportunity o : trigger.new)
            accountIdSet.add(o.AccountId);

    //Query for all of the accounts assoicated with the opportunities in the trigger using the above created set of Ids
    Map<Id, Account> accountMap = new Map<Id, Account>([select Id, Name, Total_Number_of_Opportunities__c, Num_of_Won_Opportunities__c, Num_of_Closed_Opportunities__c  from Account where Id IN :accountIdSet]);

    ////////////////////////////////////////////////////
    //loop through each of the opportunities associated with the above accounts
    //add them to lists in the totalCountMap
    //**Note that in a delete trigger (since this is after delete), any deleted opportunities will NOT appear in the query
    ////////////////////////////////////////////////////
    for(Opportunity o: [select Id, AccountId, IsWon, IsClosed from Opportunity where AccountId IN :accountMap.keySet()]){

        //temporarily list to either get existing list from Map or insert new list to map
        List<Opportunity> tempList = new List<Opportunity>();

        //if this account already exists, get the list of opportunities so we can add this opportunity to it.
        if(totalCountMap.containsKey(accountMap.get(o.AccountId)))
            tempList = totalCountMap.get(accountMap.get(o.AccountId));

        //add the opportunity to the list (whether it is new or existing)
        tempList.add(o);

        //Add the Account and list of opportunites into the Map. This will replace a map entry if it already exists
        totalCountMap.put(accountMap.get(o.AccountId),tempList);
    }

    ////////////////////////////////////////////////////
    //loop through all of the accounts in the map and get the counts for total number of opps,
    //count of closed and count of won opps.
    ////////////////////////////////////////////////////
    for(Account a : totalCountMap.keySet()){
        //initialize our counters
        Integer wonOpps = 0;
        Integer closedOpps = 0;

        //loop through the associated opportunities and count up the opportunities
        for(Opportunity o : totalCountMap.get(a)){
            if(o.IsClosed){
                closedOpps++;
                if(o.IsWon) wonOpps++; //can't be won without being closed, reduce script statments by checking this here
            }
        }

        //set the counts
        a.Total_Number_of_Opportunities__c = totalCountMap.get(a).size();
        a.Num_of_Won_Opportunities__c = wonOpps;
        a.Num_of_Closed_Opportunities__c = closedOpps;

        //add the account to the list
        accountUpdateList.add(a);
    }

    //update all of the accounts if the list isn't empty
    if(!accountUpdateList.IsEmpty()) update accountUpdateList;
}
Of course we need to test the trigger as well. My test class creates 200 opportunities and adds them to an account. It then updates deletes and undeletes opportunities confirming the proper number of accounts each time:
Test Class
@isTest
private class testUpdateAccountOpportunityCounts {

    static testMethod void myUnitTest() {
        //Create an account
        Account a = new Account(Name='My Freakin Awesome Test Account');
        insert a;

        //create, say, 200 opportunites attached to said account
        List<Opportunity> oList = new List<Opportunity>();
        for(Integer i=1; i<201; i++){
          oList.add(new Opportunity(Name='Opportunity ' + i,
                        AccountId=a.id,
                        StageName='Qualification',
                        closeDate=Date.newInstance(2100,01,01)
                        )
         );
        }
        insert oList;

        //Make sure we actually have 200 opportunities and none of them are closed or closed won.
        a = [select Total_Number_of_Opportunities__c, Num_of_Won_Opportunities__c, Num_of_Closed_Opportunities__c from Account where Id = :a.id limit 1];
        System.assertEquals(200, a.Total_Number_of_Opportunities__c);
        System.assertEquals(0, a.Num_of_Won_Opportunities__c);
        System.assertEquals(0, a.Num_of_Closed_Opportunities__c);

        //Now let's close half of the opportunities, 50 of those won, other 50 lost
        for(Integer i=0; i<100; i++){
          if(i<50)
            oList[i].StageName='Closed Won';
          else
            oList[i].StageName='Closed Lost';
        }

        update oList;
        a = [select Total_Number_of_Opportunities__c, Num_of_Won_Opportunities__c, Num_of_Closed_Opportunities__c from Account where Id = :a.id limit 1];
        System.assertEquals(200, a.Total_Number_of_Opportunities__c);
        System.assertEquals(50, a.Num_of_Won_Opportunities__c);
        System.assertEquals(100, a.Num_of_Closed_Opportunities__c);

        //Let's delete some opportunities now (going to delete every other in the list)
        List<Opportunity> deleteList = new List<Opportunity>();
        for(Integer i=0; i<200; i++){
          deleteList.add(oList[i]);
          i++; //to skip every other
        }

        delete deleteList;
        a = [select Total_Number_of_Opportunities__c, Num_of_Won_Opportunities__c, Num_of_Closed_Opportunities__c from Account where Id = :a.id limit 1];
        System.assertEquals(100, a.Total_Number_of_Opportunities__c);
        System.assertEquals(25, a.Num_of_Won_Opportunities__c);
        System.assertEquals(50, a.Num_of_Closed_Opportunities__c);

        //Finally, let's undelete the deleted opportunities
        undelete deleteList;
        a = [select Total_Number_of_Opportunities__c, Num_of_Won_Opportunities__c, Num_of_Closed_Opportunities__c from Account where Id = :a.id limit 1];
        System.assertEquals(200, a.Total_Number_of_Opportunities__c);
        System.assertEquals(50, a.Num_of_Won_Opportunities__c);
        System.assertEquals(100, a.Num_of_Closed_Opportunities__c);

    }
}

You can install this trigger and class along with the above three fields. You will need to add the fields to your page layouts if you choose too.
https://login.salesforce.com/packaging/installPackage.apexp?p0=04tE00000000Rnx

Oops! I Didn’t Want to Dismiss All

The infamous Matt Brown threw out a question the other day

After some back and forth with Matt it turned out there are many questions on the Salesforce.com Answers forums related to getting reminders back after a user clicks ‘Dismiss All’ on the reminders pop up. I decided to give this a stab and the following is the result.

I created a Visualforce Page that simply has a button on it along with a disclaimer of what the button will do.

<apex:page controller="resetReminderController" sidebar="false">
    <apex:form >
        <apex:panelGrid columns="2">
            <apex:outputPanel >
                <apex:outputText >
                    <br/><br/>
                    To reset all of your <b>open</b> task and <b>future</b> event reminders click the button.<br/>
                    Any open tasks and any future events will have the reminders turned on. <br/><br/>
                </apex:outputText>
            </apex:outputPanel>
            <apex:commandButton value="Reset Reminders" action="{!processItems}"/>
        </apex:panelGrid>
    </apex:form>

    <apex:outputText value="No tasks or events processed" rendered="{!noRecords}" style="color:red"/>

    <apex:pageBlock title="Updated Tasks" tabStyle="Task" rendered="{!RenderTasks}" id="theTasks">
        <apex:pageBlockTable value="{!updateTaskList}" var="ut">
            <apex:column value="{!ut.Subject}"/>
            <apex:column value="{!ut.ActivityDate}"/>
            <apex:column value="{!ut.IsReminderSet}"/>
            <apex:column value="{!ut.ReminderDateTime}"/>
            <apex:column value="{!ut.whoId}"/>
            <apex:column value="{!ut.whatId}"/>
        </apex:pageBlockTable>
    </apex:pageBlock>

    <apex:pageBlock title="Updated Events" tabStyle="Event" rendered="{!RenderEvents}" id="theEvents">
        <apex:pageBlockTable value="{!updateEventList}" var="ue">
            <apex:column value="{!ue.Subject}"/>
            <apex:column value="{!ue.ActivityDate}"/>
            <apex:column value="{!ue.IsReminderSet}"/>
            <apex:column value="{!ue.ReminderDateTime}"/>
            <apex:column value="{!ue.whoId}"/>
            <apex:column value="{!ue.whatId}"/>
        </apex:pageBlockTable>
    </apex:pageBlock>
</apex:page>

The main purpose of the controller is to query for all open tasks and future events owned by the current user and set the reminder flag to true, allowing them to show up in the reminder pop-up when logging in. The controller will not set the reminder flag for any Tasks that never had a reminder set.  We know this because the Reminder Date is null.  Had it been set previously, it would still be set; the reminder flag was just unchecked.

public with sharing class resetReminderController {

    public List&lt;Task&gt; updateTaskList {get;set;}
    public List&lt;Event&gt; updateEventList {get;set;}
    public Boolean noRecords {get;set;}

    //This is our constructor. initialize the lists and noRecords
    public resetReminderController(){
        updateTaskList = new List&lt;Task&gt;();
        updateEventList = new List&lt;Event&gt;();
        noRecords=false;
    }

    public boolean getRenderTasks(){
        return !updateTaskList.IsEmpty();
    }

    public boolean getRenderEvents(){
        return !updateEventList.IsEmpty();
    }

    public void processItems(){
        //make sure the lists are clear
        updateTaskList.clear();
        updateEventList.clear();

        //if there are no records, we want to display that message to the user
        noRecords=true;

        //loop though users open tasks and update any task with no reminder.  if reminder date is null, then reminder was never set in the first place
        for(Task t : [select Id, Subject, ActivityDate, ReminderDateTime, IsReminderSet, whoId, whatId from Task where OwnerId = :UserInfo.getUserId() and IsClosed=false]){
            if(!t.IsReminderSet &amp;&amp; t.ReminderDateTime &lt;&gt; null){
                t.IsReminderSet = true;
                updateTaskList.add(t);
            }
        }

       //loop through all future events and turn on the reminder.  since reminder for events is a picklist, it won't be null. no need to account for that
       for(Event e : [select Id, Subject, ActivityDate, ReminderDateTime, IsReminderSet, whoId, whatId from Event where OwnerId = :UserInfo.getUserId() AND (ActivityDateTime &gt;= :DateTime.now() OR ActivityDate &gt;= :Date.Today()) ]){
            if(!e.IsReminderSet){
                e.IsReminderSet = true;
                updateEventList.add(e);
            }
        }

        //update any tasks that were changed
        if(!updateTaskList.IsEmpty()){
            update updateTaskList;
            noRecords=false;
        }

        //update any events that were changed
        if(!updateEventList.IsEmpty()){
            update updateEventList;
            noRecords=false;
        }
    }
}

Finally, I created a very simply home page component with a link to the visualforce page. The component name is “Reset Reminders For My Open Tasks and Event” and the html (be sure to check the ‘show html’ checkbox) is:

&lt;a href=&quot;/apex/resetReminders&quot;&gt;Click here&lt;/a&gt; to reset the reminders for tasks and events.&lt;div&gt;&lt;br&gt;&lt;/div&gt;

I figured the easiest way to show the functionality was with a quick demo.

Finally, you can install an unmanaged package of the home page component (don’t forget to add it to a page layout), visualforce page, controller and test method with this link:
https://login.salesforce.com/packaging/installPackage.apexp?p0=04tE00000000RkA
*Remember, you can change the path to https://test.salesforce.com&#8230; to install to a sandbox.

Overcoming Visualforce Standard List Controller Issue

I ran into an interesting issue while using a standard list controller on a visualforce page today.  This page has been working fine for a while but recently encountered an error due to a new trigger.  The trigger was “bulkified” so I found it odd that the following error was being thrown:

System.LimitException: Too many SOQL queries: 101

Let me set this up for you.  The visualforce page is a simple page (edited here to be even simpler) that is invoked from a list of opportunities.  The user can select any opportunities in the list view, click Edit Selected Opportunities and quickly update basic info on the opportunities (there are more fields on the actual page, but I will just include Name and Stage for brevity).

List View:

VisualforcePage:

Visualforce Code:

<apex:page standardController="Opportunity" recordSetVar="opps" sidebar="false">
    <apex:form id="theForm">
    <apex:pageBlock >
        <apex:pageMessages />

        <apex:pageBlockButtons >
            <apex:commandButton action="{!save}" value="Save All and Close"/>
            <apex:commandButton action="{!cancel}" value="Cancel"/>
        </apex:pageBlockButtons>

        <apex:pageBlockTable width="100%" value="{!selected}" var="o" id="theUSList" rendered="{!$User.US_User__c}">
            <apex:column value="{!o.AccountId}"/>

            <apex:column headerValue="Opportunity Name">
                <apex:inputField value="{!o.Name}"/>
            </apex:column>

            <apex:column HeaderValue="Stage">
                <apex:inputField value="{!o.StageName}"/>
            </apex:column>

        </apex:pageBlockTable>
    </apex:pageBlock>
    </apex:form>
</apex:page>

Problem

One of my users was using the tool after a new trigger was implemented and ran into the above mentioned error. It turned out that he was working with 53 records, which should work fine.

After some investigation it turned out that the standard save functionality was saving each record individually. These individual saves caused the trigger to fire for each record, rather than working on the set in bulk. Not cool salesforce.com, not cool at all. The problem was, there are 2 SOQL statements in the trigger so anything more than 50 records exceeded the limit of 100 SOQL queries. So to counteract this issue I wrote a controller extension which simply grabs the selected opportunities and saves them when the button is clicked.

Note, I had to change two lines in the above VF code

1. The page tag was changed to :


<apex:page standardController="Opportunity" <strong>extensions="selectedOpportunityEditorExtension"</strong> recordSetVar="opps" sidebar="false">

2. The save button was chaged to:


<apex:commandButton action="{!save<strong>Records</strong>}" value="Save All and Close"/>

Apex Class


public with sharing class selectedOpportunityEditorExtension {

    //Our list of opportunities to work on
    private final List<Opportunity> opps;

    //set the list to the selected opportunites. Same list that the page is working on
    public selectedOpportunityEditorExtension(ApexPages.StandardSetController controller) {
        this.opps = controller.getSelected();
    }

    //save the opportunities and return a page refernce to the retURL
    public PageReference SaveRecords(){
    	update opps;
    	PageReference pageRef = new PageReference(ApexPages.currentPage().getParameters().get('retURL'));
    	return pageRef;
    }
}

Test Method

@isTest
private class testSelectedOpportunityEditorExtension {

    static testMethod void myUnitTest() {
        //set up the page reference to the selectedOpportunityEditor and add retURL param
        PageReference pageRef = new PageReference('SelectedOpportunityEditor');
        //add the return URL to the list view
        pageRef.getParameters().put('retURL','/006');
        Test.setCurrentPageReference(pageRef);

        List<Opportunity> oppsList = new List<Opportunity>();
        //Use the current user as owner of new opps
        Id owner = UserInfo.getUserId();
        //Create 101 new opportunties to test with
        for(Integer i=1; i<102; i++){
        	oppsList.add(new Opportunity(Name='Opportunity ' + i,
        								 OwnerId = owner,
        								 Net_Gain__c = 100,
        								 StageName = 'Some Stage',
        								 Probability = 0.2,
        								 CloseDate=Date.newInstance(2100,01,01),
        								 Description='A description',
        								 Sales_Manager__c=owner

        	));
        }
        insert oppsList;

        //set up the set controller then select all opps
        ApexPages.StandardSetController ssc = new ApexPages.StandardSetController(oppsList);
        ssc.setSelected(oppsList);

        //initialize the extension
        selectedOpportunityEditorExtension sOEE = new selectedOpportunityEditorExtension(ssc);

        //Start the test
        Test.startTest();
        //get selected opportunites and change the Net gain for each
        List<Opportunity> loopList = ssc.getSelected();
        for(Opportunity o : loopList){
        	o.Net_Gain__c = 200;
        }

        //call the save records method and make sure it returns the right pagereference
        system.assertEquals('/006', sOEE.SaveRecords().getUrl() );

        //Check that all opportunities were in fact updated
        loopList = ssc.getSelected();
        for(Opportunity o : loopList){
        	System.AssertEquals(200, o.Net_Gain__c);
        }

        Test.stopTest();
    }
}

I hope that this proves useful for somebody. Please note the above code may be altered for this post and is specific to my companies org so it won’t work for you. It is just meant to serve as an example.

A special thanks to Alex Berg for helping me work though this issue.

Trigger to Deactivate Users

Kevin O’Hara posed a question on twitter:

Elizabeth Davidson liked the idea and posed another question:

After some back and forth on this topic Kevin mentioned:

So I decided to implement it.  Feel free to steal the code below.  The code does assume two three things.

  1. You have a profile called ‘DEACTIVATED’ – I made this the most barebones (ie useless) profile I could
  2. You have a field called Notes (Notes__c)
  3. You have an available license to create the user in the test code [Updated: Thanks Jay!]

The trigger simply looks for a user update and checks if the Profile has been changed to DEACTIVATED.  If so, it will set the users IsActive flag to false and add the name of the old profile to Notes__c. If you do this from the UI (rather than, say, the Data Loader) you will be redirected to the “Remove user from all Opportunities, etc.” screen.

So here is what I have

The trigger [updated, there was a typo due to copy-paste; Thanks Kevin!]:

trigger DeactivatedUser on User (before update) {

    //We need the Id of our 'DEACTIVATED' profile
    List<Profile> profileList = [select id from Profile where name = 'DEACTIVATED' limit 1];

    //If the Deactivated profile exists, process records
    if(!profileList.IsEmpty()){
        Id deactivatedProfile = profileList[0].Id;

        //Create a map of all profiles.  We will need this to add the old profile name
        //to the Notes__c field
        Map<Id, Profile> profileMap = new Map<Id, Profile>();
        profileMap.putAll([select Id, Name from Profile]);

        //Loop through users in trigger and process accordingly
        for(Integer i=0; i<Trigger.new.size(); i++){
            User u = Trigger.new[i];
            //process user if profile is the DEACTIVATED profile
            if(u.ProfileId == deactivatedProfile){
                u.IsActive = false;
                //set the Notes__c field accordingly
                if(trigger.old[i].ProfileId <> trigger.new[i].ProfileId){
                    if(u.Notes__c <> null)
                        u.Notes__c += '--Old Profile: ' + profileMap.get(Trigger.old[i].ProfileId).Name;
                    else
                        u.Notes__c = 'Old Profile: ' + profileMap.get(Trigger.old[i].ProfileId).Name;
                }
            }
        }
    }
}

And the test Class:

@isTest
private class testDeactivatedUser {

    static testMethod void myUnitTest() {
        Id initialProfile =  [Select Id from Profile where Name != 'DEACTIVATED' limit 1].Id;
        Id deactivatedProfile =  [Select Id from Profile where Name = 'DEACTIVATED'limit 1].Id;
        //Create user
        User u = new User(LastName='TestUser',
                          Alias='testAlia',
                          Email='someone@email.com',
                          Username='someone@email.com.dev',
                          CommunityNickname='some.one',
                          profileId=initialProfile,
                          TimeZoneSidKey='America/New_York',
                          LocaleSidKey='en_Us',
                          EmailEncodingKey='ISO-8859-1',
                          LanguageLocaleKey='en_US');
        insert u;
        //update user profile to deactivated we expect the user to be deactivated and
        //the old profile name to be added to the notes
        u.profileId=deactivatedProfile;
        update u;
        //Query for the user details
        u = [select Id, IsActive, Notes__c from User where id = :u.id];
        //verify that user is inactive and notes are not null
        System.assertEquals(false, u.IsActive);
        System.assertNotEquals(null, u.Notes__c);

        //test that the Notes aren't updated when the profile isn't changed
        Integer notesLength = u.Notes__c.length();
        update u;
        u = [select Id, IsActive, Notes__c from User where id = :u.id];
        System.assertEquals(notesLength, u.Notes__c.length());

        //set profile back to initial profile so we can trigger the deactive one more time
        //and test that the notes are updated when notes already exist
        u.ProfileId=initialProfile;
        u.IsActive = true;
        update u;
        //deactivate user again
        u.ProfileId=deactivatedProfile;
        update u;
        u = [select Id, IsActive, Notes__c from User where id = :u.id];
        System.assert(notesLength < u.Notes__c.length());
    }
}