• Tuan Lu
  • NEWBIE
  • 175 Points
  • Member since 2016
  • Salesforce Consultant
  • EigenX


  • Chatter
    Feed
  • 5
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 0
    Questions
  • 41
    Replies
 Normally I would try to fix the code myself but I have zero experience with Java. Pretty much all the time I just use the GUI interface that Dataloader is built with when I need to use it. However the interface is very poorly designed. For example when you are in the settings screen, the OK and cancel button are off the bottom of the screen. Resizing by dragging the edge of the window is pointless for the controls can't be scrolled down to when the box is made smaller. The only way I can access the control is to tab to it. 
Another example is when you are doing an export. The controls on the screen are so small - list of querry fields, the value field is cut in the middle, the window itself is the wrong size....I can keep going but you get the point here.
What I'd like to do is simply edit the interface so the controls and windows are not only the right size but in positions so that they are actually useable. 
Any suggestions or help on this would be great.  Thanks in advance
There is an idea that is marked as delivered through lightning.... https://success.salesforce.com/ideaView?id=08730000000Ycj6AAC

But I am struggling to see how I can add more than 2 columns to a page layout, i know you can add components to lightning pages and this gives good flexability but the Record Detail component takes from the pagelayout you have created which I cannot see allows more than 2 columns...

please can someone tell me how to add more that 2 columns to pagelayout using lightning?

 

I may have promised my boss more than I can deliver, but hopefully you all can help me with something. I created a VisualForce form with "soft-required" fields, which are marked with a red asterisk, and do not prevent the user from saving the record if they are not filled out. This way our field salesmen can start a form, save it, but complete it later. They won't be able to submit for approval unless all those fields are filled, thanks to an additional formula field that doesn't checkmark itself unless all soft-required fields are filled out. 

This part works great, but here's where I'm running into trouble. What I would love to do for our dear team (who have been waiting for this feature for so long) is help them with an additional prompt that says:
"Are you sure you'd like to save this form? Looks like you still have some fields to fill before this is ready to submit."

...What if they don't, though?
Based on what I've seen, I can only add a prompt directly to my button action, and not include it conditionally if such-and-such is true.
Can anyone point me in the right direction?

Hi I'm getting back into SF development and was setting up the Force.com IDE today.  When pulling my project from my sandbox, I gave it about 10 minutes and nothing - frozen completely.  I tried The Welkin Suite and was able to get the project to download, but it took forever.  Now I'm trying to pull down individual classes and triggers and am getting similar delays (two minutes for a class that is < 30 lines of code deep - currently on a 5 minute wait for a 200-line trigger).  I'm on na30 - is this wait time normal?

I've tried disabling Windows firewall and my connection is 100+Mbps both up and down.

I have a problem. Or rather, I have a solution that I was expecting to be a problem, and that's bad! 
In the code below, after following some tutorial steps for creating a controller extension, I found that I was able to successfully reference a quote from Salesforce CPQ by binding expressions to a variable named "quote". However, I never named a variable "quote" in any of my code, my controller is pointing to a custom object called "EAM_Form__c", and Salesforce CPQ's custom quote object is called SBQQ__Quote__c, rather than just quote. So, I don't understand why I'm able to successfully reference a variable that I never named, for example "{!quote.Voltage__c}".  

A snippet of my page:
 

<apex:page standardController="EAM_Form__c" extensions="EAMFormExtension" showHeader="true">            
    <apex:form>
        <apex:pageBlock title="Application Analysis">                
            <apex:pageBlockSection columns="1">
                <apex:inputField value="{!quote.Voltage__c}"/>
                <apex:inputField value="{!quote.Phase__c}"/>
                <apex:inputField value="{!quote.Conveyor_Height__c}"/>
            </apex:pageBlockSection>
        </apex:pageBlock>
    <apex:form>
</apex:page>

My controller extension:
public class EAMFormExtension {
    private final EAM_Form__c myForm;

    // The extension constructor initializes the private member
    // variable mysObject by using the getRecord method from the standard
    // controller.
    public EAMFormExtension(ApexPages.StandardController stdController) {
        this.myForm = (EAM_Form__c)stdController.getRecord();
    }

    public SBQQ__Quote__c getQuote() {
        SBQQ__Quote__c myQuote = [Select Id, Name, Voltage__c, Phase__c, Conveyor_Height__c,SBQQ__Opportunity2__c From SBQQ__Quote__c Where Id = :this.myForm.Quote__c Limit 1];
        return myQuote;
    }
}

For the sake of learning how this works, can anyone explain this mysterious reference name to me?
Dear All,

I am immense need of help from all of you. After giving a much thought and so much brainstorming happened finally I turned up here for advise.

Requirement:
I need to fetch coordinates value of account based on Map address provided

Solution approach
I create few fields on accounts like MapAddressCity,MapAddressState,MapAddressStreet,MapAddressPostalCode and MapAddresscountry on account. When an user enters values in Map fields and clicks on save button I am calling Google API. Google API will returns one coordinate value based on address filled in Map fields. I have created one field called "Location"(Data Type-Geolocation) which will stores coordinates and also I created 2 formula fields which stores the longitude and latitude values of coordinates in "LonField" and "LatField" respectively

