• Justin Mitchell
  • NEWBIE
  • 60 Points
  • Member since 2015
  • Salesforce Business Process Analyst
  • Integra


  • Chatter
    Feed
  • 1
    Best Answers
  • 1
    Likes Received
  • 0
    Likes Given
  • 10
    Questions
  • 13
    Replies
Hi I am just having the most frustrating day. 

I have developer mode turned on for my use but when I go to my page:
https://cs14.salesforce.com/apex/folders

I am redirected to:
https://c.cs14.visual.force.com/apex/folders

And no developer mode is available. I checked to make sure developer mode was setup both from Users -> My Account and from My Settings -> Advanced User settings. Please help.
 
I need to query a list of accounts and their related contracts, but I need the accounts listed in order of the contract end dates.

So if Account_A has two contracts with end dates of 1/1/2020 and 1/1/2021
And Account_B has two contracts with end dates of 1/1/2019 and 1/1/2025

Then Account B needs to be on the top of the list because it has a contract which is ending sooner.
Is this possible to do in a single query?
Here's how the syntax would look in my mind if it helps explain what I'm trying to do. This query doesn't work though:
SELECT Id, Name, (SELECT Id, ContractNumber, EndDate FROM Contracts ORDER BY EndDate DESC)
FROM Accounts
ORDER BY Contracts[0].EndDate DESC NULLS LAST
Is this even possible?
I'm using Conga Composer (so Apex isn't an option here) and trying to create a query. It looks like this:
SELECT <fields>
FROM OpportunityLineItem
WHERE OpportunityId = <id>
AND OpportunityId IN (SELECT OpportunityId FROM OpportunityLineItem WHERE ProductCode = <product_code_1>)
AND ProductCode = <product_code_2>
When I try the above with real values I get an error:
The inner and outer selects should not be on the same object type

Explanation:
I'm trying to recreate a report that shows fields from <product_2>, but only if the parent opportunity has products on it with <product_code_1>.
I can do this with a standard report, so I assume there must be a way to do it with SOQL. Here's a screenshot of what that looks like (Sales Price is an Opportunity Product field):
User-added image
 
I have a trigger to track how long opportunies remain in each stage. I wrote it in a full copy sandbox and it tested it manually and it works properly. I then wrote a test class which covers the trigger at 100% and the tests all passed. Next, I deployed it to production and ran the test upon deployment and it passed and deployed. I then ran the test a second time just to be extra sure and all tests passed. All good so far! Finally I tried manually testing the trigger in production (using the exact same method I used in the sandbox) and... it's not working. The trigger IS firing, I know, because one element is being updated properly, but the rest is not. 

It's a bit hard for me to read through the debug log but I believe I'm getting a null pointer exception error as a result of the trigger running, and since I have a try/catch method looking for that error, it's skipping over that block of code.
12:50:39.412 (436621934)|VARIABLE_SCOPE_BEGIN|[37]|npe|System.NullPointerException|true|false
12:50:39.412 (436760589)|VARIABLE_ASSIGNMENT|[37]|npe|"common.apex.runtime.impl.ExecutionException: Attempt to de-reference a null object"|0x66e078e8
What I can't figure out is why this works fine in the sandbox but produces this error in production??
Also, why isn't the test class producing the same error?

Here's my trigger and test class. I am always open to learning so if you have a more efficient way to write this I'd love to learn. 

Trigger
trigger trackOpportunityStageDuration on Opportunity (before insert, before update) {

  for(Opportunity o : Trigger.new) {
    //for all new Opportunities, update the current stage start to NOW()
    if(Trigger.isinsert) {
      o.Current_Stage_Start__c = datetime.now();
    }

    if(Trigger.isupdate) {
      try {
        Opportunity oldOpp = Trigger.oldMap.get(o.Id);
        Decimal elapsedTime = (Decimal.valueof(datetime.now().getTime()).setscale(2) - Decimal.valueof(o.Current_Stage_Start__c.getTime()).setscale(2)) / 86400000;

        //if the stage field is changed: 1) add the number of days between today and the current stage start date to the value currently in the appropriate "stage duration" field, then 2) update the "current stage start" field to now()
        if(oldOpp.StageName != o.StageName && elapsedTime != null) {
          if(oldOpp.StageName == 'Qualification') {
            o.Stage_Duration_Qualification__c = o.Stage_Duration_Qualification__c + elapsedTime;
          }
          if(oldOpp.StageName == 'Needs Analysis') {
            o.Stage_Duration_Needs_Analysis__c = o.Stage_Duration_Needs_Analysis__c + elapsedTime;
          }
          if(oldOpp.StageName == 'Proposal/Price Quote') {
            o.Stage_Duration_Proposal_Price_Quote__c = o.Stage_Duration_Proposal_Price_Quote__c + elapsedTime;
          }
          if(oldOpp.StageName == 'Negotiation/Review') {
            o.Stage_Duration_Negotiation_Review__c = o.Stage_Duration_Negotiation_Review__c + elapsedTime;
          }
          if(oldOpp.StageName == 'Contract Sent') {
            o.Stage_Duration_Contract_Sent__c = o.Stage_Duration_Contract_Sent__c + elapsedTime;
          }
          if(oldOpp.StageName == 'Closed - Billing Review') {
            o.Stage_Duration_Closed_Billing_Review__c = o.Stage_Duration_Closed_Billing_Review__c  + elapsedTime;
          }
          o.Current_Stage_Start__c = datetime.now();
        }
      }
      catch (NullPointerException npe) {
        o.Current_Stage_Start__c = datetime.now();
      }
    }
  }
}

Test Class
@isTest
private class trackOpportunitStageDuration_test2 {

	@isTest static void testStageDuration_Qualification() {
		//1. create new account and opportunity
		Account a = new Account(Name='Test Account',Type='Prospect',Industry='Advertising');
		insert a;
		Opportunity o = new Opportunity(Name='Test Opportunity',AccountId=a.id,CloseDate=date.today(),StageName='Qualification');
		insert o;

		//2. confirm that the current stage start field is equal to "now()"
		Opportunity resultOppty1 = [SELECT Current_Stage_Start__c FROM Opportunity WHERE Id = :o.Id];
    System.AssertNotEquals (null, resultOppty1.Current_Stage_Start__c);

		//3. update current stage start field, subtract some Time
		o.Current_Stage_Start__c = resultOppty1.Current_Stage_Start__c - 1;
		update o;

		//4. update stage field
		o.StageName = 'Needs Analysis';
		update o;

		//5. Check tha the proper Stage Duration field has been updated
		Opportunity resultOppty2 = [
			SELECT Stage_Duration_Qualification__c,Stage_Duration_Needs_Analysis__c,Stage_Duration_Proposal_Price_Quote__c,Stage_Duration_Negotiation_Review__c,Stage_Duration_Contract_Sent__c,Stage_Duration_Closed_Billing_Review__c
			FROM Opportunity
			WHERE Id = :o.Id];
		System.Assert (resultOppty2.Stage_Duration_Qualification__c > 0);

		//update Current Stage Start to blank, then update the stage again
		o.Current_Stage_Start__c = null;
		o.StageName = 'Needs Analysis';
		update o;

		//Check that the current stage start field is not blank
		Opportunity resultOppty3 = [
			SELECT Current_Stage_Start__c
			FROM Opportunity
			WHERE Id = :o.Id];
		System.AssertNotEquals (null,resultOppty3.Current_Stage_Start__c);
	}

//test Needs Analysis stage
	@isTest static void testStageDuration_NeedsAnalysis() {
		//1. create new account and opportunity
		Account a = new Account(Name='Test Account',Type='Prospect',Industry='Advertising');
		insert a;
		Opportunity o = new Opportunity(Name='Test Opportunity',AccountId=a.id,CloseDate=date.today(),StageName='Needs Analysis');
		insert o;
		Opportunity resultOppty1 = [SELECT Current_Stage_Start__c FROM Opportunity WHERE Id = :o.Id];

		//3. update current stage start field, subtract some Time
		o.Current_Stage_Start__c = resultOppty1.Current_Stage_Start__c - 1;
		update o;

		//4. update stage field
		o.StageName = 'Qualification';
		update o;

		//5. Check tha the proper Stage Duration field has been updated
		Opportunity resultOppty2 = [
			SELECT Stage_Duration_Qualification__c,Stage_Duration_Needs_Analysis__c,Stage_Duration_Proposal_Price_Quote__c,Stage_Duration_Negotiation_Review__c,Stage_Duration_Contract_Sent__c,Stage_Duration_Closed_Billing_Review__c
			FROM Opportunity
			WHERE Id = :o.Id];
		System.Assert (resultOppty2.Stage_Duration_Needs_Analysis__c > 0);
	}

