• Colbridge
  • NEWBIE
  • 94 Points
  • Member since 2017
  • SFDC Training and Development
  • colbridge.com


  • Chatter
    Feed
  • 0
    Best Answers
  • 1
    Likes Received
  • 1
    Likes Given
  • 15
    Questions
  • 31
    Replies
I am trying to figure out, how to go about Google SSO and User Provisioning. 
 
I have already set up Google SSO. 
 
A google account is created when a person joins the company. Then person then be able to log in to SF using Google SSO. 
 
I can also go ahead and modify the auto generated registration hander methods to create a user account in the SF org.
 
Ideally what I want to do is, when a user is being created, I should be able to set different profile for different users. Maybe an admin approves a user then can decide which profile needs to be set for that user or something.
 
Also when the google account is deleted, the SF user account should also be de-activated. (when the person leaves the company).
 
How can I achieve this?
The flow (record triggered) should run when a check box is made true on update. It runs when the check box is checked manually on an update and saved. It also should run when the check box is checked by an approval process - but this doesn't seem to work.

If this is an issue, is there a work around?
I am getting the following error:
 
QuoteTrigger: execution of BeforeUpdate caused by: System.DmlException: Update failed. First exception on row 0 with id 0Q05D0000007jC3SAI; first error:

ELF_REFERENCE_FROM_TRIGGER, Object (id = 0Q05D0000007jC3) is currently in trigger QuoteTrigger, therefore it cannot recursively update itself: [] Trigger.QuoteTrigger: line 35, column 1

Trigger code is:
 
public static Boolean preventRecursive = true;
    if(preventRecursive){
        preventRecursive = false;
        // Uncheck all latest quotes except for the one manually made latest 
        if(Trigger.isUpdate && Trigger.isBefore){
            if(Trigger.new[0].Latest_quote__c == true) { // proceed only if latest quote is checked
                List<Quote> qtList = [SELECT Id, opportunityId, Latest_quote__c 
                    FROM quote WHERE opportunityId IN :oppIds ORDER BY LastModifiedDate DESC];
                if (qtList.size() > 1) {
                    for(Integer i = 0; i < qtList.size(); i++){ // uncheck all from being latest
                        qtList[i].Latest_quote__c = false;
                    }
                }
                qtList[0].Latest_quote__c = true; // mark only the manually marked as checked
                update qtList;
            }
        }
    }



Line 35 is: update qtList;

 
I have this trigger in which, when a new quote record is inserted, I am updating couple records, which works fine in the after insert serction.

But when an approval process updates a record, I want some records to be updated in the after update section, which is causing the recurssive error: 

QuoteTrigger: execution of AfterUpdate caused by: System.DmlException: Update failed. First exception on row 0 with id 0Q05D0000007jBySAI; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, QuoteTrigger: maximum trigger depth exceeded Quote trigger event AfterUpdate Quote trigger event 

How can I get around this error and implement my logic? Trigger code is below. Error occours on update qtList; line. I am trying to implement in the // If the quote is approved unmark - section.

 
trigger QuoteTrigger on Quote (after insert,after update) {
    
    Set<String> oppIds = new Set<String>();
    for(Quote q : Trigger.New){
        oppIds.add(q.opportunityId);  
    }
    
    public static Boolean preventRecursive = true;
    if(preventRecursive){
        preventRecursive = false;
        
        // To mark the newly inserted quote as latest and unmark the previous quote if there is any
        if(Trigger.isInsert && Trigger.isAfter){
            List<Quote> quoteList = [select id,opportunityId,Latest_quote__c from quote where opportunityId IN :oppIds ORDER BY CreatedDate DESC LIMIT 2];
            if(quoteList.size() == 1){
                quoteList[0].Latest_quote__c = true;
                update quoteList;
            } else if (quoteList.size() > 1) {
            quoteList[0].Latest_quote__c = true;
                quoteList[1].Latest_quote__c = false;
                update quoteList;
            }
        }
        
        if(Trigger.isAfter && Trigger.isUpdate){
            if(trigger.new != null){
                for(quote qt:trigger.new){
                    if(Trigger.new[0].Status== 'Approved' && qt.Quote_Link__c == Null && qt.Proposal_PDF__c == Null && qt.Site_Services_PDF__c == Null){                
                       // Quote_Lcs.sendemailtemplate(qt.id);
                    } 
                } 
                
                // If the quote is approved unmark all as latest and mark last updated (approved) quote as latest
                if(Trigger.new[0].Status== 'Approved'){ 
                    System.debug('Approved');
                    List<Quote> qtList = [select id,opportunityId,Latest_quote__c from quote where opportunityId IN :oppIds  ORDER BY LastModifiedDate DESC];
                    if (qtList.size() > 1) {
                        for(Integer i = 0; i < qtList.size(); i++){ // uncheck all from being latest
                            qtList[i].Latest_quote__c = false;
                        }
                    }
                    qtList[0].Latest_quote__c = true; // mark only the last updated/approved quote as latest
                    update qtList;
                }
            }
        }
    }
}

 
else if line is getting covered and is shown in blue/green, but the next two lines are in red. How to get that covered?
 
} else if ((checkedSummaryPlanIds == totalSummaryPlanIds) && (planIdMatch == false)) {
      skippedRecords += ddRecs.Plan_id__c + ' - ' + ddRecs.account_name__c + '\n'; // concatinated list of skipped records plan ids
      totalSkippedCtr++;
}

 
Looking to get coverage for the else part:
 
