• Andrew G
  • 1854 Points
  • Member since 2014
  • Salesforce Learner

  • Chatter
  • 61
    Best Answers
  • 0
    Likes Received
  • 1
    Likes Given
  • 10
  • 402
Hello, I hope someone might be able to provide me some guidance!

I work in an area where we provide training to school districts, and we have recently started building out a tracking system to monitor our technical assistance to the districts. We currently have it where we have an object built which stores districts as record pages, and an object to create technical assistant events as a record. It currently uses a lookup field to link a technical assistant event to the school district. We are hoping to learn how we can make it possibile to link the technical assistant event to more than one school district.  I would like to be able to still have the function of the lookup field to search the school district, but the added ability of attaching a single technical assistant event to a district.

This was if I am out training at District 1 and District 2 I can record that in the same event, not have to create two different events.

I have attached a screenshot of the current new event creation form.

Any help is appriciated, thanks!

User-added image
I created a trigger to update a custom field (Mailing County) before insert of a Contact.  The trigger takes the MailingPostalCode entered by the user and finds the County in which that zip code is found.  This is done via a custom object (Zip_Code__c) in which the Postal Codes are stored along with their respective Counties.

I would love any feedback on how to make this trigger better, but specifically I am confused because one of my test methods is not working (TestContactWithValidZip).  This particular test gets caught by my addError clause of my trigger.