	//test Proposal/Price Quote stage
	@isTest static void testStageDuration_ProposalPriceQuote() {
		//1. create new account and opportunity
		Account a = new Account(Name='Test Account',Type='Prospect',Industry='Advertising');
		insert a;
		Opportunity o = new Opportunity(Name='Test Opportunity',AccountId=a.id,CloseDate=date.today(),StageName='Proposal/Price Quote');
		insert o;
		Opportunity resultOppty1 = [SELECT Current_Stage_Start__c FROM Opportunity WHERE Id = :o.Id];

		//3. update current stage start field, subtract some Time
		o.Current_Stage_Start__c = resultOppty1.Current_Stage_Start__c - 1;
		update o;

		//4. update stage field
		o.StageName = 'Qualification';
		update o;

		//5. Check tha the proper Stage Duration field has been updated
		Opportunity resultOppty2 = [
			SELECT Stage_Duration_Qualification__c,Stage_Duration_Needs_Analysis__c,Stage_Duration_Proposal_Price_Quote__c,Stage_Duration_Negotiation_Review__c,Stage_Duration_Contract_Sent__c,Stage_Duration_Closed_Billing_Review__c
			FROM Opportunity
			WHERE Id = :o.Id];
		System.Assert (resultOppty2.Stage_Duration_Proposal_Price_Quote__c > 0);
	}

	//test Negotiation/Review stage
	@isTest static void testStageDuration_NegotiationReview() {
		//1. create new account and opportunity
		Account a = new Account(Name='Test Account',Type='Prospect',Industry='Advertising');
		insert a;
		Opportunity o = new Opportunity(Name='Test Opportunity',AccountId=a.id,CloseDate=date.today(),StageName='Negotiation/Review');
		insert o;
		Opportunity resultOppty1 = [SELECT Current_Stage_Start__c FROM Opportunity WHERE Id = :o.Id];

		//3. update current stage start field, subtract some Time
		o.Current_Stage_Start__c = resultOppty1.Current_Stage_Start__c - 1;
		update o;

		//4. update stage field
		o.StageName = 'Qualification';
		update o;

		//5. Check tha the proper Stage Duration field has been updated
		Opportunity resultOppty2 = [
			SELECT Stage_Duration_Qualification__c,Stage_Duration_Needs_Analysis__c,Stage_Duration_Proposal_Price_Quote__c,Stage_Duration_Negotiation_Review__c,Stage_Duration_Contract_Sent__c,Stage_Duration_Closed_Billing_Review__c
			FROM Opportunity
			WHERE Id = :o.Id];
		System.Assert (resultOppty2.Stage_Duration_Negotiation_Review__c > 0);
	}

	//test Contract Sent stage
	@isTest static void testStageDuration_ContractSent() {
		//1. create new account and opportunity
		Account a = new Account(Name='Test Account',Type='Prospect',Industry='Advertising');
		insert a;
		Opportunity o = new Opportunity(Name='Test Opportunity',AccountId=a.id,CloseDate=date.today(),StageName='Contract Sent');
		insert o;
		Opportunity resultOppty1 = [SELECT Current_Stage_Start__c FROM Opportunity WHERE Id = :o.Id];

		//3. update current stage start field, subtract some Time
		o.Current_Stage_Start__c = resultOppty1.Current_Stage_Start__c - 1;
		update o;

		//4. update stage field
		o.StageName = 'Qualification';
		update o;

		//5. Check tha the proper Stage Duration field has been updated
		Opportunity resultOppty2 = [
			SELECT Stage_Duration_Qualification__c,Stage_Duration_Needs_Analysis__c,Stage_Duration_Proposal_Price_Quote__c,Stage_Duration_Negotiation_Review__c,Stage_Duration_Contract_Sent__c,Stage_Duration_Closed_Billing_Review__c
			FROM Opportunity
			WHERE Id = :o.Id];
		System.Assert (resultOppty2.Stage_Duration_Contract_Sent__c > 0);
	}

	//test Closed - Billing Review stage
	@isTest static void testStageDuration_ClosedBillingReview() {
		//1. create new account and opportunity
		Account a = new Account(Name='Test Account',Type='Prospect',Industry='Advertising');
		insert a;
		Opportunity o = new Opportunity(Name='Test Opportunity',AccountId=a.id,CloseDate=date.today(),StageName='Closed - Billing Review');
		insert o;
		Opportunity resultOppty1 = [SELECT Current_Stage_Start__c FROM Opportunity WHERE Id = :o.Id];

		//3. update current stage start field, subtract some Time
		o.Current_Stage_Start__c = resultOppty1.Current_Stage_Start__c - 1;
		update o;

		//4. update stage field
		o.StageName = 'Qualification';
		update o;

		//5. Check tha the proper Stage Duration field has been updated
		Opportunity resultOppty2 = [
			SELECT Stage_Duration_Qualification__c,Stage_Duration_Needs_Analysis__c,Stage_Duration_Proposal_Price_Quote__c,Stage_Duration_Negotiation_Review__c,Stage_Duration_Contract_Sent__c,Stage_Duration_Closed_Billing_Review__c
			FROM Opportunity
			WHERE Id = :o.Id];
		System.Assert (resultOppty2.Stage_Duration_Closed_Billing_Review__c > 0);
	}
}


 
I have two visualforce pages.
Page #1 has an editable apex:inputTextArea field on it, on the left side.
Page #2 is rendered as a pdf, and it is embedded into page #1 on the right side. Displayed in page #2 there is a Visualfore component. The component needs to include the text from the inputTextArea on page #1.
There is a button on page #1 (Generate Preview) that should update page #2 with any changes made in the text area.

How can I do this?

Here's what I've tried:
-Passing the text area as a variable in the url does not work, as page breaks in the are not maintained
-I am able to get the desired result by creating a PageReference method in the controller, then having the button action use that method, but that redirects me to page #2 when I click the button, as opposed to letting me reload it as an iframe inside page #1

Here's my super simplified code:

