• Chris Walters 9
  • NEWBIE
  • 35 Points
  • Member since 2020

  • Chatter
    Feed
  • 1
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 14
    Questions
  • 17
    Replies
Can a trigger know what fired it? Example -  LiveChatTranscriptTrigger.bulkAfter()   creates several new Contacts. This fires off several ContactTrigger methods. But is there a way ContractTrigger can know that these new Contacts "came from" LiveChatTranscriptTrigger?

Any ideas?

Still-learning Chris
class LiveChatTranscript has fields AccountId and ContactId .
class Contact has field AccountId .
class Account has field Contact__c .  ( custom field - our business logic is such that a Contact will always relate to one and only one Account but an Account may not have a Contact )

class  LiveChatTranscriptHandler is where our trigger logic lives, including bulkBefore() and bulkAfter() .

an instance of LiveChatTranscript will always have AccountId set to an existing instance of Account. Account instance may or may not point to an existing Contact via Account.Contact__c .

Goal - for all new LiveChatTranscript instances find associated Accounts NOT pointing to an existing Contact, create Contacts with dummy-but-unique FirstName, LastName and Email fields , assign Contacts to Accounts and to LiveChatTranscript.

In a non-SF traditional language you'd do something like
for( LiveChatTranscript lct : List<LiveChatTranscript> Trigger.new) {
    Account acc = getAccount( lct.AccountId);
    if( acc.Contact__c == null) {
        Contact con = new Contact();
        con.FirstName = magicUniqifier();
        con.LastName = magicUniqifier();
        con.Email = magicUniqifier();
        insert con;  
        // now con has an Id
        acc.Contact__c = con.Id;
        update acc;
        lct.ContactId = con.Id;
        update lct;
    }
}
// now update Contacts based on some requirements baked into AdjustContact
for( LiveChatTranscript lct : List<LiveChatTranscript> Trigger.new) {
    Contact con = getContact( lct.ContactId);
    AdjustContact( con);
    update con;
}

Turns out SF will let me write a bulkBefore that will create and insert Contacts but not =persist= them to the db. And moving that code to an bulkAfter will create, insert, and persist the Contacts but trying to  make the assignments to LiveChatTranscript.ContactId recursively triggers the handler again. 

Now there might be a sneaky way to achieve this because we're dealing with LiveChatTranscript , which I think only gets created at the completion of a LiveAgentSession - perhaps creating a LiveAgentSessionTrigger/LiveAgentSessionHandler and putting the Contact-creation logic there would do the trick. I might try that if all else fails. 

Ideas anyone?

Still-learning Chris

 
v47

Running into a bulkification problem - given a number of Tasks from TaskHandler.afterBulk I'm trying to access the fields inside the subquery and use them in a WHERE clause.
for( Account a : [SELECT Id, Name, (SELECT Id, Email_Direction__c  FROM Tasks ) FROM Account WHERE foo.id IN :Trigger.new] ) {
    doSomething( a.Id, foo.Email_Direction__c);
}
What would the right syntax be to achieve this? 

TIA,

Chris
version 47

We've several objects, both std and custom,  that contain  Address compound fields. I'd like to create an AddressHandler, similar to ContactHandler, to apply various corrections to an Address regardless of which object it is tied to. Is this possible? I can reference System.Address in my Apex but there are no setters to go with the getters (!???!) Or must I put  boilerplate into ContactHandler, AccountHandler, LeadHandler and all the other Handlers for objects with one or more Address compound field?  Surely there's a better way.

 
version 47

Given
SELECT Id, Name, (SELECT Last_Contact_Method__c FROM Contacts ) FROM Account

and
SELECT Id, Status, WhatId FROM Task
where Task.WhatId =  account.Id from the above query

how would I nest the downward SOQLs to achieve
 
Select Id, Status, Email_Direction__c, (SELECT Name, (SELECT Last_Contact_Method__c FROM Contacts ) FROM ???? ) FROM Task

I've tried some variations of WhatId like
  • What
  • Whats
  • WhatId
  • WhatIds
  • What__r
  • Whats__r
to no avail. 

 
I've crafted a map of names of testing functions win initial results:
     
        Map<String,Boolean> mapTestsToRun = new Map<String,Boolean>();
        mapTestsToRun.put('test_01',False);
        mapTestsToRun.put('test_02',False);
        mapTestsToRun.put('test_03',False);
        
And now I'd like to execute them

        for( String testToRun : mapTestsToRun.keySet()) {
            Boolean result = somethingCleverGoesHere( testToRun);
            mapTestsToRun.put( testToRun, result);
        }

But I need a way to execute a function by it's name. Any ideas?

TIA,