If an user enters below in account:
MapAddressCity: San Francisco  
MapAddressCountry: United States  
MapAddressPostalCode: 94105  
MapPostalState: CA  
MapAddressStreet: One Market Street
and clicks on Save-Google API call will be made and below information wiull be stored on account:
Location-37°47'38''N 122°23'41''W  
LongValue-122.3948  
LatValue37.7939

My Question:
In our org there is already one trigger written on account and there is already one accounthandler class and we always follow best practices so I didnt write a separate trigger and class to achieve above mentioned requirement. I am reusing same accounttriggerhandler class and apex trigger which is written on account.
If I write separate class and trigger to achieve above mentioned functionality then I have no issue everything works smoothly but when I am trying to include my code in already existing account trigger handler then I am not able to make my code bulkify. I am calling my class method on after insert and after update and coordinates fields are updating perfectly but only for single account because I am not able to make my code bulkify and runs for multiple accounts.

Kindly help me. Below is trigger which is already existing on account:
//Single Master Trigger on Account using Handlers for each individual actions
trigger AccountTrigger on Account (before delete, before insert, before update, after insert, after update,after delete) {

    checkRecursive.isRunOnce = true; // ToDo : Need to change the recursive handling logic
    AccountTriggerHandler accHandler = new AccountTriggerHandler(trigger.new,trigger.old,trigger.newMap,trigger.oldMap,trigger.isUpdate);
    
 
    if(trigger.isBefore && trigger.isInsert){
        accHandler.HandleBeforeInsert();
        
    }
    if(trigger.isBefore && trigger.isUpdate){
        accHandler.HandleBeforeUpdate();
       
    }
    if(trigger.isAfter && trigger.isInsert) {  
        accHandler.HandleAfterInsert();
    
    }
  
    if(trigger.isAfter && trigger.isUpdate){
        accHandler.HandleAfterUpdate();
    
    }
 
    if(trigger.isBefore && trigger.isDelete)
        accHandler.HandleBeforeDelete();

    if(trigger.isAfter && trigger.isDelete)
        accHandler.HandleAfterDelete();       
}

My class code is as belows:
 
//Handler Class to handle Account Trigger
public class AccountTriggerHandler {
    
    public static Boolean runAccountTriggerHandler = true;
    private static Boolean geocodingCalled = false;

    
    public static boolean run = true;
    public static boolean runOnce(){
        if(run){
            run=false;
            return true;
        }else{
            return run;
        }
    }
    
    //trigger variables
    List<Account> newAccs;
    List<Account> oldAccs;
    Map<Id,Account> newAccMap;
    Map<Id,Account> oldAccMap;
    Id accountId;
    boolean isUpdate;
    
    //constructor
    public AccountTriggerHandler(List<Account> newAccs, List<Account> oldAccs, 
                                 Map<Id,Account> newAccMap, Map<Id,Account> oldAccMap, boolean isUpdate){
        this.newAccs = newAccs;
        this.oldAccs = oldAccs;
        this.newAccMap = newAccMap;
        this.oldAccMap = oldAccMap;
        this.isUpdate = isUpdate;
        this.accountId= accountId;                          
        this.consentService = new ConsentManagementService(Account.sObjectType);
    }
    

 
    
    public void HandleAfterInsert(){ 
        
		//if(!System.isFuture())	           
		//getLocation(newAccs[0].Id);
		DoAddressGeocode(newAccs[0].id);
            
            
        }    
    }
        
    public void HandleAfterUpdate(){
        
                //if(!System.isFuture())     
                    //getLocation(newAccs[0].Id);
                    DoAddressGeocode(newAccs[0].id);
                    
               
            }
               
            
        }    
    }

    public void HandleBeforeDelete(){
        
    }
 
    public void HandleAfterDelete(){
        
    }
    
    
    
    // wrapper method to prevent calling futuremethods from an existing future context
public static void DoAddressGeocode(id accountId) {
 				 if(geocodingCalled || System.isFuture()) {
                    System.debug(LoggingLevel.WARN,'***Address Geocoding Future Method Already Called - Aborting...');
   						 return;
  					}
                
  		// if not being called from future context, geocode the address
  						geocodingCalled= true;
  						getLocation(accountId);
	}
    @future (callout=true)  // future method needed to run callouts from Triggers
      static public void getLocation( id accountId){
        
        // gather account info
      Account a =[SELECT MapAddressCity__c,MapAddressCountry__c,MapAddressPostalCode__c,MapAddressStreet__c,MapPostalState__c FROM Account  WHERE id =: accountId];
      //List<Account> a= new List<Account>();
      //a= [SELECT id, MapAddressCity__c,MapAddressCountry__c,MapAddressPostalCode__c,MapAddressStreet__c,MapPostalState__c FROM Account  WHERE id =: accountId];
      
        // create an address string
        String address = '';
        if (a.MapAddressStreet__c!= null)
            address += a.MapAddressStreet__c+', ';
        if (a.MapAddressCity__c != null)
            address += a.MapAddressCity__c +', ';
        if (a.MapPostalState__c!= null)
            address += a.MapPostalState__c+' ';
        if (a.MapAddressPostalCode__c!= null)
            address += a.MapAddressPostalCode__c+', ';
        if (a.MapAddressCountry__c!= null)
            address += a.MapAddressCountry__c;

        address = EncodingUtil.urlEncode(address, 'UTF-8');

        // build callout
        Http h = new Http();
        HttpRequest req = new HttpRequest();
        req.setEndpoint('http://maps.googleapis.com/maps/api/geocode/json?address='+address+'&sensor=false');
        req.setMethod('GET');
        req.setTimeout(60000);

        try{
            // callout
            HttpResponse res = h.send(req);

            // parse coordinates from response
            JSONParser parser = JSON.createParser(res.getBody());
            double lat = null;
            double lon = null;
            while (parser.nextToken() != null) {
                if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) &&
                    (parser.getText() == 'location')){
                       parser.nextToken(); // object start
                       while (parser.nextToken() != JSONToken.END_OBJECT){
                           String txt = parser.getText();
                           parser.nextToken();
                           if (txt == 'lat')
                               lat = parser.getDoubleValue();
                           else if (txt == 'lng')
                               lon = parser.getDoubleValue();
                       }

                }
            }

            // update coordinates if we get back
            if (lat != null){
                a.Location__Latitude__s = lat;
                a.Location__Longitude__s = lon;
                update a;
            }

        } catch (Exception e) {
        }
    }

}