Page #1:
<apex:page showHeader="true" sidebar="true" controller="pdfTest_Class" applyBodyTag="false" tabstyle="opportunity" title="PDF Test">
	<apex:form >
		<apex:pageblock >
			<apex:pageBlockButtons location="top" >
				<apex:commandButton value="Generate Preview" reRender="preview" />
			</apex:pageBlockButtons>

			<apex:outputPanel layout="block">
				<div style="width:50%; float:left;">
					<apex:pageblock mode="edit">
						<apex:pageblocksection columns="1" >	 
			                <apex:pageBlockSectionItem >
			                     <apex:outputlabel value="Company Name" /> 
			                    <apex:inputText value="{!companyName}" />
			                </apex:pageBlockSectionItem>

			                <apex:pageBlockSectionItem >
			                     <apex:outputlabel value="Description"  /> 
			                    <apex:inputTextarea value="{!description}" cols="30" rows="5"  />
			                </apex:pageBlockSectionItem>		
		                </apex:pageblocksection>
	                </apex:pageblock>
                </div>
                
                <div style="width:50%; float:right;" >
                	<apex:pageBlock id="preview">
                		<apex:pageBlockSection columns="1">
                			<apex:iframe src="pdfTest_PreviewPage?companyName={!URLENCODE(companyName)}&description={!URLENCODE(description)}" height="300"/>
                		</apex:pageBlockSection>
            		</apex:pageBlock>
        		</div>
            </apex:outputPanel>
        </apex:pageblock>
    </apex:form>
</apex:page>
Controller:
public with sharing class pdfTest_Class {
	public String companyName {get; set;}
	public String description {get; set;}

    public pdfTest_Class() {
    	companyName = '<enter company name>';
    	description = '<enter description>'
    }

}
Page #2:
<apex:page showHeader="false" sidebar="false" applyBodyTag="false" renderAs="pdf">
	<c:pdfTest_Component 
	companyName="{!$CurrentPage.parameters.companyName}"
	description="{!$CurrentPage.parameters.description}" 
	/>
</apex:page>

Component:
<apex:component >
	<apex:attribute name="companyName" description="Company Name" type="String" />
	<apex:attribute name="description" description="Description" type="String" />

	The name of the company is {!companyName}
	<br />
	Description:
    <br />
	{!description}
</apex:component>

There's GOT to be a better way to do this but this is the only way I know how, and now that I need text area fields, it doesn't even work. Help!

 
tl;dr - Is there a way to configure the authentication provider settings in Salesforce to allow my Salesforce user email address to not match the Google username?

I have My Domain configured in a sandbox, and I am trying to add Google as an authentication provider. I have set it up, and it is working, however we have an unusual situation which is causing an issue.

My company uses Gmail for our corporate email. A long time ago, the company changed names, which means everyone has a Google username with the old domain (...@c--tech.com), however we all use an alias email address to send and receive email (...@f--ts.com). So in Salesforce, every user's email address is ...@f--ts.com, but when we sign into Google, we have to use the ...@c--tech.com login, otherwise we're not able to sign in.

After enabling Google as an authentication provider, I am now able to log into my Google account from the mydomain.salesforce.com login page and it successfully logs me into the sandbox. Hooray! However, every time I do, I get two emails, one notifying me that "We received a request to change your Salesforce account's email address" (from jmitchell@f--ts.com to jmitchell@c--tech.com), and a second email asking me to confirm this change.

This wouldn't be such a big deal if it happened only once, but it happens every time I log in using Google authentication.

How do I prevent this? Is there a way to use Google as an authentication provider if the user's email address does not match their Google username?
I am trying to teach myself Apex, so I've come up with a project to create and am figuring it out step-by-stumbling-step. Here is the step I am stuck on.

Here is my goal: I want a page that shows you a list of records in a table. When you click the name of one of the records, the whole list disappears and you see a page showing information from that record.

Here's my code so far which is not working. It's a page which loads the two separate pages, and decides which one to render based on whether a certain variable (the selected record id) is null or not.

Controller:
public class testController {
    public id gameId{get; set;}
    
    public List<Game__c> getGames() {
    	List<Game__c> results = Database.query(
        	'SELECT id,name,owner.name,LastModifiedDate FROM game__c'
        );
        return results;
    }
}

Page 1:
<apex:page showheader="true" controller="testController">
    <apex:include pageName="listPage" rendered="{! ISNULL( gameId ) }"/>
    <apex:include pageName="detailPage" rendered="{! NOT( ISBLANK( gameId )) }"/>
</apex:page>
listPage:
<apex:page showHeader="false" controller="testController" id="display">

        <apex:form >
            <apex:pageblock >
                <apex:pageblocktable value="{! games}" var="g">                   
                    
                    <apex:column headerValue="Name">
                        <apex:commandLink value="{!g.Name}" rerender="display" >
                            <apex:param assignTo="{!gameId}" name="{!g.Id}" value="{!g.Id}"/>
                        </apex:commandLink>
                    </apex:column>

                </apex:pageblocktable>
           </apex:pageblock>
       </apex:form>
</apex:page>

detailPage:
<apex:page showHeader="false" controller="testController">    
    <apex:outputtext value="test" />
</apex:page>
Expected behavior: I click the the name of the any of the Game records in the list on the listPage and the whole list disappears and is replaced with a blank white screen and the word "test".
Actual results: Clicking the name does nothing.

Am I on the right track trying to do this with three separate pages? Or should this all be handled in one visualforce page?
I have this trigger that works when I test it manually, but I am having trouble writing a unit test that actually initiates the trigger. Therefore I can't get more than about 30% coverage. 

The gist of the trigger is this: when a chatter post is made in a chatter group called "Deal Committee", and there is an attachment to the chatter post, then that document is added to a Library called "Deal Committee Attachments". If the document is already in the LIbrary, then it updates a field called Date_Added_to_Library__c to NOW()