message.subject = messageSub;
        message.plainTextBody = messageBody;
        Messaging.SingleEmailMessage[] messages = 
            new List<Messaging.SingleEmailMessage> {message};
                Messaging.SendEmailResult[] results = Messaging.sendEmail(messages);
        if (results[0].success) {
            System.debug('The email was sent successfully.');
        } else {
            System.debug('The email failed to send: '
                + results[0].errors[0].message);
        }

 
How to get the coverage for the // dml operation failed part?
 
// records to be updated received from json
jsonBody = '[{"count__c":"445", "downloads__c":"340"}, {"count__c":"440", "downloads__c":"240"}]';

List<Data__c> dList = (List<Data__c>) System.JSON.deserialize(jsonBody, List<Data__c>.class);

countList has unique count__c values, say: 445,440 // to use in the IN clause.

// Querry parent for those plan ids in daily data json
List<Parent__c> parentList = [SELECT Id, Name FROM Parent__c 
    WHERE count__c IN :countList];

List<Data__c> dataToInsert = new List<Data__c>();

// Loop through dList - inner loop
for(Data__c dRecords : dList) {
     for(Parent__c parentRecords : parentList) {         
          if(dRecords.count__c  == parentRecords.count__c) {
                dRecords.downloads__c  = parentRecords.downloads__c ;
                dataToInsert.add(dRecords );
           }
      } 
} 

List srList = Database.insert(dataToInsert, false);
for(Integer i=0;i<srList.size();i++){
    if (srList.get(i).isSuccess()){
        srList.get(i).getId();

    }else if (!srList.get(i).isSuccess()){
        // DML operation failed
        Database.Error error = srList.get(i).getErrors().get(0);
        String failedDML = error.getMessage();
        recsToInsert.get(i);//failed record from the list
        system.debug('Failed Id: '+recsToInsert.get(i).Your_field__c);
    }
}



// Test class:
 
@isTest
private class Connect_Test {
    @isTest static void testCall() {
        Profile p = [SELECT Id FROM Profile WHERE Name='System Administrator' LIMIT 1]; 
        user intUser = new User(Alias = 'standt', Email='standarduser@testorg.com', 
            EmailEncodingKey='UTF-8', LastName='Integration User', LanguageLocaleKey='en_US', 
            LocaleSidKey='en_US', ProfileId = p.Id, 
            TimeZoneSidKey='America/Los_Angeles', UserName='intuser@co.com');
        insert intUser;

        System.runAs(intUser) {
            List<Parent__c> ms = new List<Parent__c>();
            Parent__c msRec1 = new Parent__c(count__c = '445');
            Parent__c msRec2 = new Parent__c(count__c = '440');
            ms.add(msRec1);
            ms.add(msRec2);
            insert ms;

            String strIds = '445, 440';
            list<String> countList = strIds.split(',');

            List<Parent__c> parentList = [SELECT Id, Name FROM Parent__c 
                WHERE count__c IN :countList];

            List<Data__c> recsToInsert = new List<Data__c>();
            Data__c ddRecs1 = new Data__c(downloads__c = 'a1IO001110AakH2MAJ');
            Data__c ddRecs2 = new Data__c(downloads__c = null);
            recsToInsert.add(ddRecs1);
            recsToInsert.add(ddRecs2);
            try {
                List<Database.SaveResult> srList = Database.insert(recsToInsert, false);
            } catch(DMLException e) {
                throw new DMLException('Unable to Perform the DML Operation: ' +e.getMessage());
            }
            Test.startTest();
            Test.setMock(HttpCalloutMock.class, new MockHttpResponse());
            Connect.call();
            Test.stopTest();
        }
    }
}

 
I have created an integration user account with name Integration User. How can I update the created by (ownerid) and last updated by fields with the details of this integration user while doing a bulk dml insert in apex? Right now its showing the logged in users name when the apex class is run.
 
