Skip to main content

#TDTM0 人がディスカッション中

***reposting from another TB group to see if it gets better answers here**

 

Summary of Issue

  • I received an Apex trigger error email when trying to create a lead as a Guest User from my Experience Cloud Site using the OOTB 'Lead Form' component in the Experience Builder.

EMAIL ERROR MESSAGE

npsp.TDTM_Lead : npsp.TDTM_Lead: execution of BeforeInsert caused by: line 33, column 5: Variable does not exist: TDTM_Config_API

 

Troubleshooting steps already taken

Additional context/details

  • I have implemented a 'Create a Lead' Form component in my Experience Cloud Site for Unauthenticated Guest Users. I mapped the required field and some other fields within the component from the Experience Builder.
  • I configured all the necessary S&S / permissions and other setup steps needed, then published the site.
  • We have NPSP installed.
  • The Experience Cloud Site with the Lead From is for Guest Users to create Leads.

#Experience Cloud #Forms #Leads #NPSP #Triggers #NPSP TDTM #TDTM

2 件の回答
  1. 2023年9月1日 23:45

    TDTM_Lead is actually an Apex trigger.  But you are correct, there are no out-of-the-box TDTM handlers for the Lead object.  The TDTM_Config_API class is not a TDTM handler itself, it's more of a dispatcher to the specific TDTM handlers.

     

    It sure feels like an object permissions error, even though you say you've set all the correct permissions.  You should not need to set permissions on the Apex triggers / classes since those are running in system context already.

0/9000

I think this is something deep in NPSP that I can't see when you delete a HH account with an address and a contact.

 

I have a trigger on Account written using TDTM, and includes a BeforeDelete action. The code works as intended except in one specific instance. I have one Contact at a Household, and there is a record in the Address object (works fine when there is not an address). I click Delete on the Contact button, and it brings up the CON_DeleteContactOverride VF page. I click Delete Account, and I get an error:

 

The record you attempted to access has been deleted. The user who deleted this record may be able to recover it from the Recycle Bin. Deleted data is stored in the Recycle Bin for 15 days. 

 

But the error seems to be triggered just because I have BeforeDelete as a trigger action. If I remove all the code in my class that references BeforeDelete, I still get the error - so it seems to be something about invoking BeforeDelete with TDTM in this scenario that breaks something in NPSP. If I delete just delete the contact and leave the HH with no contacts, and then delete the HH it works fine...

9 件の回答
  1. 2023年5月15日 14:14

    Did y'all ever find an answer to this? We just went live with SSH and I suddenly started getting the "You tried to merge a deleted record with another record. Choose a different record and try again." error message when neither Contact record is deleted. A perusal of the losing Contact's related records doesn't seem to be anything out of the ordinary that wouldn't get popped over to the winning Contact (Application, Ed History, Attribute, Relationship, Address) - all those are standard objects and I merged 2 dupes then suddenly couldn't merge remaining dupes anymore. 

0/9000

We are using EDA and want to extend the TDTM functionality with an additional class on the Affiliation object. This class should evaluate if an Affiliation's primary checkbox field was previously TRUE and was changed to FALSE. If so, it should change the values of status and end date on the Affiliation. Our goal is that when the aligned Primary Affiliation field on the Contact is changed, the Affiliation record that is "unchecked" (formally the primary record but no longer) has an end date added and the status gets changed.

I created my class, added an entry to the Trigger Handler object, and have activated the class. However whenever I try to change the Primary Affiliation field on the Contact, I get the following error:: "System.SObjectException: DML statement cannot operate on trigger.new or trigger.old"

I have also pasted my code below, any help is appreciated. I'd like assurance that I have extended the TDTM functionality correctly, as the documentation is sparse and the error appears to be with how the class is trying to DML the record.

//

global class Aff_Extend_TDTM extends hed.TDTM_Runnable {

global override hed.TDTM_Runnable.DmlWrapper run(

List<Sobject> newlist,

List<SObject> oldlist,

hed.TDTM_Runnable.Action triggerAction,

Schema.DescribeSObjectResult objResult) {

hed.TDTM_Runnable.DmlWrapper dmlWrapper = new hed.TDTM_Runnable.DmlWrapper();

list<hed__Affiliation__c> loadAff = new list<hed__Affiliation__c>();

// Cast the trigger.new and trigger.old list into an Affiliation__c list

List<hed__Affiliation__c> triggernew = (list<hed__affiliation__c>)newlist;

List<hed__Affiliation__c> triggerold = (list<hed__affiliation__c>)oldlist;

// Make trigger.oldmap from triggr.old list

Map<Id, hed__Affiliation__c> triggeroldmap = new Map<Id, hed__Affiliation__c>();

for ( hed__Affiliation__c aff1 : triggerold )

triggeroldmap.put(

aff1.id

, aff1);

if (triggerAction == hed.TDTM_Runnable.Action.BeforeUpdate) {

// Compare values and determine if box was unchcked in this run

for (hed__Affiliation__c aff2 : triggernew ) {

hed__Affiliation__c oldAff = triggeroldmap.get(

aff2.Id

);

if(aff2.hed__Primary__c != oldAff.hed__Primary__c) {

System.debug('--* Aff Primary is changed*--');

aff2.hed__status__c = 'former';

aff2.hed__enddate__c = date.today();

loadAff.add(aff2);

}

}

dmlWrapper.objectsToUpdate.addAll((list<SObject>)loadAff);

}

return dmlWrapper;

}

}