I have removed all the extra codes and methods from class and only kept my method in class to have a better visibility for code to all of you.
I am calling "DoAddressGeocode​" method on HandleAfterInsert and HandleAfterUpdate.
Right now I am not able to do bulkification of my code and wrote only for 1 accounts like DoAddressGeocode(newAccs[0].id)

Any help would be greatly appreciated.

Thanks in advance!

Kindly help

 
I hope you are all having a good day. I am a recent hire and want to help my company build a process of automating invoices. Currently, we are going to create a list of active employees with a unique employee ID. We have data that we are going to feed into SalesForce to match up the quantity and services, by month, by client. Do any of you have any recommendations on how to efficiently build an invoicing process? The data we feed in only includes the quantityof each service. It does not include the cost. Each client has a different pricing schedule. Some have a flat fee that can have overages at a certain amount. Others have different pricing tiers (i.e. one customer may be charged $0.08 per amount used for a quantity of less than 1,000 and $0.07 per amount used for a quantity of over 1,000 and other clients may have a different pricing schedule). Some have certain minimums. What are your recommendations on building out a systematic way of calculating invocies for each service for each client? We currently use Excel and I believe SalesForce has much better capabilities.
I have a visualforce page with the following code:
<apex:page showHeader="false" sidebar="false" controller="cc_AppChecklist_List" standardStylesheets="false" html-lang="en-US">  
    <c:cc_App_Header />
    <c:cc_App_TopNav activeSection="Personal" />
    <div class="gridlock gridlock-16 appPage">
        <div class="page page_container clearfix"> 
            <div class="row page_row">
                <div class="content page_content max-push-1 max-14 desktop-push-1 desktop-14 tablet-full mobile-full margined">
                    
                    <div class="row page_row content_block background">
                        <div class="desktop-12 tablet-6 mobile-6 min-full left" >
                            <h1 style="margin: 0;">My Application Checklist Items</h1>
                        </div>
                        
                        <apex:pageBlock title=""> 
                            <apex:pageBlockTable value="{!Records}" var="Record" style="width:100%"> 
                                <apex:column style="width:35%"> 
                                    <apex:facet name="header">Checklist ID</apex:facet> 
                                    <apex:outputText value="{!Record.Id}"/> 
                                </apex:column> 
                                <apex:column style="width:35%"> 
                                    <apex:facet name="header">Checklist Name</apex:facet> 
                                    <apex:outputText value="{!Record.CC_Document_Name__c}"/> 
                                </apex:column> 
                                <apex:column style="width:10%"> 
                                    <apex:facet name="header">Status</apex:facet> 
                                    <apex:outputText value="{!Record.CC_Document_Status__c}"/> 
                                </apex:column> 
                                <!-- apex:column > 
                                    <apex:facet name="header">Date Requested</apex:facet> 
                                    <apex:outputText value="{0, date, MMMM d','  yyyy}">
                                        <apex:param value="{!Record.CC_Date_Requested__c}" /> 
                                    </apex:outputText>
                                </apex:column> 
                                <apex:column > 
                                    <apex:facet name="header">Date Due</apex:facet> 
                                    <apex:outputText value="{0, date, MMMM d','  yyyy}">
                                        <apex:param value="{!Record.CC_Due_Date__c}" /> 
                                    </apex:outputText>
                                </apex:column --> 
                                <apex:column style="width:15%"> 
                                    <apex:facet name="header">Date Received</apex:facet> 
                                    <apex:outputText value="{0, date, MMMM d','  yyyy}">
                                        <apex:param value="{!Record.CC_Date_Received__c}" /> 
                                    </apex:outputText>
                                </apex:column>
                                <apex:column style="width:40%"> 
                                    <apex:facet name="header">Action</apex:facet> 
                                    <apex:form >
                                         <apex:inputFile title="file_upload" value="{!file.body}" fileName="{!file.name}" id="file_upload" onchange="return checkFileSize(this);"/>
                                         <apex:commandButton styleClass="btn app-btn-success" value="Upload" action="{!uploadFile}" />
                                    </apex:form> 
                               </apex:column> 
                               
                            </apex:pageBlockTable> 
                        </apex:pageBlock> 
                   </div>
                
                    

                </div>
            </div>
        </div>
    </div>
   
    <!-- <c:App_Footer /> -->