// records to be updated received from json
jsonBody = '[{"count__c":"445", "downloads__c":"340"}, {"count__c":"440", "downloads__c":"240"}]';

List<Data__c> dList = (List<Data__c>) System.JSON.deserialize(jsonBody, List<Data__c>.class);

countList has unique count__c values, say: 445,440 // to use in the IN clause.

// Querry parent for those plan ids in daily data json
List<Parent__c> parentList = [SELECT Id, Name FROM Parent__c 
    WHERE count__c IN :countList];

List<Data__c> dataToInsert = new List<Data__c>();

// Loop through dList - inner loop
for(Data__c dRecords : dList) {
     for(Parent__c parentRecords : parentList) {         
          if(dRecords.count__c  == parentRecords.count__c) {
                dRecords.downloads__c  = parentRecords.downloads__c ;
                dataToInsert.add(dRecords );
           }
      } 
} 
insert dataToInsert;

 
How to generate a string with a list of skipped record ids.
Here I am skipping the records for which there is no matching count__c. 
I need to concatinate a string (skippedRecords) with ids of those skipped records. How would I achive this?
 
List<Parent__c> parentList = [SELECT Id, Name,downloads__c  FROM Parent__c 
    WHERE count__c IN :countList];

List<Data__c > datatoupdate = new List<Data__c >();

String skippedRecords = '';

    for(Data__c dRecords : dList) { 
        for(Parent__c parentRecords : parentList) {
            if(dRecords.count__c  == parentRecords.count__c) {
		        dRecords.downloads__c  = parentRecords.downloads__c ;
		        datatoupdate.add(dRecords );
            }
    } 
} 
update  datatoupdate;

 
P.S. No need to send entire record, just a few specific field on each failed records. Code so far is below:
 
Database.SaveResult[] srList = Database.insert(recsToInsert, false);

Integer successCtr = 0;
Integer failedCtr = 0;

for (Database.SaveResult sr : srList) {
    if (sr.isSuccess()) {
        successCtr ++;
    } else {
        // Operation failed, get all errors
        failedCtr ++;
        for(Database.Error err : sr.getErrors()) {
            System.debug('The following error has occurred.');
            System.debug(err.getStatusCode() + ': ' + err.getMessage());
            System.debug('Fields that affected this error: ' + err.getFields());
        }
    }
}
System.debug('Total successful record inserts: ' + successCtr);
System.debug('Total failed record inserts: ' + failedCtr);

 
What I am trying to do is to update a child object field (downloads__c) in each of the child records in the child object (Data__c) record collection, with the value of a field (downloads__c) from its parent object (Parent__c). The parent object also has the field count__c.
 
Once all the records are updated in the child collection, do a dml insert after the loop. Can't seem to get this to work. Hope I have explained correctly.
 
jsonBody = '[{"count__c":"45","downloads__c":"30"},{"count__c":"40","downloads__c":"20"}]'; // child records to be updated

List<Data__c> dList = (List<Data__c>) System.JSON.deserialize(jsonBody, List<Data__c>.class);

countList has unique count__c values, say 45,40 // to use in the IN clause.

// Querry parent for those plan ids in daily data json
List<Parent__c> parentList = [SELECT Id, Name FROM Parent__c 
    WHERE count__c IN :countList];

