• Caleb_Sidel
  • NEWBIE
  • 75 Points
  • Member since 2009

  • Chatter
    Feed
  • 3
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 12
    Questions
  • 14
    Replies

I am writing a test class for a trigger that has multiple for loops in it and When I run the test the lines that are not covered are the for loops.

 

Here is part of the trigger:

trigger AutoCreateIncident on Account (after update) { List<Case> c = new List<Case>(); for (Integer i = 0; i < Trigger.new.size(); i++) { Account newCase = Trigger.new[i]; Account OldCase = Trigger.old[i]; if(newCase.Operational_Status__c == 'Operational' && oldCase.Operational_Status__c == 'IT GO'){ if(newCase.Account_Services_Rep__c == 'Ade Adeyemi' || oldCase.Account_Services_Rep__c == 'Ade Adeyemi'){ for(Integer j = 0; j < 24; j++){ c.add(new Case(Type = 'Health Check', Reason__c = 'Health Check', AccountId = newCase.Id, OwnerId = '005700000016ePl', Priority = 'High', Due_date__c = System.today() + (j*30) + 1)); } } else if(newCase.Account_Services_Rep__c == 'Chris Nelson' || oldCase.Account_Services_Rep__c == 'Chris Nelson'){ for(Integer k = 0; k < 24; k++){ c.add(new Case(Type = 'Health Check', Reason__c = 'Health Check', AccountId = newCase.Id, OwnerId = '005700000016eQ4', Priority = 'High', Due_date__c = System.today() + (k*30) + 1)); } } else if(newCase.Account_Services_Rep__c == 'Deborah Kerr' || oldCase.Account_Services_Rep__c == 'Deborah Kerr' ){ for(Integer l = 0; l < 24; l++){ c.add(new Case(Type = 'Health Check', Reason__c = 'Health Check', AccountId = newCase.Id, OwnerId = '005700000016ePr', Priority = 'High', Due_date__c = System.today() + (l*30) + 1)); } } else if(newCase.Account_Services_Rep__c == 'Elyssa Kim' || oldCase.Account_Services_Rep__c == 'Elyssa Kim'){ for(Integer m = 0; m < 24; m++){ c.add(new Case(Type = 'Health Check', Reason__c = 'Health Check', AccountId = newCase.Id, OwnerId = '00570000001IbB3', Priority = 'High', Due_date__c = System.today() + (m*30) + 1)); } } } } insert c; }

I understand this is not the most efficent or best way to code this trigger, but this is how i have chosen to code it for now. The lines of code that I am not sure how to test are the for loop lines and the "c.add(new Case(" lines. any suggestions on how to tackle this one?

 

I also have another one that has a few Field.addErrors in it and I am not sure how to test those lines of code either 

 

Thanks

  • November 24, 2009
  • Like
  • 0

Has anyone successfully used addError on a field dynamically on an SObject?

 