Here's the trigger. The comments are mainly for my benefit. :)
(I am aware I have two queries inside a FOR loop and that's not good, and I would like to rewrite it when I have a chance, but for now I'm on a tight schedule and it's what I have and it works. Suggestions around fixing that are welcome but mainly I want to get this unit test written.)
trigger dealCommitteeChatterAttachment on FeedItem (after insert) {
    
    //find the ID of the chatter group called "Deal Committee" and then find the id of the Library called "Deal Committee Attachments
    id cgid = [SELECT id FROM CollaborationGroup WHERE Name = 'Deal Committee'].id;
    id lid  = [SELECT id FROM ContentWorkspace WHERE Name = 'Deal Committee Attachments'].id;
    Set<ID> ids = Trigger.newMap.keySet();
     
    for (FeedItem f : Trigger.new) {
        
        //whenever a new chatter post is made, first check if it's being posted in the Deal Committee group AND check if it has any attachments
        if (f.ParentId == Id.valueOf(cgid) && f.Type == 'ContentPost' ) {
            
            //If either answer (from above) is false, then do nothing
            //If both answers (from above) are true, then do a check to find out if the attached document has already been shared in the Deal Committee Attachments library
            ContentVersion[] contentId = [SELECT ContentDocumentId FROM ContentVersion WHERE Id = :f.RelatedRecordId];            
            integer duplicatecheck     = [SELECT count() from ContentWorkspaceDoc WHERE ContentDocumentID = :contentId[0].ContentDocumentId];
                
                //If it has been shared to the library already, don't add it again, but simply update the "Date Added to Library" field to NOW()
                if( duplicatecheck > 0 ) {
                   ContentVersion cv = contentId[0];
                   cv.Date_Added_to_Library__c = System.now();
                   update cv;
                }
                
                //If it has never been added to the library, then add it           
                else if( duplicatecheck == 0 ) { 
            
                    ContentWorkspaceDoc c = new ContentWorkspaceDoc();            
                    c.ContentDocumentID   = contentId[0].ContentDocumentId;
                    c.ContentWorkspaceID  = Id.valueOf(lid);                       
                    insert c;
                }
        } 
                
    //Otherwise do nothing
    else  {}
    }
}

Here's my unit test as it is now. It says it covers the trigger at 31%. As far as my knowledge goes, it should be covering everything. Clearly I'm wrong but I don't understand what I'm missing. I think it's not even initiating the trigger to create the ContentWorkspaceDoc at all, which means none of the other code is going to run, and i don't know why.
@isTest
private class dealCommitteeChatterAttachment_test {
           
    @isTest(SeeAllData=True) static void addToLibraryTest() {
        List<CollaborationGroup> cgId = [SELECT id FROM CollaborationGroup WHERE Name = 'Deal Committee' LIMIT 1];
        List<ContentWorkspace> lid = [SELECT id FROM ContentWorkspace WHERE Name = 'Deal Committee Attachments' LIMIT 1];

        ContentVersion cv = new ContentVersion();
        cv.ContentURL = '<a target="_blank" href="http://www.google.com/">http://www.google.com</a>';
        cv.Title ='Google.com'; 
        insert cv;

        ContentVersion datecheck1 = [SELECT Date_Added_to_Library__c,ContentDocumentId FROM ContentVersion WHERE id = :cv.id];
        System.Debug(datecheck1.ContentDocumentId);
        
        FeedItem fi1 = new FeedItem();
        fi1.ParentId = cgid[0].id;
        fi1.body     = 'test';
        fi1.Type     = 'ContentPost';
        insert fi1; 

        FeedAttachment fa1 = new FeedAttachment();
        fa1.FeedEntityId = fi1.id;
        fa1.type         = 'Content';
        fa1.RecordId     = cv.id;
        insert fa1;
            
        FeedItem fi2 = new FeedItem();
        fi2.ParentId = cgid[0].id;
        fi2.body     = 'test 2';
        fi2.Type     = 'ContentPost';
        insert fi2;

        FeedAttachment fa2 = new FeedAttachment();
        fa2.FeedEntityId = fi2.id;
        fa2.type         = 'Content';
        fa2.RecordId     = cv.id;
        insert fa2;        

        ContentVersion datecheck2 = [SELECT Date_Added_to_Library__c FROM ContentVersion WHERE id = :cv.id];
		System.Debug(datecheck1.Date_Added_to_Library__c);
        System.Debug(datecheck2.Date_Added_to_Library__c);
        
    }
}


 
Maybe I'm going about this wrong, but here's what I want to do:
I have a table on a visualforce page. Each column needs to be formatted conditionally based upon the "Status__c" field.
I have a class called "open". If the value of status__c = "open", then the class (styleClass) of the row should be "open". If the value of status__c is not "open", then the styleClass value should be null.

I know how to do this already inline on the visualforce page, and it works perfectly:
<apex:column value="{! ws.Name }" styleClass="{! CASE( ws.Status__c, 'Open', 'open', '' ) }" />
However, I want to move this logic to the controller and then reference it. In reality, the logic is much longer and more complext than this, so I don't want to have to repeat it over and over. Here is what I have tried and it is not working:

Controller:
public String getStyleLogic() {
        return '{! CASE( ws.Status__c, \'Open\', \'open\', \'\' )}';}
Visualforce:
<apex:column value="{! ws.Name }" styleClass="{! StyleLogic }">
 What is confusing me, is if I just put "{! StyleLogic }" at the bottom of the page, I get this result displayed:
{! CASE( ws.Status__c, 'Open', 'open', '' ) }
so my string is successfully being passed from the controller to the Visualforce page, however it is not letting me use that string as a styleClass. It is even more confusing, because if I change the StyleLogic variable to just say " return 'open' " (instead of the CASE statement) it works, and the whole column is formatted using the "open" class. 

What am I missing here?
 
This is probably very simple but I'm having trouble figuring out the syntax. I am trying to display a link to the record owner's record on a visualforce page. If it's a user, the link should be 
'/{!ws.Owner.id}'
If it's a queue I believe it should be
'/p/own/Queue/d?id={!ws.Owner.id}'

I have tried to add this conditionally into the outputLink but I either get a syntax error one way, or I get a bad url. 
Here's one thing I've tried:
<apex:outputLink value="{!IF( ws.Owner.Type = 'User', '/{!ws.Owner.id}', '/p/own/Queue/d?id={!ws.Owner.id}')}" target="_blank"> {!ws.Owner.Name} </apex:outputlink>

The resulting urls generated from the code above is
"https://cs45.salesforce.com/#{ws.Owner.id}"
and
"https://cs45.salesforce.com/p/own/Queue/d?id=%7B!ws.Owner.id%7D"
respectively. 

Question 1: Is there a simpler way to link to the Owner's record than using conditional output (ie: <apex:outputLink value="/{!ws.Owner.IdNoMatterIfTheyAreAUserOrAQueue}"> )?

Question 2: If not, what is the proper syntax to use when trying to insert variables (might not be the correct terminology) into a condtional statement?

Thanks!
 

I know there must be 10 different ways to do this but I am reaching my knowledge limit here and need some help.

I have a table on my visualforce page which is pulling a list of all Workstep__c records that are related to a defined Sub_Order__c object.
Here's a much simplified version of my list:
<apex:pageBlock >
        <apex:pageBlockSection columns="1">            
            <apex:pageBlockTable value="{!wsList}" var="ws">   
                                             
                <apex:column headerValue="Name" value="{!ws.Name}" />                   
                <apex:column headerValue="Duration" value="{!ws.Duration__c}" />
                 
            </apex:pageBlockTable>
        </apex:pageBlockSection>
    </apex:pageBlock>
I need to have a button or a link at the top of the page that, when pressed, toggles visibility for any Workstep__c records on the list that have a Duration__c value of 0.

Right now I have a bunch of style classes defined in CSS and I've applied conditional styling to each column in order to hide the rows with a duration of 0, and it works just fine (though it's messy.. still trying to figure out how to clean it up a bit), however I want to be able to toggle the visibility of those rows on or off with a button. Suggestions for what direction to look?
 
I have a trigger to track how long opportunies remain in each stage. I wrote it in a full copy sandbox and it tested it manually and it works properly. I then wrote a test class which covers the trigger at 100% and the tests all passed. Next, I deployed it to production and ran the test upon deployment and it passed and deployed. I then ran the test a second time just to be extra sure and all tests passed. All good so far! Finally I tried manually testing the trigger in production (using the exact same method I used in the sandbox) and... it's not working. The trigger IS firing, I know, because one element is being updated properly, but the rest is not. 

It's a bit hard for me to read through the debug log but I believe I'm getting a null pointer exception error as a result of the trigger running, and since I have a try/catch method looking for that error, it's skipping over that block of code.
12:50:39.412 (436621934)|VARIABLE_SCOPE_BEGIN|[37]|npe|System.NullPointerException|true|false
12:50:39.412 (436760589)|VARIABLE_ASSIGNMENT|[37]|npe|"common.apex.runtime.impl.ExecutionException: Attempt to de-reference a null object"|0x66e078e8
What I can't figure out is why this works fine in the sandbox but produces this error in production??
Also, why isn't the test class producing the same error?

Here's my trigger and test class. I am always open to learning so if you have a more efficient way to write this I'd love to learn. 

