• thunksalot
  • NEWBIE
  • 200 Points
  • Member since 2009

  • Chatter
    Feed
  • 7
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 26
    Questions
  • 52
    Replies

It appears that I have code that works perfectly in both a production and a sandbox environment, but does not work when called from a unit test that performs the same operations that work just fine using the GUI.

 

I've modified the CampaignCallDownController to have filters and a search box.  The below test adds one Contact and one Lead to a Campaign, then invokes the CampaignCallDown VF page and controller.  When I do those steps using the GUI in production or the sandbox, the call list shows two records, one Contact and one Lead.  But when I run this unit test, it says there are zero records in the call list.  I've tracked the problem down to this query in the CampaignCallDownController...

 

members = [select Id, ContactId, LeadId, Status, CampaignId, Level_of_Interest__c, 

                    Last_Action__c, Next_Action__c, Campaign.Name,

                    Lead.Id, Lead.Salutation, Lead.Title, Lead.Name, Lead.Company, Lead.Phone, 

                    Lead.Street, Lead.State, Lead.Email,

                    Contact.ID, Contact.AccountId, Contact.Salutation, Contact.Title, Contact.Name

                    Contact.Phone, Contact.MailingState, Contact.Email, Contact.Account.name

                    from CampaignMember where CampaignId = :camp AND Next_Action__c LIKE :desiredNA AND 

                    (NOT Next_Action__c LIKE :excludedNA) AND Level_of_Interest__c LIKE :desiredLI AND 

                    (NOT Level_of_Interest__c LIKE :excludedLI) AND

                    (Contact.Account.Name LIKE :searchFilter OR Contact.Name LIKE :searchFilter

ORContact.Email LIKE :searchFilter 

                    OR Contact.Title LIKE :searchFilter OR Contact.MailingState LIKE :searchFilter OR 

                    Lead.Name LIKE :searchFilter OR Lead.Company LIKE :searchFilter  OR 

                    Lead.Email LIKE :searchFilter OR Lead.Title LIKE :searchFilter OR Lead.State LIKE :searchFilter

                    ORDER BY Contact.Account.name LIMIT :recordsPerPage OFFSET :offset ];

 

I've highlighted the part of the query that performs the search function because that's where the problem is.  When that query gets called from the GUI, it will return all Leads *and* Contacts that match the searchFilter criteria.  But when called from the test, it will only return an empty list, not matter what search or filter criteria are input.  I've stripped the query criteria down to just the red and blue parts and found that if I remove one or the other (the Contact field matching or the Lead field matching criteria) it will return records when called from the below test.  In other words, if I remove the red part it will return 1 Lead in the test below.  Or, if I leave in the red part and remove the blue part, it will return 1 Contact in the test below.  But, if I leave both in, it will return zero leads and zero contacts.  When the same operations are performed in the GUI, it returns two records - both the Lead and the Contact.

 

Anybody know what's going  on?  Have I hit a bug in the way tests are executed by SFDC?  I'm about to pull my hair out - or write a unit test that is really a non-test!! :(

 

 

@isTest
private class CampaignCallDownControllerTest {

     static testMethod void testNormalFlow(){
     	
     	//get campaign member record type ID
     	RecordType rt = [select id,Name from RecordType where SobjectType='CampaignMember' and Name='Email Campaign Member' Limit 1];
     	
        //campaign
        Campaign testCampaign       = new Campaign();
        testCampaign.name           = 'TestCampaign';
        testCampaign.CampaignMemberRecordTypeId = rt.ID;
        insert testCampaign;
        
        Account testAccount		= new Account();
        testAccount.name		= 'TestAccount';
        insert testAccount;  
                
        //Lead
        Lead testLead1          = new Lead();
        testLead1.FirstName     = 'LeadFirstName1';
        testLead1.LastName      = 'LeadLastName1';
        testLead1.Company       = 'Test1';
        insert testLead1;
        
        //Contact
        Contact testContact1         = new Contact();
        testContact1.FirstName       = 'ContactFirstName';
        testContact1.LastName        ='ContactLastName';
        testContact1.Email           = 'Adress1@Adress.com';
        testContact1.Title           = 'ContactTitle';
        testContact1.AccountID 		 = testAccount.ID;
        insert testContact1;
        
        //make campaign members
        CampaignMember testCM1       = new CampaignMember();
        testCM1.leadID               = testLead1.Id;
        testCM1.contactID			 = null;
        testCM1.campaignID           = testCampaign.Id;
        testCM1.Status               = 'Sent';
        testCM1.Level_of_Interest__c = 'Interested';
        testCM1.Next_Action__c 		 = 'contact now';
        insert testCM1;
        
        CampaignMember testCM3      = new CampaignMember();
        testCM3.ContactId           = testContact1.Id;
        testCM3.LeadID			 	= null;
        testCM3.CampaignId          = testCampaign.Id;
        testCM3.Status              = 'Sent';
        testCM3.Level_of_Interest__c= 'Interested';        
        testCM3.Next_Action__c 		= 'contact now';
        insert testCM3;
        
		// Check to make sure the contacts and leads made it into the campaign        
        testCampaign = [SELECT ID, NumberofContacts, NumberOfLeads FROM Campaign WHERE ID = :testCampaign.ID];       
        System.assertEquals(1,testCampaign.NumberofContacts);
        System.assertEquals(1,testCampaign.NumberofLeads);
                
        //begin tests
 		// instantiate page
 		PageReference pageRef = Page.CampaignCallDown;
 		Test.setCurrentPage(pageRef);
 		ApexPages.currentPage().getParameters().put('camp',testCampaign.Id);

        CampaignCallDownController ccdc1 = new CampaignCallDownController();
	System.assert(ccdc1.getHasCampaignID() == TRUE);
	System.assertequals(2, ccdc1.getLeadPlusTasks().size()); // FAILS HERE
		 		
 	}

 

I want to concatenate two object IDs in order to make a hash value for a map, but this doesn't work:

 

conversionMap.put(entry.Pricebook2Id + entry.Product2Id), entry);

If I could convert the IDs to strings first, then I should be able to concatenate them in this way.  But, while there is a function to convert a string to an ID, I can't find any way to convert an ID to a string.  Anybody know how to do that?  Or, a better way to do what I'm trying to do?

 

I'm working with a VF page and Apex controller and I want to be able to do SOQL queries that are limited to 200 results but that start the results at different places in the total query results.  In other words have queries that would get me the first 200 results, the second 200 results and so on...  BUT, I want to be able to jump around so that the user could jump straight from the 1st page of results (records 1-200) to the 5th page of results (query for results 1,000 to 1,200).  Is that possible?  I cannot query *all* the records and then just return 200 to the page at a time because the query returns too much data.  So, I'd want to run the query again each time but getting a specific subset.   Kind of like a row limit but starting at a certain record count.  

 

Totally crazy?

I deployed a class *successfully* on 1/14/2012.  Seven days later, I discovered that when I try to deploy anything at all, even a class that only has whitespace changes, the deployment fails with the message that the test for the class that I deployed successfully on 1/14 has "Too many script statements: 200001".  How can that be?  How can it have passed the test successfully while deploy successfully 10 days ago and now I can't deploy anything because it is failing, when I haven't changed it in any way?!

The worst part is that aside from keeping me from being able to deploy anything, which I discovered on Friday, one of my users discovered yesterday that using the button that calls this class is now resulting in the "Too many script statements: 200001" error message.  So, I now do have business processes being interrupted.  Which is really, really strange because right after I *successfully* deployed that class on 1/14, I used that button to *successfully* process far more records (180) than my users are processing when they use it (1-2).  

 

Anybody have any idea what could have changed between when it was deploying and working fine and now?  I'm totally at a loss to explain what could have changed.  I have all the info about how to deal with this error, in general, such as using @future and reducing for loops, but I want to know how the code could have become broken *after* deploying successfully and running correctly under much greater stress than it is failing under now.  That is the most disconcerting thing to me.

Thanks for any clues!

 

For over a year now, my org has been generating and sending invoices and receipts using VF Components that are rendered as PDFs and attached to VF Email Templates.  The invoices and receipts each use CSS styles defined within a <style> tag in the header.  I just discovered that after the Summer '12 release, those styles are no longer being rendered.  As a result, the CSS style definitions are being printed at the top of the PDFs and the invoices and receipts have no styling.

 

Is anyone else having this problem?  I'm on na7.  I don't see it in the Known Issues but have submitted a support case.

 

I'm going to try moving the style definitions into a CSS stylesheet, loading that as a static resource and then referencing it with the <apex:stylesheet> tag.  Hopefully, that will work.  If not, I'm not sure what to try next.

 

So far, I've only been able to figure out how to generate PDF email attachments that my users can send from an object by embedding the Visualforce code for the PDF within the <messaging:attachment> tag for a Visualforce Email Template.  The downside to this is that the message body of the email is not editable by the user.  This means my generated attachments always get sent with the same impersonal boilerplate message body.

 

I didn't know it was possible to do any better until I got my AppExchange newsletter today and saw the demo of Steel Brick's QuoteQuickly app.  I was surprised to see at the 1:30 mark of the video's second part that they claim they are using Force.com's built-in Send Email functionality to send quotes - and then they show the Send Email form load with an editable message body AND with their generated PDF already attached.  

 

How are they doing that?  Anybody know or have a guess?  

 

Unfortunately, QuoteQuickly doesn't meet my needs, so I need to figure out how to replicate that functionality.

 

Much thanks in advance for any assistance!

For each Account, I need to know the ID of the Opportunity related to it that has the newest renewal date.  I was thinking that I could query Opportunity records for their ID with a GROUP BY on AccountID and a MAX(Renewal_Date__c), like this:

 

AggregateResult[] groupedResults
= [SELECT ID, AccountID, MAX(Renewal_Date__c)
FROM Opportunity
WHERE AccountID in :acctIDs AND RecordTypeID = '012A0000000qpET'
GROUP BY AccountID];

That results in a query failed error message:

 

MALFORMED_QUERY: Field must be grouped or aggregated: Id

I get why an aggregate query won't allow me to return the Opportunity ID, given that I could have several aggregate functions like AVG() and MIN() in the same query, each returning a value that corresponds to a different Opportunity ID.  But, I don't know what else to do.  

 

What is the correct way to populate the AccountID-OppID relationship map that I need in this scenario?

I have noticed that when I use a custom button to call a visualforce page that does some work via a custom controller class before returning the user to the original page (the one on which they clicked the button), that I end up with an accumulation of development mode footers.  See screenshot here  Do I need to do something special when the pageref is returned at the end of my custom controller work such that the development mode footer closes?

 

In the screenshot linked above, I've navigated to four different Opportunities and clicked my custom button, thus resulting in 4 development mode footers all piled up.  It doesn't seem to matter what I go on to do after I click the custom button, the development footer doesn't go away.  The only way that I've found to get rid of the footers when so many have accumulated that it's bothersome is to close the tab completely and start with a fresh tab.  Something tells me there has to be a better way.

SHORT PROBLEM STATEMENT:  If someone has good guidance for the best way to go about splitting the below pdf-rendered visualforce page into a component(s) that will render identically when included in an Apex Page AND when pulled into a VF email template, I would be most grateful!  Obviously, my goal is to use (as much as possible) the same VF code and Apex controller code for the PDF both when it is rendered as an email attachment and when it is rendered from a VF page in a browser.

 

MORE DETAILS:

I created a Visualforce page (pasted below) to produce PDF invoices for our Opportunities.  I created a custom link to it so our staff can generate a PDF invoice for any given Opportunity with a click of their mouse.  It works beautifully.  Then, I wanted to attach the VisualForce page to VisualForce email templates we use for automating our renewal invoicing.  From the documentation, it appears that I have to convert it from a Page it into a Component in order to do that.  So, I tried turning it into a component that can be reference both by the Visualforce page that my custom link calls AND that can be pulled into my Visualforce email templates within <messaging:attachment> tag.  Sounds simple, right? 

 

Unfortunately, I'm pulling my hair out right now because my VF page uses the standard Opportunity controller, which I extended - whereas components cannot use standard controllers at all!  Does that mean I have to write a controller now that mimics everything that my VF page gets from the Opportunity controller?  Is there any easy way to create a controller that mimics everything a standard controller does? 

 

Obviously, my goal is to use (as much as possible) the same VF code and Apex controller code for both the PDF rendered as an email attachment and the PDF when rendered from a browser.  If someone has general guidance for the best way to go about splitting the below pdf-rendered visualforce page into a component(s) that will render identically when included in an Apex Page AND when pulled into a VF email template, I would be most grateful!  

 

BTW - you may notice that my styles include data from the controller.  That's because putting data in a PDF header or footer requires putting it in the "content" attributes of the @page styles.  This has proven to be a problem in my experiments with componentizing this page.  Advice on how to handle the styles, given that they need access to Opportunity data, would be a big help, too.

 

THANK YOU ALL IN ADVANCE!!!!!!!

 

<apex:page standardController="Opportunity" showHeader="FALSE" standardStylesheets="false" renderas="pdf">
<head>
<style type="text/css">
@page{
    size: letter;
    margin: 10%;
    @top-center {
        content: "Invoice Date: {!MONTH(TODAY())}/{!DAY(TODAY())}/{!YEAR(TODAY())}";
            font-family: Helvetica, Arial, sans-serif;
            font-size: 12px;
            font-weight: bolder;
    }
    @top-right {
        content: "Invoice #: {!opportunity.ID_for_invoices__c}";
        font-family: Helvetica, Arial, sans-serif;
        font-size: 12px;
        font-weight: bolder;
    }
    @top-left {
        content: "INVOICE";
        font-family: Helvetica, Arial, sans-serif;
        font-size: 12px;
        font-weight: bolder;
    }
    @bottom-left {
        content: "";
        font-family: Helvetica, Arial, sans-serif;
        font-size: 10px;
    }
    @bottom-right {
        content: "Page " counter(page) " of " counter(pages);
        font-family: Helvetica, Arial, sans-serif;
        font-size: 10px;
    }
}
body {
    font-family: Helvetica, Arial, sans-serif;
    font-size: 11px;
}
table {
    font-family: Helvetica, Arial, sans-serif;  
}
td {
    border: 1px solid #000000;  
}
.tablelabel {
    background: #000000;
    color: #FFFFFF;
    padding: 5px;
    font-weight: bolder;
}
.tableheader {
    font-weight: bolder;
}
.invisiblecell {
    border-left: 0;
    border-bottom: 0;
    border-top: 0;
}
span#warningtext{
    font-size: 80%;
    background: #FFF000;
    float: left;
    padding: 3px;
    margin-right: 8px;
    width: 90px;
    align: middle;
    text-align: right;
}

</style>
</head>

<p><strong>Billed To:</strong></p>
<p>{!opportunity.Account.Name}<br/>
<apex:outputText value="{! IF(ISBLANK(opportunity.Account.BillingStreet),"", opportunity.Account.BillingStreet &"<br/>")}" escape="false"/>
{!opportunity.Account.BillingCity}, {!opportunity.Account.BillingState} {!opportunity.Account.BillingPostalCode}<br/>
{!opportunity.Account.BillingCountry}
</p>

<!-- OUTPUT INVOICE COMMENT, IF ANY  -->
<apex:outputpanel rendered="{! NOT(ISBLANK(opportunity.invoice_comment__c))}">
<p><strong>Comment:</strong> {!opportunity.Invoice_Comment__c}</p>
</apex:outputpanel>

<!-- OUTPUT PROMOTION DESCRIPTION, IF PROMOTION APPLIED -->
<apex:outputpanel rendered="{! NOT(ISBLANK(opportunity.promotion_code__c))}">
<p><strong>Promotion:</strong> {!opportunity.Promotion_Code__c}</p>
</apex:outputpanel>

<!-- OUTPUT ORDERED ITEMS TABLE -->
<table class="tables" cellpadding="6" cellspacing="0" width="100%">
<tr><td colspan="5" class="tablelabel">Order</td></tr>
<tr class="tableheader"><td>Item Description</td><td align="right">List Price</td><td align="right">Sale Price</td><td align="center">Quantity</td><td align="right">Amount</td></tr>
<tr>
</tr>

<apex:repeat var="lineitem" value="{!opportunity.OpportunityLineItems}">
<tr>
<td align="left" width="50%">{!lineitem.PricebookEntry.Product2.Name}</td>
<td align="right"><apex:outputfield value="{!lineitem.ListPrice}" /></td>
<td align="right"><apex:outputfield value="{!lineitem.UnitPrice}" /></td>
<td align="center">{!lineitem.Quantity}</td>
<td align="right"><apex:outputfield value="{!lineitem.TotalPrice}" /></td>
</tr>
</apex:repeat>
<tr><td class="invisiblecell"></td><td colspan="3" class="tablelabel">Order Total</td><td class="tablelabel" align="right"><apex:outputfield value="{!opportunity.Amount}" /></td></tr>
</table>

<p>&nbsp;</p>
<p><strong>To Pay by Credit Card</strong><br/>
We are available to take credit card payments over the phone between 8am and 5pm ET at XXX-XXX-XXXX.</p>

<p>
<strong>To Pay by Check</strong> <br/>
Make checks payable to “XXXXX”, include a memo that the amount is for "XXXXX" and mail to:</p>


<p><span id="warningtext">Please note our<br />new address<br />for payments</span>AASHE<br />
PO Box XXXXXXX<br />
Philadelphia, PA XXXXXX 
</p>

<p><strong><em>Thank you!</em></strong>
</p>

</apex:page>

 

I'm using the online Visualforce documentation to try to learn how to render a visualforce component as a PDF attachment on a visualforce email.  But, when I try creating a component exactly like the one in the documentation I get an error.  Am I missing something or is there a mistake in the documentation??

 

Here's the code I can't get to work (gray box below).  When I copy and paste it into a new visualforce component, it won't save and gives me this error message: Error: Unknown property 'account'

 

Defining a Custom Component as an Attachment

By creating a custom component and using it on the Visualforce email form and to render the PDF for the email, users can see a preview of the content they are trying to send.

The following markup defines a custom component namedattachmentthat represents the attachment for the email:
<apex:component access="global">
  <h1>Account Details</h1>
  
  <apex:panelGrid columns="2">

      <apex:outputLabel for="Name" value="Name"/>
      <apex:outputText id="Name" value="{!account.Name}"/>
      
      <apex:outputLabel for="Owner" value="Account Owner"/>
      <apex:outputText id="Owner" value="{!account.Owner.Name}"/>
      
      <apex:outputLabel for="AnnualRevenue" value="Annual Revenue"/>
      <apex:outputText id="AnnualRevenue" value="{0,number,currency}">
          <apex:param value="{!account.AnnualRevenue}"/>
      </apex:outputText>
      
      <apex:outputLabel for="NumberOfEmployees" value="Employees"/>
      <apex:outputText id="NumberOfEmployees" value="{!account.NumberOfEmployees}"/>
      
  </apex:panelGrid>
</apex:component>
Replace yourattachmentPDFpage like this:

I have a visualforce pdf page that list outs the order (custom object) details.

I am getting this error while loading the pdf page.

 

UNABLE_TO_LOCK_ROW, unable to obtain exclusive access to this record: []

 

the code is performing an update to this object every time, but there is no other trigger on this object.

can't figure out the reason for this error

 

Also, the error comes only in the production environment not in the sandbox.

 

Please help.

Hello. I want to use the Description field in the CampaignMember object for user data entry. However, when I place it on a page layout, it's automatically set to read-only and I can't change it. Is there a way around this? What's the reason for this field to be read-only?