• paddington
  • NEWBIE
  • 25 Points
  • Member since 2009

  • Chatter
    Feed
  • 1
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 9
    Questions
  • 9
    Replies

Hi there,

 

I have created three VF pages (view, edit and new) to display my data in three columns and have overridden the relevant buttons, but I'm having a bit of trouble with the clone override. I can get the clone to work using this syntax in the view VF page:

 

<apex:commandButton action="{!UrlFor($Action.CustomObject__c.Clone,CustomObject__c.Id)}" value="Clone"/>

 This returns a standard clone page with the URL:

 

https://na6.salesforce.com/{!CustomObject__c.Id}/e?clone=1&retURL=/apex/ViewCustomObject

 

 

This works a treat apart from two things:

 

1. Pressing 'Cancel' returns a blank ViewCustomObject page. How can I get 'Cancel' to return to the original Custom Object?

 

2. I want to display my data in three columns, so I set the 'Clone' override to my 'New' VF page, but the clone functionality doesn't work any more and I just get the original custom object in my 'New' VF page format. Is there any way to get the clone functionality to work with VF pages?

 

I dug around in the forums and found the following example syntax for a clone:

 

<apex:commandButton action="!UrlFor($Action.CustomObject__c.Clone,CustomObject__c.Id,[cloneli=1],true)}" value="Clone"/>

