• voutcher
  • NEWBIE
  • 25 Points
  • Member since 2009

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

Hopefully a quick question? How does one access relationships in a testmethod?

What I'm doing is building an environment something like:

Account a = new Account(Name='myaccount');
insert a;

customobj c = new customobj(Aname = 'Harry', Account = a.ID);
insert c;

controller.mymethodtobetested();

 

I want to do something like c.Account__r.Name in a SOQL query in mymethodtobetested() but the object relationships aren't built at that point because nothing is committed. For a user, there is no possibility that the relationships wouldn't be available at that point.

How do I test methods that use object relationships like this?

Thanks all.

 

We have some strange effects with respect to attachments. They don't seem to behave like a normal object, which is both concerning and limiting. The problem is:

 

Users are normally restricted to the objects they own and those which are shared with them through the sharing settings. We have shared some of our objects on the basis of roles such that a user can see the records of another in the same department. What we are finding however is the following:

 

  • Attachments can be viewed regardless of whether they have access to the parent record
  • Attachments can be found and opened in the quick search even if they have no access to the parent record (most disturbing)

The work around to this is apparently to set the IsPrivate flag, however:
  • If you set the IsPrivate flag it doesn't respect the normal sharing settings of the parent object (i.e. it is restricted only to the creator of the attachment.)
  • If you set the IsPrivate flag you can't open the attachment but the attachment is still listed in searches (you just get an insufficient privileges error)
  • If you don't set the IsPrivate flag any user can see any attachment if they search for something obvious like 'pdf'

Is there a workaround? Is there another setting I should look at? Is the security for attachments just broken?

 

Thanks for any assistance.

Hello,

I get the following error at runtime when a given contact has  more than 499 related Cases:

Error: Invalid Data. 
Review all error messages below to correct your data.
common.apex.runtime.impl.TriggerExecutionException: Apex trigger TotalsUpdate caused an unexpected exception, contact your administrator: TotalsUpdate: execution of AfterUpdate caused by: System.Exception: Too many query rows: 1002: Trigger.TotalsUpdate: line 44, column 11
 

 

Line 44 corresponds to this:

 

conts = [select Id, Last__Date__c, First__Date__c, Vol_Hours__c, Num_of_shift__c, (select of_Hours__c, Activity_Date__c from Cases order by Activity_Date__c Desc) from Contact where ID in :contIDs ];

 

Is this an issue with the governor limit?

 

If this is the case, is there a way to avoid the limit?

 

Thanks a lot.

 

Pierre

 

Here is the full trigger: 

trigger TotalsUpdate on Case (after delete, after insert, after update) { set<ID> contIDs = new Set<ID>(); if(Trigger.isInsert) { for(Case c : System.Trigger.new){ if (c.of_Hours__c <> NULL) {contIDs.add(c.ContactId);} } Contact[] conts = new List<Contact>(); conts = [select Id, Last__Date__c, First__Date__c, Vol_Hours__c, Num_of_shift__c, (select of_Hours__c, Activity_Date__c from Cases order by Activity_Date__c Desc) from Contact where ID in :contIDs ]; Case[] ca = new List<Case>(); Map<Id, Case[]> contcase = new Map<Id, Case[]>(); for (Contact eachCont: conts){ contcase.put(eachCont.Id, eachCont.Cases); } Contact[] updatedContacts = new List<Contact>(); Case[] cas = new List<Case>(); for (Contact c : conts ){ cas=contcase.get(c.Id); c.Last__Date__c = cas[0].Activity_Date__c; c.First__Date__c = cas[cas.size()-1].Activity_Date__c; Double SumOfHours = 0; Double NumOfShift = 0; for(Case cse : cas) { SumOfHours += cse.of_Hours__c; NumOfShift = NumOfShift + 1; } c.Vol_Hours__c = SumOfHours; c.Num_of_shift__c = NumOfShift; updatedContacts.add(c); } if (updatedContacts.size()>0) {update updatedContacts;} } if(Trigger.isDelete || Trigger.isUpdate) { for(Case c : System.Trigger.old){ if (c.of_Hours__c <> NULL) {contIDs.add(c.ContactId);} } Contact[] conts = new List<Contact>(); conts = [select Id, Last__Date__c, First__Date__c, Vol_Hours__c, Num_of_shift__c, (select of_Hours__c, Activity_Date__c from Cases order by Activity_Date__c Desc) from Contact where ID in :contIDs ]; Case[] ca = new List<Case>(); Map<Id, Case[]> contcase = new Map<Id, Case[]>(); for (Contact eachCont: conts){ contcase.put(eachCont.Id, eachCont.Cases); } Contact[] updatedContacts = new List<Contact>(); Case[] cas = new List<Case>(); for (Contact c : conts ){ cas=contcase.get(c.Id); Double SumOfHours = 0; Double NumOfShift = 0; c.Last__Date__c = NULL; c.First__Date__c = NULL; if(cas.size()>0){ c.Last__Date__c = cas[0].Activity_Date__c; c.First__Date__c = cas[cas.size()-1].Activity_Date__c; for(Case cse : cas) { SumOfHours += cse.of_Hours__c; NumOfShift = NumOfShift + 1; } } c.Vol_Hours__c = SumOfHours; c.Num_of_shift__c = NumOfShift; updatedContacts.add(c); } if (updatedContacts.size()>0) {update updatedContacts;} } }

 

 

   