// Loop through the list of returned parent records - outer loop
for(Parent__c parentRecords : parentList) {
    // Loop through dList - inner loop
    for(Data__c dRecords : dList) {
        // look for matching count__c in parent 
        // update corresponding downloads__c in the child record with its parents downloads__c value
    } 
} 

Should I use maps, if so how?

// dml insert of child collection

 
With the validation rule active, getting validation error saying cannot update closed opportunity, while trying to insert the opportunity record. Any pointers to solve this?
I am getting the following error in http response in salesforce apex, when I do an http post:
oauth_problem=timestamp_refused&message=Timestamp has been refused
Any pointers on how to fix it will be appreciated.
Thanks.
Hi, 

How would you deploy/migrate custom settings from one org to another?

Thanks. 
Hi,

I am getting the error "The Lightning Bundle expensesApp is not a legal name" when trying to create this new app.

Trailhead unit: https://trailhead.salesforce.com/en/content/learn/modules/lex_dev_lc_basics/lex_dev_lc_basics_forms

Note sure why. Can someone give me a pointer?

Thanks,
Colbridge. 
Hi,

I am getting the error "The Lightning Bundle expensesApp is not a legal name" when trying to create this new app.

Trailhead unit: https://trailhead.salesforce.com/en/content/learn/modules/lex_dev_lc_basics/lex_dev_lc_basics_forms

Note sure why. Can someone give me a pointer?

Thanks,
Colbridge. 
I am trying to figure out, how to go about Google SSO and User Provisioning. 
 
I have already set up Google SSO. 
 
A google account is created when a person joins the company. Then person then be able to log in to SF using Google SSO. 
 
I can also go ahead and modify the auto generated registration hander methods to create a user account in the SF org.
 
Ideally what I want to do is, when a user is being created, I should be able to set different profile for different users. Maybe an admin approves a user then can decide which profile needs to be set for that user or something.
 
Also when the google account is deleted, the SF user account should also be de-activated. (when the person leaves the company).
 
How can I achieve this?
The flow (record triggered) should run when a check box is made true on update. It runs when the check box is checked manually on an update and saved. It also should run when the check box is checked by an approval process - but this doesn't seem to work.

If this is an issue, is there a work around?
I am getting the following error:
 
QuoteTrigger: execution of BeforeUpdate caused by: System.DmlException: Update failed. First exception on row 0 with id 0Q05D0000007jC3SAI; first error:

ELF_REFERENCE_FROM_TRIGGER, Object (id = 0Q05D0000007jC3) is currently in trigger QuoteTrigger, therefore it cannot recursively update itself: [] Trigger.QuoteTrigger: line 35, column 1

Trigger code is:
 
public static Boolean preventRecursive = true;
    if(preventRecursive){
        preventRecursive = false;
        // Uncheck all latest quotes except for the one manually made latest 
        if(Trigger.isUpdate && Trigger.isBefore){
            if(Trigger.new[0].Latest_quote__c == true) { // proceed only if latest quote is checked
                List<Quote> qtList = [SELECT Id, opportunityId, Latest_quote__c 
                    FROM quote WHERE opportunityId IN :oppIds ORDER BY LastModifiedDate DESC];
                if (qtList.size() > 1) {
                    for(Integer i = 0; i < qtList.size(); i++){ // uncheck all from being latest
                        qtList[i].Latest_quote__c = false;
                    }
                }
                qtList[0].Latest_quote__c = true; // mark only the manually marked as checked
                update qtList;
            }
        }
    }



Line 35 is: update qtList;

 
I have this trigger in which, when a new quote record is inserted, I am updating couple records, which works fine in the after insert serction.

But when an approval process updates a record, I want some records to be updated in the after update section, which is causing the recurssive error: 

QuoteTrigger: execution of AfterUpdate caused by: System.DmlException: Update failed. First exception on row 0 with id 0Q05D0000007jBySAI; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, QuoteTrigger: maximum trigger depth exceeded Quote trigger event AfterUpdate Quote trigger event 