Trigger
trigger trackOpportunityStageDuration on Opportunity (before insert, before update) {

  for(Opportunity o : Trigger.new) {
    //for all new Opportunities, update the current stage start to NOW()
    if(Trigger.isinsert) {
      o.Current_Stage_Start__c = datetime.now();
    }

    if(Trigger.isupdate) {
      try {
        Opportunity oldOpp = Trigger.oldMap.get(o.Id);
        Decimal elapsedTime = (Decimal.valueof(datetime.now().getTime()).setscale(2) - Decimal.valueof(o.Current_Stage_Start__c.getTime()).setscale(2)) / 86400000;

        //if the stage field is changed: 1) add the number of days between today and the current stage start date to the value currently in the appropriate "stage duration" field, then 2) update the "current stage start" field to now()
        if(oldOpp.StageName != o.StageName && elapsedTime != null) {
          if(oldOpp.StageName == 'Qualification') {
            o.Stage_Duration_Qualification__c = o.Stage_Duration_Qualification__c + elapsedTime;
          }
          if(oldOpp.StageName == 'Needs Analysis') {
            o.Stage_Duration_Needs_Analysis__c = o.Stage_Duration_Needs_Analysis__c + elapsedTime;
          }
          if(oldOpp.StageName == 'Proposal/Price Quote') {
            o.Stage_Duration_Proposal_Price_Quote__c = o.Stage_Duration_Proposal_Price_Quote__c + elapsedTime;
          }
          if(oldOpp.StageName == 'Negotiation/Review') {
            o.Stage_Duration_Negotiation_Review__c = o.Stage_Duration_Negotiation_Review__c + elapsedTime;
          }
          if(oldOpp.StageName == 'Contract Sent') {
            o.Stage_Duration_Contract_Sent__c = o.Stage_Duration_Contract_Sent__c + elapsedTime;
          }
          if(oldOpp.StageName == 'Closed - Billing Review') {
            o.Stage_Duration_Closed_Billing_Review__c = o.Stage_Duration_Closed_Billing_Review__c  + elapsedTime;
          }
          o.Current_Stage_Start__c = datetime.now();
        }
      }
      catch (NullPointerException npe) {
        o.Current_Stage_Start__c = datetime.now();
      }
    }
  }
}

Test Class
@isTest
private class trackOpportunitStageDuration_test2 {

	@isTest static void testStageDuration_Qualification() {
		//1. create new account and opportunity
		Account a = new Account(Name='Test Account',Type='Prospect',Industry='Advertising');
		insert a;
		Opportunity o = new Opportunity(Name='Test Opportunity',AccountId=a.id,CloseDate=date.today(),StageName='Qualification');
		insert o;

		//2. confirm that the current stage start field is equal to "now()"
		Opportunity resultOppty1 = [SELECT Current_Stage_Start__c FROM Opportunity WHERE Id = :o.Id];
    System.AssertNotEquals (null, resultOppty1.Current_Stage_Start__c);

		//3. update current stage start field, subtract some Time
		o.Current_Stage_Start__c = resultOppty1.Current_Stage_Start__c - 1;
		update o;

		//4. update stage field
		o.StageName = 'Needs Analysis';
		update o;

		//5. Check tha the proper Stage Duration field has been updated
		Opportunity resultOppty2 = [
			SELECT Stage_Duration_Qualification__c,Stage_Duration_Needs_Analysis__c,Stage_Duration_Proposal_Price_Quote__c,Stage_Duration_Negotiation_Review__c,Stage_Duration_Contract_Sent__c,Stage_Duration_Closed_Billing_Review__c
			FROM Opportunity
			WHERE Id = :o.Id];
		System.Assert (resultOppty2.Stage_Duration_Qualification__c > 0);

		//update Current Stage Start to blank, then update the stage again
		o.Current_Stage_Start__c = null;
		o.StageName = 'Needs Analysis';
		update o;

		//Check that the current stage start field is not blank
		Opportunity resultOppty3 = [
			SELECT Current_Stage_Start__c
			FROM Opportunity
			WHERE Id = :o.Id];
		System.AssertNotEquals (null,resultOppty3.Current_Stage_Start__c);
	}

//test Needs Analysis stage
	@isTest static void testStageDuration_NeedsAnalysis() {
		//1. create new account and opportunity
		Account a = new Account(Name='Test Account',Type='Prospect',Industry='Advertising');
		insert a;
		Opportunity o = new Opportunity(Name='Test Opportunity',AccountId=a.id,CloseDate=date.today(),StageName='Needs Analysis');
		insert o;
		Opportunity resultOppty1 = [SELECT Current_Stage_Start__c FROM Opportunity WHERE Id = :o.Id];

		//3. update current stage start field, subtract some Time
		o.Current_Stage_Start__c = resultOppty1.Current_Stage_Start__c - 1;
		update o;

		//4. update stage field
		o.StageName = 'Qualification';
		update o;

		//5. Check tha the proper Stage Duration field has been updated
		Opportunity resultOppty2 = [
			SELECT Stage_Duration_Qualification__c,Stage_Duration_Needs_Analysis__c,Stage_Duration_Proposal_Price_Quote__c,Stage_Duration_Negotiation_Review__c,Stage_Duration_Contract_Sent__c,Stage_Duration_Closed_Billing_Review__c
			FROM Opportunity
			WHERE Id = :o.Id];
		System.Assert (resultOppty2.Stage_Duration_Needs_Analysis__c > 0);
	}

	//test Proposal/Price Quote stage
	@isTest static void testStageDuration_ProposalPriceQuote() {
		//1. create new account and opportunity
		Account a = new Account(Name='Test Account',Type='Prospect',Industry='Advertising');
		insert a;
		Opportunity o = new Opportunity(Name='Test Opportunity',AccountId=a.id,CloseDate=date.today(),StageName='Proposal/Price Quote');
		insert o;
		Opportunity resultOppty1 = [SELECT Current_Stage_Start__c FROM Opportunity WHERE Id = :o.Id];

		//3. update current stage start field, subtract some Time
		o.Current_Stage_Start__c = resultOppty1.Current_Stage_Start__c - 1;
		update o;

		//4. update stage field
		o.StageName = 'Qualification';
		update o;

		//5. Check tha the proper Stage Duration field has been updated
		Opportunity resultOppty2 = [
			SELECT Stage_Duration_Qualification__c,Stage_Duration_Needs_Analysis__c,Stage_Duration_Proposal_Price_Quote__c,Stage_Duration_Negotiation_Review__c,Stage_Duration_Contract_Sent__c,Stage_Duration_Closed_Billing_Review__c
			FROM Opportunity
			WHERE Id = :o.Id];
		System.Assert (resultOppty2.Stage_Duration_Proposal_Price_Quote__c > 0);
	}

	//test Negotiation/Review stage
	@isTest static void testStageDuration_NegotiationReview() {
		//1. create new account and opportunity
		Account a = new Account(Name='Test Account',Type='Prospect',Industry='Advertising');
		insert a;
		Opportunity o = new Opportunity(Name='Test Opportunity',AccountId=a.id,CloseDate=date.today(),StageName='Negotiation/Review');
		insert o;
		Opportunity resultOppty1 = [SELECT Current_Stage_Start__c FROM Opportunity WHERE Id = :o.Id];

		//3. update current stage start field, subtract some Time
		o.Current_Stage_Start__c = resultOppty1.Current_Stage_Start__c - 1;
		update o;

		//4. update stage field
		o.StageName = 'Qualification';
		update o;

		//5. Check tha the proper Stage Duration field has been updated
		Opportunity resultOppty2 = [
			SELECT Stage_Duration_Qualification__c,Stage_Duration_Needs_Analysis__c,Stage_Duration_Proposal_Price_Quote__c,Stage_Duration_Negotiation_Review__c,Stage_Duration_Contract_Sent__c,Stage_Duration_Closed_Billing_Review__c
			FROM Opportunity
			WHERE Id = :o.Id];
		System.Assert (resultOppty2.Stage_Duration_Negotiation_Review__c > 0);
	}