I have an object which is basically a store for some metadata about an attachment. I then attach a document to it which creates a neat parcel of the document and its metadata.

 

The problem is that this object has its Sharing Settings set to  'Private' but when I upload the attachment it is visible to everyone. The problem seems to be that when you upload an attachment the 'IsPrivate' flag can't be set on upload.

 

Is it possible to make the attachment follow the sharing rules of its parent?

 

Thanks for any help.

I'm pretty sure I'm just trying to do some straightforward AJAX here.  When I use oncomplete or reRender widhin actionFunction, I see the following Javascript error (via Firebug):

 

element.selectNodes is not a function

 

And the Javascript engine basically choke at this point.   The error happens within the Salesforce AJAX library: 

3_3_0.GAorg.ajax4jsf.javascript.AjaxScript on line 101.  This occurs at a point where the code does a try{selectNodes()} to figure out of it should run either selectNodes() or getElementsByTagName().  If the try{} fails, the catch(){} should run the getElementsByTagName().

 

I've seen this in FF3.5.6, though things seem to work fine in FF3.0.16.   In IE7 and IE8 I get data back inconsistently.  Generally if I put trash data in yahooProduct and then try good data, I will things will work fine.  However, until I do this special sequence, the AJAX will not work in IE.  I know, this part this sounds like a bug of my own making... probably is... but for the life of me I cannot pin point it.  The code isn't all that complicated.

 

If I take out oncomplete and reRender, I get no Javascript errors.  Of course, I have no way to see if the AJAX did anything, either.

 

Strangely, I can find no references to this issue on the discussion boards.  I'm not doing anything particularly fancy.  Anything stand out in my code below?

 

 

My Visualforce:

 

 

<apex:page standardController="Purchase__c" extensions="PurchaseExtension" recordSetVar="purchases" title="New Purchase">

<apex:sectionHeader title="Purchase Edit" subtitle="New Purchase"/>

<apex:messages layout="table"/>

<style>
td.labelCol {
vertical-align: middle;
}
</style>
<apex:form styleclass="p-form" id="p_form">

<apex:pageBlock title="Purchase Edit" mode="edit">

<apex:actionFunction name="updateProductDetails" action="{!updateProductDetails}" immediate="true" reRender="field_table">
<apex:param name="firstParam" assignTo="{!yahooProduct}" value="" />
</apex:actionFunction>

<apex:outputPanel id="field_table">
<table cellspacing="0" cellpadding="0" border="0">
<tbody>
<tr>
<td class="labelCol requiredInput">Contact</td>
<td class="dataCol col02" style="height:20px;">
<apex:inputField value="{!p.Contact__c}" required="true"/>
</td>
</tr>
<tr>
<td class="labelCol requiredInput">Purchase Date</td>
<td class="dataCol col02">
<apex:inputField value="{!p.Purchase_Date__c}" required="true"/>
</td>
</tr>
<tr>
<td class="labelCol requiredInput">Yahoo! Product</td>
<td class="dataCol col02">
<apex:inputField value="{!p.Yahoo_Product__c}" required="true" onchange="updateProductDetails(this.value)" />
</td>
</tr>
<tr>
<td class="labelCol requiredInput">Item Description</td>
<td class="dataCol col02">
<input disabled="true" id="item-desc" type="text" value="{!productDesc}"/>
</td>
</tr>
<tr>
<td class="labelCol requiredInput">Item Price</td>
<td class="dataCol col02">
<input disabled="true" id="item-price" type="text" value="{!productPrice}"/>
</td>
</tr>
<tr>
<td class="labelCol requiredInput">Quantity</td>
<td class="dataCol col02">
<apex:inputField value="{!p.Quantity__c}"/>
</td>
</tr>
<tr>
<td class="labelCol requiredInput">Total</td>
<td class="dataCol col02">
<input id="total" type="text"/>
</td>
</tr>
<tr>
<td class="labelCol requiredInput">Ship Date</td>
<td class="dataCol col02">
<apex:inputField value="{!p.Ship_Date__c}" />
</td>
</tr>
</tbody>
</table>
</apex:outputPanel>

<apex:inputHidden value="{!p.Name}"/>
<apex:inputHidden value="{!p.Contact__c}"/>

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

</apex:pageBlock>

</apex:form>

</apex:page>

 

 

 

 and my Extension:

 

 