How can I get around this error and implement my logic? Trigger code is below. Error occours on update qtList; line. I am trying to implement in the // If the quote is approved unmark - section.

 
trigger QuoteTrigger on Quote (after insert,after update) {
    
    Set<String> oppIds = new Set<String>();
    for(Quote q : Trigger.New){
        oppIds.add(q.opportunityId);  
    }
    
    public static Boolean preventRecursive = true;
    if(preventRecursive){
        preventRecursive = false;
        
        // To mark the newly inserted quote as latest and unmark the previous quote if there is any
        if(Trigger.isInsert && Trigger.isAfter){
            List<Quote> quoteList = [select id,opportunityId,Latest_quote__c from quote where opportunityId IN :oppIds ORDER BY CreatedDate DESC LIMIT 2];
            if(quoteList.size() == 1){
                quoteList[0].Latest_quote__c = true;
                update quoteList;
            } else if (quoteList.size() > 1) {
            quoteList[0].Latest_quote__c = true;
                quoteList[1].Latest_quote__c = false;
                update quoteList;
            }
        }
        
        if(Trigger.isAfter && Trigger.isUpdate){
            if(trigger.new != null){
                for(quote qt:trigger.new){
                    if(Trigger.new[0].Status== 'Approved' && qt.Quote_Link__c == Null && qt.Proposal_PDF__c == Null && qt.Site_Services_PDF__c == Null){                
                       // Quote_Lcs.sendemailtemplate(qt.id);
                    } 
                } 
                
                // If the quote is approved unmark all as latest and mark last updated (approved) quote as latest
                if(Trigger.new[0].Status== 'Approved'){ 
                    System.debug('Approved');
                    List<Quote> qtList = [select id,opportunityId,Latest_quote__c from quote where opportunityId IN :oppIds  ORDER BY LastModifiedDate DESC];
                    if (qtList.size() > 1) {
                        for(Integer i = 0; i < qtList.size(); i++){ // uncheck all from being latest
                            qtList[i].Latest_quote__c = false;
                        }
                    }
                    qtList[0].Latest_quote__c = true; // mark only the last updated/approved quote as latest
                    update qtList;
                }
            }
        }
    }
}

 
How to get the coverage for the // dml operation failed part?
 
// records to be updated received from json
jsonBody = '[{"count__c":"445", "downloads__c":"340"}, {"count__c":"440", "downloads__c":"240"}]';

List<Data__c> dList = (List<Data__c>) System.JSON.deserialize(jsonBody, List<Data__c>.class);

countList has unique count__c values, say: 445,440 // to use in the IN clause.

// Querry parent for those plan ids in daily data json
List<Parent__c> parentList = [SELECT Id, Name FROM Parent__c 
    WHERE count__c IN :countList];

List<Data__c> dataToInsert = new List<Data__c>();

// Loop through dList - inner loop
for(Data__c dRecords : dList) {
     for(Parent__c parentRecords : parentList) {         
          if(dRecords.count__c  == parentRecords.count__c) {
                dRecords.downloads__c  = parentRecords.downloads__c ;
                dataToInsert.add(dRecords );
           }
      } 
} 

List srList = Database.insert(dataToInsert, false);
for(Integer i=0;i<srList.size();i++){
    if (srList.get(i).isSuccess()){
        srList.get(i).getId();

    }else if (!srList.get(i).isSuccess()){
        // DML operation failed
        Database.Error error = srList.get(i).getErrors().get(0);
        String failedDML = error.getMessage();
        recsToInsert.get(i);//failed record from the list
        system.debug('Failed Id: '+recsToInsert.get(i).Your_field__c);
    }
}



// Test class:
 