Chris
I can create a new Task but cannot set AccountId as one of the fields - it gets assigned implicity somehow. 
Task task = new Task(
            Description = 'test_02',
            TaskSubType = 'Email',
            Email_Direction__c = 'Outbound',
            WhoId = contact_EC_email.Id,
            OwnerId = user_EC.Id,
//          AccountId = null,       // non-writable fields, where are they getting their values from?
            Actual_End__c = Datetime.valueOf( '2020-05-20 00:00:00')
        );

By what magic can I assign a specific Account object's Id to a Task.AccountId field ?
version 47.0

A curious thing: I've written a unit test that exercises a Task.afterInsert() method. I've added debug  -entering and -exiting statements to this method as well as the @isTest method, which creates and inserts a new Task.

Upon executing of the test I see my @isTest debug statements in my logs, the log shows the Id of the newly created Task, good so far ... but I do not see the debug statements from the method-under-test.
Why is that?

TIA,

Still-learning Chris
version 47.0

Trying to craft a unit test. Using @testSetup method, which instantiates some objects within a System.RunAs to avoid the DML problem. But (at least) one of my objects instantiated within the System.RunAs is not visible to the test method even tho it does indeed get instantiated and inserted in the test setup method
@isTest
public class TaskHandlerTest {
    public static Id profileId  = [SELECT Id FROM Profile WHERE Name ='ASUO API User Profile'].Id;
    public static User thisUser = [SELECT Id FROM User WHERE Name = 'API ASU EdPlus ASUO'];
    
    public static UserRole testUserRole_ASU;
    public static Contact contact_ASU;

    @testSetup
    static void setUpTest() {

        testUserRole_ASU = new UserRole(
            Name = 'ASU Local',
            OpportunityAccessForAccountOwner = 'Edit'
        );
        insert testUserRole_ASU;
        System.RunAs( thisUser) {
            contact_ASU = new Contact(
                FirstName = 'Pete',
                LastName = 'Townshend',
                Email = 'thewho1@who.com',
                Last_Contact_Method__c = 'text',
                Last_Contact_Attempt__c = Datetime.valueOf('2020-04-04 00:00:00')
            );
            insert contact_ASU;
            System.debug('contact_ASU inserted with Id: ' + contact_ASU.Id);
        }
    }

    @IsTest
    static void test_pass_new_EmailOutbound() {
        Test.startTest();
        TestDataFactory.createCustomSetting('Object Triggers');
        Task task = new Task(
            Description = 'pass_new_EmailOutbound',
            TaskSubType = 'Email',
            Email_Direction__c = 'Outbound',
            WhoId = contact_ASU.Id,  // <--- throws "dereferencing null value" msg here
            Actual_End__c = Datetime.valueOf( '2020-05-20 00:00:00')
        );
        insert task;  // should trigger TaskHandler after_insert()

        System.assertEquals( contact_ASU.Last_Contact_Method__c, 'Email');
        System.assertEquals( contact_ASU.Last_Contact_Attempt__c, task.Actual_End__c);
        Test.stopTest();
    }
}
contact_ASU is declared static outside of setUpTest().
The debug log shows my contact_ASU does get instantiated and inserted and has an Id.  Both setUpTest and test_pass_new_EmailOutbound() are declared static.

So I would expect contact_ASU to be visible to test_pass_new_EmailOutbound() --  what am I doing wrong/ not doing right ?

TIA,

Chris

 
Given a Task has a OwnerId that ties to a User, and
User has a UserRoleId field that ties to a UserRole, and
UserRole has a string Name field, I'd like to extract the role of the owner of a given task. This loads without error:
 
public String getRoleOfOwner( Task task) {
    User user = [SELECT Id FROM User WHERE Id = :task.ownerId];
    UserRole roleObj = [SELECT Id FROM UserRole WHERE Id = :user.UserRoleId]; 
    return roleObj.Name;
}

But that seems so old-school and unnecessary. Isn't there some dot-notation like
String roleOfOwner = task.OwnerId.User.UserRole.Name

where I can get the value directly?

Thx,

Chris , SF Developer Day 20
I see where there is a TimeZone object (under the Marketing Cloud API) and have seen a few posts where an variable of such datatype can be instantiated in Apex.

But, can a field of this datatype be added to Contact ?

TIA,

Chris
version 47
Lightning

I've crafted a Report  in sandbox QA. How can I get the Report itself  - not the data it generates - copied to sandbox UAT? Where does SF put the code that makes up the Report, an Apex class? Some table?

 
version 47
I've a tiny upload.csv file written on a Windoze box with Notepad++ , confirmed to be using CRLF containing two whimsical Contacts:

Name,Phone,Email
Bart Simpson,313-555-1212,haveacow@fox.com
Lisa Simpson,543-434-8474,prez@whitehouse.gov

I've crafted a python script for bulk-inserting these two and all works great right up until the very end when my status response says "JobComplete" and numberRecordsFailed': 2 and the response of calling failedResults is:

