Apex trigger which provides targets on sub campaign generates the error on parent campaign - salesforce

I have a problem with one trigger. I was trying to set up the solution which will give me the possibility to assign flexible targets for campaigns. I was trying to solve it via formula field but it occurred to be too complex and I was advised it needs to be the apex trigger. I created the custom setting of list type, so then I could query it in the apex trigger. I created the "Apex_Calculator__c" field which combined values from two fields (Event Region [located on the parent campaign level] and Started Campaign [located on the sub-campaign level]). The value from the "Apex_Calculator__c" field was about to bring the same values as in the custom setting.
My knowledge of Apex triggers is limited, so I asked for the help on the internet. I received the help and the trigger was bringing target values in the sub campaign. However, the problem occurred on the parent campaign level. As far as I wanted to change the Event Region (which as I mentioned is part of the "Apex_Calculator__c" formula field), I started to receive the error message:
*
PopulateTarget: execution of BeforeUpdate caused by:
System.NullPointerException: Attempt to de-reference a null object:
Trigger.PopulateTarget: line 18, column 1
*
trigger PopulateTarget on Campaign (before insert, before update)
{
Map <String, Id> recordTypes = new Map <String, Id> ();
for (RecordType recordType : [SELECT Id, DeveloperName FROM RecordType WHERE sObjectType = 'Campaign'])
{
if (recordType.DeveloperName == 'Conference')
{
recordTypes.put(recordType.DeveloperName, recordType.Id);
}
}
for(Campaign campaign : Trigger.new)
{
// Make sure that the campaign record type is not in the map (in the map we keep the ones that we want to exclude)
if (recordTypes.get(campaign.RecordTypeId) == null && String.isNotBlank(campaign.Apex_Calculator__c) == true)
{
String target = DSTargets__c.getInstance(campaign.Apex_Calculator__c).Target__c;
campaign.DS_Target_Multiplier__c = Target;
}
}
}
I feel really lost what is wrong in here. Could anyone help me with this error?