@isTest
private class Connect_Test {
    @isTest static void testCall() {
        Profile p = [SELECT Id FROM Profile WHERE Name='System Administrator' LIMIT 1]; 
        user intUser = new User(Alias = 'standt', Email='standarduser@testorg.com', 
            EmailEncodingKey='UTF-8', LastName='Integration User', LanguageLocaleKey='en_US', 
            LocaleSidKey='en_US', ProfileId = p.Id, 
            TimeZoneSidKey='America/Los_Angeles', UserName='intuser@co.com');
        insert intUser;

        System.runAs(intUser) {
            List<Parent__c> ms = new List<Parent__c>();
            Parent__c msRec1 = new Parent__c(count__c = '445');
            Parent__c msRec2 = new Parent__c(count__c = '440');
            ms.add(msRec1);
            ms.add(msRec2);
            insert ms;

            String strIds = '445, 440';
            list<String> countList = strIds.split(',');

            List<Parent__c> parentList = [SELECT Id, Name FROM Parent__c 
                WHERE count__c IN :countList];

            List<Data__c> recsToInsert = new List<Data__c>();
            Data__c ddRecs1 = new Data__c(downloads__c = 'a1IO001110AakH2MAJ');
            Data__c ddRecs2 = new Data__c(downloads__c = null);
            recsToInsert.add(ddRecs1);
            recsToInsert.add(ddRecs2);
            try {
                List<Database.SaveResult> srList = Database.insert(recsToInsert, false);
            } catch(DMLException e) {
                throw new DMLException('Unable to Perform the DML Operation: ' +e.getMessage());
            }
            Test.startTest();
            Test.setMock(HttpCalloutMock.class, new MockHttpResponse());
            Connect.call();
            Test.stopTest();
        }
    }
}

 
How to generate a string with a list of skipped record ids.
Here I am skipping the records for which there is no matching count__c. 
I need to concatinate a string (skippedRecords) with ids of those skipped records. How would I achive this?
 
List<Parent__c> parentList = [SELECT Id, Name,downloads__c  FROM Parent__c 
    WHERE count__c IN :countList];

List<Data__c > datatoupdate = new List<Data__c >();

String skippedRecords = '';

    for(Data__c dRecords : dList) { 
        for(Parent__c parentRecords : parentList) {
            if(dRecords.count__c  == parentRecords.count__c) {
		        dRecords.downloads__c  = parentRecords.downloads__c ;
		        datatoupdate.add(dRecords );
            }
    } 
} 
update  datatoupdate;

 
What I am trying to do is to update a child object field (downloads__c) in each of the child records in the child object (Data__c) record collection, with the value of a field (downloads__c) from its parent object (Parent__c). The parent object also has the field count__c.
 
Once all the records are updated in the child collection, do a dml insert after the loop. Can't seem to get this to work. Hope I have explained correctly.
 
jsonBody = '[{"count__c":"45","downloads__c":"30"},{"count__c":"40","downloads__c":"20"}]'; // child records to be updated

List<Data__c> dList = (List<Data__c>) System.JSON.deserialize(jsonBody, List<Data__c>.class);

countList has unique count__c values, say 45,40 // to use in the IN clause.

// Querry parent for those plan ids in daily data json
List<Parent__c> parentList = [SELECT Id, Name FROM Parent__c 
    WHERE count__c IN :countList];

// Loop through the list of returned parent records - outer loop
for(Parent__c parentRecords : parentList) {
    // Loop through dList - inner loop
    for(Data__c dRecords : dList) {
        // look for matching count__c in parent 
        // update corresponding downloads__c in the child record with its parents downloads__c value
    } 
} 

Should I use maps, if so how?

// dml insert of child collection

 
With the validation rule active, getting validation error saying cannot update closed opportunity, while trying to insert the opportunity record. Any pointers to solve this?
I am getting the following error in http response in salesforce apex, when I do an http post:
oauth_problem=timestamp_refused&message=Timestamp has been refused
Any pointers on how to fix it will be appreciated.
Thanks.
Hi, 

How would you deploy/migrate custom settings from one org to another?

Thanks. 
Hi,

I am getting the error "The Lightning Bundle expensesApp is not a legal name" when trying to create this new app.

Trailhead unit: https://trailhead.salesforce.com/en/content/learn/modules/lex_dev_lc_basics/lex_dev_lc_basics_forms

Note sure why. Can someone give me a pointer?

Thanks,
Colbridge. 

We have recently contracted several Salesforce customization  projects and need some extra help (paid by the hour).  Please send your credentials, describe your past involvement with Salesforce, and references if possible to Taylor at timesmith@solvate.com.

hi ,i am trying the Lightning Experience Specialist

while i installed the  unmanaged LEX Superbadge package.
here comes the issue

"Install the unmanaged package from the pre-work if you haven’t already. Rename all of the standard objects in the schema as specified, and set the default page layouts for Adventure, Adventure Package, and Opportunity to the Relaxation Gauntlet custom layouts. Update the Opportunity stage values, create a sales path for sales reps (highlighting key fields and giving specific coaching guidance), and create an approval process as specified in the business requirements."

i am confused what i should do next .as i am unable to understand ....

help me