• Dahveed
  • NEWBIE
  • 140 Points
  • Member since 2010

  • Chatter
    Feed
  • 5
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 18
    Questions
  • 30
    Replies
I am working with the chatter in apex APIs. I created a page which lists feeditems and allows the user to mute a feeditem using a checkbox. It worked great until I moved it into a visualforce component and is now giving me a ConnectApi:DML currently not allowed. Is there some kind of capability issue when using chatter ConnectApi through a visualforce component?

Below is the part of the component which parses through the wrapper to show the feed items. When I click the Mark As Read checkbox it throws the error ConnectApi:DML currently not allowed .  However if I put the same code in a normal VF page it works without the error. The system.debug shows the proper Id which needs to be deleted.

<apex:repeat value="{!unreadItems}" var="fItems"> 
                                    <div class="slds-media slds-comment slds-hint-parent">
                                      <div class="slds-media__figure">
                                        <div class="slds-avatar slds-avatar--circle slds-avatar--medium">
                                          <a href="#void" title="{!fItems.fi.actor.Name}">
                                            <img src="{!fItems.fi.photoUrl}" alt="{!fItems.fi.actor.Name}" />
                                          </a>
                                        </div>
                                      </div>
                                      <div class="slds-media__body">
                                        <div class="slds-grid slds-grid--align-spread slds-has-flexi-truncate">
                                          <p class="slds-truncate"><a href="#void" title="{!fItems.fe.header.text}">{!fItems.fe.header.text}</a></p>
                                           <div class="slds-form-element">
                                              <div class="slds-form-element__control">
                                                <label class="slds-checkbox">

                                                  <apex:inputCheckbox value="{!fItems.markAsRead}" onclick="markAsRead();"/>
                                                  
                                                  <span class="slds-checkbox--faux"></span>
                                                  <span class="slds-form-element__label">Mark As Read</span>
                                                </label>
                                              </div>
                                            </div>
                                          </div>
                                        
                                        <p class="slds-text-body--small"><a href="#void" title="Click for single-item view of this post">{!fItems.fe.relativeCreatedDate}</a></p>
                                        <div class="slds-comment__content slds-text-longform">
                                          <p>{!fItems.fe.body.text}</p>
                                        </div>
                                      </div>
                                    </div>                        
                                  </apex:repeat>
                                  <apex:actionFunction name="markAsRead" action="{!muteMsg}" reRender="nTabsPanelContainer1">
                            
                                  </apex:actionFunction>

Public List<FeedItemWrapper> unreadItems{get;set;}
// I populate the wrapper calling the unreadNote()
    public void unreadNote(){
        //unread.clear();
        unreadItems = new List<FeedItemWrapper>();
        ConnectApi.FeedElementPage fep =ConnectApi.ChatterFeeds.getFeedElementsFromFeed(null,ConnectApi.FeedType.Groups, 'me');
        System.Debug('unread : ' + JSON.serializePretty(fep));
        for(ConnectApi.FeedElement fe : fep.elements){  
            unreadItems.add(new FeedItemWrapper(fe));        
        }       
    }

public PageReference muteMsg(){
        for(FeedItemWrapper fiw: unreadItems){
            if(fiw.markAsRead == true){
                System.Debug('Id being muted : ' + fiw.fi.id);
                ConnectApi.ChatterFeeds.setIsMutedByMe(null,fiw.fi.id,true);
            }
        }
        return null;
    }

    // Wrapper class for  chatter notifications
    public class FeedItemWrapper {
        public Boolean markAsRead {get;set;}
        public ConnectApi.FeedElement fe {get;set;}
        public ConnectAPI.FeedItem fi {get;set;}
        public ConnectApi.FilesCapability sourceca {get;set;}
        public ConnectApi.CommentPage fecomments {get;set;}
        
        public FeedItemWrapper (ConnectApi.FeedElement fit) {
            fe = fit;
            markAsRead = false;
            system.debug(JSON.serializePretty(fe.header));
        
            if (fe.feedElementType == ConnectAPI.FeedElementType.FeedItem) {
                fi = (ConnectAPI.FeedItem)fe;
            }
        
            if (fit.capabilities != NULL) {
                if (fit.capabilities.files != NULL) {
                    sourceca = fit.capabilities.files;
                }
               
                if (fit.capabilities.comments != NULL) {
                    fecomments = fit.capabilities.comments.page ;
                }
            } 
                  
        }
    }