['"sf__Id","sf__Error",Email,Name,Phone\r', '"","INVALID_FIELD_FOR_INSERT_UPDATE:Unable to create/update fields: Name. Please check the security settings of this field and verify that it is read/write for your profile or permission set.:Name --","haveacow@fox.com","Bart Simpson","313-555-1212"\r', '"","INVALID_FIELD_FOR_INSERT_UPDATE:Unable to create/update fields: Name. Please check the security settings of this field and verify that it is read/write for your profile or permission set.:Name --","prez@whitehouse.gov","Lisa Simpson","543-434-8474"\r', '']

Pay close attention to the \r and all the double-quotes -- am I formatting my csv file incorrectly? I do explicitly set contentType:CSV and lineEnding: CRLF  when setting up the job

Any ideas?
version 47.0
Bulk API 2.0

Built up a python script using requests and requests_oathlib modules against test.salesforce.com/services/oauth2/token to generate access tokens
and a function that concatenates chunks of results until last chunk is detected then creates a json string from the results.

we know we have 1479552 rows in Contact.
Problem: 
SELECT id,Name,Email,Phone FROM Contact LIMIT 1850000
returns all 1479552 rows but
SELECT id,Name,Email,Phone FROM Contact
returns only 492196 !!!
What is up with that??!!??

And I noticed that when using the LIMIT clause, only two chunks are returned, the first one contains all or close to all the data and the second only 110 bytes or so, while without the LIMIT  3 chunks of roughly equal size are returned.

Can anyone verify and/or explain this behaviour? Better still, tell me how to get around it?

First post, YAY!

TIA,

Chris
 
v47

Running into a bulkification problem - given a number of Tasks from TaskHandler.afterBulk I'm trying to access the fields inside the subquery and use them in a WHERE clause.
for( Account a : [SELECT Id, Name, (SELECT Id, Email_Direction__c  FROM Tasks ) FROM Account WHERE foo.id IN :Trigger.new] ) {
    doSomething( a.Id, foo.Email_Direction__c);
}
What would the right syntax be to achieve this? 

TIA,

Chris
version 47

We've several objects, both std and custom,  that contain  Address compound fields. I'd like to create an AddressHandler, similar to ContactHandler, to apply various corrections to an Address regardless of which object it is tied to. Is this possible? I can reference System.Address in my Apex but there are no setters to go with the getters (!???!) Or must I put  boilerplate into ContactHandler, AccountHandler, LeadHandler and all the other Handlers for objects with one or more Address compound field?  Surely there's a better way.

 
version 47

Given
SELECT Id, Name, (SELECT Last_Contact_Method__c FROM Contacts ) FROM Account

and
SELECT Id, Status, WhatId FROM Task
where Task.WhatId =  account.Id from the above query

how would I nest the downward SOQLs to achieve
 
Select Id, Status, Email_Direction__c, (SELECT Name, (SELECT Last_Contact_Method__c FROM Contacts ) FROM ???? ) FROM Task

I've tried some variations of WhatId like
  • What
  • Whats
  • WhatId
  • WhatIds
  • What__r
  • Whats__r
to no avail. 

 
I've crafted a map of names of testing functions win initial results:
     
        Map<String,Boolean> mapTestsToRun = new Map<String,Boolean>();
        mapTestsToRun.put('test_01',False);
        mapTestsToRun.put('test_02',False);
        mapTestsToRun.put('test_03',False);
        
And now I'd like to execute them

        for( String testToRun : mapTestsToRun.keySet()) {
            Boolean result = somethingCleverGoesHere( testToRun);
            mapTestsToRun.put( testToRun, result);
        }

But I need a way to execute a function by it's name. Any ideas?

TIA,

Chris
version 47.0

A curious thing: I've written a unit test that exercises a Task.afterInsert() method. I've added debug  -entering and -exiting statements to this method as well as the @isTest method, which creates and inserts a new Task.

Upon executing of the test I see my @isTest debug statements in my logs, the log shows the Id of the newly created Task, good so far ... but I do not see the debug statements from the method-under-test.
Why is that?

TIA,

Still-learning Chris
version 47.0

Trying to craft a unit test. Using @testSetup method, which instantiates some objects within a System.RunAs to avoid the DML problem. But (at least) one of my objects instantiated within the System.RunAs is not visible to the test method even tho it does indeed get instantiated and inserted in the test setup method
@isTest
public class TaskHandlerTest {
    public static Id profileId  = [SELECT Id FROM Profile WHERE Name ='ASUO API User Profile'].Id;
    public static User thisUser = [SELECT Id FROM User WHERE Name = 'API ASU EdPlus ASUO'];
    
    public static UserRole testUserRole_ASU;
    public static Contact contact_ASU;