Something like the below in concept (note the below doesn't work because get(FieldName) returns the value in that field, not the field itself...

 

Account a = [Select fields FROM Account WHERE stuff];

SObject obj = (SObject)a;

obj.get('FieldName__c').addError('Something or other');

 

Thank you,

Caleb

 

Has anyone seen this issue.

 

I have a VF controller extension of Opportunity which does something very simple, it sets the oppty.StageName = 'Closed Won'; and then updates the oppty.

 

This all works fine, but today we noticed that the Probability is not being updated to be 100% and the Forecast Category is not being updated to Closed/Won.

 

All API documentation states that you only need to set the StageName. I've done this before, with data loader, apex, etc and not had a problem. But today I have a problem.

 

We tried flushing the browser cache, we tried forcing the probability = 100, but since Forecast Category is read/only we can't affect that.

 

The Apex class was API 18.0, we updated it to API 20.0 - no affect.

 

We tried putting a workflow behind the code, so that if the StageName = 'Closed Custom' (not a real stage) then have Workflow that does a field update to 'Closed Won' ==> results? It works!

 

But this is such a hack! Anyone run into this and/or a solution?

 

Thanks,

Caleb

 

 

Can someone confirm that Master-Detail children do NOT inherit currency code from the parent?

 

My test shows it does NOT, but I deperately want it to inherit so thought I'd ask the community before building Apex (Currency Code is not available in Workflow).

 

Test:

I enable Multi-Currency.

I created a Master-Detail Relationship from Opportunity to Custom Object.

If I change the currency on the Opportunity, the currency on the Custom Object (child) does not change?

 

 

Thank you,

Caleb

 

 

 

 

 

 

I need to find the most recent Contract and update the Account with the End Date of that Contract.

 

Prior to Spring'10:

 

I trigger on Contract update, get the Account Ids, query every active, non-expired Contract for those accounts ordered by End Date descending. Because we're in a bulk friendly trigger my query is potentially accross mutliple accounts so I have to loop over the Contracts and take the first Contract per unique Account Id and use that. All of this takes mulitple loops, 3 queries (actually 1 is just to be "thread safe"), and some fun with Maps. I also have to worry about heapsize (I used to worry about query rows - only 1,000)...but still heapsize is a concern now.

 

Now with Aggregate Functions I can remove a query, use less memory, and no mind games to optimize my loops:

  AggregateResult [] arList = [SELECT AccountId, MAX(EndDate) FROM Contract WHERE ActivatedDate <> null AND EndDate >= :Date.today() AND AccountId IN :accountIdList GROUP BY AccountId];System.debug(arList); 

//Try to avoid DB race conditions/be thread safe (not strictly needed, I could simply create the Account in memory and set the Id...but this seems more polite to me in case several Contracts are updated for the same Account in different batches at the "same time")

Map<Id,Account> accountMap = new Map<Id,Account>([Select Id, Most_Recent_Active_Contract__c FROM Account Where Id IN :accountIdList  FOR UPDATE]); for( AggregateResult ar : arList ) {//Most Recent Contract Date recentContractDate = (Date)ar.get('expr0');//For Id accountId = (Id)ar.get('AccountId'); Account a = accountMap .get(AccountId);a.Most_Recent_Active_Contract__c = recentContractDate; } update accountMap.values();

 

 

Of course there might be other/better ways of doing this, if so please share. But I had to share my first foray into Aggregate Functions b/c I like them so much!

 

Thank you,

Caleb

 

PS - MAX() appears to work with dates...bonus!

 

I recently tried to package an app with custom settings. Unfortunately I couldn't write test methods because I wanted to create custom settings instances to test the various areas of my code. The error message I got is well known to me: MIXED_DML_OPERATION, DML operation on setup object is not permitted after you have updated a non-setup object (or vice versa).

 

Since inserting a Custom Settings object is a setup operation I can not create a custom settings and then proceed to create my test data. I tried creating my custom settings inside an @future method and this didn't work either (I did wrap my @future call with Test.startTest() and Test.stopTest() to ensure my @future method completed (i.e. to force synchornous execution). But I still got the same error message.

 

Ultimately what I did was write my code in such a way that the Class which relied on the custom settings had a local variable for the custom settings which I could set. In normal operation my code will query the custom settings using .getInstance() however my testMethods will all override this normal behavior and "force" set the custom settings.

 

My class which uses custom settings is below as is my class which tests my code. I hope you find this useful, and if you spot anything wrong with this please let me know. Thanks,

Caleb

 

------------ Class --------------

 public without sharing class CrossObjectUtil {
 private Map<Id,gii__AccountAdd__c> childrenToUpdateParent;
 private List<Account> parentsToUpdate;
 private Boolean isTest = false;

//This is the key!
 private CrossObjectSettings__c crossObjSettingsInstance = null;
 
 public CrossObjectUtil() {
  childrenToUpdateParent = new Map<Id,gii__AccountAdd__c>();
  parentsToUpdate = new List<Account>();
  setCrossObjectSettings(null);
 }

//Used by the test methods!

 public void setCrossObjectSettings(CrossObjectSettings__c cos) {
  if(cos == null) {
   CrossObjectSettings__c crossObjSettingsInstance = null;
   Map<String,CrossObjectSettings__c> crossObjSettingsInstanceMap = CrossObjectSettings__c.getAll();
   
   for(CrossObjectSettings__c cosInstance : crossObjSettingsInstanceMap.values()) {
    if(cosInstance.Child_Object_Name__c == 'gii__AccountAdd__c'&&
       cosInstance.Parent_Object_Name__c == 'Account') {
        crossObjSettingsInstance = cosInstance;
       }     
   }
  } else {
   crossObjSettingsInstance = cos;
  }
 }
 
 public void addChildToUpdateParent(Id parentId, gii__AccountAdd__c child) {
  childrenToUpdateParent.put(parentId,child);
 }

 public void updateParents() {
  if (childrenToUpdateParent.size() > 0) {
   updateParents(childrenToUpdateParent,false);
  }
 
  update parentsToUpdate;
 }
 
 private void updateParents(Map<Id,gii__AccountAdd__c> children,Boolean isDelete) {
  System.debug('updateParents: isDelete = ' + isDelete);
  for(Id parentId : children.keySet()) {
    SObject parent = new Account(Id=parentId);
    SObject child = children.get(parentId);
        
    if(crossObjSettingsInstance == null) {
     setCrossObjectSettings(null);
     if(crossObjSettingsInstance == null) {
      return;
     }
    }
    
    List<String> fieldMappings = crossObjSettingsInstance.Child_to_Parent_Field_Mapping__c.split(';',0);
    
    if(fieldMappings.size() == 0) return;
    
    for(String mapping : fieldMappings) {
     List<String> fields = mapping.split('=',0);
     if(fields.size() == 2) {
      if(!isDelete) {
       parent.put(fields[1],child.get(fields[0]));
      } else {
       parent.put(fields[1],null);
      }
     }
    }
    parentsToUpdate.add((Account)parent);
   } 
 }
}

 

-----------Test Method -------------

    static testMethod void test_CrossObjectUtil_Self() {
     Account a = insertAccount();
     gii__Warehouse__c w = insertWharehouse();
     gii__AccountAdd__c acctAdd = getAccountAdd(a,w);
    
      CrossObjectUtil coUtil = new CrossObjectUtil();

//Set the custom settings - the object is never saved!
      coUtil.setCrossObjectSettings(createCustomSettings());
        coUtil.addChildToUpdateParent(a.Id,acctAdd);
        coUtil.updateParents();
        Account assertAccount = [SELECT Name, Description FROM Account WHERE Id =:a.Id LIMIT 1];
        System.assertEquals(w.Id,assertAccount.Name);
        System.assertEquals(acctAdd.Name,assertAccount.Description);
    }
      
 //Notice that I do NOT insert the object! it's all in memory!
    static CrossObjectSettings__c createCustomSettings() {
     CrossObjectSettings__c crossObjSettingsInstance = new CrossObjectSettings__c(Name = 'Test Account Add to Account');
     crossObjSettingsInstance.Child_Object_Name__c = 'gii__AccountAdd__c';
     crossObjSettingsInstance.Parent_Object_Name__c = 'Account';
     crossObjSettingsInstance.Child_to_Parent_Field_Mapping__c = 'Name=Description;gii__DefaultWarehouse__c=Name';
     return crossObjSettingsInstance;
    }

Has anyone else experienced issues when testing @future where if the method calling @future clears the input list then all of your test methods fail because the @future method thinks it has recieved a null list? See the code below. Thoughts: bug or feature?

 

There is a work around: do not use .clear() but instead re-create the list (i.e. move the list  

subsetAccountIds inside of the While loop below).

 

So next question - what is better for memory? clear an array or "re-create" the array? I would think clear() is more explicit and would free up the memory "immediately" whereas overwriting the array would be subject to gargage collection to dump the memory.

 

Thanks,

Caleb 

 

 

public without sharing class CustomerProductHandler {

 

//Takes the list of Accounts and breaks it into 10 equal parts

 public static void deleteCustomerProducts(List<Id> forAccountIds) {System.debug('BEGIN: CustomerProductHandler: deleteCustomerProducts(List<Id> forAccountIds)');

 

Integer smallerLooops = Math.mod(forAccountIds.size(),10);

List<Id> subsetAccountIds = new List<Id>();System.debug('smallerLooops = ' + smallerLooops);

 

while(!forAccountIds.isEmpty()) {System.debug(

'forAccountIds.size() = ' + forAccountIds.size());

 

for(Integer i=0; i < smallerLooops; i++) {

Id acctId = forAccountIds.remove(i);

subsetAccountIds.add(acctId);

}

 

System.debug('subsetAccountIds.size() = ' + subsetAccountIds.size());

 

if(!subsetAccountIds.isEmpty()) {

deleteCustomerProducts_AT_FUTURE(subsetAccountIds);

//IF I UNCOMMENT THIS LINE OF CODE BELOW the test method fails and my debug statements indicate that the size of the list passed to my @future method below is 0. However if I comment this out (as is done here) then the test methods work just fine.

//The problem is, I want to call @futurre with this array, then clear it, then call @future again. 

//subsetAccountIds.clear();

}

}

}

 

//Deletes all customer products related to the AccountIds

@future

 public static void deleteCustomerProducts_AT_FUTURE(List<Id> forAccountIds) {System.debug('BEGIN: CustomerProductHandler: deleteCustomerProducts_AT_FUTURE(List<Id> forAccountIds)');

 

EmailUtils eutils = new EmailUtils();

 

for(List<Customer_Product__c> custProducts : [SELECT Id

FROM Customer_Product__c

 WHERE Account__c IN :forAccountIds]) {

 

if(Limits.getDmlStatements() + 1 > Limits.getLimitDmlStatements()) {

emailError(eutils, forAccountIds,'Exceeded DML Statements.');}

else {

try {System.debug(

'deleting products: ' + custProducts);

delete custProducts;System.debug(

'products deleted');} catch(Exception exp) {

emailError(eutils, forAccountIds,exp.getMessage());

}

}

}

}

 

public static void emailError(EmailUtils eutils, List<Id> objectIds, String errorMsg) {System.debug('errorMsg = ' + errorMsg);

 

String objIds = ' ';

for(Id objId : objectIds){objIds += 'https://na3.salesforce.com/' + objId + '/n';

}

eutils.sendTextErrorEmailToAdmins('ERROR: CustomerProductHandler: deleteCustomerProducts', errorMsg + '/n /n Please review each of these accounts and manually review and possibly delete their Customer Products. Accounts: ' + objIds);

}

 

static testMethod void test_processAccounts() {

Account a = new Account();a.

Name = 'test';

a.Netsuite_Internal_ID__c = '999';

insert a;

 

Customer_Product__c cp = new Customer_Product__c();

cp.Name = 'test';cp.Customer_Product_ID__c =

'test';

cp.Account__c = a.Id;

insert cp;

 

Feature__c f = new Feature__c();

f.Name = 'test';

insert f;

 

Customer_Product_Feature__c cpf = new Customer_Product_Feature__c();

cpf.Name = 'Test' + cp.Id;cpf.Customer_Feature_ID__c =

'test';

cpf.Customer_Product__c = cp.Id;cpf.

Feature__c = f.Id; insert cpf;

 

Integer cpCount = [SELECT count() FROM Customer_Product__c WHERE Account__c =: a.Id];

System.assertEquals(1,cpCount);

 

Integer cpfCount = [SELECT count() FROM Customer_Product_Feature__c WHERE Feature__c =: f.Id];

System.assertEquals(1,cpfCount);

 

a.Netsuite_Internal_ID__c = '123';

Test.startTest();

update a;

Test.stopTest();

 

cpCount = [SELECT count() FROM Customer_Product__c WHERE Account__c =: a.Id];

System.assertEquals(0,cpCount);

 

//cpfCount = [SELECT count() FROM Customer_Product_Feature__c WHERE Feature__c =: f.Id];

//System.assertEquals(0,cpfCount);

 

}

 

}

Page 143 of the Apex Guide states

 

All Apex sharing reason names have the following format:

MyReasonName__c

Apex sharing reasons can be referenced programmatically as follows:

Schema.CustomObject__Share.rowCause.SharingReason__c

For example, an Apex sharing reason called Recruiter for an object called Job can be referenced as follows:

Schema.Job__Share.rowCause.Requester__c

 

 

however when I try to save my code I get the error that the variable doesn't exist. If I try Schema.CustomObject__Share.rowCause.Manual I also get an error.

 

So it seems that that Schema is not where rowCauses are stored and/or I'm missing something. Has anyone successfully used custom rowCauses? If so what's the format?

 

Thank you,

Caleb

The error I get is:

 SObject row was retrieved via SOQL without querying the requested field: Opportunity.Name

 

Here is my VF page (quite simple I thought)

 

<apex:page standardController="Opportunity" extensions="PolicyHandler">

<apex:form >

<apex:pageBlock title="Close & Bind Opportunity">

<apex:messages />

<apex:outputText value="Once you close and bind an Opportunity it can no longer be edited. Are you sure you want to proceed?"/>

<apex:pageBlockButtons location="bottom">

<apex:commandButton value="Close & Bind" action="{!processCloseBoundOpportunity}"/>

<apex:commandButton value="Cancel" action="{!cancel}"/>

</apex:pageBlockButtons>

</apex:pageBlock>

</apex:form>

</apex:page> 

 

Here is my Controller, the code never gets to the yeah made it part

 

 public PolicyHandler(ApexPages.StandardController controller) {

this.myOppty = (Opportunity)controller.getRecord();

}

 

public PageReference processCloseBoundOpportunity() {

try {

System.debug('*************** LOOK *************');

System.debug(this.myOppty.Name);         

                        System.debug('***********YEAH MADE IT************');

//Do stuff

       PageReference p = new PageReference('/' + myOppty.Id);

       p.setRedirect(true);

       return p;

} catch (Exception exp) {

         ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR,exp.getMessage()));

         return null;

        }

}

 