Here is the exert from the debug log.
18:32:48.0 (72445222)|SYSTEM_METHOD_EXIT|[5]|FeedElement
18:32:48.0 (72696983)|HEAP_ALLOCATE|[35]|Bytes:35
18:32:48.0 (72724894)|USER_DEBUG|[35]|DEBUG|Id being muted : 0D57A000002zUrBSAU
18:32:48.0 (72732086)|STATEMENT_EXECUTE|[36]
18:32:48.0 (72737454)|HEAP_ALLOCATE|[36]|Bytes:14
18:32:48.0 (72779459)|VARIABLE_ASSIGNMENT|[EXTERNAL]|this|{"fe":"0x7da92efc","fecomments":"0xc9094dd","fi":"0x7da92efc","markAsRead":true}|0x5f26855a
18:32:48.0 (72885369)|HEAP_ALLOCATE|[36]|Bytes:953
18:32:48.0 (72894786)|SYSTEM_METHOD_ENTRY|[5]|ChatterFeeds.ChatterFeeds()
18:32:48.0 (72897158)|STATEMENT_EXECUTE|[5]
18:32:48.0 (72903311)|SYSTEM_METHOD_EXIT|[5]|ChatterFeeds
18:32:48.0 (72924236)|METHOD_ENTRY|[36]||ConnectApi.ChatterFeeds.setIsMutedByMe(String, String, Boolean)
18:32:48.0 (202377656)|METHOD_EXIT|[36]||ConnectApi.ChatterFeeds.setIsMutedByMe(String, String, Boolean)
18:32:48.0 (202399885)|SYSTEM_MODE_EXIT|false
18:32:48.0 (202499469)|FATAL_ERROR|System.LimitException: ConnectApi:DML currently not allowed Class.ConnectApi.ChatterFeeds.setIsMutedByMe: line 232, column 1 Class.SM_Notifications.muteMsg: line 36, column 1
18:32:48.0 (202514491)|CODE_UNIT_FINISHED|SM_Notifications invoke(muteMsg)
I'm connecting to a .Net framework via OData 4.0 connector.The connection has been created and sync'd successfully showing all fields that are in the metadata. However when I navigate to the external object or try to SOQL query it I get 
External Object Error
Could not deserialize feed: 

It seems salesforce is expecting the data in a way that the oData connector is not sending. I have access to the oData connector. How should the data be getting sent?
What is the best way to troublshoot this?
I am following Shamil's advice combined with Ankit Arora's advice on being able to create a custom VF page and display the quote through an iFrame. 
https://developer.salesforce.com/forums/ForumsMain?id=906F000000090bMIAQ
https://developer.salesforce.com/forums/#!/feedtype=SINGLE_QUESTION_SEARCH_RESULT&id=906F00000008mUaIAI

My problem is even without the iFrame if I use this link, the page isn't seeing my Headers and Footers properly. 
https://cs14.salesforce.com/quote/quoteTemplateDataViewer.apexp?id=0Q0c00000007Czx&headerHeight=20&footerHeight=10&summlid=0EHc0000000Cxvl#toolbar=1&navpanes=0&zoom=90

They look like this ....
User-added image
Are there more parameters I need to add because when I do a getcontentaspdf() it also looks like this so it's unusable.

Thanks for any advice!

Dahveed

My users want to run a report which shows whether or not an Account have contacts which have any of  5 particular contact Titles.  My idea was to create checkboxes of each title on the Account and have a workflow run on the contact which updates these fields on Account when a title contains one of the key titles. However Salesforce cofirmed that I cannot run cross object field updates from a contact to an Account. I can only do this on a custom object with a master detail. I now am doing this via trigger.

I first grab the AccountId from the contact being edited  and put them into a set.

public class contactTitleHandler{
     private Set<Id> AccountIds = new Set<Id>();
     private Map<Id,Account> AccountMap = new Map<Id,Account>();
     private List<Account> AccountsToUpdate = new List<Account>();
     private boolean treasurer;
     private boolean assistantTreasurer;
     private boolean cashManager;
     private boolean CIO;
     private boolean CFO;
     private Id acctId;

 