</apex:page>

Control class:
public with sharing class cc_AppChecklist_List{ 

    public List<Application_Checklist__c> Records {get; set;} 
    String AppID = ApexPages.currentPage().getParameters().get('appid');
    
    public cc_AppChecklist_List(){ 
    Records = 
    [SELECT Id, Name, CC_Document_Name__c, CC_Document_Status__c, CC_Date_Received__c,CC_Date_Requested__c, CC_Due_Date__c FROM Application_Checklist__c WHERE Application_CC__c = :AppID];    
    }
    
    // system.debug('-----ChecklistID')
    // Upload Code
    private Id itemId {get; set;}
    public Application_Checklist__c item {get; set;}
    public SObject obj {get; set;} 
    public Attachment file {
        get {
            if(file == null) {
                file = new Attachment(ParentId = itemId);
            }
            return file;
        } 
        set;
    }
    private Boolean isOld {get; set;}

    public PageReference uploadFile() {
        PageReference pr = null;
        try {
            system.debug('-----ChecklistID'+itemId);
            insert file;
            if(isOld) {
                item.CC_Date_Received__c = Date.today();
                update item;
            } else {
                obj.put('CC_Date_Received__c', Date.today());
                obj.put('CC_Document_Status__c','Received');
                update obj;
            }
            pr = Page.cc_App_Status;
        } catch (Exception ex) {
            cc_App_BaseController.addError(Label.Upload_Attachment_Error);
            System.debug(ex.getMessage());
        } finally {
            file = null;
        }
        return pr;
    }
}

What I am trying to do is make the {!Record.Id} value for each row in the visualforce page pass across to the "itemId" value so the upload button will upload to the correct record. The upload function works when I hard code a value but I am having trouble passing the data to the variable when the upload button is selected. The goal of this is to query an application id and display all checklist items on the visualforce page with an upload button for each item. 
Hi All,

We are using the User-Agent OAuth Authentication Flow so that vendors can insert the data from thier internal/exteranal sites  buy using simple insert rest api endpoint call using javascript/ajax calls. 

we have shared the sample endpoint for authorization like 
https://login.salesforce.com/services/oauth2/authorize?response_type=token&
client_id=3MVG9lKcPoNINVBIPJjdw1J9LLJbP_pqwoJYyuisjQhr_LLurNDv7AgQvDTZwCoZuD
ZrXcPCmBv4o.8ds.5iE&redirect_uri=https%3A%2F%2Fwww.mysite.com%2Fuser_callback.jsp&
state=mystate 
 
so vendors would call the above endpoint and grant authorization like accept/reject pop getting displayed in thier front end screens for first time call,On sucessfully redirection. the screen gets redirect to redirect url mentioned in connected app. 
we have mentioned that redirect url as www.vendordoamin.page/sfdc.jsp. where sfdc.jsp is the page where user submited the date from. so when user authorizes via pop, the sfdc authorization servers should respond back with access token.  
Once the access token is received vendor should store the access through out the request and should use the same to insert the custom lead data via standard rest url generated via workbench. 

If incase the access token is expired , the request should be made to below url to get new token

POST /services/oauth2/token HTTP/1.1
Host: https://test.salesforce.com/
grant_type=refresh_token&client_id=3MVG9lKcPoNINVBIPJjdw1J9LLM82HnFVVX19KY1uA5mu0
QqEWhqKpoW3svG3XHrXDiCQjK1mdgAvhCscA9GE&client_secret=111111111121111
&refresh_token=your token here

We have used this apporach so that we can share authorize endpoint and code, simple authorization inputs from front end user when submitting data, and then system inserting data to sfdc.
(we want this simple approach so that many other vendor can simple insert our rest api code and can insert data)

Since the vendors are unable to test or help us with sfdc support I am bangging my head to replicate this cors issue in sfdc side. like 


Now for the problems
-- for the first time vendors were able to authorize
-- they got access token, however the second time for refreshing acess tokens they are getting CORS errors and unable to proceed further.
-- how do  i actually replicate the issue ? i had minimum expeirence in java web apps, but developing java based web app like using jsp, 
tomcat and rest webservice is only the way to replicate the cors issue? 
-- there are many sample codes but using maven/jaxb/some other rest api in eclipse /configuring buildpath is all hell for me.
-- Is there any other way to test  User-Agent OAuth Authentication Flow ??
-- if testing only via creation java project etc can anyone share any sample code/ eclipse configurtaion.


** already whitelisted  vendors domain in CORS option in saleforce. 

we have a connected app with a clientid and secret that are used to access the API. we are suddenly (after years of working) getting errors on the authorization_code grant. We successfully get an authorization code, but when we try to retrieve the access token, the call fails with an error: {"error":"invalid_grant","error_description":"authentication failure"}

unfortunately this is the only response we get, and have no other visibility into the issue. We are getting this in our production instance, but other customers who integrate with Salesforce through our platform are getting the same error. In other words, it is not isolated to a single org or user account, but all users trying to authorize us to interact with Salesforce.