    @testSetup
    static void setUpTest() {

        testUserRole_ASU = new UserRole(
            Name = 'ASU Local',
            OpportunityAccessForAccountOwner = 'Edit'
        );
        insert testUserRole_ASU;
        System.RunAs( thisUser) {
            contact_ASU = new Contact(
                FirstName = 'Pete',
                LastName = 'Townshend',
                Email = 'thewho1@who.com',
                Last_Contact_Method__c = 'text',
                Last_Contact_Attempt__c = Datetime.valueOf('2020-04-04 00:00:00')
            );
            insert contact_ASU;
            System.debug('contact_ASU inserted with Id: ' + contact_ASU.Id);
        }
    }

    @IsTest
    static void test_pass_new_EmailOutbound() {
        Test.startTest();
        TestDataFactory.createCustomSetting('Object Triggers');
        Task task = new Task(
            Description = 'pass_new_EmailOutbound',
            TaskSubType = 'Email',
            Email_Direction__c = 'Outbound',
            WhoId = contact_ASU.Id,  // <--- throws "dereferencing null value" msg here
            Actual_End__c = Datetime.valueOf( '2020-05-20 00:00:00')
        );
        insert task;  // should trigger TaskHandler after_insert()

        System.assertEquals( contact_ASU.Last_Contact_Method__c, 'Email');
        System.assertEquals( contact_ASU.Last_Contact_Attempt__c, task.Actual_End__c);
        Test.stopTest();
    }
}
contact_ASU is declared static outside of setUpTest().
The debug log shows my contact_ASU does get instantiated and inserted and has an Id.  Both setUpTest and test_pass_new_EmailOutbound() are declared static.

So I would expect contact_ASU to be visible to test_pass_new_EmailOutbound() --  what am I doing wrong/ not doing right ?

TIA,

Chris

 
Given a Task has a OwnerId that ties to a User, and
User has a UserRoleId field that ties to a UserRole, and
UserRole has a string Name field, I'd like to extract the role of the owner of a given task. This loads without error:
 
public String getRoleOfOwner( Task task) {
    User user = [SELECT Id FROM User WHERE Id = :task.ownerId];
    UserRole roleObj = [SELECT Id FROM UserRole WHERE Id = :user.UserRoleId]; 
    return roleObj.Name;
}

But that seems so old-school and unnecessary. Isn't there some dot-notation like
String roleOfOwner = task.OwnerId.User.UserRole.Name

where I can get the value directly?

Thx,

Chris , SF Developer Day 20
I see where there is a TimeZone object (under the Marketing Cloud API) and have seen a few posts where an variable of such datatype can be instantiated in Apex.

But, can a field of this datatype be added to Contact ?

TIA,

Chris
version 47
I've a tiny upload.csv file written on a Windoze box with Notepad++ , confirmed to be using CRLF containing two whimsical Contacts:

Name,Phone,Email
Bart Simpson,313-555-1212,haveacow@fox.com
Lisa Simpson,543-434-8474,prez@whitehouse.gov

I've crafted a python script for bulk-inserting these two and all works great right up until the very end when my status response says "JobComplete" and numberRecordsFailed': 2 and the response of calling failedResults is:

['"sf__Id","sf__Error",Email,Name,Phone\r', '"","INVALID_FIELD_FOR_INSERT_UPDATE:Unable to create/update fields: Name. Please check the security settings of this field and verify that it is read/write for your profile or permission set.:Name --","haveacow@fox.com","Bart Simpson","313-555-1212"\r', '"","INVALID_FIELD_FOR_INSERT_UPDATE:Unable to create/update fields: Name. Please check the security settings of this field and verify that it is read/write for your profile or permission set.:Name --","prez@whitehouse.gov","Lisa Simpson","543-434-8474"\r', '']

Pay close attention to the \r and all the double-quotes -- am I formatting my csv file incorrectly? I do explicitly set contentType:CSV and lineEnding: CRLF  when setting up the job

Any ideas?
version 47.0
Bulk API 2.0

Built up a python script using requests and requests_oathlib modules against test.salesforce.com/services/oauth2/token to generate access tokens
and a function that concatenates chunks of results until last chunk is detected then creates a json string from the results.

we know we have 1479552 rows in Contact.
Problem: 
SELECT id,Name,Email,Phone FROM Contact LIMIT 1850000
returns all 1479552 rows but
SELECT id,Name,Email,Phone FROM Contact
returns only 492196 !!!
What is up with that??!!??

And I noticed that when using the LIMIT clause, only two chunks are returned, the first one contains all or close to all the data and the second only 110 bytes or so, while without the LIMIT  3 chunks of roughly equal size are returned.

Can anyone verify and/or explain this behaviour? Better still, tell me how to get around it?

First post, YAY!

TIA,

Chris