     public void onBeforeUpdate(List<Contact> updatedRecords){
         for(Contact c: updatedRecords){
             AccountIds.add(c.Account.Id);   
         }
         calculateTitles();
     }

 

// The idea hear was to  grab every contact attached to the Account and check if it contains a key title.

// the problem is I want to set the values on the account only after I've iterated through all the contacts for that one account

// I would then set the values and add it to a list for update

 

     public void calculateTitles(){
         for(Contact c: [SELECT Title, Account.Id FROM Contact WHERE Account.Id IN: AccountIds ORDER BY Account.Id]){
 

// I was thinking some kind of while loop where it checks contacts until the AccountId changes.  Once it does then set the values on

// the account and add it to a list for update

         
             if(c.Title.contains('Treasurer')){
                 treasurer = true;
             }Else If(c.Title.contains('Assistant Treasurer')){
                 assistantTreasurer = true;                 
             }Else If(c.Title.contains('Cash Manager')){
                 cashManager = true;
             }Else If(c.Title.contains('CIO')){
                 CIO = true;
             }Else If(c.Title.contains('CFO')){
                 CFO = true;
             }

         }

 

My question is how would I write something where it iterates until the Account Id changes in the SOQL query?

 

Thanks for any help!!

 

Dahveed

Because of particular integration I have to leave certain line items out of the quote based on a checkbox. Because of this I can't use the default quote templates unless anyone else knows how to exclude quotelineitems from a quote. What I did was model it after Jeff Douglas attaching a pdf to an object. I have a custom button called 'Create PDF'.  The button goes to the VF page below. On it is a commandlink which references the viewPDF method in the QuoteConsultingExtension to view the PDF before saving. This works great and I can view the PDF no problem with all the quote fields.

However when I click the savePDF button. I get "SObject row was retrieved via SOQL without querying the requested field:" on all the quote standard fields. I even tried to write my own SOQL query which references all the default quote fields and it then throws an error SObject row was retrieved via SOQL without querying the requested field: User.LastName when I'm not even referencing User.LastName on my VF page.  This is crazy?? Can anyone help me with this or provide a better solution?

 

Thanks heaps

 

Dahveed

 

<apex:page standardController="Quote" showHeader="true"  extensions="QuoteConsultingExtension" >
  <apex:sectionHeader title="Create and attach a quote for signing" subtitle="Attach a PDF" 
    description="You must attach a PDF quote for use with docusign"/>
  <apex:form >
    <apex:pageBlock title="PDF Input">
 
      <apex:pageBlockButtons >
      <apex:commandLink  action="{!viewPDF}" value="View PDF" target="_blank" />
      <apex:commandButton action="{!savePDF}" value="Save"/>
      <apex:commandButton action="{!Cancel}" value="Cancel"/>
      </apex:pageBlockButtons>
      <apex:pageMessages />
 
      <apex:pageBlockSection >
 
        <apex:pageBlockSectionItem >
            <apex:outputLabel value="File Name" for="pdfName"/>
   <!--       <apex:inputText value="{!pdfName}" id="pdfName"/> -->
        </apex:pageBlockSectionItem>
 
        <apex:pageBlockSectionItem >
            <apex:outputLabel value="Account ID" for="id"/>
  <!--        <apex:inputText value="{!parentId}" id="id"/> -->
        </apex:pageBlockSectionItem>
 
      </apex:pageBlockSection>
 
    </apex:pageBlock>
  </apex:form>

 

public class QuoteConsultingExtension {
    
    private List<QuoteLineItem> conLineItems;
    private decimal conTotal;
    public final Quote myQuote;
   
    
    public QuoteConsultingExtension(ApexPages.StandardController stdController) {
        this.myQuote = (Quote)stdController.getRecord();

    }

    
    public List<QuoteLineItem> consultingLineItems{
        get{
            if(conLineItems == null)
                conLineItems = new List<QuoteLineItem>();
            
            conLineItems = [SELECT Id,Product_CodeF__c, Product_NameF__c,Quantity,
                            ListPrice,Discount,UnitPrice,TotalPrice, 
                            isConsultingF__c, isGlobalProductF__c 
                            FROM QuoteLineItem 
                            WHERE isConsultingF__c = true AND isGlobalProductF__c = false];                                                        
            
            return conLineItems;
        
        }
        set;
        
     }
     
    public decimal consultingTotal{
         get{    
             conTotal=0;
             for(QuoteLineItem qli: conLineItems){
                 conTotal += qli.Quantity * qli.UnitPrice;   
             }
         return conTotal;
         }  
         set;
    } 
    public PageReference viewPDF() {
        string quoteId = ApexPages.currentPage().getParameters().get('id');
        PageReference thePDF = Page.Consulting_Services_Quote;
        thePDF.getParameters().put('id',quoteId);
        thePDF.setRedirect(true);
        return thePDF;
    
    }     
    public PageReference savePDF() { 
        string qId = ApexPages.currentPage().getParameters().get('id');
        System.debug(qId);
        PageReference thePDF = Page.Consulting_Services_Quote;
        thePDF.getParameters().put('id',qId);
        thePDF.setRedirect(true);
                
        quotedocument qd = new quotedocument();
        qd.document = thePDF.getContentAsPDF();
        qd.quoteId = qId;
        insert qd;
    
        PageReference quotePage = new PageReference('/'+ qId);
        quotePage.setRedirect(true);
        return quotePage;
    }
     
}

 

I'm finding when passing the parameters it fills it out correctly but seems to create almost another value. If I manually go and select the second value then the filter works, otherwise it's not seeing it correctly.  My guess is its something like passing report filters where for the first filter you use pvo.

 

I click my button on the Products related list on an opportunity. The button contains the below url
Ex:
https://cs14.salesforce.com/p/opp/SelectSearch?addTo=006c00000079xsa&PricebookEntrycol0=Product Family&PricebookEntryoper0=contains&PricebookEntryfval0=Consulting&PricebookEntrycol1=Global Product&PricebookEntryoper1=equals&PricebookEntryfval1=false&retURL=%2F006c00000079xsa

Where

PricebookEntrycol0=Product Family
PricebookEntryoper0=contains
PricebookEntryfval0=Consulting

However I get multiple Product Familys and the filter doesn't work. If I manually go select the second "Product Family" in the drop down the filter works. Should I be using different values?

 

Thanks

 

Dahveed

 

 

 

Hi

 

Anyone else having this problem since Summer 13? When I refresh our Sandbox it only copies over our Custom price books but not the Standard one. Naturally this makes some of my (fully working in Production) code just die. To top it off, you can't actually create a Standard pricebook.

 

It started happening immediately after Summer 13 was released (where they "promoted" the Pricebook object) so I assume I can't be the only victim.

 

Anyone figure out a workaround?

 

Regards

MellowRen

I needed to make a visualforce email template so that I could select a language based on a field on my contact record. It is required to have the {!Case.Thread_Id} merge field in the subject line so it doesn't create a new case everytime a user responds. However in a visualforce email template it tells me it doesn't exist.

Error: Invalid field Thread_Id for SObject Case

 

This is my email header.  Is the Thread_Id merge field not available when using a visualforce email template?

 

<messaging:emailTemplate subject=" {!relatedTo.Thread_Id} {!$Label.Portal_Case_Comment_Subject} {!relatedTo.CaseNumber}" recipientType="Contact" language="{!recipient.Language__c}" relatedToType="Case">

Anyone have a good idea for a workaround?

 

Thanks,

 

Dahveed

 

I am creating a visualforce email template. How do I know which object salesforce looks at when sending the "New User Template" via the customer portal?  What sobjects go into

1. recipientType

2. relatedToType

I know it's user or contact or both however if it is both it's not working. What I am trying to do is set the language based on the LanguageLocaleKey field on the User object by either using

language="{!recipient.LanguageLocaleKey}"

or

language="{!relatedToType.LanguageLocaleKey}"

 

but it's not working. I have to create a new portal user evertime I test this so I was hoping someone could help.  I am not finding much documentation when it comes to salesforce automatic emails which go out. 

 

Also does it use the email address from the User object or the contact object?

 

Thanks,

 

Dahveed

I every few weeks get the following in my customer portal and it's when I go to a contact in my salesforce database and login to portal as user.

 

caused by: System.QueryException: List has no rows for assignment to SObject

Class.portalHomePageController.<init>: line 12, column 1

 

It is referencing this controller which is my portal home page.

Line 12 is oContact=[select Id,Name,AccountId,Account.Name,Account.Protocol__c, Account.Banks__c,Account.Plateforme_ASP__c from Contact where id=:oUser.ContactId];

 

This would mean that there is no contact returned for which I just logged in as portal user. Is this just a bug that will happen if the SOQL query errors? Is there something I can do to prevent this? Should I put it into a list and check it and if it's size()=0 then requery it?  There is no reason that the SOQL query would ever return null because it would mean there is no portal user.

 

Thanks for any help,

 

Dahveed

 

public class portalHomePageController {
    
    public List <AlertManagement__c> listFlux {get;set;}
    public List <Portal_Marketing__c> listFluxMK {get;set;}
    public Contact oContact {get;set;}
    public Account oAccount {get;set;}
    public User oUser {get;set;}
    
    public portalHomePageController(){
                
        oUser=[SELECT id, ContactId, LanguageLocaleKey FROM User WHERE id=:userinfo.getuserid()];
        oContact=[select Id,Name,AccountId,Account.Name,Account.Protocol__c, Account.Banks__c,Account.Plateforme_ASP__c from Contact where id=:oUser.ContactId];
        oAccount=[select id, Name, Plateforme_ASP__c, ID_base_production__c, Banks__c, Protocol__c from Account where Id=:oContact.AccountId];  

 

........rest of logic

I need to use a Visual Force email Template when cases are closed so I can customize the Reply To Field.

 

How do I include the Case thread ID?

How do I include the Case Owner's Email Signature?

 

<messaging:emailTemplate recipientType="Contact" 
relatedToType="Case"
replyTo="{!relatedTo.Owner.email}"
subject="Notice of Closed Case & Client Survey: {!relatedto.CaseNumber}" >
<messaging:htmlEmailBody >
<html>
<body>
<messaging:htmlEmailBody >
        <html>
            <body>

            <p>Dear {!recipient.name},</p>
            <p>This is to inform you that Case # {!relatedto.CaseNumber} which was reported by you on {!relatedto.CreatedDate} has been marked as 'Closed'.   If you feel that this case has been closed in error, please do not hesitate to contact us.</p>

       <p>Sincere regards,</p>
            <br></br>
            <p>{!relatedTo.owner.name}</p>
<p>CASE OWNER SIGNATURE HERE</p>
            <br></br>
            <br></br>     
<p>CASE THREAD ID HERE</p>
          
            </body>
        </html>
    </messaging:htmlEmailBody>
</messaging:emailTemplate>

 

We have two pages, aptly named QuotePDF and QuotePDF1. The former is designed to allow the user to preview the quote and save it to the quote and optionally send an email with it attached. Yes, we know this is standard functionality, but we're doing "extra" stuff with our code that we wanted to retain.

 

At any rate, with no changes to our code, we suddenly had a break in our code. Previously, it was working great without a problem. Now, the Preview works as expected, but Page.QuotePDF1.getContent() is failing with the error "SObject row was retrieved via SOQL without querying the requested field: Quote.ShippingName", regardless of what we try to do to fix the problem. Here's what we've got in place so far:

 

public with sharing class quotePDFExtension {
    public quotePDFExtension(Apexpages.standardcontroller con) {
        controller = con;
        if(!test.isrunningtest()) {
            con.reset();
// Cached field describe as a String[] con.addfields(data_util.getobjectfields('Quote')); } } // Other non-interesting stuff here, including controller variable public apexpages.pagereference saveToQuote() { quotedocument qd = new quotedocument(); apexpages.pagereference ref = page.quotepdf1; ref.getparameters().put('id',quote.id); qd.document = ref.getcontent(); // also tried getcontentaspdf
// ref.setredirect(true/false); -- neither had any effect qd.quoteid = quote.id; insert qd; return controller.view(); } }

The controller explicitly has all fields added to it, we've tried to force a redirect.

 

Yes, both pages use the same standardController(Quote) and extensions(quotePDFExtension). I'd rather not split them apart if I can help it.

 

Up until this previous weekend, everything was running just fine. However, whatever happened this weekend broke several pieces of code that was previously working. I can't seem to debug this either, as the error causes the entire page to crash rather ungracefully.

 

I've tried several fixes that mentioned this problem from 2009, but to no avail, including static variables, etc. The only thing I don't want to do is hardcode a query in place, as this is rather limiting. I'd like to have the system determine what fields should be queried dynamically, the way it should be.