	//test Contract Sent stage
	@isTest static void testStageDuration_ContractSent() {
		//1. create new account and opportunity
		Account a = new Account(Name='Test Account',Type='Prospect',Industry='Advertising');
		insert a;
		Opportunity o = new Opportunity(Name='Test Opportunity',AccountId=a.id,CloseDate=date.today(),StageName='Contract Sent');
		insert o;
		Opportunity resultOppty1 = [SELECT Current_Stage_Start__c FROM Opportunity WHERE Id = :o.Id];

		//3. update current stage start field, subtract some Time
		o.Current_Stage_Start__c = resultOppty1.Current_Stage_Start__c - 1;
		update o;

		//4. update stage field
		o.StageName = 'Qualification';
		update o;

		//5. Check tha the proper Stage Duration field has been updated
		Opportunity resultOppty2 = [
			SELECT Stage_Duration_Qualification__c,Stage_Duration_Needs_Analysis__c,Stage_Duration_Proposal_Price_Quote__c,Stage_Duration_Negotiation_Review__c,Stage_Duration_Contract_Sent__c,Stage_Duration_Closed_Billing_Review__c
			FROM Opportunity
			WHERE Id = :o.Id];
		System.Assert (resultOppty2.Stage_Duration_Contract_Sent__c > 0);
	}

	//test Closed - Billing Review stage
	@isTest static void testStageDuration_ClosedBillingReview() {
		//1. create new account and opportunity
		Account a = new Account(Name='Test Account',Type='Prospect',Industry='Advertising');
		insert a;
		Opportunity o = new Opportunity(Name='Test Opportunity',AccountId=a.id,CloseDate=date.today(),StageName='Closed - Billing Review');
		insert o;
		Opportunity resultOppty1 = [SELECT Current_Stage_Start__c FROM Opportunity WHERE Id = :o.Id];

		//3. update current stage start field, subtract some Time
		o.Current_Stage_Start__c = resultOppty1.Current_Stage_Start__c - 1;
		update o;

		//4. update stage field
		o.StageName = 'Qualification';
		update o;

		//5. Check tha the proper Stage Duration field has been updated
		Opportunity resultOppty2 = [
			SELECT Stage_Duration_Qualification__c,Stage_Duration_Needs_Analysis__c,Stage_Duration_Proposal_Price_Quote__c,Stage_Duration_Negotiation_Review__c,Stage_Duration_Contract_Sent__c,Stage_Duration_Closed_Billing_Review__c
			FROM Opportunity
			WHERE Id = :o.Id];
		System.Assert (resultOppty2.Stage_Duration_Closed_Billing_Review__c > 0);
	}
}


 
I need to query a list of accounts and their related contracts, but I need the accounts listed in order of the contract end dates.

So if Account_A has two contracts with end dates of 1/1/2020 and 1/1/2021
And Account_B has two contracts with end dates of 1/1/2019 and 1/1/2025

Then Account B needs to be on the top of the list because it has a contract which is ending sooner.
Is this possible to do in a single query?
Here's how the syntax would look in my mind if it helps explain what I'm trying to do. This query doesn't work though:
SELECT Id, Name, (SELECT Id, ContractNumber, EndDate FROM Contracts ORDER BY EndDate DESC)
FROM Accounts
ORDER BY Contracts[0].EndDate DESC NULLS LAST
Is this even possible?
I'm using Conga Composer (so Apex isn't an option here) and trying to create a query. It looks like this:
SELECT <fields>
FROM OpportunityLineItem
WHERE OpportunityId = <id>
AND OpportunityId IN (SELECT OpportunityId FROM OpportunityLineItem WHERE ProductCode = <product_code_1>)
AND ProductCode = <product_code_2>
When I try the above with real values I get an error:
The inner and outer selects should not be on the same object type

Explanation:
I'm trying to recreate a report that shows fields from <product_2>, but only if the parent opportunity has products on it with <product_code_1>.
I can do this with a standard report, so I assume there must be a way to do it with SOQL. Here's a screenshot of what that looks like (Sales Price is an Opportunity Product field):
User-added image
 
Hi I am just having the most frustrating day. 

I have developer mode turned on for my use but when I go to my page:
https://cs14.salesforce.com/apex/folders

I am redirected to:
https://c.cs14.visual.force.com/apex/folders

And no developer mode is available. I checked to make sure developer mode was setup both from Users -> My Account and from My Settings -> Advanced User settings. Please help.
 
I have a trigger to track how long opportunies remain in each stage. I wrote it in a full copy sandbox and it tested it manually and it works properly. I then wrote a test class which covers the trigger at 100% and the tests all passed. Next, I deployed it to production and ran the test upon deployment and it passed and deployed. I then ran the test a second time just to be extra sure and all tests passed. All good so far! Finally I tried manually testing the trigger in production (using the exact same method I used in the sandbox) and... it's not working. The trigger IS firing, I know, because one element is being updated properly, but the rest is not. 

It's a bit hard for me to read through the debug log but I believe I'm getting a null pointer exception error as a result of the trigger running, and since I have a try/catch method looking for that error, it's skipping over that block of code.
12:50:39.412 (436621934)|VARIABLE_SCOPE_BEGIN|[37]|npe|System.NullPointerException|true|false
12:50:39.412 (436760589)|VARIABLE_ASSIGNMENT|[37]|npe|"common.apex.runtime.impl.ExecutionException: Attempt to de-reference a null object"|0x66e078e8
What I can't figure out is why this works fine in the sandbox but produces this error in production??
Also, why isn't the test class producing the same error?

Here's my trigger and test class. I am always open to learning so if you have a more efficient way to write this I'd love to learn. 

Trigger
trigger trackOpportunityStageDuration on Opportunity (before insert, before update) {

  for(Opportunity o : Trigger.new) {
    //for all new Opportunities, update the current stage start to NOW()
    if(Trigger.isinsert) {
      o.Current_Stage_Start__c = datetime.now();
    }

    if(Trigger.isupdate) {
      try {
        Opportunity oldOpp = Trigger.oldMap.get(o.Id);
        Decimal elapsedTime = (Decimal.valueof(datetime.now().getTime()).setscale(2) - Decimal.valueof(o.Current_Stage_Start__c.getTime()).setscale(2)) / 86400000;

        //if the stage field is changed: 1) add the number of days between today and the current stage start date to the value currently in the appropriate "stage duration" field, then 2) update the "current stage start" field to now()
        if(oldOpp.StageName != o.StageName && elapsedTime != null) {
          if(oldOpp.StageName == 'Qualification') {
            o.Stage_Duration_Qualification__c = o.Stage_Duration_Qualification__c + elapsedTime;
          }
          if(oldOpp.StageName == 'Needs Analysis') {
            o.Stage_Duration_Needs_Analysis__c = o.Stage_Duration_Needs_Analysis__c + elapsedTime;
          }
          if(oldOpp.StageName == 'Proposal/Price Quote') {
            o.Stage_Duration_Proposal_Price_Quote__c = o.Stage_Duration_Proposal_Price_Quote__c + elapsedTime;
          }
          if(oldOpp.StageName == 'Negotiation/Review') {
            o.Stage_Duration_Negotiation_Review__c = o.Stage_Duration_Negotiation_Review__c + elapsedTime;
          }
          if(oldOpp.StageName == 'Contract Sent') {
            o.Stage_Duration_Contract_Sent__c = o.Stage_Duration_Contract_Sent__c + elapsedTime;
          }
          if(oldOpp.StageName == 'Closed - Billing Review') {
            o.Stage_Duration_Closed_Billing_Review__c = o.Stage_Duration_Closed_Billing_Review__c  + elapsedTime;
          }
          o.Current_Stage_Start__c = datetime.now();
        }
      }
      catch (NullPointerException npe) {
        o.Current_Stage_Start__c = datetime.now();
      }
    }
  }
}