I am completely at a loss as to where to go for help, so any guidance is appreciated.

Hi all,

I have been struggling to insert a list of records in Salesforce via APEX with populating a lookup field. Each item in the list will have a different parent. How can I map the Id of the specific parent to each child item without doing a SOQL for each child item?

I have a retrieved a list of values from a JSON string called strResponse and parse it via a JSON2APEX class. This list will have 2 items Code and Value.

The code value is also available as an external Id on the parent object ParentObject__c.Code__c that is related via ChildObject__c .ParentObject__c

If I insert the following code I get an error that the lookup field does not contain a valid Id. How can I populate the ParentObject__c  field with an Id of the matching parent record?
ChildObject__c [] Childs = new List<ChildObject__c>();
String strResponse = httpResponse.getBody();
List<JSON2Apex>  delegationMap = (List<JSON2Apex>)JSON.deserialize(strResponse, List<JSON2Apex>.class);
                
                for(JSON2Apex cp : delegationMap) {                 
         
                    ChildObject__c Child = new ChildObject__c (ParentObject__c = cp.Code,                                        
                                                               ValueField__c = cp.Value);                 
                 
                    Childs.add(Child);                  
                    
                }
                insert Childs;

 
I have a somewhat limited understanding of what Salesforce's capabilities are, but I'm wondering if anyone has any insights on whether my idea below is possible and, if so, what would be the best way to go about implementing such a design?

Here is the basic idea - say we have a large, complex order management system.  This order management system has a RESTful API that allows us to get a real-time representation of the current information about a given Order.

For customer support purposes, we would like to manage all of our customer tickets and contact details in Salesforce.  For our customer support people to be effective, they need to have access to a lot of information about the Order from the order management system and, ideally, we would like them to not have to switch between the order management system and Salesforce - they would just be able to pull up all the Order information (on a read-only basis) within Salesforce itself and then attach any subsequent customer support information to that Order in Salesforce.