3 件の回答
  1. 2020年2月11日 21:38

    So you don't need to add the records to the list/add the list to the DML wrapper. You are updating the records in the trigger by reference, so you don't then need to also have a separate DML statement run on it. So if you just comment out the lines:

    loadAff.add(aff2);

    And then this one

    dmlWrapper.objectsToUpdate.addAll((list<SObject>)loadAff);

     

    you should fine it works as intended.

     

    You only need those DML wrappers if you are trying update other data e.g. related accounts you have queried for, new records you want to create.

0/9000

Assets ready for our fifth and final session of the Optimize Your Org for Education Webinar series. Listen in as @Natalie Vaynberg​ walks you through the basics of Table Driven Trigger Management (TDTM)!

 

foundation.my.salesforce.com

1 件のコメント
0/9000

I'm running into an issue using DLRS to roll up an Account Soft Credit field onto Opportunity that appears to be TDTM related. It looks like the NPSP trigger is failing due to something currency related when I try to deploy the DLRS trigger.

There are a number of Account Soft Credit records that already exist (i.e. they are being created ok, just hitting a problem w/ DLRS trigger). Suggestions welcomed.

Error message:

dlrs_npsp_Account_Soft_CreditTest.testTrigger System.DmlException: Insert failed. First exception on row 0; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, npsp.TDTM_AccountSoftCredit: execution of BeforeInsert caused by: System.NullPointerException: Attempt to de-reference a null object Class.npsp.OPP_AccountSoftCredit_TDTM.synchronizeCurrencyIsoCode: line 88, column 1 Class.npsp.OPP_AccountSoftCredit_TDTM.run: line 57, column 1 Class.npsp.TDTM_TriggerHandler.runClass: line 193, column 1 Class.npsp.TDTM_TriggerHandler.run: line 113, column 1 Class.npsp.TDTM_Config_API.run: line 92, column 1 Trigger.npsp.TDTM_AccountSoftCredit: line 33, column 1: [] Class.dlrs.RollupService.testHandler: line 282, column 1 Class.dlrs_npsp_Account_Soft_CreditTest.testTrigger: line 11, column 1

8 件の回答
  1. 2020年12月9日 21:11

    Thanks for the group link, didn't realize that existed. Apparently there is a whole article on issues deploying triggers and that it's not that uncommon for them to fail. I dug into the debug log and realized for some reason it's failing to create an Account in the test class for some reason (missing a name, can find that in the debug log); possibly due to order of operations with NPSP triggers or something else. The recommended workaround is to edit the test class in sandbox to provide the missing value(s), then deploy to production rather than letting the app handle it for you. I haven't done that yet but will try to remember to post an update when I get to it.

     

    So—not perhaps directly related to NPSP, but not totally unexpected when there's a lot of other automation in the org (i.e., NPSP). I have no idea if the currency thing is the difference between this org and the ones where it works, but it's another layer of "stuff" that could possibly create an issue (like, maybe the DLRS test class doesn't set a default currency??).

     

    Anyways - still in progress. Thanks for the ideas, if adding Account Name to the test class fixes it I will post for reference!

0/9000

I've read the TDTM documentation, done some web searching, and perused a bit of the code. I still have some technical questions. (I see that there are questions here with a TDTM topic, but it wasn't one of the choices in the "Add topics" section when I created this question.)

1. I've seen other questions raised here about whether the trigger handlers are processed in the same order in a test as they are normally. This appears to have something to do with how the data is loaded into the triggerHandlers variable in the test class, i.e. the fact that the handler being tested is loaded last, and therefore isn't necessarily in the Load Order. Is this the case, i.e. are there differences, and if so, why? How do we ensure we're testing the same order as will be live?

2. On a related note, the sample test code shows making a call to get the "default" records, then adding the class being tested to the local triggerHandlers variable. But, related to #1, if we have more than one additional handler in production, and they're not loaded in the test class for handler X, then we're again not testing what's actually going to run in a live environment. Shouldn't we load *all* of our handlers into the variable in a test class? (This is more theoretical for us at the moment, but I want to know how to deal with it going forward.)

3. The call to get the cached records in fact inserts the "default" TDTM records into the trigger handler table. So after the call, they're loaded in the table, and we have them in the triggerHandlers local list variable. We then load our handler being tested into that variable. But it's not in the table. I'm missing how just having it in a local variable is causing it to be called during testing.