Looks like you don't have DSTargets custom settings for some campaign.Apex_Calculator__c values.
Try this:
// Make sure that the campaign record type is not in the map (in the map we keep the ones that we want to exclude)
if (recordTypes.get(campaign.RecordTypeId) == null && String.isNotBlank(campaign.Apex_Calculator__c) == true)
{
if (DSTargets__c.getInstance(campaign.Apex_Calculator__c) == null)
{
System.debug('### A DSTargets named \'' + campaign.Apex_Calculator__c + '\' doesn't exist');
continue;
}
String target = DSTargets__c.getInstance(campaign.Apex_Calculator__c).Target__c;
campaign.DS_Target_Multiplier__c = Target;
}

Related

How to check if records related to fields in custom metadata are changed

I have a scenario where I need to check in opportunity update if particular field values of opportunity which are mentioned in metadata are changed or not, if these values are changed meaning that that record would be considered for update. I have done this with field sets but not sure how we can achieve the same using custom metadata. Attaching the code used for field sets here
Public static boolean isValuesChanged(List<Opportunity> newOpportunitiesList, Map<id,Opportunity> oldOpportunityMap)
{
for(Opportunity oppRecord : newOpportunitiesList)
{
for(Schema.FieldSetMember fieldSetMemberObj : SObjectType.Opportunity.FieldSets.Opportunity_Comparision_FieldSet.getFields())
{
if(oppRecord.get(fieldSetMemberObj.getFieldPath()) != oldOpportunityMap.get(oppRecord.id).get(fieldSetMemberObj.getFieldPath()) && oppRecord.Amount > 0)
{
return true;
}
}
}
return false;
}
This is what I have done when I used field sets. The same I want to do using custom metadata.How can I check changes in Apex ?
Thanks in Advance
Cut it into 2 problems.
Given a set of strings with field api names - how to detect changes
Set<String> fields = new Set<String>{'Name', 'CloseDate', 'StageName'};
Set<Id> oppsToProcess = new Set<Id>();
for(Opportunity opp: newList){
Opportunity old = oldMap.get(opp.Id);
for(String field : fields){
if(opp.get(field) != old.get(field)){
oppsToProcess.add(opp.Id);
break;
}
}
}
Given a custom metadata with field names - how do I make a set of strings out of it.
Solution for this one depends what exactly you have in custom meta:
list with multiple records, each with single field's name?
1 record with field names saved in columns like Field1__c, Field2__c, Field3__c
1 record with list of fields stored comma-separated, like Fields__c = 'Name,CloseDate,StageName'
You'll have to do it yourself, query and loop through first one or call String.split(','); on the last one or...

Creating a Multi-Contact Event with Apex in Salesforce

I am attempting to use Apex to create a multi-contact event.
I have already enabled Allow Users to Relate Multiple Contacts to Tasks and Events in the activity settings in the scratch org.
I am following the guide and the example at the bottom of these docs but I am constantly getting an error when pushing to the scratch org:
// ...
event.setEventWhoIds(attendeeContactIds);
// ...
Method does not exist or incorrect signature: void setEventWhoIds(List<String>) from the type Event.
I also tried to write directly to the field with:
event.EventWhoIds = attendeeContactIds;
With that, I get the error, that the field is not writable.
attendeeContactIds is a List of Strings representing Contact IDs.
What could I be missing? 🤔🙇🏻‍♂️
It's bit stupid, it's readonly in apex. It's exposed so integrations can quickly create event and essentially a related list together in one all-or-nothing transaction. See also https://salesforce.stackexchange.com/questions/238094/eventwhoids-is-not-writeable-in-apex-class-but-working-on-jsforce
Try something like that?
Savepoint sp = Database.setSavepoint();
event e = new Event(
StartDateTime = System.now(),
EndDateTime = System.now().addHours(1)
);
insert e;
List<EventRelation> invitations = new List<EventRelation>();
for(Contact c : [SELECT Id FROM Contact LIMIT 5]){
invitations.add(new EventRelation(
EventId = e.Id,
RelationId = c.Id,
IsInvitee = true
));
}
insert invitations;
Database.rollback(sp); // unless you really want to send it out

Salesforce Apex Class update custom object lookup field with id from parent

I am new to Apex and I’m struggling with creating a class to help me with some data analysis. I have data from a 3rd party (transactions__C) that has a field (fin_acct_txt__c) that is the pointer to another object (fin_accounts__C). I want to updated transactions__c with the id from fin_accounts__C into the lookup field transactions__c.fin_acct__c.
I want to do this in a class versus a trigger as there would be thousands of records loaded from the 3rd party on a monthly basis. I think doing this in bulk would be more efficient.
My thought is I create a list for transactions__c and a map for fin_accounts__c. Using the fin_acct_txt__c=fin_accounts__c.name I would be able to get the fin_accounts__c.id and update the transactions__c.fin_acct__c with that data.
But being new to Apex seems to be causing me some problems that I’m unsure how to resolve.
Here’s a copy of what I’ve done to date:
public class updateTxnFinAcctID {
// Build map of financial accts since that is unique
map<string ,fin_acct__c> finAccts = new map<string, fin_acct__c>
([select id,name from fin_acct__c where name!=null]);
//Iterate through the map to find the id to update the transactions
{
for(fin_acct__c finAcct: finAccts.values())
{
if (finAcct.name != Null)
{
finAccts.put(finAcct.name, finAcct);
}
// Find all records in transaction__c where fin_acct__c is null
//and the pointer is the name in the map
list<Transaction__c> txns =[
select id,fin_acct_txt__c from Transaction__c where fin_acct__c = null
and fin_acct_txt__c=:finaccts[0].name];
//create the list that will be used to update the transaction__c
list <Transaction__c> txnUpdate = new list <Transaction__c>();
{
//Find the id from fin_acct__c where name = fin_acct_txt__c
for (Transaction__c txn: txns){
finacct[0].Id =txn.fin_acct__c;
txnUpdate.add(txn);
}
//3. Update transaction with ID
}
}
// if (txnUpdate.size()>0 { update txnUpdate};
system.debug(txnUpdate.size());
}
}
I seem to be in a doom loop. The error I get is “Expression must be a list type: Map” pointing to the list txns = [ …]. But as that is not unique, it must be list. But I would believe I’ve got something structurally wrong here and that is a symptom of a larger issue.
Thanks.
I tried to understand what should to do your code, and I have a few tips, possibly they help to solve your issue:
1) In first loop over values of map finAccts you really don't need validation with if (finAcct.name != Null), because you already add it in SOQL query (where name!=null).
2) It's a bad practice - to put as a key to map different entities (for example, Ids and Names). I mean that when you queried fin_acct__c into the map finAccts, keys of the map are Ids of fin_acct__c. And then in the first loop you put in the same map the same objects only using their names as a key. If you really need such map with names as a keys is better to create new map and put the data there.
3) You execute SOQL query to Transaction__c object into the loop. It is likely to be the cause of an exception related to the SF limits (Especially if you are sure that the code will handle large amounts of data). Better collect all fin_acct__c names in list and move SOQL query out from the loop, using IN instead of = in where condition.
If I understood correctly that fin_acct_txt__c field contains names, not Ids, your class should looks something like:
public class updateTxnFinAcctID {
Map<String ,fin_acct__c> finAccts = new Map<String, fin_acct__c>
([select id,name from fin_acct__c where Name != null]);
Map<String, fin_acct__c> finAcctByNames = new Map<String, fin_acct__c>();
for(fin_acct__c finAcct: finAccts.values()){
finAcctByNames.put(finAcct.Name, finAcct);
}
List<Transaction__c> txns =[select id, fin_acct_txt__c, fin_acct__c
from Transaction__c where fin_acct__c = null
and fin_acct_txt__c IN finAcctByNames.keySet()];
List <Transaction__c> txnUpdate = new List<Transaction__c>();
for (Transaction__c txn: txns){
fin_acct__c relatedFinAcct = finAcctByNames.get(txn.fin_acct_txt__c);
if(relatedFinAcct != null){
txn.fin_acct__c = relatedFinAcct.Id;
txnUpdate.add(txn);
}
}
if(!txnUpdate.isEmpty()){
update txnUpdate;
system.debug(txnUpdate.size());
}
}
It possibly can contains some spelling mistakes, but it's a common idea.