I tried this with the clone override I described above in point 2 and it just returned the standard clone page. Having checked out the documentation for URLFOR (http://www.salesforce.com/us/developer/docs/pages/index_Left.htm#StartTopic=Content/pages_variables_functions.htm?SearchType=Stem) I was wondering where people got the example syntax.

 

The documentation just specifies resource and path as attributes for the function, but the example syntax has two further attributes: [cloneli=1] and a boolean set to 'true'. Can someone please shed some light on this?

 

Thanks.

Message Edited by paddington on 12-05-2009 04:40 AM

Edit note: This post was a bit epic, so I've edited it down to something that's quicker to read and, hopefully,easier to respond to. Thanks in advance!!!

===

I'm trying to write tests for a VF extension class and am hitting a brick wall with respect to an assert. Any help would be greatly appreciated.

 

Scenario:

Custom object Assessment__c has View override set to the SelectAssessment VF page:

<apex:page standardController="Assessment__c" extensions="AssessmentSelectionExtension" action="{!viewAssessment}">
<apex:outputText value="{!Assessment__c.Owner.Name}" rendered="false"/>
<apex:outputText value="{!Assessment__c.Account__c}" rendered="false"/>
<apex:outputText value="{!Assessment__c.Recommendation__c}" rendered="false"/>
<apex:outputText value="{!Assessment__c.RecordTypeId}" rendered="false"/>
<apex:pageMessages />
<apex:outputPanel layout="block" rendered="{!errorExists}">
</apex:outputPanel>
</apex:page>

The extension, AssessmenSelectionExtension, sets the user as the owner of the assessment, as long as they do not own any other assessments of the relevant record type related to an account. Everything seems to work fine in manual testing, but my test class is having issues around the assert at the bottom of this test class.

 

//Create account and assessments
System.debug('Creating test account');
Account z = new Account(Name = 'Acme');
insert z;

System.debug('Creating test assessments');
//Create list to insert
List<Assessment__c> assessments = new List<Assessment__c> ();
Assessment__c a1 = new Assessment__c();
a1.Account__c = z.Id;
a1.Recommendation__c = 'null';
a1.RecordTypeId = Utility.iefASRT;
a1.OwnerId = Utility.iefOwner;
assessments.add(a1);
assessments.add(a1.clone());

//Insert the assessments
insert assessments;

//Create list of inserted assessments
Assessment__c [] testassess = [SELECT Id, Owner.Name, OwnerId, Account__c, Recommendation__c, RecordTypeId
FROM Assessment__c
WHERE Account__c = :z.Id
AND RecordTypeId = :Utility.iefASRT];

//Create page reference and set to test page
PageReference pageRef = Page.SelectAssessment;
Test.setCurrentPage(pageRef);

//Set URL parameters
ApexPages.currentPage().getParameters().put('id', testassess[0].id);

//Create instance of page controller
ApexPages.StandardController con = new ApexPages.StandardController(testassess[0]);

//Extend controller with extension, referencing base controller
AssessmentSelectionExtension ext = new AssessmentSelectionExtension(con);

//Call method in extension
ext.viewAssessment();

//Assert the url for the page to conduct an assessment
System.assertEquals('/'+testassess[0].Id+'?nooverride=1', ext.viewAssessment().getUrl());

//Populate recommendation on testassess[0]
//testassess[0].Recommendation__c = 'Approve';
//update testassess[0];

Assessment__c [] testassess2 = [SELECT Id, Owner.Name, OwnerId, Account__c, Recommendation__c, RecordTypeId
FROM Assessment__c
WHERE Id = :testassess[0].Id];

//Assert that running user has taken ownership of the assessment
System.assertEquals(UserInfo.getUserId(), testassess2[0].OwnerId);

When I run the test, the owner of the assessment doesn't change to the running user, as it should do, but stays with the queue. The other asserts work and I've manually tested this functionality and the extension works fine, so something must be amiss with the test.

 

It seems like I'm not calling the extension correctly, so it doesn't execute the change of ownership, although the other posts on extension testing seem to suggest that my code should work.

 

Please help!

 

 

Message Edited by paddington on 11-25-2009 05:31 AM
Message Edited by paddington on 11-25-2009 08:09 AM

Note the code pasted in normal text format in blue for those who see garbled code.

 

Hi all,

 

The key problem here is how to take a multi-select picklist on two separate instances of an object related to the account and populate a multi-select picklist on the account with a merged set of their values. Sounds simple, but I'm stumped.

 

Here are the details:

 

An account is being assessed by two independent users via a related custom object called Assessment. In their assessments they give feedback via a multi-select picklist called Decline/Refer Feedback and then make a recommendation by choosing a value in a picklist called Recommendation.

 

When they save an assessment record and Recommendation has switched from null to not null, an after update trigger on the assessment calls a decision method with a list of the affected accounts. This method creates nested maps of account to assessment to recommendation and account to assessment to decline/refer feedback:

 

        //Create nested map of account ID to map of IEF assessment IDs to recommendations
        Map<ID,Map<ID,String>> recMap = new Map<ID,Map<ID,String>> ();
        Map<ID,String> recNestMap = new Map<ID,String> ();
       
        //Create nested map of account ID to map of IEF assessment IDs to decline/refer feedback
        Map<ID,Map<ID,String>> feedMap = new Map<ID,Map<ID,String>> ();
        Map<ID,String> feedNestMap = new Map<ID,String> ();

 

After populating these maps, I iterate through the accounts and count the instances of a certain recommendation occurring, which allows me to decide on the appropriate action. This is relatively easy as we're dealing with a picklist with four values: Decline, Refer to Level 1, Refer to Level 2 and Approve:

 

//Iterate through accounts
        for(Account a:accs){
                      
            //Declare counting variables
            Integer approvecount=0;
            Integer declinecount=0;
            Integer refertwocount=0;
            Integer earlycount=0;
            Integer grantcount=0;

            //Count approvals, declinations and referrals for each account
            for(ID rec :recMap.get(a.Id).keySet()){
                if(recMap.get(a.Id).get(rec) == 'Approve'){
                    approvecount++;
                }
                if(recMap.get(a.Id).get(rec) == 'Decline'){
                    declinecount++;
                }
                if(recMap.get(a.Id).get(rec) == 'Refer to Level 2'){
                    refertwocount++;
                }
            }               

            //Decide on appropriate action
            if(approvecount>=2){
                a.SAQ_Sub_stage__c='SAQ to be sent';
                a.Initial_Enquiry_Sub_stage__c='Assessment complete (No conflict)';
                a.Advantage_Stage__c='SAQ';             
            }
            else if(approvecount==1){  
                a.SAQ_Sub_stage__c='SAQ to be sent';
                a.Initial_Enquiry_Sub_stage__c='Assessment complete (Conflict)';
                a.Advantage_Stage__c='SAQ';             
            }
            else if(declinecount>=2){  
                a.Initial_Enquiry_Sub_stage__c='Assessment complete (No conflict)';             
                a.Advantage_Status__c='To be declined';
            }
            else if(refertwocount>=2){  
                a.Initial_Enquiry_Sub_stage__c='Assessment complete (No conflict)';             
                a.Advantage_Status__c='To be referred to Level 2';
            }
            else if(refertwocount==1){  
                a.Initial_Enquiry_Sub_stage__c='Assessment complete (Conflict)';             
                a.Advantage_Status__c='To be referred to Level 2';
            }
            else if(declinecount==1){ 
                a.Initial_Enquiry_Sub_stage__c='Assessment complete (Conflict)';            
                a.Advantage_Status__c='To be referred to Level 1';
            }
            else{          
                a.Initial_Enquiry_Sub_stage__c='Assessment complete (No conflict)';             
                a.Advantage_Status__c='To be referred to Level 1';
            }

 

 The problem comes with the multi-picklists, as combinations increase exponentially with increase in the number of values. I started with two feedback values: Too early and Requests grant. With only two values it's quite easy to count the occurrence of each value across the assessment objects:

 

//Count feedback given
            for(ID feed :feedMap.get(a.Id).keySet()){
                if(feedMap.get(a.Id).get(feed) == 'Too Early'){
                    earlycount++;
                }
                if(feedMap.get(a.Id).get(feed) == 'Requests Grant'){               
                    grantcount++;
                }
                if(feedMap.get(a.Id).get(feed) == 'Too Early;Requests Grant'
                  || feedMap.get(a.Id).get(feed) == 'Requests Grant;Too Early'){                               
                    earlycount++;
                    grantcount++;
                }
            }
           
            //Decide on appropriate action based on feedback counts
            if(earlycount>0 && grantcount>0){
                a.Assessment_Feedback__c='It is too early stage;You require grant finance';
            }
            else if(earlycount>0){
                a.Assessment_Feedback__c='It is too early stage';
            }
            else if(grantcount>0){
                a.Assessment_Feedback__c='You require grant finance';
            }
            else{
                a.Assessment_Feedback__c=null;
            }
        }

 

 The problem comes when the users want to have six values in the feedback multi-select picklist. Counting occurrences of a value now becomes a bit of a nightmare. I've tried using the contains String method, but when I try it with the case of only two multi-select options, it fails my test class.

 

  //Count feedback given
            for(ID feed :feedMap.get(a.Id).keySet()){               
                if(feedMap.get(a.Id).get(feed).contains('Too Early')){
                    earlycount++;
                }
                if(feedMap.get(a.Id).get(feed).contains('Requests Grant')){               
                    grantcount++;
                }               
            }
           
            //Decide on appropriate action based on feedback counts
            if(earlycount>0 && grantcount>0){
                a.Assessment_Feedback__c='It is too early stage;You require grant finance';
            }
            else if(earlycount>0){
                a.Assessment_Feedback__c='It is too early stage';
            }
            else if(grantcount>0){
                a.Assessment_Feedback__c='You require grant finance';
            }
            else{
                a.Assessment_Feedback__c=null;
            }

 

 The error is "Attempt to de-reference a null object" and is pinned to this line at "get(feed)":

 

if(feedMap.get(a.Id).get(feed).contains('Too Early'))

 

Now this is weird, as it passes my tests when I use:

 

 if(feedMap.get(a.Id).get(feed) == 'Too Early')

 

 

Looking in the string method documentation, it seems that 'contains' is an instance method, which might be what is screwing things up.

 

Regardless, there has to be a better way of querying multi-select picklists than looking for equivalency for 63 different combinations (6_C_6 + 6_C_5 + 6_C_4 + 6_C_3 + 6_C_2 + 6_C_1 = 63 [link]). The second problem is then how do I populate the multi-select picklist on the Account, based upon the occurrence of different multi-select values. At the moment, I'm writing a string to the account field, which is fine for two values, as there are only three combinations. With six, however, we're dealing with 63 different strings again. I can't find any documentation on selecting a multi-select value without overwriting what is in the field already, which is what I would do in an ideal world.

 

Any advice on how to deal with these two problems would be very gratefully received.

 

Thanks in advance,

 

Paddington

Message Edited by paddington on 11-20-2009 11:23 AM
Message Edited by paddington on 11-20-2009 11:24 AM

I'm slightly confused....I'm going through the debug log for a test and when I insert an account, a trigger fires which is AfterUpdate only:

 

20091113150327.165:Class.TEST_Assessments.TESTcreateIEFfromAccount: line 9, column 9: SINGLE CASE - creating test account
20091113150327.165:Class.TEST_Assessments.TESTcreateIEFfromAccount: line 11, column 9: Insert: SOBJECT:Account
*** Beginning IEFsubStage on Account trigger event AfterUpdate for 001T000000EbVdA

 

Does this mean that AfterUpdate triggers fire on inserts as well? I've scoured the documentation and can't find any references to this anywhere, with the opposite being explicitly specified:

 

"The update DML operation modifies one or more existing sObject records, such as individual accounts or contacts, in your organization’s data. "

 

 If the account doesn't exist until I insert it, then how does SFDC interpret this as an update?

 

Hi everyone,

 

Another schoolboy error to reveal to the forum I'm afraid - thanks in advance for any help.

 

I have the following method, which I thought I'd coded to deal with bulk updates:

 

public static void createIEFfromAccount(List<Account> accs){ //Declare owner ID variable for IEF Assessments queue Id ownerId = [SELECT q.Queue.Id FROM QueueSobject q WHERE q.Queue.Name = 'IEF Assessments' AND q.SobjectType = 'Assessment__c'].Queue.Id; //Create a list of assessments to be inserted List<Assessment__c> assessments = new List<Assessment__c> (); //Call setOfIdFromListOfSObject Utility method to populate a map of account ID to client form ID Map<Id,Id> IEFmap = new Map<Id,Id>(); for (Client_Form__c form : [SELECT ID, Account__c FROM Client_Form__c WHERE RecordTypeId = '01280000000BQlBAAW' AND Account__c in :Utility.setOfIdFromListOfSObject(accs)]) { IEFmap.put(form.Account__c, form.Id); } //For each account, create two IEF assessments for(Account a:accs){ Assessment__c assess = new Assessment__c(); assess.Client_Form__c = IEFmap.get(a.Id); assess.RecordTypeId = '01280000000BR0VAAW'; assess.OwnerId = ownerId; assess.Account__c = a.Id; assessments.add(assess); assessments.add(assess.clone()); } //Insert the assessments insert assessments; }

 

 However, when I run the following test method, I get 804 DML rows. I'm probably being really stupid, but I can't see where I have DML statements in loops. Any ideas?

 

 

static testMethod void TESTcreateIEFfromAccount(){ //Test the creation of two IEF assessments from an account for which //Initial Enquiry Sub-stage has been changed to 'Awaiting two assessments //SINGLE CASE //Create a new account System.debug('SINGLE CASE - creating test account'); Account z = new Account(Name = 'Acme', Initial_Enquiry_Sub_stage__c = null); insert z; //Update the Initial Enquiry Sub-stage System.debug('SINGLE CASE - update Initial Enquiry Sub-stage and fire IEFsubStage trigger'); Account updatez = [SELECT Id, Initial_Enquiry_Sub_stage__c FROM Account WHERE Id = :z.Id]; updatez.Initial_Enquiry_Sub_stage__c = 'Awaiting two assessments'; update updatez; //Updating should fire the IEFsubStage trigger and create two assessments of IEF record type Account testz = [SELECT Id, Initial_Enquiry_Sub_stage__c FROM Account WHERE Id = :z.Id]; Integer num = 0; Integer recType = 0; List<Assessment__c> testAssess = new List<Assessment__c> ([SELECT Id, RecordTypeId FROM Assessment__c WHERE Account__c = :z.Id]); for(Assessment__c assess :testAssess){ num++; if(assess.RecordTypeId == '01280000000BR0VAAW'){ recType++; } } System.assertEquals(2,num,'Incorrect number of assessments have been created'); System.debug(+num+' assessments have been created.'); System.assertEquals(2,recType,'Incorrect number of assessments with IEF record Type'); System.debug(+recType+' assessments of IEF record type have been created.'); Integer DMLlimit = Limits.getDMLStatements(); System.debug('Number of DML Statements is ' +DMLlimit); //BULK CASE //Create 200 accounts System.debug('BULK CASE - inserting 200 accounts'); List<Account> insertAccs = new List<Account>(); for(integer i=0; i<200; i++){ insertAccs.add(new Account(Name = 'Test Account '+i, Initial_Enquiry_Sub_stage__c = null)); } insert insertAccs; //Update the 200 accounts List<Account> updateAccs = new List<Account> ([SELECT Id, Name, Initial_Enquiry_Sub_stage__c FROM Account WHERE Id IN :Utility.setOfIdFromListOfSObject(insertAccs)]); for(Account a: updateAccs){ a.Initial_Enquiry_Sub_stage__c = 'Awaiting two assessments'; } update updateAccs; //IEF subStage Trigger should fire for all 200 records, creating 400 assessments of record type IEF Integer bulkNum = 0; Integer bulkRecType = 0; List<Assessment__c> bulkTestAssess = new List<Assessment__c> ([SELECT Id, RecordTypeId FROM Assessment__c WHERE Account__c IN :Utility.setOfIdFromListOfSObject(updateAccs)]); for(Assessment__c assess :bulkTestAssess){ bulkNum++; if(assess.RecordTypeId == '01280000000BR0VAAW'){ bulkRecType++; } } System.assertEquals(400,bulkNum,'Incorrect number of assessments have been created'); System.debug(+bulkNum+' assessments have been created.'); System.assertEquals(400,bulkRecType,'Incorrect number of assessments with IEF record Type'); System.debug(+bulkRecType+' assessments of IEF record type have been created.'); }

 

 Thanks again...

 

 

I'm trying to be really good and not loop SOQL, so I have tried rewriting some code to see how I get on. I've come up against a problem with querying nested Maps, which I didn't have when looping SOQL.

 

This is how I used to create a Map in a method that deals with a list of accounts accs passed from the trigger and a related object called assessments:

 

 

//Create nested map of account ID to map of SAQ assessment IDs to recommendations
Map<ID,Map<ID,String>> assessMap = new Map<ID,Map<ID,String>> ();
Map<ID,String> recMap = new Map<ID,String> ();
for(Account a:accs){
for(Assessment__c assess : [SELECT Id, Recommendation__c
FROM Assessment__c
WHERE Account__c = :a.Id
AND RecordTypeId = '01280000000BR0aAAG']){
recMap.put(assess.Id,assess.Recommendation__c);
}
assessMap.put(a.Id,recMap);
}

 

Note how SOQL is called for each account, which increases the chance of hitting governor limits.

 

I've tried rewriting to this and it seems to validate okay, but doesn't work in testing - I seem to be de-referencing a null object on the last line, which must be the fact that I'm getting from the null map I created before. Any ideas on how to fix this?

 

 

//Create nested map of account ID to map of SAQ assessment IDs to recommendations
Map<ID,Map<ID,String>> assessMap = new Map<ID,Map<ID,String>> ();

for(Account a:accs){
assessMap.put(a.Id,null);
}

for(Assessment__c assess : [SELECT Id, Account__c, Recommendation__c
FROM Assessment__c
WHERE RecordTypeId = '01280000000BR0aAAG'
AND Account__c
IN :Utility.setOfIdFromListOfSObject(accs)]){
assessMap.get(assess.Account__c).put(assess.Id,assess.Recommendation__c);
}

 

Be aware that I've used a utility class to get a set of the account IDs from the list that is passed to the method.

The second problem comes when I try to query the map. For each account in the list passed from the trigger I want to iterate through the assessment IDs that have been mapped to it, for which I'm trying to use the keySet() method. This returns the compile error: "Loop variable must be of type Id", which it must be, as that is the key type specified by the nested Map. What am I doing wrong?

 

 

//Iterate through accounts
for(Account a:accs){

//Declare counting variables
Integer approvecount=0;
Integer declinecount=0;
Integer refertwocount=0;

//Count approvals, declinations and referrals for each account, then decide appropriate action
for(Assessment__c assess :assessMap.get(a.Id).keySet()){
if(assessMap.get(a.Id).get(assess.Id) == 'Approve'){
approvecount++;
}
if(assessMap.get(a.Id).get(assess.Id) == 'Decline'){
declinecount++;
}
if(assessMap.get(a.Id).get(assess.Id) == 'Refer to Level 2'){
refertwocount++;
}
}

 

 

 

 

 

Message Edited by paddington on 11-10-2009 08:42 AM

The boards have been really supportive of late, so, firstly, thanks, and, secondly, any help with the following problem would be much appreciated.

 

I have an object (Assessment__c) related to Account from which I am triggering code that executes on lists of accounts. The way the system is set up means that each account has two Assessment objects, which start off with the Recommendation__c picklist at --None selected--. When this changes, i.e. someone makes a recommendation, I want the trigger to fire and put the related account in the appropriate list of accounts and send that list to the appropriate method in the Assessments class.

 

I've tested the methods that I'm calling using system log and everything's good with them, but I can't get the following trigger to fire. I have a sneaking suspicion that it may be something to do with either:

  1. Recommendation__c is a picklist and therefore non-nillable, although I've dealt with that by using '', which I've read on the boards is equivalent to null for picklists.
  2. The condition on the related account - am I allowed to do this with Apex, or should I be getting a list of related accounts and iterating through those?

Thanks in advance for any help!

 

 

trigger RecommendationMade on Assessment__c (after update) { //Create list of account IDs for which a second recommendation has been made List<ID> SecondRecIDs = new List<ID> (); //Create list of account IDs for which only one recommendation has been made List<ID> FirstRecIDs = new List<ID> (); //Iterate through trigger set for(Integer i=0; i<Trigger.new.size(); i++){ if(Trigger.new[i].RecordTypeId == '01280000000BR0VAAW' && Trigger.old[i].Recommendation__c == '' && Trigger.new[i].Recommendation__c != '' && Trigger.new[i].Account__r.Initial_Enquiry_Sub_stage__c == 'Awaiting one assessment'){ SecondRecIDs.add(Trigger.new[i].Account__c); } else if(Trigger.new[i].RecordTypeId == '01280000000BR0VAAW' && Trigger.old[i].Recommendation__c == '' && Trigger.new[i].Recommendation__c != '' && Trigger.new[i].Account__r.Initial_Enquiry_Sub_stage__c == 'Awaiting two assessments'){ FirstRecIDs.add(Trigger.new[i].Account__c); } } //Create list of accounts for which the second recommendation has been made List<Account> SecondRec = new List<Account>([SELECT Name FROM Account WHERE Id IN :SecondRecIDs]); //Pass this list to the Assessments class Assessments.decideActionIEF(SecondRec); //Create list of accounts for which only the first recommendation has been made List<Account> FirstRec = new List<Account>([SELECT Name FROM Account WHERE Id IN :FirstRecIDs]); //Pass this list to the Assessments class Assessments.updateIEFsubStage(FirstRec); }

 

 

 

Hi there,

 

So I think that I kind of understand Maps, in that if you create a map with a SOQL query, such as

 

 

Map<ID,sObject> sObMap = new Map<ID,sObject>([SELECT *fields* FROM sObject WHERE *conditions*]);

 you get the key/value pairing of an sObject ID and the sObject itself. I'm slightly unsure as to the purpose of the *fields* in the SOQL query, but it seems to work where I need it to, namely in specifying an sObject from a list of IDs.

 

Today I was trying to create an <ID,ID> map, so I can take a list of accounts and iterate through them to get a key/value pairing for the IDs of a set of Master-Detail related sObjects (Clent_Form__c). I want to insert a set of a third object (Assessments__c), which has lookups to the Account and the related Client_Form__c. The only way I think I can do this is by putting SOQL in a FOR loop (METHOD 1 below), which I know is bad practice for bulk triggers.

 

Is there a better way of taking a list of Accounts and mapping them to detail sObjects?

 

Here's the working (messy) class as it stands.

 

 

public with sharing class createAssessments { public static void IEF(List<Account> accs){ //Declare owner ID variable for IEF Assessments queue Id ownerId = [Select q.Queue.Id from QueueSobject q where q.Queue.Name = 'Application Screenings' and q.SobjectType = 'Assessment__c'].Queue.Id; //Create a list of assessments to be inserted List<Assessment__c> assessments = new List<Assessment__c> (); //METHOD 1 - works but I've got SOQL in a loop //Create map of Account ID => Client Form ID Map<ID,ID> IEFs = new Map<ID,ID>(); for (Account a:accs){ IEFs.put(a.Id,[SELECT Id FROM Client_Form__c WHERE Account__c = :a.Id].Id); } //METHOD 2 - doesn't work as I'm putting sObject Client_Form__c into an ID field when I create the assessments //Create list of account IDs for object list accs - is this necessary or could I reference the object list directly? //List<ID> refAccs = new List<ID> (); //for (Account z:accs){ //refAccs.add(z.Id); //} //Query client forms for account IDs and put in a map //Map<ID,Client_Form__c> IEFs = new Map<ID,Client_Form__c>([SELECT Id, Account__c FROM Client_Form__c WHERE Account__c IN :refAccs]); //For each account, create two IEF assessments for(Account a:accs){ Assessment__c assess = new Assessment__c(); assess.Client_Form__c = IEFs.get(a.Id); assess.RecordTypeId = '01280000000BR0VAAW'; assess.OwnerId = ownerId; assess.Account__c = a.Id; assessments.add(assess); assessments.add(assess.clone()); } //Insert the assessments insert assessments; } }

Thanks in advance,

 

Joe

 

 

 

Hi there,

 

I'm new to this coding lark and am having an issue with a test that is driving me up the wall.

 

I have a basic trigger firing off the insertion of a Contact:

 

trigger ContactInsert on Contact (after insert){ PopulateNotificationContact.updateAccount(Trigger.new); }

 This calls a class that populates a custom contact lookup on the Account called Notification_Contact__c with the ID of the inserted contact, if Notification_Contact__c is null:

 

 

public with sharing class PopulateNotificationContact { public static void updateAccount(Contact[] cons){ for(Contact c:cons){ string s=c.AccountId; Account a=[select Id, Notification_Contact__c from Account where Id=:s]; if(a.Notification_Contact__c==null){ a.Notification_Contact__c=c.Id; update a; } } } }

 This all works fine, which is great, although I suspect that I'm not writing very good code. Whatever, I want to get it into live, so have written the following test class, which is where the problem is:

 

 

public class TEST_PopulateNotificationContact{ static testMethod void testInitialEnquiry(){ Account a = new Account(name = 'Acme'); insert a; //Assert that Notification_Contact__c is null System.assertEquals(a.Notification_Contact__c,null); // Inserting the record automatically assigns a value to its ID field Contact c = new Contact(LastName = 'Coyote'); c.accountId = a.Id; // The new contact now points at the new account insert c; //Inserting the contact fires the InitialEnquiryTrue trigger, which should populate //the Notification_Contact__c field System.assertEquals(a.Notification_Contact__r.Id,c.Id,'IDs not the same.'); } }

 The second assert is trying to prove that inserting a new contact on the Acme account populates the Notification_Contact__c field, but the following error is returned:

 

System.Exception: Assertion Failed: IDs not the same.: Expected: null, Actual: 003S0000005UplTIAS

 

I'm sure that I'm making a schoolboy error, but can't work it out. Any ideas would be much appreciated.

 

Thanks,

 

Joe

 

 

 

 

 

 

Edit note: This post was a bit epic, so I've edited it down to something that's quicker to read and, hopefully,easier to respond to. Thanks in advance!!!

===

I'm trying to write tests for a VF extension class and am hitting a brick wall with respect to an assert. Any help would be greatly appreciated.

 

Scenario:

Custom object Assessment__c has View override set to the SelectAssessment VF page:

<apex:page standardController="Assessment__c" extensions="AssessmentSelectionExtension" action="{!viewAssessment}">
<apex:outputText value="{!Assessment__c.Owner.Name}" rendered="false"/>
<apex:outputText value="{!Assessment__c.Account__c}" rendered="false"/>
<apex:outputText value="{!Assessment__c.Recommendation__c}" rendered="false"/>
<apex:outputText value="{!Assessment__c.RecordTypeId}" rendered="false"/>
<apex:pageMessages />
<apex:outputPanel layout="block" rendered="{!errorExists}">
</apex:outputPanel>
</apex:page>

The extension, AssessmenSelectionExtension, sets the user as the owner of the assessment, as long as they do not own any other assessments of the relevant record type related to an account. Everything seems to work fine in manual testing, but my test class is having issues around the assert at the bottom of this test class.

 

//Create account and assessments
System.debug('Creating test account');
Account z = new Account(Name = 'Acme');
insert z;

System.debug('Creating test assessments');
//Create list to insert
List<Assessment__c> assessments = new List<Assessment__c> ();
Assessment__c a1 = new Assessment__c();
a1.Account__c = z.Id;
a1.Recommendation__c = 'null';
a1.RecordTypeId = Utility.iefASRT;
a1.OwnerId = Utility.iefOwner;
assessments.add(a1);
assessments.add(a1.clone());

//Insert the assessments
insert assessments;

//Create list of inserted assessments
Assessment__c [] testassess = [SELECT Id, Owner.Name, OwnerId, Account__c, Recommendation__c, RecordTypeId
FROM Assessment__c
WHERE Account__c = :z.Id
AND RecordTypeId = :Utility.iefASRT];

//Create page reference and set to test page
PageReference pageRef = Page.SelectAssessment;
Test.setCurrentPage(pageRef);

//Set URL parameters
ApexPages.currentPage().getParameters().put('id', testassess[0].id);

//Create instance of page controller
ApexPages.StandardController con = new ApexPages.StandardController(testassess[0]);

//Extend controller with extension, referencing base controller
AssessmentSelectionExtension ext = new AssessmentSelectionExtension(con);

//Call method in extension
ext.viewAssessment();

//Assert the url for the page to conduct an assessment
System.assertEquals('/'+testassess[0].Id+'?nooverride=1', ext.viewAssessment().getUrl());

//Populate recommendation on testassess[0]
//testassess[0].Recommendation__c = 'Approve';
//update testassess[0];

Assessment__c [] testassess2 = [SELECT Id, Owner.Name, OwnerId, Account__c, Recommendation__c, RecordTypeId
FROM Assessment__c
WHERE Id = :testassess[0].Id];

//Assert that running user has taken ownership of the assessment
System.assertEquals(UserInfo.getUserId(), testassess2[0].OwnerId);

When I run the test, the owner of the assessment doesn't change to the running user, as it should do, but stays with the queue. The other asserts work and I've manually tested this functionality and the extension works fine, so something must be amiss with the test.

 

It seems like I'm not calling the extension correctly, so it doesn't execute the change of ownership, although the other posts on extension testing seem to suggest that my code should work.

 

Please help!

 

 

Message Edited by paddington on 11-25-2009 05:31 AM
Message Edited by paddington on 11-25-2009 08:09 AM

Note the code pasted in normal text format in blue for those who see garbled code.

 

Hi all,

 

The key problem here is how to take a multi-select picklist on two separate instances of an object related to the account and populate a multi-select picklist on the account with a merged set of their values. Sounds simple, but I'm stumped.

 

Here are the details:

 

An account is being assessed by two independent users via a related custom object called Assessment. In their assessments they give feedback via a multi-select picklist called Decline/Refer Feedback and then make a recommendation by choosing a value in a picklist called Recommendation.

 

When they save an assessment record and Recommendation has switched from null to not null, an after update trigger on the assessment calls a decision method with a list of the affected accounts. This method creates nested maps of account to assessment to recommendation and account to assessment to decline/refer feedback:

 

        //Create nested map of account ID to map of IEF assessment IDs to recommendations
        Map<ID,Map<ID,String>> recMap = new Map<ID,Map<ID,String>> ();
        Map<ID,String> recNestMap = new Map<ID,String> ();
       
        //Create nested map of account ID to map of IEF assessment IDs to decline/refer feedback
        Map<ID,Map<ID,String>> feedMap = new Map<ID,Map<ID,String>> ();
        Map<ID,String> feedNestMap = new Map<ID,String> ();

 

After populating these maps, I iterate through the accounts and count the instances of a certain recommendation occurring, which allows me to decide on the appropriate action. This is relatively easy as we're dealing with a picklist with four values: Decline, Refer to Level 1, Refer to Level 2 and Approve:

 

//Iterate through accounts
        for(Account a:accs){
                      
            //Declare counting variables
            Integer approvecount=0;
            Integer declinecount=0;
            Integer refertwocount=0;
            Integer earlycount=0;
            Integer grantcount=0;

            //Count approvals, declinations and referrals for each account
            for(ID rec :recMap.get(a.Id).keySet()){
                if(recMap.get(a.Id).get(rec) == 'Approve'){
                    approvecount++;
                }
                if(recMap.get(a.Id).get(rec) == 'Decline'){
                    declinecount++;
                }
                if(recMap.get(a.Id).get(rec) == 'Refer to Level 2'){
                    refertwocount++;
                }
            }               

            //Decide on appropriate action
            if(approvecount>=2){
                a.SAQ_Sub_stage__c='SAQ to be sent';
                a.Initial_Enquiry_Sub_stage__c='Assessment complete (No conflict)';
                a.Advantage_Stage__c='SAQ';             
            }
            else if(approvecount==1){  
                a.SAQ_Sub_stage__c='SAQ to be sent';
                a.Initial_Enquiry_Sub_stage__c='Assessment complete (Conflict)';
                a.Advantage_Stage__c='SAQ';             
            }
            else if(declinecount>=2){  
                a.Initial_Enquiry_Sub_stage__c='Assessment complete (No conflict)';             
                a.Advantage_Status__c='To be declined';
            }
            else if(refertwocount>=2){  
                a.Initial_Enquiry_Sub_stage__c='Assessment complete (No conflict)';             
                a.Advantage_Status__c='To be referred to Level 2';
            }
            else if(refertwocount==1){  
                a.Initial_Enquiry_Sub_stage__c='Assessment complete (Conflict)';             
                a.Advantage_Status__c='To be referred to Level 2';
            }
            else if(declinecount==1){ 
                a.Initial_Enquiry_Sub_stage__c='Assessment complete (Conflict)';            
                a.Advantage_Status__c='To be referred to Level 1';
            }
            else{          
                a.Initial_Enquiry_Sub_stage__c='Assessment complete (No conflict)';             
                a.Advantage_Status__c='To be referred to Level 1';
            }

 

 The problem comes with the multi-picklists, as combinations increase exponentially with increase in the number of values. I started with two feedback values: Too early and Requests grant. With only two values it's quite easy to count the occurrence of each value across the assessment objects:

 

//Count feedback given
            for(ID feed :feedMap.get(a.Id).keySet()){
                if(feedMap.get(a.Id).get(feed) == 'Too Early'){
                    earlycount++;
                }
                if(feedMap.get(a.Id).get(feed) == 'Requests Grant'){               
                    grantcount++;
                }
                if(feedMap.get(a.Id).get(feed) == 'Too Early;Requests Grant'
                  || feedMap.get(a.Id).get(feed) == 'Requests Grant;Too Early'){                               
                    earlycount++;
                    grantcount++;
                }
            }
           
            //Decide on appropriate action based on feedback counts
            if(earlycount>0 && grantcount>0){
                a.Assessment_Feedback__c='It is too early stage;You require grant finance';
            }
            else if(earlycount>0){
                a.Assessment_Feedback__c='It is too early stage';
            }
            else if(grantcount>0){
                a.Assessment_Feedback__c='You require grant finance';
            }
            else{
                a.Assessment_Feedback__c=null;
            }
        }

 

 The problem comes when the users want to have six values in the feedback multi-select picklist. Counting occurrences of a value now becomes a bit of a nightmare. I've tried using the contains String method, but when I try it with the case of only two multi-select options, it fails my test class.

 

  //Count feedback given
            for(ID feed :feedMap.get(a.Id).keySet()){               
                if(feedMap.get(a.Id).get(feed).contains('Too Early')){
                    earlycount++;
                }
                if(feedMap.get(a.Id).get(feed).contains('Requests Grant')){               
                    grantcount++;
                }               
            }
           
            //Decide on appropriate action based on feedback counts
            if(earlycount>0 && grantcount>0){
                a.Assessment_Feedback__c='It is too early stage;You require grant finance';
            }
            else if(earlycount>0){
                a.Assessment_Feedback__c='It is too early stage';
            }
            else if(grantcount>0){
                a.Assessment_Feedback__c='You require grant finance';
            }
            else{
                a.Assessment_Feedback__c=null;
            }

 

 The error is "Attempt to de-reference a null object" and is pinned to this line at "get(feed)":

 

if(feedMap.get(a.Id).get(feed).contains('Too Early'))

 

Now this is weird, as it passes my tests when I use:

 

 if(feedMap.get(a.Id).get(feed) == 'Too Early')

 

 

Looking in the string method documentation, it seems that 'contains' is an instance method, which might be what is screwing things up.

 

Regardless, there has to be a better way of querying multi-select picklists than looking for equivalency for 63 different combinations (6_C_6 + 6_C_5 + 6_C_4 + 6_C_3 + 6_C_2 + 6_C_1 = 63 [link]). The second problem is then how do I populate the multi-select picklist on the Account, based upon the occurrence of different multi-select values. At the moment, I'm writing a string to the account field, which is fine for two values, as there are only three combinations. With six, however, we're dealing with 63 different strings again. I can't find any documentation on selecting a multi-select value without overwriting what is in the field already, which is what I would do in an ideal world.

 

Any advice on how to deal with these two problems would be very gratefully received.

 

Thanks in advance,

 

Paddington

Message Edited by paddington on 11-20-2009 11:23 AM
Message Edited by paddington on 11-20-2009 11:24 AM

I'm slightly confused....I'm going through the debug log for a test and when I insert an account, a trigger fires which is AfterUpdate only:

 

20091113150327.165:Class.TEST_Assessments.TESTcreateIEFfromAccount: line 9, column 9: SINGLE CASE - creating test account
20091113150327.165:Class.TEST_Assessments.TESTcreateIEFfromAccount: line 11, column 9: Insert: SOBJECT:Account
*** Beginning IEFsubStage on Account trigger event AfterUpdate for 001T000000EbVdA

 

Does this mean that AfterUpdate triggers fire on inserts as well? I've scoured the documentation and can't find any references to this anywhere, with the opposite being explicitly specified:

 

"The update DML operation modifies one or more existing sObject records, such as individual accounts or contacts, in your organization’s data. "

 

 If the account doesn't exist until I insert it, then how does SFDC interpret this as an update?

 

Hi everyone,

 

Another schoolboy error to reveal to the forum I'm afraid - thanks in advance for any help.

 

I have the following method, which I thought I'd coded to deal with bulk updates:

 

public static void createIEFfromAccount(List<Account> accs){ //Declare owner ID variable for IEF Assessments queue Id ownerId = [SELECT q.Queue.Id FROM QueueSobject q WHERE q.Queue.Name = 'IEF Assessments' AND q.SobjectType = 'Assessment__c'].Queue.Id; //Create a list of assessments to be inserted List<Assessment__c> assessments = new List<Assessment__c> (); //Call setOfIdFromListOfSObject Utility method to populate a map of account ID to client form ID Map<Id,Id> IEFmap = new Map<Id,Id>(); for (Client_Form__c form : [SELECT ID, Account__c FROM Client_Form__c WHERE RecordTypeId = '01280000000BQlBAAW' AND Account__c in :Utility.setOfIdFromListOfSObject(accs)]) { IEFmap.put(form.Account__c, form.Id); } //For each account, create two IEF assessments for(Account a:accs){ Assessment__c assess = new Assessment__c(); assess.Client_Form__c = IEFmap.get(a.Id); assess.RecordTypeId = '01280000000BR0VAAW'; assess.OwnerId = ownerId; assess.Account__c = a.Id; assessments.add(assess); assessments.add(assess.clone()); } //Insert the assessments insert assessments; }

 

 However, when I run the following test method, I get 804 DML rows. I'm probably being really stupid, but I can't see where I have DML statements in loops. Any ideas?

 

 

static testMethod void TESTcreateIEFfromAccount(){ //Test the creation of two IEF assessments from an account for which //Initial Enquiry Sub-stage has been changed to 'Awaiting two assessments //SINGLE CASE //Create a new account System.debug('SINGLE CASE - creating test account'); Account z = new Account(Name = 'Acme', Initial_Enquiry_Sub_stage__c = null); insert z; //Update the Initial Enquiry Sub-stage System.debug('SINGLE CASE - update Initial Enquiry Sub-stage and fire IEFsubStage trigger'); Account updatez = [SELECT Id, Initial_Enquiry_Sub_stage__c FROM Account WHERE Id = :z.Id]; updatez.Initial_Enquiry_Sub_stage__c = 'Awaiting two assessments'; update updatez; //Updating should fire the IEFsubStage trigger and create two assessments of IEF record type Account testz = [SELECT Id, Initial_Enquiry_Sub_stage__c FROM Account WHERE Id = :z.Id]; Integer num = 0; Integer recType = 0; List<Assessment__c> testAssess = new List<Assessment__c> ([SELECT Id, RecordTypeId FROM Assessment__c WHERE Account__c = :z.Id]); for(Assessment__c assess :testAssess){ num++; if(assess.RecordTypeId == '01280000000BR0VAAW'){ recType++; } } System.assertEquals(2,num,'Incorrect number of assessments have been created'); System.debug(+num+' assessments have been created.'); System.assertEquals(2,recType,'Incorrect number of assessments with IEF record Type'); System.debug(+recType+' assessments of IEF record type have been created.'); Integer DMLlimit = Limits.getDMLStatements(); System.debug('Number of DML Statements is ' +DMLlimit); //BULK CASE //Create 200 accounts System.debug('BULK CASE - inserting 200 accounts'); List<Account> insertAccs = new List<Account>(); for(integer i=0; i<200; i++){ insertAccs.add(new Account(Name = 'Test Account '+i, Initial_Enquiry_Sub_stage__c = null)); } insert insertAccs; //Update the 200 accounts List<Account> updateAccs = new List<Account> ([SELECT Id, Name, Initial_Enquiry_Sub_stage__c FROM Account WHERE Id IN :Utility.setOfIdFromListOfSObject(insertAccs)]); for(Account a: updateAccs){ a.Initial_Enquiry_Sub_stage__c = 'Awaiting two assessments'; } update updateAccs; //IEF subStage Trigger should fire for all 200 records, creating 400 assessments of record type IEF Integer bulkNum = 0; Integer bulkRecType = 0; List<Assessment__c> bulkTestAssess = new List<Assessment__c> ([SELECT Id, RecordTypeId FROM Assessment__c WHERE Account__c IN :Utility.setOfIdFromListOfSObject(updateAccs)]); for(Assessment__c assess :bulkTestAssess){ bulkNum++; if(assess.RecordTypeId == '01280000000BR0VAAW'){ bulkRecType++; } } System.assertEquals(400,bulkNum,'Incorrect number of assessments have been created'); System.debug(+bulkNum+' assessments have been created.'); System.assertEquals(400,bulkRecType,'Incorrect number of assessments with IEF record Type'); System.debug(+bulkRecType+' assessments of IEF record type have been created.'); }

 

 Thanks again...

 

 

I'm trying to be really good and not loop SOQL, so I have tried rewriting some code to see how I get on. I've come up against a problem with querying nested Maps, which I didn't have when looping SOQL.

 

This is how I used to create a Map in a method that deals with a list of accounts accs passed from the trigger and a related object called assessments:

 

 

//Create nested map of account ID to map of SAQ assessment IDs to recommendations
Map<ID,Map<ID,String>> assessMap = new Map<ID,Map<ID,String>> ();
Map<ID,String> recMap = new Map<ID,String> ();
for(Account a:accs){
for(Assessment__c assess : [SELECT Id, Recommendation__c
FROM Assessment__c
WHERE Account__c = :a.Id
AND RecordTypeId = '01280000000BR0aAAG']){
recMap.put(assess.Id,assess.Recommendation__c);
}
assessMap.put(a.Id,recMap);
}

 

Note how SOQL is called for each account, which increases the chance of hitting governor limits.

 

I've tried rewriting to this and it seems to validate okay, but doesn't work in testing - I seem to be de-referencing a null object on the last line, which must be the fact that I'm getting from the null map I created before. Any ideas on how to fix this?

 

 

//Create nested map of account ID to map of SAQ assessment IDs to recommendations
Map<ID,Map<ID,String>> assessMap = new Map<ID,Map<ID,String>> ();

for(Account a:accs){
assessMap.put(a.Id,null);
}

for(Assessment__c assess : [SELECT Id, Account__c, Recommendation__c
FROM Assessment__c
WHERE RecordTypeId = '01280000000BR0aAAG'
AND Account__c
IN :Utility.setOfIdFromListOfSObject(accs)]){
assessMap.get(assess.Account__c).put(assess.Id,assess.Recommendation__c);
}

 

Be aware that I've used a utility class to get a set of the account IDs from the list that is passed to the method.

The second problem comes when I try to query the map. For each account in the list passed from the trigger I want to iterate through the assessment IDs that have been mapped to it, for which I'm trying to use the keySet() method. This returns the compile error: "Loop variable must be of type Id", which it must be, as that is the key type specified by the nested Map. What am I doing wrong?

 

 

//Iterate through accounts
for(Account a:accs){

//Declare counting variables
Integer approvecount=0;
Integer declinecount=0;
Integer refertwocount=0;

//Count approvals, declinations and referrals for each account, then decide appropriate action
for(Assessment__c assess :assessMap.get(a.Id).keySet()){
if(assessMap.get(a.Id).get(assess.Id) == 'Approve'){
approvecount++;
}
if(assessMap.get(a.Id).get(assess.Id) == 'Decline'){
declinecount++;
}
if(assessMap.get(a.Id).get(assess.Id) == 'Refer to Level 2'){
refertwocount++;
}
}

 

 

 

 

 

Message Edited by paddington on 11-10-2009 08:42 AM

The boards have been really supportive of late, so, firstly, thanks, and, secondly, any help with the following problem would be much appreciated.

 

I have an object (Assessment__c) related to Account from which I am triggering code that executes on lists of accounts. The way the system is set up means that each account has two Assessment objects, which start off with the Recommendation__c picklist at --None selected--. When this changes, i.e. someone makes a recommendation, I want the trigger to fire and put the related account in the appropriate list of accounts and send that list to the appropriate method in the Assessments class.

 

I've tested the methods that I'm calling using system log and everything's good with them, but I can't get the following trigger to fire. I have a sneaking suspicion that it may be something to do with either:

  1. Recommendation__c is a picklist and therefore non-nillable, although I've dealt with that by using '', which I've read on the boards is equivalent to null for picklists.
  2. The condition on the related account - am I allowed to do this with Apex, or should I be getting a list of related accounts and iterating through those?

Thanks in advance for any help!

 

 

trigger RecommendationMade on Assessment__c (after update) { //Create list of account IDs for which a second recommendation has been made List<ID> SecondRecIDs = new List<ID> (); //Create list of account IDs for which only one recommendation has been made List<ID> FirstRecIDs = new List<ID> (); //Iterate through trigger set for(Integer i=0; i<Trigger.new.size(); i++){ if(Trigger.new[i].RecordTypeId == '01280000000BR0VAAW' && Trigger.old[i].Recommendation__c == '' && Trigger.new[i].Recommendation__c != '' && Trigger.new[i].Account__r.Initial_Enquiry_Sub_stage__c == 'Awaiting one assessment'){ SecondRecIDs.add(Trigger.new[i].Account__c); } else if(Trigger.new[i].RecordTypeId == '01280000000BR0VAAW' && Trigger.old[i].Recommendation__c == '' && Trigger.new[i].Recommendation__c != '' && Trigger.new[i].Account__r.Initial_Enquiry_Sub_stage__c == 'Awaiting two assessments'){ FirstRecIDs.add(Trigger.new[i].Account__c); } } //Create list of accounts for which the second recommendation has been made List<Account> SecondRec = new List<Account>([SELECT Name FROM Account WHERE Id IN :SecondRecIDs]); //Pass this list to the Assessments class Assessments.decideActionIEF(SecondRec); //Create list of accounts for which only the first recommendation has been made List<Account> FirstRec = new List<Account>([SELECT Name FROM Account WHERE Id IN :FirstRecIDs]); //Pass this list to the Assessments class Assessments.updateIEFsubStage(FirstRec); }

 

 

 

Hi there,

 

So I think that I kind of understand Maps, in that if you create a map with a SOQL query, such as

 

 

Map<ID,sObject> sObMap = new Map<ID,sObject>([SELECT *fields* FROM sObject WHERE *conditions*]);

 you get the key/value pairing of an sObject ID and the sObject itself. I'm slightly unsure as to the purpose of the *fields* in the SOQL query, but it seems to work where I need it to, namely in specifying an sObject from a list of IDs.

 

Today I was trying to create an <ID,ID> map, so I can take a list of accounts and iterate through them to get a key/value pairing for the IDs of a set of Master-Detail related sObjects (Clent_Form__c). I want to insert a set of a third object (Assessments__c), which has lookups to the Account and the related Client_Form__c. The only way I think I can do this is by putting SOQL in a FOR loop (METHOD 1 below), which I know is bad practice for bulk triggers.

 

Is there a better way of taking a list of Accounts and mapping them to detail sObjects?

 

Here's the working (messy) class as it stands.

 

 

public with sharing class createAssessments { public static void IEF(List<Account> accs){ //Declare owner ID variable for IEF Assessments queue Id ownerId = [Select q.Queue.Id from QueueSobject q where q.Queue.Name = 'Application Screenings' and q.SobjectType = 'Assessment__c'].Queue.Id; //Create a list of assessments to be inserted List<Assessment__c> assessments = new List<Assessment__c> (); //METHOD 1 - works but I've got SOQL in a loop //Create map of Account ID => Client Form ID Map<ID,ID> IEFs = new Map<ID,ID>(); for (Account a:accs){ IEFs.put(a.Id,[SELECT Id FROM Client_Form__c WHERE Account__c = :a.Id].Id); } //METHOD 2 - doesn't work as I'm putting sObject Client_Form__c into an ID field when I create the assessments //Create list of account IDs for object list accs - is this necessary or could I reference the object list directly? //List<ID> refAccs = new List<ID> (); //for (Account z:accs){ //refAccs.add(z.Id); //} //Query client forms for account IDs and put in a map //Map<ID,Client_Form__c> IEFs = new Map<ID,Client_Form__c>([SELECT Id, Account__c FROM Client_Form__c WHERE Account__c IN :refAccs]); //For each account, create two IEF assessments for(Account a:accs){ Assessment__c assess = new Assessment__c(); assess.Client_Form__c = IEFs.get(a.Id); assess.RecordTypeId = '01280000000BR0VAAW'; assess.OwnerId = ownerId; assess.Account__c = a.Id; assessments.add(assess); assessments.add(assess.clone()); } //Insert the assessments insert assessments; } }

Thanks in advance,

 

Joe

 

 

 

Hi there,

 

I'm new to this coding lark and am having an issue with a test that is driving me up the wall.

 

I have a basic trigger firing off the insertion of a Contact:

 

trigger ContactInsert on Contact (after insert){ PopulateNotificationContact.updateAccount(Trigger.new); }

 This calls a class that populates a custom contact lookup on the Account called Notification_Contact__c with the ID of the inserted contact, if Notification_Contact__c is null:

 

 

public with sharing class PopulateNotificationContact { public static void updateAccount(Contact[] cons){ for(Contact c:cons){ string s=c.AccountId; Account a=[select Id, Notification_Contact__c from Account where Id=:s]; if(a.Notification_Contact__c==null){ a.Notification_Contact__c=c.Id; update a; } } } }

 This all works fine, which is great, although I suspect that I'm not writing very good code. Whatever, I want to get it into live, so have written the following test class, which is where the problem is:

 

 

public class TEST_PopulateNotificationContact{ static testMethod void testInitialEnquiry(){ Account a = new Account(name = 'Acme'); insert a; //Assert that Notification_Contact__c is null System.assertEquals(a.Notification_Contact__c,null); // Inserting the record automatically assigns a value to its ID field Contact c = new Contact(LastName = 'Coyote'); c.accountId = a.Id; // The new contact now points at the new account insert c; //Inserting the contact fires the InitialEnquiryTrue trigger, which should populate //the Notification_Contact__c field System.assertEquals(a.Notification_Contact__r.Id,c.Id,'IDs not the same.'); } }

 The second assert is trying to prove that inserting a new contact on the Acme account populates the Notification_Contact__c field, but the following error is returned:

 

System.Exception: Assertion Failed: IDs not the same.: Expected: null, Actual: 003S0000005UplTIAS

 

I'm sure that I'm making a schoolboy error, but can't work it out. Any ideas would be much appreciated.

 

Thanks,

 

Joe