My Controller works when I do a query, but why should I have to run a query? Shouldn't the Standard Controller getRecord() give me the ENTIRE record??? The examples I've seen in the VF doco shows that there is no need to query so I'm confused.

 

public PolicyHandler(ApexPages.StandardController controller) {

this.myOppty = (Opportunity)controller.getRecord();

}

 

public PageReference processCloseBoundOpportunity() {

try {

Opportunity oppty = [SELECT 

oppty.Name,

           oppty.Id,

           oppty.Policy_Number__c,

           oppty.Policy_Type__c,

           oppty.Policy_Type_Level_II__c,

           oppty.Insurance_Carrier__c,              

           oppty.OwnerId,

           oppty.AccountId,

           oppty.Split_Owner__c,

           oppty.CloseDate,

           oppty.Effective_Date__c,                    

           oppty.Expiration_Date__c

        FROM Opportunity oppty

        WHERE oppty.Id = : this.myOppty.Id];

System.debug('*************** LOOK *************');

System.debug(oppty.Name);      

 

 

Thanks all for your help!

 

Caleb 

 

/* 
 * ==========================================================================
 *   Copyright (C)  2009  Caleb Sidel
 *   
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * ==========================================================================
 */    
public class EmailUtils {
public static void sendEmailWithStandardAttachments(List<String> recipients,String emailSubject,String body,Boolean useHTML,List<Id> attachmentIDs) {
List<Attachment> stdAttachments = [SELECT id, name, body FROM Attachment WHERE Id IN:attachmentIDs];
sendEmailWithStandardAttachments(recipients, emailSubject, body, useHTML, stdAttachments);
}
public static void sendEmailWithStandardAttachments(List<String> recipients,String emailSubject,String body,Boolean useHTML,List<Attachment> stdAttachments) {
List<Messaging.EmailFileAttachment> fileAttachments = new List<Messaging.EmailFileAttachment>();
for(Attachment attachment : stdAttachments) {
Messaging.EmailFileAttachment fileAttachment = new Messaging.EmailFileAttachment();
fileAttachment.setFileName(attachment.Name);
fileAttachment.setBody(attachment.Body);
fileAttachments.add(fileAttachment);
}
sendEmail(recipients, emailSubject, body, useHTML, fileAttachments);
}
 
public static void sendTextEmail(List<String> recipients,String emailSubject,String textBody) { 
sendEmail(recipients, emailSubject, textBody, false, null);
}
public static void sendHTMLEmail(List<String> recipients,String emailSubject,String htmlBody) { 
sendEmail(recipients, emailSubject, htmlBody, true, null);
}
public static void sendEmail(List<String> recipients,String emailSubject,String body,Boolean useHTML,List<Messaging.EmailFileAttachment> fileAttachments) { 
if(recipients == null) return;
if(recipients.size() == 0) return;
   // Create a new single email message object
   // that will send out a single email to the addresses in the To, CC & BCC list.
   Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();    
   //the email is not saved as an activity.
   mail.setSaveAsActivity(false);
   // Assign the addresses for the To lists to the mail object.
   mail.setToAddresses(recipients);      
   // Specify the subject line for your email address.
   mail.setSubject(emailSubject);
   // Set to True if you want to BCC yourself on the email.
   mail.setBccSender(false);
   // The email address of the user executing the Apex Code will be used.
   mail.setUseSignature(false);
   if (useHTML) {
    // Specify the html content of the email.
    mail.setHtmlBody(body);
   } else {
   // Specify the text content of the email.
   mail.setPlainTextBody(body);
   }
   // Specify FileAttachments
   if(fileAttachments != null && fileAttachments.size() > 0) {
    mail.setFileAttachments(fileAttachments);
   }
   // Send the email you have created.
   Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
static testMethod void testsendEmail_test() {
system.debug('## Start the testSendSupportEmails_test');
List<String> recepients=new String[]{'test@test.com','test2@test.com'};
sendTextEmail(recepients,'Test method', 'This is to test the sendTextNotificationEmail method');
sendHTMLEmail(recepients,'Test method', 'This is to test the sendTextNotificationEmail method');
static testMethod void testsendEmailNoReceipients_test() {
system.debug('## Start the testSendSupportEmails_test');
List<String> recepients=null;
sendTextEmail(recepients,'Test method', 'This is to test the sendTextNotificationEmail method');
recepients=new List<String>();
sendHTMLEmail(recepients,'Test method', 'This is to test the sendTextNotificationEmail method');
}
static testMethod void testsendEmailWithAttachment_test() {
system.debug('## Start the testSendSupportEmails_test');
List<String> recepients=new String[]{'test@test.com','test2@test.com'};
List<Attachment> stdAttachments = new List<Attachment>();
Attachment a = new Attachment();
a.Name = 'Test';
a.Body = EncodingUtil.base64Decode('Test Body');
stdAttachments.add(a);
sendEmailWithStandardAttachments(recepients,'Test method', 'This is to test the sendTextNotificationEmail method',false,stdAttachments);
}
static testMethod void testsendEmailWithAttachmentIDs_test() {
system.debug('## Start the testSendSupportEmails_test');
List<String> recepients=new String[]{'test@test.com','test2@test.com'};
List<ID> stdAttachments = new List<ID>();
Account acct = new Account(name='Test Account');
insert acct;
Attachment a = new Attachment();
a.ParentId = acct.Id;
a.Name = 'Test';
a.Body = EncodingUtil.base64Decode('Test Body');
insert a;
stdAttachments.add(a.Id);
sendEmailWithStandardAttachments(recepients,'Test method', 'This is to test the sendTextNotificationEmail method',false,stdAttachments);
}
}

I'm getting a heap size exception. I know I can call @future and I know I can check the limit with Limits.getHeapSize() and Limits.getLimitHeapSize(). But I'd like to avoid @future and I'd like to avoid simply stopping my operation before the limit is reached.

 

Ideally I'd like to be able tofigure out what is taking up memory and clean up my memory!

 

I'm doing a query which returns 432 records and then I'm looping over those records as follows:

 

         for(Record__c child:children)
        {
            totalPages += child.Pages__c != null ? child.Pages__c : 0;
            pagesTriaged += child.Pages_Triaged_Sum__c != null ? child.Pages_Triaged_Sum__c : 0;
            pagesToTriage += child.Pages_to_Triage__c != null ? child.Pages_to_Triage__c : 0;
            pagesMined += child.Pages_Mined_Sum__c != null ? child.Pages_Mined_Sum__c : 0;
            pagesToMine += child.Pages_to_Mine__c != null ? child.Pages_to_Mine__c : 0;
            pagesReviewed += child.Pages_Reviewed_Sum__c != null ? child.Pages_Reviewed_Sum__c : 0;
            pagesToReview += child.Pages_to_Review__c != null ? child.Pages_to_Review__c : 0;
        }

 

The heapsize exception occurs during this loop. I'm not storing a lot in memory but I'm thinking that somehow when I do variable += 1; the heap is making a copy of the variable and the heap isn't cleaning itself up?

 

So I've changed my code to as below and I'm trying to deploy it to test it, but while I'm waiting for it to deploy I thought I'd ask the community...any other ideas? I will post back with results once deployed and/or other things I try until it is either solved or I revert to using @future.

 

        while(children.size() > 0)
        {
            Record__c child = children.remove(i);
            totalPages += child.Pages__c != null ? child.Pages__c : 0;
            pagesTriaged += child.Pages_Triaged_Sum__c != null ? child.Pages_Triaged_Sum__c : 0;
            pagesToTriage += child.Pages_to_Triage__c != null ? child.Pages_to_Triage__c : 0;
            pagesMined += child.Pages_Mined_Sum__c != null ? child.Pages_Mined_Sum__c : 0;
            pagesToMine += child.Pages_to_Mine__c != null ? child.Pages_to_Mine__c : 0;
            pagesReviewed += child.Pages_Reviewed_Sum__c != null ? child.Pages_Reviewed_Sum__c : 0;
            pagesToReview += child.Pages_to_Review__c != null ? child.Pages_to_Review__c : 0;
            child = null;
            i++;           
        }

 

Thank you,

Caleb

We had a nice pageBlockTable like so:
 
    <apex:pageBlockTable value="{!RecordView}" var="record" id="record">
    <apex:column headerValue="Name" value="{!record.RecordName}"/>
    <apex:column headerValue="Pages" value="{!record.Pages}"/>
    </apex:pageBlockTable> 
 
And it worked great in Firefox, but failed in IE. The problem was if Pages was ever null the table rendered without a line under that cell. So the table looked very strange. The question, how to get a white space into the value instead of nothing?
 
We changed it to:
    <apex:pageBlockTable value="{!RecordView}" var="record" id="record">
    <apex:column headerValue="Name">&nbsp;{!record.RecordName}</apex:column>
    <apex:column headerValue="Pages">&nbsp;{!record.Pages}</apex:column>
    </apex:pageBlockTable>  
 
Maybe we could have modified the Controller, however we fixed it in the page, it works, so I thought I'd share. Please comment if you have other solutions, or thoughts, or...well...comments.
 
Thanks,
Caleb

UNKNOWN_EXCEPTION, portal account owner must have a role

 

I can not seem to create a customer portal user for my testMethod...has anyone else had success?

 

I really want to runAs() a portal user since the code will be run from there. Currently I'm simply querying for an existing portal user, but that means I have to ensure the same Account/Contact/User are created in every environment including Production and I'd like to avoid having to rely on "dummy" data in Production for my tests to work.

 

I create an account, I create a contact, the account is owned by a user who has a role and profile...but I still get the error above

 

Here is my simplified code (removed personal info, etc) which throws the above error...

 

     static testMethod void Test_getSubjects() {
        Profile pp = [select id from Profile where name LIKE '%Portal%' LIMIT 1];
        Profile sysp = [select id from Profile where name LIKE 'System Administrator' LIMIT 1];
        UserRole r = [select id from UserRole where name = 'CEO' LIMIT 1];
        System.assertNotEquals(null,r);
        User sysU = new User(alias = 'admin',
                    email='admin@testorg.com',
                    emailencodingkey='UTF-8',
                    lastname='Testing',
                    languagelocalekey='en_US',
                    localesidkey='en_US',
                    profileid = sysp.Id,
                    userroleid = r.Id,
                    timezonesidkey='America/Los_Angeles',
                    username='admin@testorg.com');
        insert sysU;
        Account acct = new Account(name='test');
        acct.owner = sysU;
        insert acct;


        User assertUser = [select userroleid from user where id =: acct.ownerId LIMIT 1];

        System.assertNotEquals(null,assertUser.userRoleId);

 

        Contact cont = new Contact();
        cont.lastname = 'test';
        cont.phone = '555-555-5555';
        cont.Account = acct;
        insert cont;
        User u = new User(alias = 'port',
                            email='portaluser@testorg.com',
                            emailencodingkey='UTF-8',
                            lastname='Testing',
                            languagelocalekey='en_US',
                            localesidkey='en_US',
                            profileid = pp.Id,
                            contactid = cont.Id,
                            timezonesidkey='America/Los_Angeles',
                            username='portaluser@testorg.com');
        insert u;
        Test.startTest();
        System.runAs(u) {
            Boolean result = myMethod();

            System.assertEquals(true,result);
        }
        Test.stopTest();
    }

 

Thank you very much. Any and all help is greatly appreciated!

Caleb

Probably its just me, because I do not see anybody complaining about this. I have a simple VF page with pageblock referencing to a wrapper object. I need to display text from that wrapper object in headerValue for a column, but cannot do that, After trying for almost half a day, I have given up. 

 

Please look at column 2, dynamic referencing cannot be simple that this. It is just calling a string field, objType from the wrapper class. If one argues, that it has to be sObject field, please look at column 3. I am typecasting it with hardcoded 'ListPrice' field, but it still won't work. 

 

What is most frustrating, inputText values within those 2 columns which is replica of 'headerValue' works just fine, I can see ObjectType and field Lable in 2nd and 3rd column respt. 

 

Please help me , am I missing something here? are 'headerValues' exception to dynamic binding. I am sure someone might have come across this in the past. 

 

VF page:

<apex:pageBlock >
 <apex:pageBlockTable id="tbl1" value="{!wObjs}" var="wObj">                  
  <apex:column headerValue="Select">   
    <apex:inputCheckbox value="{!wObj.selected}" required="true" />
  </apex:column>               
  <apex:column headerValue="{!wObj.objType}">   
    <apex:inputText value="{!wObj.objType}" required="true" /> 
  </apex:column>              
  <apex:column headerValue="{!$ObjectType[wObj.objType].Fields.ListPrice.Label}">   
    <apex:inputText value="{!$ObjectType[wObj.objType].Fields['ListPrice'].Label}" required="true" /> 
  </apex:column>                             
 </apex:pageBlockTable>
</apex:pageBlock>

 Apex class (wrapper object):

public class wObj{
 public sObject sObj {get; set;}
 public string objType {get; set;}
 public Boolean selected {get; set;}
		        
 public wObj(sObject childObjRecord, boolean selected){
   this.sObj = childObjRecord; 
   this.objType = childObjRecord.getSObjectType().getDescribe().getName(); 
   this.selected = selected;
 }
}

 

Has anyone successfully used addError on a field dynamically on an SObject?

 

Something like the below in concept (note the below doesn't work because get(FieldName) returns the value in that field, not the field itself...

 

Account a = [Select fields FROM Account WHERE stuff];

SObject obj = (SObject)a;

obj.get('FieldName__c').addError('Something or other');

 

Thank you,

Caleb

 

Is this possible and, if so, how? Any advice would be much appreciated. I am trying to avoid the VF route because the rich text fields have more flexibility with the pictures. However, most of my clients show up with 1000+ pictures that need to be associated with a custom object in my app and I need to mass upload. 

 

 

I've Downloaded Eclipse 3.5 SR2 (from the link provided in Installation of Force.come IDE), and I'm trying to install Force.come IDE in it, and am facing this error: Cannot complete the install because one or more required items could not be found. Software being installed: Force.com IDE 18.0.0.201004191706 (com.salesforce.ide.feature.feature.group 18.0.0.201004191706) Missing requirement: Force.com IDE Compatibility 18.0.0.201004191706 (com.salesforce.ide.core.compatibility 18.0.0.201004191706) requires 'package org.apache.log4j 0.0.0' but it could not be found Cannot satisfy dependency: From: Force.com IDE 18.0.0.201004191706 (com.salesforce.ide.feature.feature.group 18.0.0.201004191706) To: com.salesforce.ide.core.compatibility [18.0.0.201004191706] I could not install the IDE :( .. please help.
  • April 20, 2010
  • Like
  • 0

I am writing a test class for a trigger that has multiple for loops in it and When I run the test the lines that are not covered are the for loops.

 

Here is part of the trigger:

trigger AutoCreateIncident on Account (after update) { List<Case> c = new List<Case>(); for (Integer i = 0; i < Trigger.new.size(); i++) { Account newCase = Trigger.new[i]; Account OldCase = Trigger.old[i]; if(newCase.Operational_Status__c == 'Operational' && oldCase.Operational_Status__c == 'IT GO'){ if(newCase.Account_Services_Rep__c == 'Ade Adeyemi' || oldCase.Account_Services_Rep__c == 'Ade Adeyemi'){ for(Integer j = 0; j < 24; j++){ c.add(new Case(Type = 'Health Check', Reason__c = 'Health Check', AccountId = newCase.Id, OwnerId = '005700000016ePl', Priority = 'High', Due_date__c = System.today() + (j*30) + 1)); } } else if(newCase.Account_Services_Rep__c == 'Chris Nelson' || oldCase.Account_Services_Rep__c == 'Chris Nelson'){ for(Integer k = 0; k < 24; k++){ c.add(new Case(Type = 'Health Check', Reason__c = 'Health Check', AccountId = newCase.Id, OwnerId = '005700000016eQ4', Priority = 'High', Due_date__c = System.today() + (k*30) + 1)); } } else if(newCase.Account_Services_Rep__c == 'Deborah Kerr' || oldCase.Account_Services_Rep__c == 'Deborah Kerr' ){ for(Integer l = 0; l < 24; l++){ c.add(new Case(Type = 'Health Check', Reason__c = 'Health Check', AccountId = newCase.Id, OwnerId = '005700000016ePr', Priority = 'High', Due_date__c = System.today() + (l*30) + 1)); } } else if(newCase.Account_Services_Rep__c == 'Elyssa Kim' || oldCase.Account_Services_Rep__c == 'Elyssa Kim'){ for(Integer m = 0; m < 24; m++){ c.add(new Case(Type = 'Health Check', Reason__c = 'Health Check', AccountId = newCase.Id, OwnerId = '00570000001IbB3', Priority = 'High', Due_date__c = System.today() + (m*30) + 1)); } } } } insert c; }

I understand this is not the most efficent or best way to code this trigger, but this is how i have chosen to code it for now. The lines of code that I am not sure how to test are the for loop lines and the "c.add(new Case(" lines. any suggestions on how to tackle this one?

 

I also have another one that has a few Field.addErrors in it and I am not sure how to test those lines of code either 

 

Thanks

  • November 24, 2009
  • Like
  • 0

Page 143 of the Apex Guide states

 

All Apex sharing reason names have the following format:

MyReasonName__c

Apex sharing reasons can be referenced programmatically as follows:

Schema.CustomObject__Share.rowCause.SharingReason__c

For example, an Apex sharing reason called Recruiter for an object called Job can be referenced as follows:

Schema.Job__Share.rowCause.Requester__c

 

 

however when I try to save my code I get the error that the variable doesn't exist. If I try Schema.CustomObject__Share.rowCause.Manual I also get an error.

 

So it seems that that Schema is not where rowCauses are stored and/or I'm missing something. Has anyone successfully used custom rowCauses? If so what's the format?

 

Thank you,

Caleb

The error I get is:

 SObject row was retrieved via SOQL without querying the requested field: Opportunity.Name

 

Here is my VF page (quite simple I thought)

 

<apex:page standardController="Opportunity" extensions="PolicyHandler">

<apex:form >

<apex:pageBlock title="Close & Bind Opportunity">

<apex:messages />

<apex:outputText value="Once you close and bind an Opportunity it can no longer be edited. Are you sure you want to proceed?"/>

<apex:pageBlockButtons location="bottom">

<apex:commandButton value="Close & Bind" action="{!processCloseBoundOpportunity}"/>

<apex:commandButton value="Cancel" action="{!cancel}"/>

</apex:pageBlockButtons>

</apex:pageBlock>

</apex:form>

</apex:page> 

 

Here is my Controller, the code never gets to the yeah made it part

 

 public PolicyHandler(ApexPages.StandardController controller) {

this.myOppty = (Opportunity)controller.getRecord();

}

 

public PageReference processCloseBoundOpportunity() {

try {

System.debug('*************** LOOK *************');

System.debug(this.myOppty.Name);         

                        System.debug('***********YEAH MADE IT************');

//Do stuff

       PageReference p = new PageReference('/' + myOppty.Id);

       p.setRedirect(true);

       return p;

} catch (Exception exp) {

         ApexPages.addMessage(new ApexPages.message(ApexPages.severity.ERROR,exp.getMessage()));

         return null;

        }

}

 

My Controller works when I do a query, but why should I have to run a query? Shouldn't the Standard Controller getRecord() give me the ENTIRE record??? The examples I've seen in the VF doco shows that there is no need to query so I'm confused.

 

public PolicyHandler(ApexPages.StandardController controller) {

this.myOppty = (Opportunity)controller.getRecord();

}

 

public PageReference processCloseBoundOpportunity() {

try {

Opportunity oppty = [SELECT 

oppty.Name,

           oppty.Id,

           oppty.Policy_Number__c,

           oppty.Policy_Type__c,

           oppty.Policy_Type_Level_II__c,

           oppty.Insurance_Carrier__c,              

           oppty.OwnerId,

           oppty.AccountId,

           oppty.Split_Owner__c,

           oppty.CloseDate,

           oppty.Effective_Date__c,                    

           oppty.Expiration_Date__c

        FROM Opportunity oppty

        WHERE oppty.Id = : this.myOppty.Id];

System.debug('*************** LOOK *************');

System.debug(oppty.Name);      

 

 

Thanks all for your help!

 

Caleb 

 

      Need help to write a trigger to pre-populate 3 look fields. 2 of these fields come from the contacts and 1 is coming from the user. We need to deploy this by this Friday. Your help would be appreciated. I am new to programming
Message Edited by susheel1 on 08-19-2009 01:03 PM

I've got an Apex trigger that I'm attempting to bulkify to handle multiple records.  Essentially what I want to do is to update a custom Number field on my Campaign records, which is a count of a number of Lead records that have a particular status (Note: Lead Status, not Campaign Member status), any time a Lead record is updated.

 

I did a proof of concept for a single record, using the following trigger:

 

trigger leadTrigger1 on Lead(after insert, after update, after delete) { CampaignMember cm = [select CampaignId from CampaignMember where LeadId = :Trigger.new[0].Id limit 1]; Campaign c = [select Id, name, Wastage__c from Campaign where Id = :cm.CampaignId limit 1]; Integer count = [select count() from CampaignMember where CampaignId = :cm.CampaignId and Lead.Status = 'Closed - Not Converted']; System.Debug( 'count = ' + count ); c.Wastage__c = (Double)count; update(c); }

 

 

This works great for one record, but it doesn't take into consideration updates of multiple Lead records that are possibly associated with different campaigns.  I'm attempting to write something to the effect of:

 

trigger leadTrigger1 on Lead(after insert, after update, after delete) { System.Debug( 'leadTrigger1 fired!' ); Set<Id> leadIds = new Set<Id>(); for( Lead l : Trigger.old ) leadIds.add(l.Id); for( Lead l : Trigger.new ) leadIds.add(l.Id); CampaignMember [] cms = [select CampaignId from CampaignMember where LeadId in :leadIds]; Set<Id> cIds = new Set<Id>(); for( CampaignMember cm : cms ) cIds.add( cm.CampaignId ); Campaign [] cList = [select Id, name, Wastage__c from Campaign where Id in :cIds]; Map<Id, Integer> counts = new Map<Id, Integer> = Some SOQL query that will give me a map of Ids and the counts associated with those Ids. for( Campaign c : cList ) { c.Wastage__c = (Double)counts.get(c.Id); update(c); } }

 

 

But I'm not having any luck coming up with a SOQL query to give me a map of the Ids with the count.  Can this be done?  Any help would be greatly appreciated.

 

Thanks in advance,

Max

I'm trying to put together an APEX class that will the User table and return the ID, based on a custom variable called Sales__c, for that user.  The ID will then be used to change the OwnerID field on the Account record.

 

Regardless of what I can think to try, I keep running in to walls.  Would greatly appreciate a gentle prodding in the correct direction.

 

 

Account[] Users = [Select a.Owner.Id, a.Owner.Sales__c from Account a  WHERE a.Owner.Sales__c  = '6579'];
           
a.OwnerID= Users.Id;

I'm getting a heap size exception. I know I can call @future and I know I can check the limit with Limits.getHeapSize() and Limits.getLimitHeapSize(). But I'd like to avoid @future and I'd like to avoid simply stopping my operation before the limit is reached.

 

Ideally I'd like to be able tofigure out what is taking up memory and clean up my memory!

 

I'm doing a query which returns 432 records and then I'm looping over those records as follows:

 

         for(Record__c child:children)
        {
            totalPages += child.Pages__c != null ? child.Pages__c : 0;
            pagesTriaged += child.Pages_Triaged_Sum__c != null ? child.Pages_Triaged_Sum__c : 0;
            pagesToTriage += child.Pages_to_Triage__c != null ? child.Pages_to_Triage__c : 0;
            pagesMined += child.Pages_Mined_Sum__c != null ? child.Pages_Mined_Sum__c : 0;
            pagesToMine += child.Pages_to_Mine__c != null ? child.Pages_to_Mine__c : 0;
            pagesReviewed += child.Pages_Reviewed_Sum__c != null ? child.Pages_Reviewed_Sum__c : 0;
            pagesToReview += child.Pages_to_Review__c != null ? child.Pages_to_Review__c : 0;
        }

 

The heapsize exception occurs during this loop. I'm not storing a lot in memory but I'm thinking that somehow when I do variable += 1; the heap is making a copy of the variable and the heap isn't cleaning itself up?

 

So I've changed my code to as below and I'm trying to deploy it to test it, but while I'm waiting for it to deploy I thought I'd ask the community...any other ideas? I will post back with results once deployed and/or other things I try until it is either solved or I revert to using @future.

 

        while(children.size() > 0)
        {
            Record__c child = children.remove(i);
            totalPages += child.Pages__c != null ? child.Pages__c : 0;
            pagesTriaged += child.Pages_Triaged_Sum__c != null ? child.Pages_Triaged_Sum__c : 0;
            pagesToTriage += child.Pages_to_Triage__c != null ? child.Pages_to_Triage__c : 0;
            pagesMined += child.Pages_Mined_Sum__c != null ? child.Pages_Mined_Sum__c : 0;
            pagesToMine += child.Pages_to_Mine__c != null ? child.Pages_to_Mine__c : 0;
            pagesReviewed += child.Pages_Reviewed_Sum__c != null ? child.Pages_Reviewed_Sum__c : 0;
            pagesToReview += child.Pages_to_Review__c != null ? child.Pages_to_Review__c : 0;
            child = null;
            i++;           
        }

 

Thank you,

Caleb

Hi all,
 
 
It seems that VF doesn't know to render currency field with the right currency Symbol when displaying the UnitPrice field of the  PriceBookEntry sObject:
 
Here my Controller Code:
 
Code:
public class TEST {public PriceBookEntry getMyProd(){  return [select Id,UnitPrice,Product2.currencyisocode from PriceBookEntry where id =:'01uR0000000bGho'];}}

 01uR0000000bGho is  PriceBookEntry record id  which currency equals to  EUR ->  EUR 1,500.00
 
Here is my VF Page
 
Code:
<apex:outputField value="{!MyProd.UnitPrice}"/><br/>Real currency Symbol : <apex:outputField value="{!MyProd.Product2.currencyisocode}"/>

 
Here is the result:
 
List Price  USD 1,500.00
Real currency Symbol : EUR 
When the expected result should be :
 
List Price  EUR 1,500.00
Real currency Symbol : EUR
 
 
This is very strange, it seems to be a serious issue.
 
Any Idea or comment?


Message Edited by Sami Cohen on 01-15-2009 04:29 AM

Message Edited by Sami Cohen on 01-15-2009 04:30 AM

Message Edited by Sami Cohen on 01-15-2009 04:31 AM

Message Edited by Sami Cohen on 01-15-2009 04:50 AM
Message Edited by Sami Cohen on 03-17-2009 11:38 PM
Adding the red required bar to an inputField is easy as when you make the field required it automatically adds the bar. Yet I am having trouble with other components such as selectList or inputText. Even if you make these required the red bar does not automatically show up so I am assuming this must be done manually with styling.

Unfortunately for me I'm not too crafty with styling (still learning) so any help is appreciated.

Thanks,
Jason