Test Class
@isTest
private class trackOpportunitStageDuration_test2 {

	@isTest static void testStageDuration_Qualification() {
		//1. create new account and opportunity
		Account a = new Account(Name='Test Account',Type='Prospect',Industry='Advertising');
		insert a;
		Opportunity o = new Opportunity(Name='Test Opportunity',AccountId=a.id,CloseDate=date.today(),StageName='Qualification');
		insert o;

		//2. confirm that the current stage start field is equal to "now()"
		Opportunity resultOppty1 = [SELECT Current_Stage_Start__c FROM Opportunity WHERE Id = :o.Id];
    System.AssertNotEquals (null, resultOppty1.Current_Stage_Start__c);

		//3. update current stage start field, subtract some Time
		o.Current_Stage_Start__c = resultOppty1.Current_Stage_Start__c - 1;
		update o;

		//4. update stage field
		o.StageName = 'Needs Analysis';
		update o;

		//5. Check tha the proper Stage Duration field has been updated
		Opportunity resultOppty2 = [
			SELECT Stage_Duration_Qualification__c,Stage_Duration_Needs_Analysis__c,Stage_Duration_Proposal_Price_Quote__c,Stage_Duration_Negotiation_Review__c,Stage_Duration_Contract_Sent__c,Stage_Duration_Closed_Billing_Review__c
			FROM Opportunity
			WHERE Id = :o.Id];
		System.Assert (resultOppty2.Stage_Duration_Qualification__c > 0);

		//update Current Stage Start to blank, then update the stage again
		o.Current_Stage_Start__c = null;
		o.StageName = 'Needs Analysis';
		update o;

		//Check that the current stage start field is not blank
		Opportunity resultOppty3 = [
			SELECT Current_Stage_Start__c
			FROM Opportunity
			WHERE Id = :o.Id];
		System.AssertNotEquals (null,resultOppty3.Current_Stage_Start__c);
	}

//test Needs Analysis stage
	@isTest static void testStageDuration_NeedsAnalysis() {
		//1. create new account and opportunity
		Account a = new Account(Name='Test Account',Type='Prospect',Industry='Advertising');
		insert a;
		Opportunity o = new Opportunity(Name='Test Opportunity',AccountId=a.id,CloseDate=date.today(),StageName='Needs Analysis');
		insert o;
		Opportunity resultOppty1 = [SELECT Current_Stage_Start__c FROM Opportunity WHERE Id = :o.Id];

		//3. update current stage start field, subtract some Time
		o.Current_Stage_Start__c = resultOppty1.Current_Stage_Start__c - 1;
		update o;

		//4. update stage field
		o.StageName = 'Qualification';
		update o;

		//5. Check tha the proper Stage Duration field has been updated
		Opportunity resultOppty2 = [
			SELECT Stage_Duration_Qualification__c,Stage_Duration_Needs_Analysis__c,Stage_Duration_Proposal_Price_Quote__c,Stage_Duration_Negotiation_Review__c,Stage_Duration_Contract_Sent__c,Stage_Duration_Closed_Billing_Review__c
			FROM Opportunity
			WHERE Id = :o.Id];
		System.Assert (resultOppty2.Stage_Duration_Needs_Analysis__c > 0);
	}

	//test Proposal/Price Quote stage
	@isTest static void testStageDuration_ProposalPriceQuote() {
		//1. create new account and opportunity
		Account a = new Account(Name='Test Account',Type='Prospect',Industry='Advertising');
		insert a;
		Opportunity o = new Opportunity(Name='Test Opportunity',AccountId=a.id,CloseDate=date.today(),StageName='Proposal/Price Quote');
		insert o;
		Opportunity resultOppty1 = [SELECT Current_Stage_Start__c FROM Opportunity WHERE Id = :o.Id];

		//3. update current stage start field, subtract some Time
		o.Current_Stage_Start__c = resultOppty1.Current_Stage_Start__c - 1;
		update o;

		//4. update stage field
		o.StageName = 'Qualification';
		update o;

		//5. Check tha the proper Stage Duration field has been updated
		Opportunity resultOppty2 = [
			SELECT Stage_Duration_Qualification__c,Stage_Duration_Needs_Analysis__c,Stage_Duration_Proposal_Price_Quote__c,Stage_Duration_Negotiation_Review__c,Stage_Duration_Contract_Sent__c,Stage_Duration_Closed_Billing_Review__c
			FROM Opportunity
			WHERE Id = :o.Id];
		System.Assert (resultOppty2.Stage_Duration_Proposal_Price_Quote__c > 0);
	}

	//test Negotiation/Review stage
	@isTest static void testStageDuration_NegotiationReview() {
		//1. create new account and opportunity
		Account a = new Account(Name='Test Account',Type='Prospect',Industry='Advertising');
		insert a;
		Opportunity o = new Opportunity(Name='Test Opportunity',AccountId=a.id,CloseDate=date.today(),StageName='Negotiation/Review');
		insert o;
		Opportunity resultOppty1 = [SELECT Current_Stage_Start__c FROM Opportunity WHERE Id = :o.Id];

		//3. update current stage start field, subtract some Time
		o.Current_Stage_Start__c = resultOppty1.Current_Stage_Start__c - 1;
		update o;

		//4. update stage field
		o.StageName = 'Qualification';
		update o;

		//5. Check tha the proper Stage Duration field has been updated
		Opportunity resultOppty2 = [
			SELECT Stage_Duration_Qualification__c,Stage_Duration_Needs_Analysis__c,Stage_Duration_Proposal_Price_Quote__c,Stage_Duration_Negotiation_Review__c,Stage_Duration_Contract_Sent__c,Stage_Duration_Closed_Billing_Review__c
			FROM Opportunity
			WHERE Id = :o.Id];
		System.Assert (resultOppty2.Stage_Duration_Negotiation_Review__c > 0);
	}

	//test Contract Sent stage
	@isTest static void testStageDuration_ContractSent() {
		//1. create new account and opportunity
		Account a = new Account(Name='Test Account',Type='Prospect',Industry='Advertising');
		insert a;
		Opportunity o = new Opportunity(Name='Test Opportunity',AccountId=a.id,CloseDate=date.today(),StageName='Contract Sent');
		insert o;
		Opportunity resultOppty1 = [SELECT Current_Stage_Start__c FROM Opportunity WHERE Id = :o.Id];

		//3. update current stage start field, subtract some Time
		o.Current_Stage_Start__c = resultOppty1.Current_Stage_Start__c - 1;
		update o;

		//4. update stage field
		o.StageName = 'Qualification';
		update o;

		//5. Check tha the proper Stage Duration field has been updated
		Opportunity resultOppty2 = [
			SELECT Stage_Duration_Qualification__c,Stage_Duration_Needs_Analysis__c,Stage_Duration_Proposal_Price_Quote__c,Stage_Duration_Negotiation_Review__c,Stage_Duration_Contract_Sent__c,Stage_Duration_Closed_Billing_Review__c
			FROM Opportunity
			WHERE Id = :o.Id];
		System.Assert (resultOppty2.Stage_Duration_Contract_Sent__c > 0);
	}