From a technical perspective (and, again, please bear with me, I'm quite new to Salesforce), I'm wondering if it would be possible to:

- Via some sort of "sync" style integration, build a bunch of stub Order objects within Salesforce
- So, for every Order in the order management system, a corresponding Order object will be built in Salesforce
- This Salesforce Order object will contain really only the {order_id} from the order management system
- When a customer support user opens an Order object within Salesforce, upon load of that object an API call will be made to the order management system's RESTful API (such as: GET /orders/{order_id}) to retrieve a real-time snapshot of that Order's state.
- This data will subsequently be rendered in Saleforce for reference purposes so that the customer support user can do what they need

Does this even make sense conceptually?  If so, can someone fill me in on what the various tools and considerations exist within the Salesforce ecosytem that could make such a design work?
 
Hi,

I try to make a quik action and a lightning component to create a quote :

Component.CMP
<aura:component controller="QuickQuoteController" 
                implements="force:lightningQuickActionWithoutHeader,force:hasRecordId">

    <aura:attribute name="opportunity" type="Opportunity" />
    <aura:attribute name="newQuote" type="Quote"
        default="{ 'sobjectType': 'Quote' }" />
    
    <!-- default to empty record -->
    
    <aura:handler name="init" value="{!this}" action="{!c.doInit}" />

    <!-- Display a header with details about the opportunity -->
    <div class="slds-page-header" role="banner">
        <p class="slds-text-heading_label">{!v.opportunity.Name}</p>
        <h1 class="slds-page-header__title slds-m-right_small
            slds-truncate slds-align-left">Créer un nouveau devis</h1>
    </div>

    <!-- Display the new quote form -->
     <lightning:input aura:id="quoteField" name="name" label="Name"
                      value="{!v.newQuote.Name}" required="true"/>

    <lightning:input aura:id="quoteField" type="date" name="date" label="Date"
                     value="{!v.newQuote.Date}" required="true"/>
    
    <lightning:button label="Cancel" onclick="{!c.handleCancel}" class="slds-m-top_medium" />
    <lightning:button label="Save Quote" onclick="{!c.handleSaveQuote}"
               variant="brand" class="slds-m-top_medium"/>
    
</aura:component>

Controller.JS
({
    doInit : function(component, event, helper) {

        // Prepare the action to load opportunity record
        var action = component.get("c.getOpportunity");
        action.setParams({"opportunityId": component.get("v.recordId")});

        // Configure response handler
        action.setCallback(this, function(response) {
            var state = response.getState();
            if(state === "SUCCESS") {
                component.set("v.opportunity", response.getReturnValue());
            } else {
                console.log('Problem getting opportunity, response state: ' + state);
            }
        });
        $A.enqueueAction(action);
    },

    handleSaveQuote: function(component, event, helper) {
        if(helper.validateQuoteForm(component)) {
            
            // Prepare the action to create the new quote
            var saveQuoteAction = component.get("c.saveQuoteWithOpportunity");
            saveQuoteAction.setParams({
                "quote": component.get("v.newQuote"),
                "opportunityId": component.get("v.recordId")
            });

            // Configure the response handler for the action
            saveQuoteAction.setCallback(this, function(response) {
                var state = response.getState();
                if(state === "SUCCESS") {

                    // Prepare a toast UI message
                    var resultsToast = $A.get("e.force:showToast");
                    resultsToast.setParams({
                        "title": "Quote Saved",
                        "message": "The new quote was created."
                    });

                    // Update the UI: close panel, show toast, refresh quote page
                    $A.get("e.force:closeQuickAction").fire();
                    resultsToast.fire();
                    $A.get("e.force:refreshView").fire();
                }
                else if (state === "ERROR") {
                    console.log('Problem saving quote, response state: ' + state);
                }
                else {
                    console.log('Unknown problem, response state: ' + state);
                }
            });

            // Send the request to create the new quote
            $A.enqueueAction(saveQuoteAction);
        }
        
    },

	handleCancel: function(component, event, helper) {
	    $A.get("e.force:closeQuickAction").fire();
    }

})

Helper.JS
({
    validateQuoteForm: function(component) {
        var validQuote = true;

        
        // Show error messages if required fields are blank
        var allValid = component.find('quoteField').reduce(function (validFields, inputCmp) {
            inputCmp.showHelpMessageIfInvalid();
            return validFields && inputCmp.get('v.validity').valid;
        }, true);

        if (allValid) {
        // Verify we have an opportunity to attach it to
        var opportunity = component.get("v.opportunity");
        if($A.util.isEmpty(opportunity)) {
            validOpportunity = false;
            console.log("Quick action context doesn't have a valid opportunity.");
        }

        return(validOpportunity);
	}
    }
})

Controller.APXC
public with sharing class QuickQuoteController {

    @AuraEnabled
    public static Opportunity getOpportunity(Id opportunityId) {
        // Perform isAccessible() checks here
        return [SELECT Name FROM Opportunity WHERE Id = :opportunityId];
    }
    
    @AuraEnabled
    public static Quote saveQuoteWithOpportunity(Quote quote, Id opportunityId) {
        // Perform isAccessible() and isUpdateable() checks here
        quote.OpportunityId = opportunityId;
        upsert quote;
        return quote;
    }

}
I have an issue and I can't find where it comes :
 
Uncaught Action failed: c:quickQuote$controller$handleSaveQuote [validOpportunity is not defined]

markup://c:quickQuote

Object.validateQuoteForm()@https://org--dev.lightning.force.com/one/components/c/quickQuote.js:89:9
handleSaveQuote()@https://org--dev.lightning.force.com/one/components/c/quickQuote.js:27:19
handleClick()@https://org--dev.lightning.force.com/components/lightning/button.js:1:470

Any idea ?
 
Hello, all,

We recently implemented this Apex code "Account Grading Method" (attached below) in our system. When an account record is created or edited, a process in the Process Builder calls the Apex code to calculate the account grade. It calculates the score of an account based on the input of a group of fields called Account Intelligence fields and returns the result to a number field called "Account Overall Grade".

The problem is whenever we mass update accounts using an upload (like API Data Loader) or via nightly API calls, the score of the Account Overall Grade get zeroed out, and they need to be re-triggered individually. The account fields we mass updated were not even related to the Account Intelligence fields. When we tried to mass update accounts in list view, the score zeroed out as well. For example, we took an account list view and selected a bunch of records to do a mass in-line editing of one of the Account Intelligence fields, the "Account Overall Grade" field zeroed out.

Any idea on how we can continue to be able to mass update accounts without this happening, or what the issue is? The person who developed this account grading process and the code had left. Any help would be much much appreciated!
My apologies this is a lot of code. Thank you for your patience.

Account Grading Method
public with sharing class AccountGradingMethod {

    public static void AccountGrading(Set<String> setAcctGradingIds) {
        List<Account> lstAGS = new List<Account>();
        List<Account> lstUpdateAcct = new List<Account>();
        Map<String, Field_Value__mdt> mapFlds = new Map<String, Field_Value__mdt>();
        String strSOQLAcct;
        String strSOQLAcctGrade;
        Set<String> setFlds = new Set<String>();
        Set<String> setFldName = new Set<String>();
        String strScore;
        Decimal maxPossScore = 0;
        Decimal numberFlds = 0;

        strSOQLAcctGrade = 'SELECT Id';
        for(Field_Value__mdt fn:[SELECT Id, Field_Score_or_Multiplier__c, Picklist_API_Value__c, Use_Greater_then_or_Less_then__c, 
                                        Field_Name__r.Field_API_Name__c, Field_Name__r.Object__c, Field_Name__r.Type_of_Field__c,
                                        Greater_then__c, Less_then__c
                                    FROM Field_Value__mdt]){
            String mapKey;
            setFldName.add(fn.Field_Name__r.Field_API_Name__c);
            if(fn.Field_Name__r.Object__c == 'Account'){
                setFlds.add(fn.Field_Name__r.Field_API_Name__c);
            }
            if(fn.Use_Greater_then_or_Less_then__c){
                mapKey = fn.Field_Name__r.Field_API_Name__c + '-' + fn.Greater_then__c + '-' + fn.Less_then__c;
            }
            else{
                mapKey = fn.Field_Name__r.Field_API_Name__c + '-' + fn.Picklist_API_Value__c.deleteWhitespace();
            }
            mapFlds.put(mapKey, fn);
        }
        for(String f:setFlds){
            strSOQLAcctGrade += ', ' + f;
        }
        numberFlds = setFlds.size();
        strSOQLAcctGrade += ' FROM Account WHERE Id in :setAcctGradingIds';
        System.debug('strSOQLAcctGrade: ' + strSOQLAcctGrade);
        lstAGS = Database.query(strSOQLAcctGrade);
        strScore = System.Label.Max_Possible_Score;
        maxPossScore = Decimal.valueOf(strScore);

        for(Account ags:lstAGS){
            Decimal subTotal = 0;
            Decimal multiplier = 1;
            Decimal decTotal = 0;
            Decimal ecommTotal = 0;
            Decimal ecommMin = 0;
            Decimal ecommMax = 0;
            Decimal fldsPopulated = 0;
            Decimal precentComplete = 0;
            for(Field_Value__mdt fldVal:mapFlds.values()){
                String value;
                Decimal score = 0;
                Boolean skip = false;
                String fld = fldVal.Field_Name__r.Field_API_Name__c;
                String strKey;
                Decimal decValue = 0;
                if(setFldName.contains(fld)){
                    if(fldVal.Field_Name__r.Object__c == 'Account'){
                        value = String.valueOf(ags.get(fld));
                        if(value != '' && value != 'null' && value != null){
                            value = value.deleteWhitespace();
                            if(fldVal.Use_Greater_then_or_Less_then__c){
                                decValue = Decimal.valueOf(value);
                                System.debug('decValue: ' + decValue);
                                if(fldVal.Greater_then__c != null && fldVal.Less_then__c != null){
                                    if(fldVal.Greater_then__c > decValue && fldVal.Less_then__c < decValue){
                                     System.debug('if 1 fldVal.Less_then__c: ' + fldVal.Less_then__c);
                                        strKey = fld + '-' + fldVal.Greater_then__c + '-' + fldVal.Less_then__c;
                                    }
                                    else{
                                        skip = true;
                                    }
                                }
                                if(fldVal.Greater_then__c == null && fldVal.Less_then__c != null){
                                    if(fldVal.Less_then__c > decValue){
                                     System.debug('if 2 fldVal.Less_then__c: ' + fldVal.Less_then__c);
                                        strKey = fld + '-' + fldVal.Greater_then__c + '-' + fldVal.Less_then__c;
                                    }
                                    else{
                                        skip = true;
                                    }
                                }
                                if(fldVal.Greater_then__c != null && fldVal.Less_then__c == null){
                                    System.debug('if 3 fldVal.Greater_then__c : ' + fldVal.Greater_then__c );
                                    if(fldVal.Greater_then__c < decValue){
                                        strKey = fld + '-' + fldVal.Greater_then__c + '-' + fldVal.Less_then__c;
                                    }
                                    else{
                                        skip = true;
                                    }
                                }
                            }
                            else if (!fldVal.Use_Greater_then_or_Less_then__c){
                                strKey = fldVal.Field_Name__r.Field_API_Name__c + '-' + value;
                            }
                            if(!String.isBlank(strKey) && mapFlds.get(strKey) != null){
                                setFldName.remove(fld);
                                score = mapFlds.get(strKey).Field_Score_or_Multiplier__c;
                            }
                            if(score != null){
                                if(fld.startsWithIgnoreCase('e-commerce solutions')){
                                    skip = true;
                                    ecommTotal = ecommTotal + score;
                                    if(ecommMax<score){
                                        ecommMax = score;
                                    }
                                    if(ecommMin>score){
                                        ecommMin = score;
                                    }
                                }
                                if(fldVal.Field_Name__r.Type_of_Field__c == 'Score' && !skip){
                                    System.debug('fld: ' + fld);
                                    System.debug('Score: ' + score);
                                    subTotal = subTotal + score;
                                }
                                if(fldVal.Field_Name__r.Type_of_Field__c == 'Multiplier' && !skip){
                                    System.debug('fld: ' + fld);
                                    System.debug('multiplier: ' + score);
                                    multiplier = multiplier * score;
                                }
                            }
                        }
                        else{
                            fldsPopulated = fldsPopulated + 1;
                            setFldName.remove(fld);
                        }
                    }
                }
            }
            if(ecommTotal>=0){
                subTotal = subTotal + ecommMax;
            }
            else{
                subTotal = subTotal + ecommMin;
            }
            if(fldsPopulated == numberFlds){
                precentComplete = 100;      }
            else{
                precentComplete = ((numberFlds - fldsPopulated)/numberFlds)*100;
            }
            System.debug('subtotal: ' +  subTotal);
            subTotal = (subTotal/maxPossScore)*100;
            System.debug('subtotal after: ' +  subTotal);
            System.debug('multiplier: ' + multiplier);
            decTotal = subTotal*multiplier;
            System.debug('decTotal: ' + decTotal );
            Account a = new Account();
                a.Id = ags.Id;
                a.Account_Overall_Grade__c = decTotal;
                a.Percent_Complete__c = precentComplete;
            lstUpdateAcct.add(a);

        }
        if(lstUpdateAcct.size()>0){
            update lstUpdateAcct;
        }
    }
}

 
We use the "Convert Products to Assets" app from app exchange.  I have emailed them, but got no response so wondering if anyone can help me with my problem.  I have found no other cases where people were trying to do what I'm trying to do and I'm having trouble getting it to work.

We recently decided we need 2 record types for our Assets so when we use the convert products to assets, we need the Visualforce page to include the option to indicate the correct Record Type.  It should be fairly easy since the page is already built so copy and paste the code, put the correct field value and voila, but record type is a special kind of field so it is not working.  I tried RecordType.Id too to see if that would work, but no luck....any suggestions would be appreciated!! 

Sample code below and I included what I tried for the Record Type ID. 
<apex:column >
            <apex:facet name="header">
              <div class="slds-text-title_caps">{!$ObjectType.Asset.Fields.SerialNumber.Label}</div>
            </apex:facet>
            <apex:inputField value="{!val.asset.SerialNumber}" styleClass="{!IF(val.asset.Quantity > 0,'','field-disabled')}"/>
          </apex:column>
          <apex:column headerValue="Record Type">
            <apex:facet name="header">
              <div class="slds-text-title_caps">{!$ObjectType.Asset.Fields.RecordType.Id.Label}</div>
            </apex:facet>
            <apex:inputField value="{!val.asset.RecordType.Id}" styleClass="{!IF(val.asset.Quantity > 0,'','field-disabled')}"/>
          </apex:column>

 
I am trying to create a new application using Salesforce and was wondering if it is better to start creating it in the Lightning Experience or try to first create the application in Classic and then transition later.
Hello awesome devs! 

I have the followign trigger which works as intended, however when I do a mass upload or mass edit on more than 10 Lead records, I always get the "Apex CPU Time Limit Exceeded" error.  Can anyone tell me how to resolve this error in my code as if my users do a mass update of more than 10 lead records to assume ownership it throws this error and any other time an insert or update of more than 10 Lead records at a time. 

Thanks so much for any help you can provide,

Shawn

Trigger code:
 
trigger LeadCountOfTasks on Task (after delete, after insert, after undelete, after update) {
    Task [] tlist;
        if(Trigger.isDelete)
            tlist= Trigger.old;
        else
            tlist = trigger.new;
    set<id> lid = new set< id> ();
    
    If(!tlist.isEmpty()){
    for(Task ts : tlist)
    {   if(ts.WhoId!=null && ts.whatId == null)
    {
        If(string.valueOf(ts.WhoId).startsWith('00Q'))
        {
        lid.add(ts.Whoid);
    }
    }
    }
    If(lid.size()>0){
    Map <id,Task > tmap = new Map <id, Task>([select id, Whoid from Task where Whoid in:lid]);
    Map <id, Lead> lmap = new Map <id, Lead>([select id,Count_Activity__c from lead where id in:lid ]);
    
        If(lmap.size()>0){
       List<Lead> llist = [SELECT Id, Count_Activity__c FROM Lead WHERE ID IN:lmap.values()]; 
    for(lead l : lmap.values())
    {
        set<id> tids = new set <id>();
        for(Task tt : tmap.values())
        {
           if(tt.WhoId== l.Id)
            tids.add(tt.id);
        }
        if(l.Count_Activity__c!=tids.size())
        l.Count_Activity__c=tids.size();
        
              tlist = [select id, Whoid from task where whoid in:lid ];
        for(lead le :llist)
        {
            for(Task te:tlist)
            {
                if(tlist.size()>0)
                le.Count_Activity__c = tlist.size();
            }
        }
        
        
    }
    If(lmap.size()>0){
    update lmap.values();
    }
    }
    }
    }
}

 
 Normally I would try to fix the code myself but I have zero experience with Java. Pretty much all the time I just use the GUI interface that Dataloader is built with when I need to use it. However the interface is very poorly designed. For example when you are in the settings screen, the OK and cancel button are off the bottom of the screen. Resizing by dragging the edge of the window is pointless for the controls can't be scrolled down to when the box is made smaller. The only way I can access the control is to tab to it. 
Another example is when you are doing an export. The controls on the screen are so small - list of querry fields, the value field is cut in the middle, the window itself is the wrong size....I can keep going but you get the point here.
What I'd like to do is simply edit the interface so the controls and windows are not only the right size but in positions so that they are actually useable. 
Any suggestions or help on this would be great.  Thanks in advance
How to get user's login/logout time, visited url, action in the page, and so on?

Hello, I'm new manager of salesforce site and looking for  management methods of user behavior. I'm now using salesforce developper edition, but I hope to use enterprise edition some time soon. 
Because to manage user, I must know when user logged in/logged out, what pages were visited by the user, what buttons/actions were selected by the user.

1) What report can I use to get above items?
2) Can I use the report by developper edition?

Best regards,
a2z 
  • December 12, 2017
  • Like
  • 0
There is an idea that is marked as delivered through lightning.... https://success.salesforce.com/ideaView?id=08730000000Ycj6AAC

But I am struggling to see how I can add more than 2 columns to a page layout, i know you can add components to lightning pages and this gives good flexability but the Record Detail component takes from the pagelayout you have created which I cannot see allows more than 2 columns...

please can someone tell me how to add more that 2 columns to pagelayout using lightning?