public class PurchaseExtension {
public Purchase__c p {
get {
if (p == null)
p = new Purchase__c();
return p;
}
set;
}

public Contact c {
get {
String contactId = Apexpages.currentPage().getParameters().get('id');
if (c == null) {
c = [select c.FirstName,c.LastName from Contact c where c.id = :contactId];
}
return c;
}
set;
}


String productDesc, productPrice;
public String getProductDesc() {
return productDesc;
}
public String getProductPrice() {
return productPrice;
}

String yahooProduct = 'init';
public void setYahooProduct(String p) {
yahooProduct = p;
}
public String getYahooProduct() {
return yahooProduct;
}

public PageReference updateProductDetails() {
if (yahooProduct != null) {
List<Yahoo_Products__c> yp = [select p.Item_Description__c,p.Price__c from Yahoo_Products__c p where p.Name = :yahooProduct];
if (yp.size() > 0) {
productDesc = yp[0].Item_Description__c;
productPrice = ''+yp[0].Price__c;
} else {
productDesc = 'No product details avalable';
productPrice = 'No product details avalable';
}
} else {
productDesc = 'No product?';
productPrice = 'No product?';
}
return null;
}

public PurchaseExtension(ApexPages.StandardSetController ctlr) {
p.Contact__c = c.Id;
p.Purchase_Date__c = Date.today();
}

public PageReference save() {
PageReference pr = null;
// stub
return pr;
}

public PageReference cancel() {
// stub
return null;
}

public static testMethod void testSave() {
Test.setCurrentPage(new PageReference('/?id=003A0000004JoTl'));
List<Purchase__c> pList = new List<Purchase__c>();
ApexPages.StandardSetController ctlr = new ApexPages.StandardSetController(pList);
PurchaseExtension e = new PurchaseExtension(ctlr);
e.c = new Contact(FirstName = 'Foo', LastName = 'Bar');
e.p.Yahoo_Product__c = 'a04A000000101DT';
e.save();
System.assertNotEquals(e, null);
}

public static testMethod void testUpdateProduct() {
Test.setCurrentPage(new PageReference('/?id=003A0000004JoTl'));
List<Purchase__c> pList = new List<Purchase__c>();
ApexPages.StandardSetController ctlr = new ApexPages.StandardSetController(pList);
PurchaseExtension e = new PurchaseExtension(ctlr);
e.setYahooProduct('HistProd');
e.updateProductDetails();
String newDesc = e.getProductDesc();
System.assertNotEquals(newDesc, null);
}
}

 

 

 

 

Message Edited by JasonGabler on 01-05-2010 11:13 AM
Message Edited by JasonGabler on 01-05-2010 02:37 PM

Logging in to the customer portal is easy, just redirect to the page and force.com does the rest.

 

But, I can't find any way of logging out! Checked the forums, documentation etc.

 

Any ideas? Thanks!

Does anyone have any solutions as to how to run historic point in time reports.

 

For instance I want to be able to run some basic (and some not so basic) tabular reports on custom objects that would give me the data as of an arbitrary date i.e.. 1/1/2007. Currently the data would be as of today.

 

Obviously this would require field tracking to be enabled but I can't find a good solution for reporting on it. My only option it seems is to look at extracting the data on a regular schedule to a custom BI solution.

 

Note that snapshot reporting wouldn't work in this instance since I might not know the exact fields I want to report on ahead of time but would want to graph the historic trend.

 

Thanks for any thoughts.

I am diving into my first Apex trigger creation, and I'm hoping someone out there has some sample code that I can drop in.  We rely heavily on account hierarchies, and I'm writing some triggers to automatically update a few fields across the entire hierarchy when a user changes a value on one account in a family.  The starting point of this trigger is therefore being able to traverse the entire account family, and get a Set of IDs to update that represent all the accounts in that account family.  Our hierarchies can be fairly deep -- sometimes as many as 3 or 4 levels, and I'd like the code to be able to work from anywhere in the hierarchy and update ALL related accounts.

Does anyone have a sample that would take a single account ID as its input and return a set of IDs for all accounts in the family?  It would be a huge time saver.

I'll be sure to post my finished trigger for all to use when it's done!

Thanks in advance.
I've had this issue for quite awhile but just assumed it was working as designed. But since I can't find any references on it in documentation, I thought I'd post here to be sure. Is this a bug or by design?

Running test cases which insert records into an object with an autonumber field cause the autonumber value to actually increment by the number of records inserted during the testmethod execution. After the test is complete, inserting a new record will result in an out-of-sequence autonumber value to be set on the new record. In other words, the autonumber values aren't rolled back during test execution.

In this simple example below the test method inserts 5 records into a custom object called "Book". The custom object contains a field called "Book Id" which is an autonumber field. After running this, the next record that is inserted into the Book object will have a Book Id 5 greater than the previously inserted record.

Code:
public class MyBookClass{

    public static void CreateNewBooks(List<String> titles){
        
        List<Book__c> booksToInsert = new List<Book__c>();
        
        for(String title : titles){
            Book__c b = new Book__c();
            b.Name = title;
            booksToInsert.add(b);
        }
        
        insert booksToInsert;
    }
    
    public static testmethod void CreateNewBookTest(){
        List<String> titles = new List<String>{'Title 1','Title 2','Title 3','Title 4','Title 5'};
        
        CreateNewBooks(titles);
        
        Integer count = [SELECT count() from Book__c where name in ('Title 1','Title 2','Title 3','Title 4','Title 5')];
        
        System.AssertEquals(5, count );
    }

}