trigger CountyLookupByZip on Contact (before insert) {
    for (Contact c : Trigger.New) {
        if(c.MailingPostalCode != null) {
        	List<Zip_Code__c> contactCounty = new List<Zip_Code__c>();
            contactCounty = [SELECT Id,
         				 FROM   Zip_Code__c 
        			     WHERE  Postal_Code__c = :c.MailingPostalCode];
            if(contactCounty.size() != 0){
            	c.Mailing_County__c = contactCounty[0].County__c;
            } else {
                c.MailingPostalCode.addError('Postal Code not found. Please ensure the postal code is a valid Virginia zip code.');
Test Clas:
public class TestCountyLookupByZip {

    public static void TestContactWithNullZip() {
        // Test data setup
        // Create a contact without a Mailing Postal Code
        // and check to ensure County is also null
        Contact contactNullZip = new Contact(LastName = 'Test');
        insert contactNullZip;
        // Perform Test
        System.assertEquals(contactNullZip.Mailing_County__c, null);

    public static void TestContactWithValidZip() {

        // Test data setup
        // Create a contact with a valid VA Mailing Postal Code
        // and check to ensure County is updated correctly
    	Contact contactValidZip = new Contact(LastName = 'Test', MailingPostalCode = '20101');
        insert contactValidZip;
        // Perform Test
        System.assertEquals(contactValidZip.Mailing_County__c, 'Loudoun');
    public static void TestContactWithInvalidZip() {
        // Test data setup
        // Create a contact with an invalid Mailing Postal Code
        // and throw an error
        try {
       		Contact contactInvalidZip = new Contact(LastName = 'Test', MailingPostalCode = '17602');
        	insert contactInvalidZip;
        // Perform Test
        } catch(Exception e) {
            System.Assert(e.getMessage().contains('Postal Code not found. Please ensure the postal code is a valid Virginia zip code.'));


Hi All, 

New to apex and having an issue with a trigger(below). Its firing everytime but i would like it to only fire on records that are of a certain record type.
Any assistance is appreciated.

trigger efs_DealTrigger on Deal__c (after update, after insert) {
    List<Deal__c> dealsToUpdate = new list<Deal__c>();
    for (Deal__c deal: trigger.new){
        if(deal.RecordTypeId == '0120Y000000ITgrQAG'){
    for(Deal__c dealsInCriteria: dealsToUpdate) {
        if(trigger.isAfter && trigger.isInsert){
        else if(trigger.isAfter && trigger.isUpdate){



 Create a checkbox on the opportunity if stage value is closed won checkbox should be true else checkbox should be false. Help me create a validation rule for the same.

I have a simple rigger that automatically creates a custom PO_Number__c record when an Opportunity is created. This PO_Number__c an Account__c lookup field and an Opportunity__c lookup field that also gets automatically populated by the trigger.


In my test class, my first test method singleOpp() succeeds, but I want to test a situation where a builk insert of Opportunities happens. My second test method is bulkOpps(). I'm not sure how to finish this method off to make sure that all the PO_Number__c records that were automatically created have the correct Account__c and Opportunity__c fields.


Any help would be greatly appreciated! Here's my code:



trigger createPurchaseOrder on Opportunity (after insert) {
    // Initialize PO Numbers to insert list
    List<PO_Number__c> ponsToInsertList = new List<PO_Number__c>();

    for (Opportunity opp : Trigger.new) {
        if (opp.Id != null && AccountId != null) {
            // Create PO Number records
            PO_Number__c pon   = new PO_Number__c();
            pon.Account__c     = opp.AccountId;
            pon.Opportunity__c = opp.Id;
        if (!ponsToInsertList.isEmpty()) {
            // Insert PO Number records 
            insert ponsToInsertList;

private class CreatePurchaseOrderTest {
    @isTest static void singleOpp() {
        // Create Account
        Account acc = new Account();
        acc.Name    = 'Test Account';
        insert acc;

        // Create Opportunity
        Opportunity opp = new Opportunity();
        opp.Name        = 'Test Opp';
        opp.CloseDate   = Date.today();
        opp.StageName   = 'Initial Contact';
        opp.AccountId   = acc.Id;
        insert opp;

        // get opp
        List<Opportunity> updatedOpp = [
            SELECT Id, AccountId
              FROM Opportunity
             WHERE Id = :opp.Id
             LIMIT 1

        // check for PO Number record
        List<PO_Number__c> pon = [
            SELECT Id, Opportunity__c, Account__c
              FROM PO_Number__c
             LIMIT 1

        System.assertEquals(1, pon.size(), 'pon list size not correct');
        System.assertEquals(updatedOpp.get(0).Id, pon.get(0).Opportunity__c, 'Opportunity on PO Number not correct');
        System.assertEquals(updatedOpp.get(0).AccountId, pon.get(0).Account__c, 'Account on PO Number not correct');

    @isTest static void bulkOpps() {
        // Create multiple Accounts
        List<Account> accList = new List<Account>();
        for (Integer i = 0; i < 500; i++) {
        Account myAcc = new Account();
        myAcc.Name    = 'Test Acc ' + i;
        insert accList;

        // Create multiple Opps
        List<Opportunity> oppList = new List<Opportunity>();
        for (Integer i = 0; i < 500; i++) {
        Opportunity myOpp = new Opportunity();
        myOpp.Name        = 'Test Opp ' + i;
        myOpp.StageName   = 'Initial Contact';
        myOpp.CloseDate   = Date.today();
        myOpp.AccountId   = accList.get(i).Id;
        insert oppList;

        // Check for PO Number records
        List<PO_Number__c> ponList = [
            SELECT Id, Account__c, Opportunity__c
              FROM PO_Number__c

        // EX: PO Number 1 has Account 1 and Opportunity 1 on it's Account__c and Opportunity__c fields
        // EX: PO Number 1 had Account 2 and Opportunity 2 on it's Account__c and Opportunity__c fields

        System.assertEquals(accList.get(0).Id, ponList.get(0).Account__c, 'Account not correct on PO Number');
        System.assertEquals(oppList.get(0).Id, ponList.get(0).Opportunity__c, 'Opportunity not correct on PO Number');

Query in Developer Console:
select count() from RecordAction where ActionDefinition!=null

Error Message: 
An unexpected error occurred. Please include this ErrorId if you contact support: 1892670731-238612 (-1863376665)

When I execute same query in batch job, I got below error:
14:38:37.0 (11628419)|SYSTEM_METHOD_EXIT|[15]|BatchableContextImpl
14:38:37.0 (11636572)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:12
14:38:37.0 (11641144)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:4
14:38:37.0 (11644929)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:4
14:38:37.0 (11651159)|VARIABLE_SCOPE_BEGIN|[31]|this|Database.BatchableContextImpl|true|false
14:38:37.0 (11720780)|VARIABLE_ASSIGNMENT|[31]|this|{}|0x2d9895fe
14:38:37.0 (11727467)|VARIABLE_SCOPE_BEGIN|[31]|jobId|Id|false|false
14:38:37.0 (11833691)|VARIABLE_ASSIGNMENT|[31]|jobId|"7076g00000BKmtGAAT"
14:38:37.0 (11839995)|VARIABLE_SCOPE_BEGIN|[31]|childJobId|Id|false|false
14:38:37.0 (11861408)|VARIABLE_ASSIGNMENT|[31]|childJobId|"7076g00000BKmk3AAD"
14:38:37.0 (35565779)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:8
14:38:37.0 (178500415)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:8
14:38:37.0 (267469628)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:8
14:38:37.0 (353732986)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:8
14:38:37.0 (476538181)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:8
14:38:37.0 (564648158)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:8
14:38:37.0 (579395805)|FATAL_ERROR|Internal Salesforce.com Error

Hi fellow developers:

I am working on an apex trigger that will assign cases to certain groups/users based on the requirements from my boss.

What is really bothering me now is that when i ran the test class in sandbox it worked perfectly but when trying to deploy in production it gives me the following error:

First exception on row 2 with id 5003a00000xQsOrAAK; first error: INVALID_CROSS_REFERENCE_KEY, invalid cross reference id: []
Stack Trace: Class.TestCaseTrigger.TestCaseStatusChange: line 101, column 1

the trigger code:
trigger CaseTrigger on Case (before update) {
    for(Case c:Trigger.New){
        // grab the version of this case before the update 
        Case oldcase = Trigger.oldMap.get(c.ID);
        // access the status before the update for this case 
        string old_status = oldcase.status;
        // access the status after the update for this case
        string new_status = c.status;
        if(old_status == 'Closed' && new_status != 'Closed'){
          // we only need to handle this scenario, for now
          boolean previous_onwer_isactive = [SELECT owner.isActive FROM case WHERE id = :oldcase.Id LIMIT 1].owner.isactive;
                // create the rules based on "Case Assignment Rule"
                string case_subject = [SELECT subject FROM case WHERE id = :c.id LIMIT 1].subject;
                string case_origin = [SELECT origin FROM case WHERE id = :c.id LIMIT 1].origin;
                string assigned_to_name; // a variable used to locate its corresponding ID later on
                string assigned_to_id;
                if((case_subject=='HCRC TR Files'||case_subject=='HCRC FY Files') && case_origin == 
                   'Email - Enrollment Process Intelligence'){
                       assigned_to_name = 'HCRC Files';
                else if(case_origin == 'Email - Enrollment Process Intelligence'){
                    assigned_to_name = 'Enrollment Process Intelligence';
                else if(case_origin == 'Email - Enrollment Reporting'){
                    assigned_to_name = 'Enrollment Reporting';
                else if(case_origin == 'Email - Enrollment Support'){
                    assigned_to_name = 'Tim';
                else if(case_origin =='Email - Elevate'){
                    assigned_to_name = 'Elevate';
                else if(case_origin =='Email - Graduate Admission'){
                    assigned_to_name = 'Graduate Admission Case Queue';
                else if(case_origin =='Email - Graduate Recruitment'){
                    assigned_to_name = 'Graduate Recruitment';
                else if(case_origin =='Email - Graduate Visit'){
                    assigned_to_name = 'Graduate Visit Case Queue';
                else if(case_origin =='Email - GR Admission Partner'){
                    assigned_to_name = 'GR Admission Partner';
                else if(case_origin =='Email - UG Admission Partner'){
                    assigned_to_name = 'UG Admission Partner';
                else if(case_origin =='Olark Live Chat' || case_origin == 'Graduate SnapEngage Chat'){
                    assigned_to_name = 'Graduate Recruitment';
                else if(case_origin =='Web'){
                    assigned_to_name = 'Enrollment Process Intelligence';
                else if(case_origin =='Email - Undergraduate Admission'){
                    assigned_to_name = 'Undergraduate Admission';
                else if(case_origin =='Email - Undergraduate International'){
                    assigned_to_name = 'Undergraduate International';
                else if(case_origin =='Email - Undergraduate Visit'){
                    assigned_to_name = 'Undergraduate Visit';
                else if(case_origin =='Form Assembly - Project Request'){
                    assigned_to_name = 'Enrollment Process Intelligence';
                else if(case_origin =='Email - Undergraduate Transfer'){
                    assigned_to_name = 'Undergraduate Transfer';
                else if(case_origin =='Email-Academic Honesty'){
                    assigned_to_name = 'Academic Honesty';
                    c.addError('did not find a queue/person to assign to!');
                // only Tim is not a queue(Group object), so handled seperately
                if(assigned_to_name !='Tim'){
                    assigned_to_id = [SELECT id FROM group where name =:assigned_to_name LIMIT 1].id;
                     assigned_to_id = '005j000000COiwwAAD';
                c.OwnerId = assigned_to_id;


trigger test class:
public class TestCaseTrigger {
    @isTest static void TestCaseStatusChange(){
        // set up the data
        // create an user(owner)
        User thisUser = [SELECT Id FROM User WHERE Id = :UserInfo.getUserId()];

        System.runAs (thisUser){
        User test_user = new User(ProfileId = [SELECT Id FROM Profile WHERE Name = 'Standard User'].Id,
                          LastName = 'James',
                          Email = 'cli112@gmail.com',
                          Username = 'newlbj@gmail.com',
                          CompanyName = 'TEST',
                          Title = 'title',
                          Alias = 'alias',
                          TimeZoneSidKey = 'America/Los_Angeles',
                          EmailEncodingKey = 'UTF-8',
                          LanguageLocaleKey = 'en_US',
                          LocaleSidKey = 'en_US',
                          isactive =  FALSE
        insert test_user;
        // create a case
        string test_user_id = [SELECT id from user where username='newlbj@gmail.com' limit 1].id;

        List<Case> testCases = new List<Case>();
        Case test_case1 = New Case(origin='Email - Enrollment Process Intelligence', subject = 'HCRC TR Files',
         status='Closed', IIT_Project_Name__c = 'Test Case1',ownerid = test_user_id);
        Case test_case2 = New Case(origin='Email - Enrollment Process Intelligence', subject = 'different subject', 
            status='Closed', IIT_Project_Name__c = 'Test Case2',ownerid = test_user_id);
        Case test_case3 = New Case(origin='Email - Enrollment Reporting', subject = 'HCRC TR Files', 
            status='Closed', IIT_Project_Name__c = 'Test Case3',ownerid = test_user_id);
        //Case test_case4 = New Case(origin='Email - Enrollment Support', subject = 'HCRC TR Files', 
            status='Closed', IIT_Project_Name__c = 'Test Case4',ownerid = test_user_id);
        Case test_case5 = New Case(origin='Email - Elevate', subject = 'HCRC TR Files', 
            status='Closed', IIT_Project_Name__c = 'Test Case5',ownerid = test_user_id);
        Case test_case6 = New Case(origin='Email - Graduate Admission', subject = 'HCRC TR Files', 
            status='Closed', IIT_Project_Name__c = 'Test Case6',ownerid = test_user_id);
        Case test_case7 = New Case(origin='Email - Graduate Recruitment', subject = 'HCRC TR Files', 
            status='Closed', IIT_Project_Name__c = 'Test Case7',ownerid = test_user_id);
        Case test_case8 = New Case(origin='Email - Graduate Visit', subject = 'HCRC TR Files', 
            status='Closed', IIT_Project_Name__c = 'Test Case8',ownerid = test_user_id);
        Case test_case9 = New Case(origin='Email - GR Admission Partner', subject = 'HCRC TR Files', 
            status='Closed', IIT_Project_Name__c = 'Test Case9',ownerid = test_user_id);
        Case test_case10 = New Case(origin='Email - UG Admission Partner', subject = 'HCRC TR Files', 
            status='Closed', IIT_Project_Name__c = 'Test Case10',ownerid = test_user_id);
        Case test_case11 = New Case(origin='Olark Live Chat', subject = 'HCRC TR Files', 
            status='Closed', IIT_Project_Name__c = 'Test Case11',ownerid = test_user_id);
        Case test_case12 = New Case(origin='Web', subject = 'HCRC TR Files', 
            status='Closed', IIT_Project_Name__c = 'Test Case12',ownerid = test_user_id);
        Case test_case13 = New Case(origin='Email - Undergraduate Admission', subject = 'HCRC TR Files', 
            status='Closed', IIT_Project_Name__c = 'Test Case13',ownerid = test_user_id);
        Case test_case14 = New Case(origin='Email - Undergraduate International', subject = 'HCRC TR Files', 
            status='Closed', IIT_Project_Name__c = 'Test Case14',ownerid = test_user_id);
        Case test_case15 = New Case(origin='Email - Undergraduate Visit', subject = 'HCRC TR Files', 
            status='Closed', IIT_Project_Name__c = 'Test Case15',ownerid = test_user_id);
        Case test_case16 = New Case(origin='Form Assembly - Project Request', subject = 'HCRC TR Files', 
            status='Closed', IIT_Project_Name__c = 'Test Case16',ownerid = test_user_id);
        Case test_case17 = New Case(origin='Email - Undergraduate Transfer', subject = 'HCRC TR Files', 
            status='Closed', IIT_Project_Name__c = 'Test Case17',ownerid = test_user_id);
        Case test_case18 = New Case(origin='Email-Academic Honesty', subject = 'HCRC TR Files', 
            status='Closed', IIT_Project_Name__c = 'Test Case18',ownerid = test_user_id);

        insert testCases;
        // select all the test cases and then update them to status as "In Progress"
        List<Case> newstatusCases = [SELECT origin, subject, Status, ownerid FROM case WHERE IIT_Project_Name__c LIKE 'Test Case%'];
        for(Case c : newstatusCases){
            c.Status = 'In Progress';
        system.debug('Size of newstatusCases: ');

        update newstatusCases;

        // test1 : 'Email - Enrollment Process Intelligence' --> 'HCRC Files'
        Case inserted_test_case = [SELECT origin, subject, status, ownerid FROM case WHERE IIT_Project_Name__c = 'Test Case1' LIMIT 1];
        string test1_owner_id = inserted_test_case.OwnerId;
        test2 : 'Email - Enrollment Process Intelligence' --> 'Enrollment Process Intelligence'
        inserted_test_case = [SELECT origin, subject, status, ownerid FROM case WHERE IIT_Project_Name__c = 'Test Case2' LIMIT 1];
        string test2_owner_id = inserted_test_case.OwnerId;
        // test3 : 'Email - Enrollment Reporting' --> 'Enrollment Reporting'
        inserted_test_case = [SELECT origin, subject, status, ownerid FROM case WHERE IIT_Project_Name__c = 'Test Case3' LIMIT 1];
        string test3_owner_id = inserted_test_case.OwnerId;
        test4 : 'Email - Enrollment Support' --> 'Tim'
        inserted_test_case = [SELECT origin, subject, status, ownerid FROM case WHERE IIT_Project_Name__c = 'Test Case4' LIMIT 1];
        string test4_owner_id = inserted_test_case.OwnerId;
        // test5 : 'Email - Elevate' --> 'Email - Elevate'
        inserted_test_case = [SELECT origin, subject, status, ownerid FROM case WHERE IIT_Project_Name__c = 'Test Case5' LIMIT 1];
        string test5_owner_id = inserted_test_case.OwnerId;
        // test6 : 'Email - Graduate Admission' --> 'Graduate Admission Case Queue'
        inserted_test_case = [SELECT origin, subject, status, ownerid FROM case WHERE IIT_Project_Name__c = 'Test Case6' LIMIT 1];
        string test6_owner_id = inserted_test_case.OwnerId;

        // test7 : 'Email - Graduate Recruitment' --> 'Graduate Recruitment'
        inserted_test_case = [SELECT origin, subject, status, ownerid FROM case WHERE IIT_Project_Name__c = 'Test Case7' LIMIT 1];
        string test7_owner_id = inserted_test_case.OwnerId;

        // test8 : 'Email - Graduate Visit' --> 'Graduate Visit Case Queue'
        inserted_test_case = [SELECT origin, subject, status, ownerid FROM case WHERE IIT_Project_Name__c = 'Test Case8' LIMIT 1];
        string test8_owner_id = inserted_test_case.OwnerId;            
        // test9 : 'Email - GR Admission Partner' --> 'GR Admission Partner'
        inserted_test_case = [SELECT origin, subject, status, ownerid FROM case WHERE IIT_Project_Name__c = 'Test Case9' LIMIT 1];
        string test9_owner_id = inserted_test_case.OwnerId; 
        // test10 : 'Email - UG Admission Partner' --> 'UG Admission Partner'
        inserted_test_case = [SELECT origin, subject, status, ownerid FROM case WHERE IIT_Project_Name__c = 'Test Case10' LIMIT 1];
        string test10_owner_id = inserted_test_case.OwnerId;

        // test11 : 'Olark Live Chat' --> 'Graduate Recruitment'
        inserted_test_case = [SELECT origin, subject, status, ownerid FROM case WHERE IIT_Project_Name__c = 'Test Case11' LIMIT 1];
        string test11_owner_id = inserted_test_case.OwnerId;

        // test12 : 'Web' --> 'Enrollment Process Intelligence'
        inserted_test_case = [SELECT origin, subject, status, ownerid FROM case WHERE IIT_Project_Name__c = 'Test Case12' LIMIT 1];
        string test12_owner_id = inserted_test_case.OwnerId;            

        // test13 : 'Email - Undergraduate Admission' --> 'Undergraduate Admission'
        inserted_test_case = [SELECT origin, subject, status, ownerid FROM case WHERE IIT_Project_Name__c = 'Test Case13' LIMIT 1];
        string test13_owner_id = inserted_test_case.OwnerId;            

        // test14 : 'Email - Undergraduate International' --> 'Undergraduate International'
        inserted_test_case = [SELECT origin, subject, status, ownerid FROM case WHERE IIT_Project_Name__c = 'Test Case14' LIMIT 1];
        string test14_owner_id = inserted_test_case.OwnerId;            

        // test15 : 'Email - Undergraduate Visit' --> 'Undergraduate Visit'
        inserted_test_case = [SELECT origin, subject, status, ownerid FROM case WHERE IIT_Project_Name__c = 'Test Case15' LIMIT 1];
        string test15_owner_id = inserted_test_case.OwnerId;            
        // test16 : 'Form Assembly - Project Request' --> 'Enrollment Process Intelligence'
        inserted_test_case = [SELECT origin, subject, status, ownerid FROM case WHERE IIT_Project_Name__c = 'Test Case16' LIMIT 1];
        string test16_owner_id = inserted_test_case.OwnerId;              
        // test17 : 'Email - Undergraduate Transfer' --> 'Undergraduate Transfer'
        inserted_test_case = [SELECT origin, subject, status, ownerid FROM case WHERE IIT_Project_Name__c = 'Test Case17' LIMIT 1];
        string test17_owner_id = inserted_test_case.OwnerId;              
        // test18 : 'Email-Academic Honesty' --> 'Academic Honesty'
        inserted_test_case = [SELECT origin, subject, status, ownerid FROM case WHERE IIT_Project_Name__c = 'Test Case18' LIMIT 1];
        string test18_owner_id = inserted_test_case.OwnerId;            

        // Tests validations

        string test1_correct_owner_id = [SELECT id FROM group where name = 'HCRC Files' LIMIT 1].id;

        string test2_correct_owner_id = [SELECT id FROM group where name = 'Enrollment Process Intelligence' LIMIT 1].id;
        string test3_correct_owner_id = [SELECT id FROM group where name = 'Enrollment Reporting' LIMIT 1].id;
        string test4_correct_owner_id = '005j000000COiwwAAD';

        string test5_correct_owner_id = [SELECT id FROM group where name = 'Elevate' LIMIT 1].id;
        string test6_correct_owner_id = [SELECT id FROM group where name = 'Graduate Admission Case Queue' LIMIT 1].id;

        string test7_correct_owner_id = [SELECT id FROM group where name = 'Graduate Recruitment' LIMIT 1].id;

        string test8_correct_owner_id = [SELECT id FROM group where name = 'Graduate Visit Case Queue' LIMIT 1].id;

        string test9_correct_owner_id = [SELECT id FROM group where name = 'GR Admission Partner' LIMIT 1].id;

        string test10_correct_owner_id = [SELECT id FROM group where name = 'UG Admission Partner' LIMIT 1].id;

        string test11_correct_owner_id = [SELECT id FROM group where name = 'Graduate Recruitment' LIMIT 1].id;
        string test12_correct_owner_id = [SELECT id FROM group where name = 'Enrollment Process Intelligence' LIMIT 1].id;
        string test13_correct_owner_id = [SELECT id FROM group where name = 'Undergraduate Admission' LIMIT 1].id;
        string test14_correct_owner_id = [SELECT id FROM group where name = 'Undergraduate International' LIMIT 1].id;
        string test15_correct_owner_id = [SELECT id FROM group where name = 'Undergraduate Visit' LIMIT 1].id;
        string test16_correct_owner_id = [SELECT id FROM group where name = 'Enrollment Process Intelligence' LIMIT 1].id;
        string test17_correct_owner_id = [SELECT id FROM group where name = 'Undergraduate Transfer' LIMIT 1].id;
        string test18_correct_owner_id = [SELECT id FROM group where name = 'Academic Honesty' LIMIT 1].id;
            // new_case.OwnerId;

I am a Salesforce admin working to finish a Trigger in our Sandbox for tesitng. I have an Apex Trigger that is being used to rollup certain activities onto the lead record. When I try to convert the lead I'm hitting an error that I'm interpreting is because it's pushing an update to the activities on the record and then looking for the Lead.Id but this no longer exists. Can someone show me how to trigger only if the Lead is not converted?

Error message:

Error: There was an error converting the lead. Please resolve the following error and try again: ActivityRollups: execution of AfterUpdate caused by: System.SObjectException: Invalid Id for Lead 
Hello Developers

I have been trying to write test class for the Below trigger, the Trigger basically syncs products from quote line items to opportunity line items, when custom checkbox is checked, i have designed a test class, but when i click run test, the code coverage shows 0, below is my trigger and tets class 

trigger QuoteLineItemTrigger on Quotes__c (after insert, after update)
    Map<Id,Id> quoteIdToOppId =new Map<Id,Id>();
    Map<Id,List<QuoteLineitem__c>> quoteIdToLineItems = new Map<Id,List<QuoteLineitem__c>>();
    List<OpportunityLineItem__c> oppLineItems = new List<OpportunityLineItem__c>();
    Map<Id,String> oppIdtoName = new Map<Id,String>();
    for(Quotes__c q : trigger.new)
        if(q.IsSyncing__c && q.IsSyncing__c  != Trigger.oldMap.get(q.Id).IsSyncing__c ) quoteIdToOppId.put(q.id, q.OpportunityId__c);
    System.debug('UAC: quoteIdToOppId ' + quoteIdToOppId);
    for( QuoteLineitem__c qli :[SELECT Id, Product2Id__c,Product2Id__r.name,Quantity__c,ServiceDate__c, QuotesId__c,ListPrice__c,Line_Item_Description__c,Total_Price__c,Product2Id__r.Product_Code__c,UnitPrice__c  FROM QuoteLineitem__c WHERE QuotesId__c =:quoteIdToOppId.keyset() ])
        List<QuoteLineitem__c> tempList = quoteIdToLineItems.get(qli.QuotesId__c) ;
        if(tempList == null)
            templist = new List<QuoteLineitem__c>();
            quoteIdToLineItems.put(qli.QuotesId__c, templist);
    System.debug('UAC: quoteIdToLineItems ' + quoteIdToLineItems);
    for(Opportunities__c opp : [SELECT Id , Name  FROM Opportunities__c WHERE ID IN :quoteIdToOppId.values()] )
        oppIdtoName.put(opp.id, opp.Name)   ;
    System.debug('UAC: oppIdtoName ' + quoteIdToLineItems);
    for(Quotes__c q : Trigger.new)
        if(q.IsSyncing__c && quoteIdToLineItems.containsKey(q.Id))
            for(QuoteLineitem__c qli : quoteIdToLineItems.get(q.Id))
                OpportunityLineItem__c oli = new OpportunityLineItem__c();
                oli.OpportunityId__c = quoteIdToOppId.get(qli.QuotesId__c); 
                System.debug(' qli.Product2Id__r.name ' +  qli.Product2Id__r.name);
                oli.Name = qli.Product2Id__r.name;
                System.debug(' qli.Product2Id__c ' +  qli.Product2Id__c);
                System.debug(' qli.ListPrice__c ' +  qli.ListPrice__c);
                System.debug(' qli.Line_Item_Description__c ' +  qli.Line_Item_Description__c);
                oli.Product2Id__c = qli.Product2Id__c; 
                oli.Quantity__c = qli.Quantity__c; 
                oli.ListPrice__c = integer.valueof(qli.ListPrice__c); 
                oli.Description__c = qli.Line_Item_Description__c;
                oli.ServiceDate__c = qli.ServiceDate__c;
                oli.Total_Price__c = qli.Total_Price__c;
                oli.ProductCode__c = qli.Product2Id__r.Product_Code__c;
                oli.Sales_Price__c =qli.UnitPrice__c;
        System.debug('UAC: oppLineItems ' + oppLineItems);
        if(oppLineItems.size() > 0) insert oppLineItems ;

My test Class

public class QuoteLineItemTestClass {							
    private static void setUpData(){
        Opportunities__c opp = new Opportunities__c();
        opp.Name = 'Test Opp';
        opp.Stage__c = 'Prospecting';
        opp.Close_Date__c = Date.today();
        insert opp;
        Quotes__c Quo = new Quotes__c();
        Quo.Name = 'Test Quote';
        Quo.OpportunityId__c = opp.Id;
        Quo.AccountId__c = opp.Id;
        insert Quo;
        QuoteLineitem__c QLI = new QuoteLineitem__c();
        QLI.QuotesId__c = Quo.Id;
        QLI.Quantity__c = 1;
        QLI.Product2Id__c = Quo.Id;
        insert QLI;
        Product2__c P = new Product2__c();
        P.Name = 'Test record';
        P.Opportunities__c = opp.Id;
        insert P;
        PricebookEntry__c PBE = new PricebookEntry__c();
        PBE.Product2Id__c = p.Id;
        PBE.IsActive__c = true;
        insert PBE;
        Pricebook2__c pb = [select Id from Pricebook2__c where Is_Standard_Price_Book__c = true limit 1]; 
    static testMethod void  basicTest() {
    QuoteLineitem qli = [Select Id,QuoteId From QuoteLineitem Limit 1];
            Insert qli;
I have a batch method that searches for all "Matters" with a certain record type. After they are found it loops though this list, assigns a new record type, and creates several "Stages" for the matter. I can't seem to write a Test class that covers more than 4% (cone of shame). Any help would be greatly appreciated!

Batch Class
global class MyBatchClass implements Database.Batchable<sObject> {
     global Database.QueryLocator start(Database.BatchableContext bc) {
        // collect the batches of records or objects to be passed to execute
         return Database.getQueryLocator(
            'SELECT ID, RecordTypeId FROM litify_pm__Matter__c Where litify_pm__Matter_Plan__c = \'a0h6A000002nWNrQAM\' AND (RecordTypeId = \'0126A000000NjDyQAK\' OR RecordTypeId = \'0126A000000xP0cQAE\')'
    global void execute(Database.BatchableContext bc, List<litify_pm__Matter__c> scope){
        // process each batch of records
        List<litify_pm__Matter__c> matters = new List<litify_pm__Matter__c>();
        //List<litify_pm__Matter_Stage_Activity__c> stages = new List<litify_pm__Matter_Stage_Activity__c>();
        //List<litify_pm__Matter_Stage_Activity__c> discoveryStages = new List<litify_pm__Matter_Stage_Activity__c>();
        litify_pm__Matter_Stage_Activity__c WorkSettled;
        litify_pm__Matter_Stage_Activity__c settled;
        litify_pm__Matter_Stage_Activity__c discovery;
        for (litify_pm__Matter__c matter : scope){
            if (matter.RecordTypeId == '0126A000000NjDyQAK'){
                matter.RecordTypeId = '0123s000000ywXyAAI';
                matter.RecordTypeId = '0123s000000ywXzAAI';
              litify_pm__Matter_Stage_Activity__c LitPrep = New litify_pm__Matter_Stage_Activity__c();
              LitPrep.Name = 'Litigation Preparation';
                LitPrep.litify_pm__Matter__c = matter.Id;
                LitPrep.litify_pm__Order__c = 8;
                LitPrep.litify_pm__Original_Matter_Stage__c = 'a0k6A00000MU022QAD';
                 LitPrep.litify_pm__Stage_Status__c = 'Idle';
              litify_pm__Matter_Stage_Activity__c Filed = New litify_pm__Matter_Stage_Activity__c();
              Filed.Name = 'Filed';
                Filed.litify_pm__Matter__c = matter.Id;
                Filed.litify_pm__Order__c = 9;
                Filed.litify_pm__Original_Matter_Stage__c = 'a0k6A00000MU02CQAT';
                 Filed.litify_pm__Stage_Status__c = 'Idle';
              litify_pm__Matter_Stage_Activity__c Served = New litify_pm__Matter_Stage_Activity__c();
              Served.Name = 'Served';
                Served.litify_pm__Matter__c = matter.Id;
                Served.litify_pm__Order__c = 10;
                Served.litify_pm__Original_Matter_Stage__c = 'a0k6A00000MU02HQAT';
                 Served.litify_pm__Stage_Status__c = 'Idle';
              litify_pm__Matter_Stage_Activity__c WrittenDiscovery = New litify_pm__Matter_Stage_Activity__c();
              WrittenDiscovery.Name = 'Written Discovery';
                WrittenDiscovery.litify_pm__Matter__c = matter.Id;
                WrittenDiscovery.litify_pm__Order__c = 11;
                WrittenDiscovery.litify_pm__Original_Matter_Stage__c = 'a0k6A00000MU02HQAT';
                 WrittenDiscovery.litify_pm__Stage_Status__c = 'Idle';
              litify_pm__Matter_Stage_Activity__c DOP = New litify_pm__Matter_Stage_Activity__c();
              DOP.Name = 'Deposition of Parties';
                DOP.litify_pm__Matter__c = matter.Id;
                DOP.litify_pm__Order__c = 12;
                DOP.litify_pm__Original_Matter_Stage__c = 'a0k6A00000MU02MQAT';
                 DOP.litify_pm__Stage_Status__c = 'Idle';
              litify_pm__Matter_Stage_Activity__c ExpertDep = New litify_pm__Matter_Stage_Activity__c();
              ExpertDep.Name = 'Expert Deposition';
                ExpertDep.litify_pm__Matter__c = matter.Id;
                ExpertDep.litify_pm__Order__c = 13;
                ExpertDep.litify_pm__Original_Matter_Stage__c = 'a0k6A00000MU02MQAT';
                 ExpertDep.litify_pm__Stage_Status__c = 'Idle';
              litify_pm__Matter_Stage_Activity__c Mediation = New litify_pm__Matter_Stage_Activity__c();
              Mediation.Name = 'Mediation';
                Mediation.litify_pm__Matter__c = matter.Id;
                Mediation.litify_pm__Order__c = 14;
                Mediation.litify_pm__Original_Matter_Stage__c = 'a0k6A00000MU02MQAT';
                 Mediation.litify_pm__Stage_Status__c = 'Idle';
              litify_pm__Matter_Stage_Activity__c Trial = New litify_pm__Matter_Stage_Activity__c();
              Trial.Name = 'Trial';
                Trial.litify_pm__Matter__c = matter.Id;
                Trial.litify_pm__Order__c = 15;
                Trial.litify_pm__Original_Matter_Stage__c = 'a0k6A00000MU02RQAT';
                 Trial.litify_pm__Stage_Status__c = 'Idle';
              litify_pm__Matter_Stage_Activity__c TrialPrep = New litify_pm__Matter_Stage_Activity__c();
              TrialPrep.Name = 'Trail Preparation';
                TrialPrep.litify_pm__Matter__c = matter.Id;
                TrialPrep.litify_pm__Order__c = 16;
                TrialPrep.litify_pm__Original_Matter_Stage__c = 'a0k6A00000MU02RQAT';
                 TrialPrep.litify_pm__Stage_Status__c = 'Idle';
                WorkSettled = [SELECT ID FROM litify_pm__Matter_Stage_Activity__c 
                           Where Name = 'Working to Settle' AND litify_pm__Matter__c = :matter.Id];
              WorkSettled.litify_pm__Order__c = 17;
              settled = [SELECT ID FROM litify_pm__Matter_Stage_Activity__c 
                           Where Name = 'Settled' AND litify_pm__Matter__c = :matter.Id];
              settled.litify_pm__Order__c = 18;
              discovery = [SELECT ID FROM litify_pm__Matter_Stage_Activity__c 
                           Where Name = 'Discovery' AND litify_pm__Matter__c = :matter.Id];
        update matters;
        //upsert stages;
        //delete discoveryStages;
    global void finish(Database.BatchableContext bc){
        // execute any post-processing operations

Test class (please don't laugh)
private class MyBatchClassTest {
   static testMethod void BatchProcessAccount_TestMethod (){
        List<litify_pm__Matter__c> matter = [SELECT ID, RecordTypeId FROM litify_pm__Matter__c Where litify_pm__Matter_Plan__c = 'a0h6A000002nWNrQAM' AND (RecordTypeId = '0126A000000NjDyQAK' OR RecordTypeId = '0126A000000xP0cQAE')];
         litify_pm__Matter__c mat = new litify_pm__Matter__c(litify_pm__Display_Name__c = 'Darth', Case_Red_Flags__c='flag',
               litify_pm__Client__c ='0016A00000ITd3QQAT');
                insert mat;
         litify_pm__Matter_Stage_Activity__c stage = new litify_pm__Matter_Stage_Activity__c(Name = 'Settled', litify_pm__Order__c  =1,
                  litify_pm__Matter__c= mat.Id, litify_pm__Stage_Status__c = 'Idle');
                insert stage;
         List<litify_pm__Matter_Stage_Activity__c> stages = new List<litify_pm__Matter_Stage_Activity__c>();
         for (litify_pm__Matter__c i : matter){
             litify_pm__Matter_Stage_Activity__c stage1 = new litify_pm__Matter_Stage_Activity__c(Name = 'Settled', litify_pm__Order__c  =1,
                  litify_pm__Matter__c= i.Id, litify_pm__Stage_Status__c = 'Idle');
   MyBatchClass objBatch = new MyBatchClass();
   ID batchprocessid = Database.executeBatch(objBatch);

When creating a new Lead via an API call, I need to set the RecordType.  To do that, it seems as if I need the RecordTypeId.  But for testing, that ID is going to be different in Sandbox vs. Production.  So I don't want to hardcode the RecordTypeId.

When creating a new Lead via API, is there a way to specify the Record Type using its name instead of its ID?  Or at least have the API look up the RecordTypeId based on its name?
This email will send an email alert when an account has 8 cases open within 7 days.  The email is being sent, but multiple emails for the Same account are being sent.  What is wrong with my code that it is creating multiple emails for the same account?

trigger CaseHandlerCountAlert on Case (after insert, after update) {
    //Case trigger that will send email alert when 8 cases are created within 7 days.
    String messageToSend;
    List <String> ListOfMessages = new List <String>();
    Set <Id> AcctIds = new Set <Id>();
    String messageBody;
    List < AggregateResult > AggregateResultList = [SELECT AccountId, Account.Name name, COUNT(Id) co
                                                    FROM Case
                                                    WHERE CreatedDate = LAST_N_DAYS:7 AND Id IN :Trigger.New
                                                    GROUP BY AccountId, Account.Name
                                                    HAVING COUNT(Id) >= 8
    Map < Id, String > accountIdEmailmessageMap = new Map < Id, String > ();
    for (AggregateResult aggr: AggregateResultList) {
        String messageToSend = 'Account name: ' + aggr.get('name') +
            ' has ' + (Integer) aggr.get('co') +
            ' cases opened in the last 8 days.';
        Id accId = (Id) aggr.get('AccountId');
        accountIdEmailmessageMap.put(accId, messageToSend);
    List < Case > caseList = [SELECT Id, AccountId, Account.Name, Parent_Project_if_applicable__r.Implementation_status__c,
                              FROM Case
                              WHERE AccountId IN: AcctIds];
    List<Messaging.SingleEmailMessage> lstASingleEmailMessage = new List<Messaging.SingleEmailMessage>();
    List<Messaging.SingleEmailMessage> lstBSingleEmailMessage = new List<Messaging.SingleEmailMessage>();
    for (Case cl: caseList) {
        if (cl.Parent_Project_if_applicable__r.Implementation_status__c == 'Live - Closed Project' ||
            cl.Parent_Project_if_applicable__r.PM_Implementation_Status__c == 'Live - Closed Project' ||
            cl.Parent_Project_If_Applicable__r.RCM_Implementation_Status__c == 'Live - Closed Project') {
                String messageBody = accountIdEmailmessageMap.get(cl.AccountId);
                List<String> emailaddr = new List<String>();
                Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
                mail.Subject = 'Multiple cases created alert message';
                String messageBody1 = accountIdEmailmessageMap.get(cl.AccountId);        
                List<String> emailAdds = new List<String>();
                Messaging.SingleEmailMessage amail = new Messaging.SingleEmailMessage();
                amail.Subject = 'Multiple cases created alert message';
    Messaging.SendEmailResult[] r = Messaging.sendEmail(lstASingleEmailMessage);   
    Messaging.SendEmailResult[] rb = Messaging.sendEmail(lstBSingleEmailMessage);


I am a newbie. I am just starting to learn salesforce programming. I wanted to know if there were any limits on how many times we could deploy/push changes to the server. I am creating a lightning web component. Even If I make a small change, I have to deploy the code to sandbox to test the change. Is this the only way to test changes? and if yes, is there any limit on how many times we can push changes from local Visual Studio to the server (sandbox for now)? Seeing so many limitations related to licenses I am worried i might hit a roadblock soon and it's not possible for a beginner to understand all types of licenses and nitty gritty of programming. Thanks!
I'm trying to prevent an opportunity from saving when StageName = Verification but picklist named Client equals No or is blank. The picklist value must equal Yes. 

Validation rule allows opportunity record to save if picklist value = No or if picklist value is blank. Can someone help me with this? thx
ISPICKVAL( StageName, 'Verification)'),
ISPICKVAL( Client_Verified__c, 'Yes'))

  • October 15, 2019
  • Like
  • 0
I am trying to query salesforce data based on information that I am pulling from our HR system via a REST API callout to the HR system. 

Basically I am tring to find all contacts in my Salesforce org where the first name = the first name in the API Call. I know that first name is not specific enough, but I am starting here and once I can get records to match I will use a more unique identifier. 

Here is my code. I NEED HELP WITH LINE 28! I have left out authorization lines for privacy sake. 
    HttpResponse response = http.send(request);
    // If the request is successful, parse the JSON response.
    if (response.getStatusCode() == 200) {
        // Deserializes the JSON string into collections of posts.
        Map<String,Object> wrapper = (Map<String,Object>) JSON.deserializeUntyped(response.getBody());
        if (wrapper.containsKey('data')) {
            Map<String, Object> wrapper2 = (Map<String,Object>) wrapper.get('data');
            if(wrapper2.containsKey('data')) {
                List<Object> people = (List<Object>)wrapper2.get('data');
                for (Object peopleWrapper : people) {
                    Map<String,Object> Employees = (Map<String,Object>) peopleWrapper;
                    String ZenefitsLastName = (String) Employees.get('last_name');
                    String ZenefitsFirstName = (String) Employees.get('first_name');
                    String ZenefitseEmployeeId = (String) Employees.get('id');
                        List<Contact> contactList = [SELECT Id, FirstName, LastName FROM Contact WHERE FirstName = Employees.get('first_name') LIMIT 200];
					//we now need to find all contacts in SF that match the contacts in Employees
                    //once we have matches we need to synce each ID 
                            system.debug('Employees ' + Employees);
                            system.debug('last name ' + ZenefitsLastName);
                        	system.debug('Employee id ' + ZenefitseEmployeeId);
                        	system.debug('first name ' + ZenefitsFirstName);
                            system.debug('Contact list ' + contactList);
            return null;
        return null;
    return null;

Hi All

I have wirrten a small Apex trigger to stop chatter group members from leaving a group, based on the permissions of the gorup which are set in a record in the custom object Chatter_Groups__c. Whenever a new chatter group is created, a record is automatically created in this custom object with the necessary fields. 

My trigger is working as intended:
trigger disableChatterDelete on CollaborationGroupMember (before delete) {
    List<Chatter__c> chatterGroups = [SELECT Id,
                                      FROM Chatter__c];
    Id userProfileId = userinfo.getProfileId();
    String userProfileName = [SELECT ID, Name from Profile Where Id = : userProfileId].Name;
    for(CollaborationGroupMember collab : Trigger.Old){
        integer index;
        for(integer i = 0; i < chatterGroups.size();i++){
            if(collab.CollaborationGroupId == chatterGroups[i].Chatter_Group_Id__c) index = i;
        if(chatterGroups[index].Allowed_to_leave__c == false){
            if(chatterGroups[index].Chatter_Group_Id__c == collab.CollaborationGroupId){
                if(userProfileName != 'System Administrator'){
                            collab.adderror('This Group is mandatory for all staff');
This is my test class:
public class disableChatterDeleteTest {
    static testMethod void testDisableChatterDeleter(){
        // Create a unique UserName
        String uniqueUserName = 'salesuser' + DateTime.now().getTime() + '@testorg.com';
        // This code runs as the system user
        Profile p = [SELECT Id FROM Profile WHERE Name='SADC Employee'];
        User usr = new User(Alias = 'suser', Email='user@testorg.com',
                            EmailEncodingKey='UTF-8', LastName='SalesTesting', LanguageLocaleKey='en_US',
                            LocaleSidKey='en_US', ProfileId = p.Id,
        // Create new Chatter Group
        CollaborationGroup grp = new CollaborationGroup();
        grp.Name = 'Test Group';
        grp.CollaborationType = 'Public';
        insert grp;
        //Create new Chatter Group record
        Chatter__c grpRec = new Chatter__c();
        grpRec.Name = 'Test Group Record';
        grpRec.Chatter_Group_Id__c = grp.Id;
        grpRec.Allowed_to_leave__c = false;
        // Create new group member
        CollaborationGroupMember grpMem = new CollaborationGroupMember();
        grpMem.MemberId = usr.Id;
        grpMem.CollaborationGroupId = grp.Id;
                delete grpMem;
            }catch(Exception ex){
            List<CollaborationGroup> groupList = [SELECT Id, MemberCount
                                                  FROM CollaborationGroup 
                                                 Where Id = : grp.Id];
            System.assertEquals(groupList[0].MemberCount, 1 );

Running this test class does not result in an error, but i have 0 code coverage. If anyone could tell me where i am going wrong it would be much appreciated!


We have a set of JavaScript buttons which are designed to generate new opportunities when a user clicks a button from a related list on an account. These buttons were working as planned yesterday. Overnight, we refreshed our full UAT sandbox from production. This morning, when I try to generate a new opportunity in the sandbox, Salesforce opens up a new page and tries to log in to production. The process then errors out, as the system is trying to create an opportunity in the wrong environment. When you take the ID generated in production, then apply it back to the sandbox, a new opportunity is then created. I have reviewed the JavaScript button, and I see no references to the production org.

Here is one of the JavaScript buttons:
{!REQUIRESCRIPT("/soap/ajax/31.0/connection.js")} {!REQUIRESCRIPT("/soap/ajax/31.0/apex.js")} var opportunity = new sforce.SObject('Opportunity'); opportunity.Name = 'Do Not Delete'; opportunity.AccountId = '{!Account.Id}'; opportunity.RecordTypeId = '{!$Setup.Opportunity_Record_Type_Ids__c.Standard_Services__c}'; opportunity.StageName = 'Qualification'; var closeDate = new Date('{!TODAY()}'); closeDate.setMonth(closeDate.getMonth()+6); opportunity.CloseDate = closeDate; var result = sforce.connection.create([opportunity]); if(result[0].success == 'true'){ var serverPrefix = '{!$Setup.Server_Prefix__c.Server_Prefix__c}'; var oppId = result[0].id; parent.window.location.href = 'https://' + serverPrefix + '.salesforce.com/' + oppId; } else{ alert('Record creation failed - please notify system administrator'); }

The Standard Services Opportunity Record ID is in Custom Settings. The Record IDs point to Record types within UAT
Here is my class:

public with sharing class BusinessUnitTriggerHandler 
    public static void checkDuplicate(List<BusinessUnits__c> units, Map<Id, BusinessUnits__c> oldMap, Boolean isInsert ) 
      Map<String, Integer> businessUnitMap = new Map<String, Integer>();
      Set<String> lineOfBusiness = new Set<String>();
      Set<Id> contactIds = new Set<Id>();
      List<BusinessUnits__c> unitsToProcess = new List<BusinessUnits__c>();

      // Get System Admin profile Id
      Id profileId = [SELECT Id FROM Profile WHERE Name = 'System Administrator' LIMIT 1].Id;
      System.debug('UAC: profileId' + profileId);

      //Get current User Profile ID
      Id userProfileId = UserInfo.getProfileId() ;
    System.debug('UAC: userProfileId' + userProfileId);

    // Iterate over all business records 
        for( BusinessUnits__c bu : units )
          // When current user Non-Admin OR these fields are updated 
          if(  profileId != userProfileId &&
            ( isInsert || ( !isInsert && ( bu.LineOfBusiness__c != oldMap.get(bu.Id).LineOfBusiness__c || bu.Contact__c != oldMap.get(bu.Id).Contact__c))) ) 
            businessUnitMap.put(bu.LineOfBusiness__c+bu.Contact__c, 0);
        System.debug('UAC: businessUnitMap' + businessUnitMap );
        if( businessUnitMap.size() == 0 ) return ;

        // Get existing Business records 
        for( BusinessUnits__c bu : [SELECT Id, LineOfBusiness__c, Contact__c FROM BusinessUnits__c 
                      WHERE Contact__c IN :contactIds AND LineOfBusiness__c IN :lineOfBusiness AND ID NOT IN :units ])
          String key = bu.LineOfBusiness__c+bu.Contact__c;
          businessUnitMap.put( key, (businessUnitMap.get(key)+1) ) ;
        System.debug('UAC: businessUnitMap' + businessUnitMap );
        if( businessUnitMap.size() == 0 ) return ;

        // Iterate again over inserted/updated records 
        for( BusinessUnits__c bu : unitsToProcess )
          String key = bu.LineOfBusiness__c+bu.Contact__c;
          // When Already exists then show error
          if( businessUnitMap.containsKey(key) && businessUnitMap.get(key) > 0 ) bu.addError('Sorry. A Business Relationship for this Business Unit already exists for this Contact.');

    public static void changeOwner(List<BusinessUnits__c> units )
        for(BusinessUnits__c bu : units )
            if( bu.Sales_Rep__c != null && bu.OwnerId != bu.Sales_Rep__c  ) bu.OwnerId = bu.Sales_Rep__c ; 

    public static Map<String, BusinessUnitRulesManagement__c> lobAndUserRoleToBusinessUnitCS
            if(lobAndUserRoleToBusinessUnitCS == null )
                lobAndUserRoleToBusinessUnitCS = new Map<String, BusinessUnitRulesManagement__c>();
                for(BusinessUnitRulesManagement__c cs : BusinessUnitRulesManagement__c.getAll().values()) 
                    lobAndUserRoleToBusinessUnitCS.put( cs.LineofBusiness__c + '' + cs.RoleDeveloperName__c, cs);
            //for(String key : lobAndUserRoleToBusinessUnitCS.keySet() ) System.debug('UAC: key ' + key  + ' value ' + lobAndUserRoleToBusinessUnitCS.get(key) );
            return lobAndUserRoleToBusinessUnitCS ;
        private set ;

    *   @Method:    updateContactFromCS()
    *   @Purpose:   When BusinessUnit is Updated then update SalesRep and EscrowOfficer fields from Contact based on Custom Setting fields 
    *   @Param:     List<BusinessUnits__c> units : List of new records - Trigger.new
    *               Map<Id,BusinessUnit__c> oldMap : map of old values - Trigger.oldMap
    *   @Return:    void : No return value
    *   @Date:      05/15/2017
    *   @Updates: 
    public static Boolean RUN_ONCE_UCFCS = true ; 
    public static void updateContactFromCS(List<BusinessUnits__c> units, Map<Id,BusinessUnits__c> oldMap, Boolean isInsert )
        System.debug('UAC: BU updateContactFromCS START ' );
        Map<BusinessUnits__c, Id> businessUnitToContactId = new Map<BusinessUnits__c, Id>();
        Map<Id,Contact> existingContacts = new Map<Id,Contact>();
        Set<Id> contactIdsAddedForUpdate = new Set<Id>();
        List<Contact> contactsToUpdate = new List<Contact>();
        Set<Id> contactIds = new Set<Id>();
        Set<Id> userIds = new Set<Id>();
        Map<Id, String> userIdToUserRole = new Map<Id, String>();

        for(BusinessUnits__c bu : units)
            BusinessUnits__c old =  !isInsert ? oldMap.get(bu.Id) : NULL ; 
            if( isInsert || ( !isInsert && (bu.Sales_Rep__c != old.Sales_Rep__c || bu.Escrow_Officer__c != old.Escrow_Officer__c)) ) 
                if(bu.Sales_Rep__c != null ) userIds.add(bu.Sales_Rep__c);
                if(bu.Escrow_Officer__c != null && bu.Sales_Rep__c != bu.Escrow_Officer__c ) userIds.add(bu.Escrow_Officer__c);
                businessUnitToContactId.put(bu, bu.Contact__c);
        System.debug('UAC: businessUnitToContactId ' + businessUnitToContactId );

        for(User u : [SELECT Id, UserRole.DeveloperName FROM User WHERE ID IN :userIds ])
            userIdToUserRole.put(u.Id, u.UserRole.DeveloperName );
        System.debug('UAC: userIdToUserRole ' + userIdToUserRole );
        for(Contact con : Database.query( 'SELECT ' + getFields('Contact') + ' FROM Contact WHERE ID IN :contactIds ') )
            existingContacts.put(con.Id, con);

        for(BusinessUnits__c bu : businessUnitToContactId.keyset() )
            String validUserRole = 
                //ContactTriggerHandler.currentUserRole == 'Administration' && 
                userIdToUserRole.containsKey(bu.Sales_Rep__c) ? userIdToUserRole.get(bu.Sales_Rep__c) : ContactTriggerHandler.currentUserRole ;

            // When no custom setting found for current User Role then Go Back
            if(!lobAndUserRoleToBusinessUnitCS.containsKey(bu.LineOfBusiness__c + '' + validUserRole)) continue ; 

            // Get Custom setting record
            BusinessUnitRulesManagement__c cs = lobAndUserRoleToBusinessUnitCS.get(bu.LineOfBusiness__c + '' + validUserRole);
            System.debug('UAC: cs ' + cs );

            if(cs == null ) continue ; 
            // Get related Contact 
            Contact con = existingContacts.get(businessUnitToContactId.get(bu));

            // When SalesRep or EscrowOfficer changed 
            if((bu.Sales_Rep__c != con.get(cs.SalesRepFieldonContactAPIName__c) || bu.Escrow_Officer__c != con.get(cs.EscrowOfficerFieldonContactAPIName__c) ) 
                    && !contactIdsAddedForUpdate.contains(con.Id) )
                Contact newContact = new Contact();
                newContact.Id = con.Id;
                System.debug('UAC: bu.Sales_Rep__c ' + bu.Sales_Rep__c );
                System.debug('UAC: bu.Escrow_Officer__c ' + bu.Escrow_Officer__c );
                if( !String.isBlank(cs.SalesRepFieldonContactAPIName__c)) newContact.put(cs.SalesRepFieldonContactAPIName__c, bu.Sales_Rep__c);
                if( !String.isBlank(cs.EscrowOfficerFieldonContactAPIName__c)) newContact.put(cs.EscrowOfficerFieldonContactAPIName__c, bu.Escrow_Officer__c);

        System.debug('UAC: contactsToUpdate ' + contactsToUpdate );

        // Update Contacts 
        if(contactsToUpdate.size() > 0 ) 
            ContactTriggerHandler.RUN_ONCE_UBUFCS = false ;  
            BusinessUnitTriggerHandler.RUN_ONCE_UCFCS = false ;
            update contactsToUpdate ;
            ContactTriggerHandler.RUN_ONCE_UBUFCS = true ;  
            BusinessUnitTriggerHandler.RUN_ONCE_UCFCS = true ;

        System.debug('UAC: BU updateContactFromCS END ' );

    *   @Method:    getFields()
    *   @Purpose:   Use to get all fields of passing object  
    *   @Param:     String objName for which you want to get fields
    *   @Return:    Comma seprated fields
    *   @Date:      05/18/2017
    *   @Updates: 
    private static String getFields(String objectName)
        //Broke this out of formatQuery because it could be used separately
        String fields = '';
        // Get All Objects List
        Map<String, Schema.SObjectType> gd = Schema.getGlobalDescribe();
        // Get object detail which passed as argument
        SObjectType objectType = gd.get(objectName);

        // Get passed object detail
        Schema.DescribeSObjectResult r = objectType.getDescribe();

        //Get all fields for passed object 
        Map<String, Schema.SObjectField> fieldMap = r.fields.getMap();

        // Itterate over all fields and check one by one 
        for (String f: fieldMap.keySet())
            // Get current field 
            Schema.SObjectField sof = fieldMap.get(f);
            // Get current field detail
            Schema.DescribeFieldResult dfr = sof.getDescribe();

            // when current field is accessible, creatable and defaultonCreare then concatinate in field string
            if( dfr.isAccessible() )
                String fname = dfr.getName(); 
                fields += fname + ', '; 
        // remove last comma
        fields = fields.substring(0, fields.length() - 2);
        return fields;

    public static Map<String, BusinessUnitRulesManagement__c> lobToBusinessUnitCS
            if(lobToBusinessUnitCS == null )
                lobToBusinessUnitCS = new Map<String, BusinessUnitRulesManagement__c>();
                for(BusinessUnitRulesManagement__c cs : BusinessUnitRulesManagement__c.getAll().values()) 
                    if(!lobToBusinessUnitCS.containsKey(cs.LineofBusiness__c)) lobToBusinessUnitCS.put( cs.LineofBusiness__c, cs);
            //for(String key : lobToBusinessUnitCS.keySet() ) System.debug('UAC: key ' + key  + ' value ' + lobToBusinessUnitCS.get(key) );
            return lobToBusinessUnitCS ;
        private set ;

    *   @Method:    clearValueOnContact()
    *   @Purpose:   When BusinessUnit is Updated then update and clearOut SalesRep and EscrowOfficer fields from Contact based on Custom Setting fields 
    *   @Param:     List<BusinessUnits__c> units : List of new records - Trigger.new
    *               Map<Id,BusinessUnit__c> oldMap : map of old values - Trigger.oldMap
    *   @Return:    void : No return value
    *   @Date:      05/15/2017
    *   @Updates: 
    public static void clearValueOnContact(List<BusinessUnits__c> units)
        System.debug('UAC: BU clearValueOnContact START ' );
        Map<Id, String> contactIdToLOB = new Map<Id, String>();
        Map<Id,Contact> contacts = new Map<Id,Contact>();

        // Iterate over BusinessUnit 
        for(BusinessUnits__c bu : units )
            if(bu.Contact__c != null) contactIdToLOB.put(bu.Contact__c, bu.LineOfBusiness__c);
        System.debug('UAC: BU contactIdToLOB ' + contactIdToLOB );
        if(contactIdToLOB.size() == 0) 
           return ; 

        // Get related Contacts 
        contacts = new Map<Id, Contact>( [SELECT Id FROM Contact WHERE ID IN :contactIdToLOB.keyset() ]);

        // Iterate over ContactIds 
        for(Id contactId : contactIdToLOB.keyset() )
            // Get Custom Setting Business Unit
            BusinessUnitRulesManagement__c cs = lobToBusinessUnitCS.get(contactIdToLOB.get(contactId));
            System.debug('UAC: cs ' + cs );

            if(cs == null ) continue ; 

            // Get Contact 
            Contact con = contacts.get(contactId);

            // Clear Out Values on Contact 
            if( !String.isBlank(cs.SalesRepFieldonContactAPIName__c)) con.put(cs.SalesRepFieldonContactAPIName__c, null);
            if( !String.isBlank(cs.EscrowOfficerFieldonContactAPIName__c)) con.put(cs.EscrowOfficerFieldonContactAPIName__c, null);
            System.debug('UAC: con ' + con );

        // Update Contact
        ContactTriggerHandler.RUN_ONCE_UBUFCS = false ;
        update contacts.values() ;
        ContactTriggerHandler.RUN_ONCE_UBUFCS = true ; 

        System.debug('UAC: BU clearValueOnContact End ' );


Test class:

private class BusinessUnitTriggerHandlerTest 
      Map<String, Integer> businessUnitMap = new Map<String, Integer>();
      Set<String> lineOfBusiness = new Set<String>();
      Set<Id> contactIds = new Set<Id>();
      List<BusinessUnits__c> unitsToProcess = new List<BusinessUnits__c>();
      Set<Id> userIds = new Set<Id>();
      Map<Id, String> userIdToUserRole = new Map<Id, String>();
     Map<BusinessUnits__c, Id> businessUnitToContactId = new Map<BusinessUnits__c, Id>();
     Map<Id,Contact> existingContacts = new Map<Id,Contact>();
     Map<String, BusinessUnitRulesManagement__c> lobToBusinessUnitCS;
       Map<Id, String> contactIdToLOB = new Map<Id, String>();
        Map<Id,Contact> contacts = new Map<Id,Contact>();
    static testMethod void testCheckDuplicate() 
        Profile profile = [Select Id from Profile where name = 'ORT Direct Sales User'];
        //UserRole ur = [Select Id from UserRole where UserRole.DeveloperName = 'Central_Direct_Agency'];

        User nonAdminUser = new User( ProfileId = profile.Id, Username = System.now().millisecond() + 'test2@test.com.dev',UserRoleId = '00E1G000000IWzyUAG',
                                    Alias = 'batman', Email='bruce.wayne@wayneenterprises.com', EmailEncodingKey='UTF-8',Firstname='Bruce',
                                    Lastname='Wayne',LanguageLocaleKey='en_US',LocaleSidKey='en_US',TimeZoneSidKey='America/Chicago' );
        System.runAs(new User( Id = UserInfo.getUserId() ))

        Account acc = TestUtility.createAccount( TestUtility.default_account_rt, false );
        acc.Name = 'sfdcpoint';
        acc.Account_Status__c = 'Active';
        acc.AccountNumber = '001';
        insert acc; 
            Contact cont = TestUtility.createContact( TestUtility.default_contact_rt , acc, false ); 
            cont.MailingStreet = 'Test Street' ;
            cont.MailingCity = 'Minneapolis';
            cont.MailingState = 'MN';
            cont.MailingPostalCode = '55347';
            cont.MailingCountry = 'United States' ; 
            insert cont;
            BusinessUnitRulesManagement__c cs = new BusinessUnitRulesManagement__c();
            cs.Name = 'AgencyManager';
            cs.EscrowOfficerFieldonContactAPIName__c = 'Text';
            cs.LineofBusiness__c = 'testlob';
            cs.RoleDeveloperName__c = 'uniquetest';
            cs.SalesRepFieldonContactAPIName__c = 'conttext';
            cs.Status__c = 'alltext';
            insert cs;
            Id userId = UserInfo.getUserId() ;

            BusinessUnits__c bu = new BusinessUnits__c( Contact__c = cont.Id, LineOfBusiness__c = ' Agency',Sales_Rep__c = UserId );
            insert bu ; 
                BusinessUnits__c bu1 = new BusinessUnits__c( Contact__c = cont.Id,LineOfBusiness__c = 'Western Title Division',Sales_Rep__c = UserId  );
                insert bu1 ;  
            catch(DmlException de )



Hi All,

Can any one help me to calculate number of sunday's in a given month and year using apex and vf page.

Ex: If i select March 2017 from vf page, i need to calculate number of sunday's from selected month and year.

Thanks in advance.

On the Visualforce page, there is a check box to select to enable the visualforce page to be available under Lightning.
User-added image

Since we use GitHub, how do I see this change in the Git Repository?  Is there an XML tag that is set to true when this check box is enabled?


We are using the FSL managed package.  Needing to write some test coverage for the Maintenance Plan.  In the test class, I am trying to create the Maintenance Plan record as such:
MaintenancePlan maintPlan 
		= new MaintenancePlan( AccountId = testaccs[0].Id,
						Billing_Account__c = testaccs[0].Id,
						WorkTypeId = mpWt[0].Id,
						StartDate = tempDate,
						Customer_Purchase_Order_No__c = 'dummy data',
						Invoicing_Method__c = 'One Invoice per Work Order',
						Crew_Size__c = 2,
						Frequency = 1,
						FrequencyType = 'Months',
						GenerationTimeframe = 1,
						GenerationTimeframeType = 'Months',
						NextSuggestedMaintenanceDate = tempDate,
						WorkOrderGenerationMethod = 'One work order line item per asset',
						SvcApptGenerationMethod = 'One service appointment per work order',
						MaintenancePlanTitle = 'Dummy Title',
						Description = 'Dummy Description'

But on Save, I get an error:
Result: [OPERATION FAILED]: classes/CS_WorkOrderTriggerHandler_Test.cls: Field does not exist: WorkOrderGenerationMethod on MaintenancePlan (Line: 313, Column: 5)
classes/CS_WorkOrderTriggerHandler_Test.cls: Field does not exist: SvcApptGenerationMethod on MaintenancePlan (Line: 313, Column: 5)
(bold added for highlights)
Now in my field list for Maintenance Plan I see :
Snippet showing the offending field names which error message says 'doesn't exist'

So, I've copy pasted the Names but same error.
I have check Field Level Security  - System Admin plus others are listed.
Thoughts or feedback?

In the FSL managed package, from a Maintenance Plan there is an action "Generate Work Orders". 
Shows action menu for Generate Work Orders action
I have done some customisation which rely on the Work Order being generated from the Maintenance Plan.

For my test coverage, how do I invoke the "Generate Work Orders" action in a test class?

I'm doing a trigger that is triggered from the Assigned Resource.  The trigger works in the UI, however, I'm having an issue with the Test Code.

I receive an error:
FIELD_CUSTOM_VALIDATION_EXCEPTION, Cannot change status from New to Scheduled: []

Now, if i do the same from the UI, there is no error regarding the status change.  The status change is allowed in the FSL administration.  I can assign using the dispatcher console - all good.  And I can mimic the process i'm using in the test code in the UI (editing the SA directly) with out error.  
Wondering if any one has seen this error before?
Code is included below:
@isTest static void test_AssignedResource_Insert() {
		List<AssignedResource> toInsert = new List<AssignedResource>();

		//retrieve a service resource
		List<ServiceResource> listSR = new List<ServiceResource>([SELECT Id, Name FROM ServiceResource WHERE Name = 'Technician One']);
		ServiceResource sr1 = listSR[0];

		// retrieve the Service Appointment created by test data
		List<WorkOrder> workOrders = new List<WorkOrder>([SELECT Id FROM WorkOrder WHERE Subject ='Test Subject1']);
		List<Id> woIds = new List<Id>();
		for (WorkOrder wo : workOrders ) {
		if (woIds.size() > 0 ) {
			List<ServiceAppointment> appts = new List<ServiceAppointment> ();
			appts = [SELECT Id FROM ServiceAppointment WHERE Work_Order__c IN :woIds];
			//for all the appts - should be one - create an assigned resource
			if(appts.size()>0) {
				for( ServiceAppointment sa : appts ) {
					sa.SchedStartTime = datetime.newInstance(2019, 4, 19, 11, 00, 0);
					sa.SchedEndTime = datetime.newInstance(2019, 4, 19, 11, 30, 0);

					AssignedResource ar = new AssignedResource(ServiceAppointmentId=sa.Id,ServiceResourceId=sr1.Id);
				update appts;

				insert toInsert;

				List<ServiceAppointment> assignedSA = new List<ServiceAppointment>([SELECT Id,Technician_Name__c FROM ServiceAppointment WHERE Work_Order__c IN :woIds]);
				System.assertEquals(assignedSA.size(), 1);

			} else {


		} else {
			System.assertNotEquals(woIds.size(), 0);

the error occurs on the insert of the assigned resources
insert toInsert;
IF i change the code such that I manually do the status change in the code example:
sa.SchedStartTime = datetime.newInstance(2019, 4, 19, 11, 00, 0);
sa.SchedEndTime = datetime.newInstance(2019, 4, 19, 11, 30, 0);
sa.Status = 'Scheduled';
the error is returned for the update of the service appointments.
update appts;

Feed back greatly appreciated.


I'm playing with an Apex trigger for Work Order Object.   In the trigger,I have a need to reference a list of Work Types on multiple occassions, in different parts of the trigger.  The question relates to how do I minimise the number of times I do a SOQL to get those work types.
Example of Trigger
trigger cs_workorderTrigger on WorkOrder (before insert, after insert, after update) {
    if ( trigger.isBefore ) {
        if ( trigger.isInsert ) {
            CS_WorkOrderTriggerHandler.handleBeforeInsert( trigger.new );
    } else {  //trigger is after
        if ( trigger.isInsert ) {
            CS_WorkOrderTriggerHandler.handleAfterInsert( trigger.new );
        } else {
            CS_WorkOrderTriggerHandler.handleAfterUpdate( trigger.new );
And my (cut down) hanlder looks like:
public with sharing class CS_WorkOrderTriggerHandler {
	public static void handleBeforeInsert(List<WorkOrder> newWorkOrders) {
		populateWorkOrder( newWorkOrders );

	public static void handleAfterInsert(List<WorkOrder> workOrders){
		//declare some variables 
		List<Id> listWorkTypeIds = new List<Id>();

		//List of Ids where their is an auto generate feature enabled
		List<Worktype> workTypes = new List<WorkType>([SELECT Id FROM WorkType WHERE ShouldAutoCreateSvcAppt = TRUE]);

		for ( WorkOrder workOrder : workOrders ) {
			//do some stuff with work Order - like checking the work type Id

	public static void handleAfterUpdate(List<WorkOrder> oldWorkOrders, List<WorkOrder> workOrders, Map<Id,WorkOrder> newValues, Map<Id,WorkOrder> oldValues) {
		//declare some variables 
		List<Id> listWorkTypeIds = new List<Id>();

		//List of Ids where their is an auto generate feature enabled - HEY , THIS IS THE SAME AS THE AFTER INSERT QUERY

		for ( WorkOrder workOrder : workOrders ) {
			//do some other stuff with the work orders, and I still need the work type ids, but this work here is different to the after Insert stuff so i can't combine into a single method.

	public static void populateWorkOrder(List<WorkOrder>workOrders) {
		System.debug('DEBUG: populate Work Order');
		//Here I am going to do some other stuff, and I need that slightly different list of that Work Type Ids
		//something like 
		List<workType> workTypes = new List<WorkType>([SELECT Id,Customer_Type__c,Name FROM WorkType WHERE ShouldAutoCreateSvcAppt = TRUE]);
		//and play with the list a bit differently

	public static void createServiceAppointments(WorkOrder workOrder, Integer saToCreate ) {
		//Create some records here

I tried doing a constructor at the top of the trigger handler, but I was getting errors like "non static method can be called form static method" or something like that.  It basically broke the other methods I have within the trigger handler.

Any pointers appreciated.

Andrew G

I'm doing a bit of code where I'm checking if a Work Type Id in a Work Order is in a List for Work Type Ids, but the contains method does not seem to be detecting the match:
Code snippet 
List<ServiceAppointment> svcAppts = new List<ServiceAppointment>();

		//List of Ids where their is an auto generate feature enabled
		List<Id> listWorkTypeIds = new List<Id>();
		for ( WorkType wt : [SELECT Id FROM WorkType WHERE ShouldAutoCreateSvcAppt = TRUE] )  {
		System.debug('DEBUG : Worktype count ' + listWorkTypeIds.size());

		for ( WorkOrder workOrder : workOrders ) {
			tempDecimal = workOrder.Crew_Size__c;
			crewSize  = tempDecimal.intValue();
			System.debug('DEBUG : crewSize: ' + crewSize);
			tempDecimal = workOrder.ServiceAppointmentCount;
			System.debug('DEBUG : RAW service count : ' + tempDecimal);
			System.debug('****DEBUG : list work type : ' + listWorkTypeIds[0]);
			System.debug('****DEBUG : WO work type : ' + workOrder.workTypeId);

			if (listWorkTypeIds.contains(workOrder.workTypeId)) {
				apptCount = tempDecimal.intValue() + 1;		
				System.debug('DEBUG : ADJUSTED service count : ' + tempDecimal);				
			} else {
				apptCount = tempDecimal.intValue();
				System.debug('DEBUG : SAME service count : ' + tempDecimal);
Now, the debug looks like this:
08:10:49.875 (1834107162)|SOQL_EXECUTE_BEGIN|[92]|Aggregations:0|SELECT Id FROM WorkType 
08:10:49.875 (1848717624)|SOQL_EXECUTE_END|[92]|Rows:1
08:10:49.875 (1849133376)|USER_DEBUG|[95]|DEBUG|DEBUG : Worktype count 1
08:10:49.875 (1849315483)|USER_DEBUG|[101]|DEBUG|DEBUG : crewSize: 1
08:10:49.875 (1849418406)|USER_DEBUG|[104]|DEBUG|DEBUG : RAW service count : 0
08:10:49.875 (1849462073)|USER_DEBUG|[105]|DEBUG|****DEBUG : list work type : 08q0l00000001jtAAA
08:10:49.875 (1849543426)|USER_DEBUG|[106]|DEBUG|****DEBUG : WO work type : 08q0l00000001jtAAA
08:10:49.875 (1849692808)|USER_DEBUG|[113]|DEBUG|DEBUG : SAME service count : 0

So, the debug shows that the Ids are apparently the same, but the IF statement using the the contains does resolve to TRUE.

Any thoughts on what I am missing?


Playing with Work Types and the Auto Create feature.  I know there is a check box to tick which will auto create the Service Appointments.
However, I have a need to generate multiple Service Appointments for a single Work Order.  The multiple appointments will have the same parameters as a crew will come together to do that particular piece of work.  (Note: the Service Crew feature in FSL does not meet the needs of the business).

Now, I have played with Process Builder to action this, but I get unusual results when the auto create feature is enabled.  (And yes, we do need the auto create feature for other business processes).
In process builder I can populate the address for the Work Order from the Case, and then address to Service Appointment from Work Order.  I can get the multiple service appointments by using the recursive feature of the Process Builder. 
However, if I set the WorkType to a type with Auto Create, I get extra Service Appointments and/or Service Appointments without addresses.

So, the question is, in the execution process of events, (i.e. before trigger, after triggers, process builder...etc), where does the Auto Create feature kick in ?  It is obviously part of the managed package and can't be viewed by us mere mortals, but it is happening, but when/where?
And a slight aside, when does the standard field Service Appointment Count (in Work Order) populate in that series of events?  As understanding that may also provide an option for a solution.

Part of the reason for asking is that I am looking to take this to a trigger, but I'm thinking i may run into the same issues there.

Potentially silly question.

We have purchased Community Licenses and intend to have/offer our customers to use the Salesforce App to access our community page. (As well as being browser based).
With Community License there is an API limit.
The question would be "Does the Salesforce App interactions count against the API limits for the Community License?"

LIttle background - our company was considering constructing a custom App using RESTful API to interacts, and these I know would count.  Just curious if the Salesforce App operated in the same manner.


Having an issue implementing some code which is to create a PDF document from a trigger.  I have used this as a reference/start point :
The code:
public with sharing class SvcApptTriggerController {
	public static void addPDFAttach(string sessionId, list<id> svcApptIdList){
		System.debug('@@@@@ in addPDFAttach of SvcApptTriggerController');

		HttpRequest req = new HttpRequest();
		req.setHeader('Authorization', 'Bearer '+ sessionId);
		req.setHeader('Content-Type', 'application/json');
		Http http = new Http();
		System.debug('@@@@@ before TEST if');
			System.debug('@@@@@ in TEST if');
			HTTPResponse res = http.send(req);
The debug log snippet:
Error message from debug log - Unauthorised
Screenshot of remote Site settings:
Remote Site Settings

So the endpoint reported in the debug logs is in the remote site settings.
The PDF creation code works from the workbench - which obviously uses a different authentication model (name/password).

Feeling that I have missed something obvious.

I am doing an inline table as a lightning component, but after the save event the button will not disappear.
I have found a post that mentions clearing the default values,
component.find("SADataTable").set("v.draftValues", null);
but playing with that line will cause the button to hide, but the table data does not reload after save.
I have also played with firing a refreshview, but no luck either
My component
<aura:component controller="ServiceAppointmentListController" implements="flexipage:availableForRecordHome,force:hasRecordId" access="global" >
    <aura:attribute name="recordId" type="Id" />
    <aura:attribute name="WorkOrder" type="WorkOrder" />
    <aura:attribute name="ServiceAppointments" type="ServiceAppointment" />
	<aura:attribute name="Columns" type="List" />
    <aura:attribute name="saveDraftValues" type="Object" />
    <aura:handler name="init" value="{!this}" action="{!c.myAction}" />
    <force:recordData aura:id="workOrderRecord" recordId="{!v.recordId}" targetFields="{!v.WorkOrder}" layoutType="FULL" />
    <lightning:card title="{! 'Service Appointment List for ' + v.WorkOrder.WorkOrderNumber}">
        <!-- Service Appointment list goes here -->
        		data="{! v.ServiceAppointments }" 
                columns="{! v.Columns }" 
                onsave="{!c.handleSave}" />
The JS controller
	myAction : function(component, event, helper) {
        component.set("v.Columns", [
            {label:"Appt Id", fieldName:"AppointmentNumber", type:"text"},
            {label:"Duration", fieldName:"Duration", type:"number", editable : 'true'},
            {label:"Duration Type", fieldName:"DurationType", type:"text", editable : 'true'}
		var action = component.get("c.getServiceAppointments");
            recordId: component.get("v.recordId")
        action.setCallback(this, function(data) {
            component.set("v.ServiceAppointments", data.getReturnValue());
    handleSave: function (component, event, helper ) {
		helper.saveDataTable(component, event, helper);
The helper manages the save and posts toast messages.
    saveDataTable : function(component, event, helper) {
        var editedRecords =  component.find("SADataTable").get("v.draftValues");
        var totalRecordEdited = editedRecords.length;
        var action = component.get("c.updateServiceAppointments");
            'editedSAList' : editedRecords
        action.setCallback(this,function(response) {
            var state = response.getState();
            if (state === "SUCCESS") {
                //***if update is successful ***
                if(response.getReturnValue() === true){
                        "title": "Record Update",
                        "type": "success",
                        "message": totalRecordEdited+" Service Appointment Records Updated"
                } else{ //***if update failed ***
                        "title": "Error!!",
                        "type": "error",
                        "message": "Error in update"

    //*** Show toast with provided params ***
    showToast : function(params){
        var toastEvent = $A.get("e.force:showToast");
        } else{
    //*** reload data table ***
    reloadDataTable : function(){
    var refreshEvent = $A.get("e.force:refreshView");
For completeness, my Server Side controller
public class ServiceAppointmentListController {
    public static List<ServiceAppointment> getServiceAppointments(Id recordId) {
       return [SELECT Id, AppointmentNumber, Duration, DurationType  FROM ServiceAppointment WHERE ParentRecordId = :recordId];
    public static boolean updateServiceAppointments(List<ServiceAppointment> editedSAList) {
        try {
            update editedSAList;
            return true;
        } catch(Exception e){
            return false;

Any assistance appreciated.  I have been troubleshooting this for a day, but seem to be going around in circles.

How to write a test class for below code
public class AccountSelectClassController{


//Our collection of the class/wrapper objects wrapAccount 
    public List<wrapContact> wrapContactList {get; set;}
    public List<contact> selectedcontacts{get;set;}
    public string searchtext1{get;set;}
    public void search(){
        if(wrapContactList == null) {
            wrapContactList = new List<wrapContact>();
            for(Contact a: [select Id, name, Phone from contact where lastname like :searchtext1 ]) {
                // As each Account is processed we create a new wrapAccount object and add it to the wrapAccountList
                wrapContactList.add(new wrapContact(a));
    public void processSelected() {
    selectedcontacts = new List<contact>();
        for(wrapContact wrapContactObj : wrapContactList) {
            if(wrapContactObj.selected == true) {
 public void clear() {
    // This is our wrapper/container class. A container class is a class, a data structure, or an abstract data type whose instances are collections of other objects. In this example a wrapper class contains both the standard salesforce object Account and a Boolean value
    public class wrapContact {
        public contact con {get; set;}
        public Boolean selected {get; set;}
        //This is the contructor method. When we create a new wrapAccount object we pass a Account that is set to the acc property. We also set the selected value to false
        public wrapContact(contact a) {
            con = a;
            selected = false;
I need some help... 

I have an idea, but am not sure how to accomplish it using an Apex trigger... 

User Action: Create a new Lead
Step #1: Enter the lead's first name, last name, email, etc.
Step #2: Select the comapny name from a custom lookup field
Step #3: Save the new lead.

Here's the issue, Company is a standard required field when creating a new Lead. I would like two things to happen during this action. The first is to check the Company field, and if it is blank, check if there is a value in the custom lookup field. If there in a value in the custom lookup field, then copy the value to the Company field. 

Can this be done using an Apex trigger? If so, can you show me how?

Hi Everyone,

I am currently reviewing the validation rules on opportunities. I've found the following lines, which I'd like to understand. Within the context of a validation rule which triggers the error only when the rule is True, what does these formulas do? Do they related to "Related Lists" child objects of the opportunity? 

Thank you.

NOT(ISBLANK($ObjectType.Live_Event_Coverage__c.Fields.Live_Event_Allotment_Opportunity__c)), /*allows Live Events to process*/
NOT(ISBLANK($ObjectType.SE_Customer_Solution__c.Fields.Opportunity__c )), /*allows SE Customer Solutions to process*/
NOT(ISBLANK( $ObjectType.Live_Event_Coverage_Timing__c.Fields.CoverageLink__c)), /*allows Live Event Timings to process*/
Hi everyone, I have an issue I can't seem to solve on my own. In our Org we have automated rating (of quality) of Contacts and I used Process Builder for that since I have no coding experience.

Contact Abc's correct rating should be 2. For some reason, formula A does not rate Abc as 2, but formula B does.

Formula A:
             [Contact].Account.Is_a_Venture_Capital_Firm__c  = TRUE ,
             [Contact].Account.Is_a_Private_Equity_Firm__c = TRUE ,
                          ISPICKVAL( [Contact].Title_Achieved__c , 'Manager') ,
                          ISPICKVAL( [Contact].Title_Achieved__c , 'Associate') ,
                          ISPICKVAL( [Contact].Title_Achieved__c , 'Partner')
                          ) ,
               CONTAINS(UPPER([Contact].Account_Industry_c) , 'Technology')
           ) ,
         NOT( CONTAINS( UPPER([Contact].Current_Title__c) , 'STUDENT' )) ,
         NOT( CONTAINS( UPPER([Contact].Current_Title__c) , 'ENGINEER' ))

Formula B
             [Contact].Account.Is_a_Venture_Capital_Firm__c  = TRUE ,
             [Contact].Account.Is_a_Private_Equity_Firm__c = TRUE ,
             ISPICKVAL( [Contact].Title_Achieved__c , 'Manager') ,
             ISPICKVAL( [Contact].Title_Achieved__c , 'Associate') ,
             ISPICKVAL( [Contact].Title_Achieved__c , 'Partner')
              ) ,
       NOT( CONTAINS( UPPER([Contact].Current_Title__c) , 'STUDENT' )) ,
       NOT( CONTAINS( UPPER([Contact].Current_Title__c) , 'ENGINEER' ))

Is there anyting wrong with my Formula A?
I am testing an Apex class that queries topics.  When creating test data, I am running into an issue with regards to Topics.  If I attempt to create topics for testing that happen to match real topics, then I get an error that says that the topic already exists.  However, if I query topics in the test class, then I get 0 results.  I'd like to run these tests without using seeAllData=true. Has anyone ever encounterd this before?  Any ideas as to how to get test topics to use in my testing?
Hi All,
I want to delete assets when its related opportunity line item is deleted.
i have a trigger helper given below:-
public  without sharing class OpportunityLineItemTriggerHelper {
    public static List<OpportunityLineItem> newOpportunityLineItem = new List<OpportunityLineItem>();
    public static List<OpportunityLineItem> oldOpportunityLineItem = new List<OpportunityLineItem>();
    public static Map<Id, OpportunityLineItem> newMapOpportunityLineItem = new Map<Id, OpportunityLineItem>();
    public static Map<Id, OpportunityLineItem> oldMapOpportunityLineItem = new Map<Id, OpportunityLineItem>(); 
    Public static void deleteAssets(){
        list<id> ProductIds=new list<id>();
        for(Product2 prod :  [SELECT id,Name
                              FROM Product2 
                              ] )
        List<Asset> deleteListAsset = new List<Asset>();
        //Collecting all child records related to Parent records
        list<Asset> listOfAssets = [ select id, Product2Id 
                                     from Asset 
                                     where Product2Id in :ProductIds ];
        for(OpportunityLineItem oli : oldOpportunityLineItem){
            for(Asset ast : listOfAssets){
                if (ast.Product2Id == oli.Product2Id){
        //deleting Asset records
        if( deleteListAsset.Size() > 0 ){
             delete deleteListAsset;
Can anyone help me with this requirement if i am doing it wrong?
Any suggestions?
Hello, I hope someone might be able to provide me some guidance!

I work in an area where we provide training to school districts, and we have recently started building out a tracking system to monitor our technical assistance to the districts. We currently have it where we have an object built which stores districts as record pages, and an object to create technical assistant events as a record. It currently uses a lookup field to link a technical assistant event to the school district. We are hoping to learn how we can make it possibile to link the technical assistant event to more than one school district.  I would like to be able to still have the function of the lookup field to search the school district, but the added ability of attaching a single technical assistant event to a district.

This was if I am out training at District 1 and District 2 I can record that in the same event, not have to create two different events.

I have attached a screenshot of the current new event creation form.

Any help is appriciated, thanks!

User-added image
How do you delete orphaned data associated with a deleted object?  I checked Storage Used and it shows 96% of my data is consumed by an object I deleted.  I downloaded Data Loader, but the object consuming the storage doesn't show up.  I also tried the Mass Delete Records and the deleted object doesn't show up there either.  This is a developer edition w/ 5MB limit.
Hi everyone!

We need to track students late payment. When they are accepted to our school, the Representatives will toggle "Acceptance Letter Issued" stage. When the students pay their fees, the Reps will toggle "Registered" as the students are ready to be enrolled.

We have a deadline for payment as well. If Reps don't toggle a different stage after "Acceptance Letter Issued" stage after the deadline, we want a custom field to indicate that the student is late on paying their fees.

What would be the best practice to accomplish this project? Please give me some advice.

Thank you!

We are happy to provide a space for you to list developer and admin openings that may be of interest to the Force.com community. Please ensure your posts are effectively titled with the position and location you're looking for, and don't forget to include instructions for applying or getting in touch with you when you post. 


If you are a developer looking for work, you are allowed to post that here, however you are not allowed to post the same information repeatedly (spamming). You also may not use this space for advertising your business. 


This board is offered as a service to our community and those found to be abusing it will be banned from posting. Examples of abuse include posting blanket generic responses to job listings & starting new topics that only serve to advertise your business.


I welcome your feedback and suggestions!