Update Multi-Picklist on updating custom object

I have custom object KeywordAccountAssociation__c. This object has three fields
Account__c - Master-Detail(Account)
Keyword__c - Master-Detail(Keyword)
Compositecp__c - Text(255) (External ID) (Unique Case Sensitive)
I have a custom field in Account
DD_Segment__c - multi-picklist
Now I want to update (Insert is fine too) values of DD_Segment__c whenever KeywordAccountAssociation__c is updated. I could write trigger for this but I don't know how? I am new to Salesforce Development and my background is ruby (so getting accustomed to apex is bit difficult for me).
KeywordAccountAssociation__c has multiple rows of Account__c which has same account_id and those account_id are related to a record of custom object Keyword__c. I want to get all keywords related to one account and update in its (account's) multi-picklist. How can I achieve this? If you have doubts about this please do ask. Thanks!
One issue is related to learning to work with triggers in general, which can be started with Salesforce Apex Developer Documents on Triggers
but to answer your actual question, you would essentially need to build a trigger against your custom object that would update the related account. It might look something like this:
trigger keywordAccountUpdate on KeywordAccountAssociation__c (after insert, after update){
set<id> = new set<id>();
for (KeywordAccountAssociation__c a : Trigger.new)
accountIds.put(a.Account__c);
map<id,Account> accountMap = new map<id,Account>([select id, DD_Segment__c from Account where id in :accountIds]);
for (KeywordAccountAssociation__c kaa : Trigger.new){
if (AccountMap.containskey(kaa.Account__c)){
Account thisAccount = AccountMap.get(kaa.Account__c);
String s = thisAccount.DD_Segment__c + ';new value'; // Always add value
if ((thisAccount.DD_Segment__c).contains('second value')
s += ';second value';
AccountsToUpdate.add(new Account(id=thisAccount.id, DD_Segment__c = s));
}
}
}
Please keep in mind that I don't have the structure to test this trigger, I just free handded it, so YMMV.

Illegal polymorphic assignment from polymorphic domain [SOBJECT:User, SOBJECT:Calendar]

I am writing a task's trigger and getting an error in salesforce Illegal polymorphic assignment from polymorphic domain [SOBJECT:User, SOBJECT:Calendar]
trigger Status_Change on Task (after update) {
List<Task>updated_tasks=trigger.new;
List<Task> tt=trigger.old;
Task_History__c history=new Task_History__c();
Integer i=0;
for(i=0;i<updated_tasks.size();i++)
{
history.Name=tt.get(i).Subject;
history=new Task_History__c();
history.OldValue__c=tt.get(i).Status;
history.NewValue__c=updated_tasks.get(i).Status;
history.User__c=updated_tasks.get(i).Owner;
insert history;
}
}
error is on line
history.User__c=updated_tasks.get(i).Owner;
When I write history.User__c=updated_tasks.get(i).owner.id then there is no error
but when I tried to get a User's email address from this id then its showing no user corresponding to this id. How do I get Owner's user id from Task SObject's owner field. I think error is due to Owner is a lookup to [SObject.User,SObject.Calender].so owner's id should be different from User'id .but how to get only User's id from Owner's field in Task object?
You are so close. The syntax is:
history.User__c=updated_tasks.get(i).OwnerId;
You were correct. the task.Owner field is an SObject, task.Owner.Id is valid, but the value being referenced is not populated in the trigger context.
Your trigger is not very well written, it has a dml statement in a loop, and there doesn't appear to be a lookup from the task history to the task, I have referenced one in the updated example below.
trigger Status_Change on Task (after update) {
List<Task_History__c> histories = new List<Task_History__c>();
Task oldValue;
for(Task task : Trigger.new) {
oldValue = Trigger.oldMap.get(task.Id);
histories.add(new Task_History__c(
Name=task.Subject,
OldValue__c=oldValue.Status,
NewValue__c=task.Status,
User__c=task.OwnerId,
//This should be created as well
Task__c=task.Id
));
}
if(histories.size() > 0) {
insert histories;
}
}

Resources