	//test Closed - Billing Review stage
	@isTest static void testStageDuration_ClosedBillingReview() {
		//1. create new account and opportunity
		Account a = new Account(Name='Test Account',Type='Prospect',Industry='Advertising');
		insert a;
		Opportunity o = new Opportunity(Name='Test Opportunity',AccountId=a.id,CloseDate=date.today(),StageName='Closed - Billing Review');
		insert o;
		Opportunity resultOppty1 = [SELECT Current_Stage_Start__c FROM Opportunity WHERE Id = :o.Id];

		//3. update current stage start field, subtract some Time
		o.Current_Stage_Start__c = resultOppty1.Current_Stage_Start__c - 1;
		update o;

		//4. update stage field
		o.StageName = 'Qualification';
		update o;

		//5. Check tha the proper Stage Duration field has been updated
		Opportunity resultOppty2 = [
			SELECT Stage_Duration_Qualification__c,Stage_Duration_Needs_Analysis__c,Stage_Duration_Proposal_Price_Quote__c,Stage_Duration_Negotiation_Review__c,Stage_Duration_Contract_Sent__c,Stage_Duration_Closed_Billing_Review__c
			FROM Opportunity
			WHERE Id = :o.Id];
		System.Assert (resultOppty2.Stage_Duration_Closed_Billing_Review__c > 0);
	}
}


 
I am trying to teach myself Apex, so I've come up with a project to create and am figuring it out step-by-stumbling-step. Here is the step I am stuck on.

Here is my goal: I want a page that shows you a list of records in a table. When you click the name of one of the records, the whole list disappears and you see a page showing information from that record.

Here's my code so far which is not working. It's a page which loads the two separate pages, and decides which one to render based on whether a certain variable (the selected record id) is null or not.

Controller:
public class testController {
    public id gameId{get; set;}
    
    public List<Game__c> getGames() {
    	List<Game__c> results = Database.query(
        	'SELECT id,name,owner.name,LastModifiedDate FROM game__c'
        );
        return results;
    }
}

Page 1:
<apex:page showheader="true" controller="testController">
    <apex:include pageName="listPage" rendered="{! ISNULL( gameId ) }"/>
    <apex:include pageName="detailPage" rendered="{! NOT( ISBLANK( gameId )) }"/>
</apex:page>
listPage:
<apex:page showHeader="false" controller="testController" id="display">

        <apex:form >
            <apex:pageblock >
                <apex:pageblocktable value="{! games}" var="g">                   
                    
                    <apex:column headerValue="Name">
                        <apex:commandLink value="{!g.Name}" rerender="display" >
                            <apex:param assignTo="{!gameId}" name="{!g.Id}" value="{!g.Id}"/>
                        </apex:commandLink>
                    </apex:column>

                </apex:pageblocktable>
           </apex:pageblock>
       </apex:form>
</apex:page>

detailPage:
<apex:page showHeader="false" controller="testController">    
    <apex:outputtext value="test" />
</apex:page>
Expected behavior: I click the the name of the any of the Game records in the list on the listPage and the whole list disappears and is replaced with a blank white screen and the word "test".
Actual results: Clicking the name does nothing.

Am I on the right track trying to do this with three separate pages? Or should this all be handled in one visualforce page?
This is probably very simple but I'm having trouble figuring out the syntax. I am trying to display a link to the record owner's record on a visualforce page. If it's a user, the link should be 
'/{!ws.Owner.id}'
If it's a queue I believe it should be
'/p/own/Queue/d?id={!ws.Owner.id}'

I have tried to add this conditionally into the outputLink but I either get a syntax error one way, or I get a bad url. 
Here's one thing I've tried:
<apex:outputLink value="{!IF( ws.Owner.Type = 'User', '/{!ws.Owner.id}', '/p/own/Queue/d?id={!ws.Owner.id}')}" target="_blank"> {!ws.Owner.Name} </apex:outputlink>

The resulting urls generated from the code above is
"https://cs45.salesforce.com/#{ws.Owner.id}"
and
"https://cs45.salesforce.com/p/own/Queue/d?id=%7B!ws.Owner.id%7D"
respectively. 

Question 1: Is there a simpler way to link to the Owner's record than using conditional output (ie: <apex:outputLink value="/{!ws.Owner.IdNoMatterIfTheyAreAUserOrAQueue}"> )?

Question 2: If not, what is the proper syntax to use when trying to insert variables (might not be the correct terminology) into a condtional statement?

Thanks!
 

I know there must be 10 different ways to do this but I am reaching my knowledge limit here and need some help.

I have a table on my visualforce page which is pulling a list of all Workstep__c records that are related to a defined Sub_Order__c object.
Here's a much simplified version of my list:
<apex:pageBlock >
        <apex:pageBlockSection columns="1">            
            <apex:pageBlockTable value="{!wsList}" var="ws">   
                                             
                <apex:column headerValue="Name" value="{!ws.Name}" />                   
                <apex:column headerValue="Duration" value="{!ws.Duration__c}" />
                 
            </apex:pageBlockTable>
        </apex:pageBlockSection>
    </apex:pageBlock>
I need to have a button or a link at the top of the page that, when pressed, toggles visibility for any Workstep__c records on the list that have a Duration__c value of 0.

Right now I have a bunch of style classes defined in CSS and I've applied conditional styling to each column in order to hide the rows with a duration of 0, and it works just fine (though it's messy.. still trying to figure out how to clean it up a bit), however I want to be able to toggle the visibility of those rows on or off with a button. Suggestions for what direction to look?
 
This is a bit of breif bit of code:

controller:
<pre>

public List<String> partTypes = new List<String>{'Accessories', 'Electronics', 'Fishing', 'Fun and Entertainment', 'Graphics and Decals', 'Pontoon Covers', 'Safety', 'Seating', 'Trailering and Covers'};

 public Map<String, List<Product2>> availablePartOptions{ get; set;}
.
.
.
List<Product2> boatOptions = [SELECT Id, Name, RecordType.Name, Family,
                                                        (SELECT Id, Name, UnitPrice, Pricebook2Id
                                                          FROM PricebookEntries WHERE Pricebook2Id = :pb2Id),
                                                        (SELECT Id, Standard__c, Maximum__c FROM From_Product_Options__r)
                                                        FROM Product2
                                                        WHERE Id IN :ids];

availablePartOptions = new Map<String,List<Product2>>();
for(String partName : partTypes) {
   availablePartOptions.put( partName, new List<Product2>() );
 }

for(Product2 opt: boatOptions() ) {
  if(opt.RecordType.Name == 'Part'){
    availablePartOptions.get(opt.Family).add(opt);
  }
}

</pre>

Visualforce test:

<pre>

<ul>
    <apex:repeat value="{!availablePartOptions}" var="key">
        <li>
              <apex:outputText value="{!key}" /> -
               <apex:outputText value="{!availablePartOptions[key].size}" />
        </li>
    </apex:repeat>
</ul>

</pre>

This all results in:

Incorrect parameter type for subscript. Expected Number, received Text
Error is in expression '{!availablePartOptions[key].size}' in component <apex:outputText> in page boatbuilder

If I omit the offending line I get a ugly but valid list of keys which is the same as my partTypes List

Accessories -
Electronics -
Fishing -
Fun and Entertainment -
Graphics and Decals -
Pontoon Covers -
Safety -
Seating -
Trailering and Covers -

This is the method every doc I have read said to use when dealing with maps in visualforce.
If anyone has any Ideas it would be a tremendous help