4. The sample test class is obviously a simple one, and shows everything happening in a single method. But because I'm not clear on #3 above, I'm not clear what we can do. Is it OK to still use a testSetup method to load the test data needed by the other test methods? Does any test method that needs to do DML need to load the triggerHandlers variable?

Thanks for any help and/or pointers!

5 件の回答
  1. 2020年6月26日 19:34

    @Vince Rice​ Great questions and sorry for the delay. I'm always happen to see our customer orgs leveraging the TDTM framework. Taking a shot at these.

    1. I have observed this, though only once and it was a few years ago. We no longer insert TriggerHandler__c records in our unit tests so I'm not necessarily sure if this is even still an issue, though we do insert them for customer tests. I would say that without evidence to the contrary this is not something to worry about in your unit tests.
    2. The sample code is just an example. If you are using multiple custom trigger handler classes in your org, it may very well make sense to use a single test factory method that adds all of your handlers to the getDefault() collection. That's completely up to you and how you've built out your trigger framework.
    3. Great point here. I believe what you have to do is make the call to getCachedRecords() first. That populates the TriggerHandler__c object with the NPSP defaults. Then insert your own custom Trigger Handler records into the object. Once that is done, the next trigger operation that goes through TDTM will requery the TriggerHandler__c object - getting the defaults as well as your custom records - and then use those for all trigger operations.
    4. A testSetup method should be fine for creating doing the first 2 parts of step 3 above - calling getCachedRecords and then inserting your own custom records. That should populate the TriggerHandler object properly and the data will persist for all test methods in that class.

     

    I hope these help. If you run into issues or have other questions, please feel free to respond back here and @-mention me.

0/9000

The NPSP TDTM Opportunity trigger is not allowing me to insert data into the opportunity object into Salesforce. The error I receive is:

"npsp.TDTM_Opportunity: execution of BeforeInsert

caused by: System.NullPointerException: Attempt to de-reference a null object

Class.npsp.OPP_OpportunityContactRoles_TDTM.setOpportunityAccountField: line 137, column 1

Class.npsp.OPP_OpportunityContactRoles_TDTM.run: line 61, column 1

Class.npsp.TDTM_TriggerHandler.runClass: line 193, column 1

Class.npsp.TDTM_TriggerHandler.run: line 113, column 1

Class.npsp.TDTM_Config_API.run: line 92, column 1

Trigger.npsp.TDTM_Opportunity: line 33, column 1"

5 件の回答
  1. 2020年3月19日 18:09

    @Mike McGibbony​ I did read about a case that was resolved by lowering the batch size to 1, which shouldn't be an issue for your size. It's likely due to either a bug in the Data Loader (that was the issue indicated on the case), or because there are so many Opty's attempting to relate to the same record, though I'd expect a row-lock or similar in that case. Can you try with 1?

0/9000

We have attempted to follow the guide on setting up a custom class to execute after the NPSP default TDTM classes on Opportunity.

When we run the test class everything seems to work in the correct order however, when we add an Opportunity in the UI our custom class does not execute last. We set an order on the Trigger Handler record of 5 which is after all of the NPSP defaults.

6 件の回答
  1. 2020年3月5日 0:14

    @Nonprofit Salesforce Developers​ 

    @Open Source Partner Success Forum​ 

0/9000

Hello!

We have EDA set up to populate the Primary Academic Program on the related Contact record when an academic program affiliation is set as primary. This morning my team noticed that there were records that did not have the primary field set, and I found that if the primary flags were updated in bulk the primary academic program field was not being updated. Our bulk integrations updated the primary flag on the affiliation as intended but the primary academic program field on the Contact was not updated accordingly. If I update the primary flag on the affiliation one record at a time (in the Salesforce interface and via API) the updates will take. Has anyone else encountered this?

18 件の回答
  1. 2020年1月29日 15:21

    Hi @Jace Bryan​ ! It was an attempt to update existing affiliations, but it turns out the test record that was generating the errors had a mismatched external system ID that was pointing to a different contact record. Once I corrected the external ID the error went away. I'm not sure of the specifics, but it was a data issue on our end.

0/9000

In other words, why use code instead of clicks?

I'm looking at Send Acknowledgments as a model for planning out a similar process to send tax receipts. I want to make sure I understand its design choices before I start stomping around inside Salesforce. Is this connected to TDTM?

4 件の回答
  1. 2019年12月19日 23:45

    So I haven’t looked at the latest changes to the send email ack as I implemented a system long before there was automation in NPSP for it. so I’m gonna take your assertions as fact.

    If I were designing it, I would make the button change a field so that automation could take over from there in a declarative way that would be East to maintain. And this would also enable the field to be set in other ways besides manual button pushing.

0/9000