You need to sign in to do that
Don't have an account?
Jess core
Update checkbox field if a record has an attachment
We would like to see which records have an attachment attached from the list view. To do this, we created a checkbox field HasAttachment, default unchecked, and the following trigger. If the Expense custom object record has an attachment, then the HasAttachment field should update to TRUE. We tested this trigger through 'Upload File' under the Notes and Attachments related list, however, the HasAttachment field remains unchecked.
trigger AttachmentonExpense on Attachment (after insert) { Set setParentId = new Set(); List Expenselst = new List(); for(Attachment att: Trigger.new) { setParentId.add(att.ParentId); } Expenselst = [select Id , HasAttachment__c from Expense__c where Id IN :setParentId]; For(Expense__c e : Expenselst) { e.HasAttachment__c = True; } update Expenselst; }
To be more precise:
The expense claim would already exist as a Content Document and would be related via the Content Document Link. If it appears in your Files & Notes related list in the Expense record, then it exists as a Content Document Link. What we are doing is is writing a trigger on the Contect Document Link record to detect if it is related to an Expense record and then updating the check box on that record.
In this way, if someone later "links" the expense change to a content document, it will also mark the checkbox in your expense record.
note: this is an after Insert trigger, so it won't update the check box on Expense records with existing Content Documents (links).
Code fix: 1. Ok, we missed declaring the tempParentId.
2. We had declared the Set setParentId but we were trying to update the list expenseIds which we hadn't declare - so updated the code to use the Set we declared.
3. The contentDocumentLinks was a list of CDLs because I prefer to write TriggerHandlers rather than write code direct in Triggers. I have changed contentDocumentLinks to Trigger.new which will work directly in the trigger.
Give that a whirl
Regards
Andrew
All Answers
Hi Jess
Are you using Salesforce Lightning?
If you are, then the trigger needs to be written on different object.
Files have a diferent object structure in Salesforce.
Please refer the link : https://developer.salesforce.com/docs/atlas.en-us.sfFieldRef.meta/sfFieldRef/salesforce_field_reference_ContentDocument.htm
Cheers!!!
Thanks, we are using Lightning.
I have updated the code so that the trigger is on the Content Document instead of Attachment but it is still not working.
You will need to do it on the ContentDocumentLink Object.
ContentDocument is the file, but ContentDocumentLink defines it's attachment to a record. We can also talk about ContentVersions but they aren't relevant here as you are only wanting to the tage the parent record.
The test for a prefix is so that the trigger doesn't try to update records that aren't an Expense Object. (and therefore don't have the checkbox).
HTH
Regards
Andrew
Here is a query of the Content Document table. As you see, Parent id is empty.
Then using the first record Id, I query the Content Document Link object.
By the highlighing, we see that this Content Document is related to a person record (prefix 005) and a case (prefix 500).
We can then check that by opening the content document and checking the Share With settings
Hope the extra info helps
Regards
Andrew
Thanks for explaining what ContentDocumentLink is. So by adding your code the expense record will become a linked entity to the content document?
I replace part of the code with yours so I now have the following, but I get the "Variable does not exist" error for contentDocumentLinks, tempParentId and expenseIds.
Where and how do I define the variables? Apologies, I am still new to apex.
To be more precise:
The expense claim would already exist as a Content Document and would be related via the Content Document Link. If it appears in your Files & Notes related list in the Expense record, then it exists as a Content Document Link. What we are doing is is writing a trigger on the Contect Document Link record to detect if it is related to an Expense record and then updating the check box on that record.
In this way, if someone later "links" the expense change to a content document, it will also mark the checkbox in your expense record.
note: this is an after Insert trigger, so it won't update the check box on Expense records with existing Content Documents (links).
Code fix: 1. Ok, we missed declaring the tempParentId.
2. We had declared the Set setParentId but we were trying to update the list expenseIds which we hadn't declare - so updated the code to use the Set we declared.
3. The contentDocumentLinks was a list of CDLs because I prefer to write TriggerHandlers rather than write code direct in Triggers. I have changed contentDocumentLinks to Trigger.new which will work directly in the trigger.
Give that a whirl
Regards
Andrew
"The expense claim would already exist as a Content Document"
The Expense record exists as its own object.
When you "attach" a file, the attached File becomes a Content Document record. So if a person attaches a receipt, that is the Content Document.
The Content Document Link establishes the link between the Content Document and the record, in this case the Expense record.
Regards
Andrew
Amazing - it works! Thanks so much for your help!
If I would like to modify the code so that any existing expense records that has an attachment will have HasAttachment = TRUE, then do I add a before update trigger in line 1? Should I add anything else to the code?
Same with 'after delete' - if I want HasAttachment = FALSE once the attachment is deleted, how can I modify the code?
Jess
Remember that it is a trigger. The trigger will on fire on the event - in this case Insert of the ContentDocumentLink record.
You could add the After Update to the Trigger in line one, and it will fire if the ContentDocumentLink is updated. It won't magically update the expense records as there needs to be that Trigger event.
To update the existing records, there are two options:
1. Do a report or SQL query on the ContentDocumentLink, extracting the Expense Record Ids, and do a dataloader to update field directly.
2. Add the After Update to the trigger, extract all the contentdocumentLink records and do an update directly to the linking record.
The thing to remember is that the content document link in not generally updated in every day activities. So adding the After Update may not bring a lot of results - remember that when viewing the Expense record, the Content Document Link record is somewhat invisible as it works as a joining record to the ContentDocument - which if you update, won't trigger the contentdocumentlink trigger.
The After Delete code would be different as you won't want to clear the field just because the documentLink is deleted as there may be other content documents inked to the expense record. Something like this should do the trick.
**not tested in my environment, but the logic looks ok at first glance.
Psuedo code would be:
for the deleted CDLs, get a list of parent Ids if parent is Expense
get a list of Expenses that have had a CDL deleted
get a list of any other CDLs that have the same ParentId (expense record)
for the Expenses that had a CDL deleted, if the Id exists in the other CDL list, then other CDLs exist for that expense record.
The conversion from list of CDL to list of Strings is required because the Select returns a list of Objects, and we want to use an Id in the Contains method.
You will need the after delete in your first line of the trigger
And you will want to group the previous code in an if statement like
if (trigger.isAfter && trigger.isInsert)
give that a whirl
Regards
Andrew
P.s.
after thought - if you have a situation where other code ensures that no more than one attachment per Expense record, then your first thoughts on simply looping the trigger.old and setting to False would work.
I added the After Delete code but it is not working - HasAttachment is still equals to TRUE. The trigger works fine when inserting a file to the record.
I just did a check on the code. I set the code up in my dev environment against the Case record.
It appears that when you delete from the File Related list, you are removing the actual Content Document, not the Content Document Link. Checking the forums, it seems this is the case. This would be why the trigger for Delete does not fire.
https://success.salesforce.com/answers?id=9063A000000eMnqQAE
The question becomes "Is the update on delete required?" If so, then a trigger on Content Document delete would be required.
This would add some complexity to handle, as the process would be to detect the delete on the Content Document, find all related Content Document Links, (not sure if/how Versions would then come into play) then find all related Expense records, then using their ids query all Content Document Links and then recalculate the check box.
Apologies on my misunderstanding on how the Content Document Links are removed.
Regards
Andrew
Could you provide the tests you used to deploy this trigger to production, please?
regards,
Alejandro
Does the Delete Functionality Works!! Could you share the test case for this trigger.
Thanks
Simple if you just want any object's field(checkbox) to be true when files are uploaded then this the way.
Code:-
trigger AttachmentonCDL on ContentDocumentLink (after insert)
{
string tempParentId;
Set<Id> setParentId = new Set<Id>();
List<Expense__c> Expenselst = new List<Expense__c>();
for (ContentDocumentLink cdl : trigger.new ) {
tempParentId = cdl.LinkedEntityId;
if (tempParentId != null) {
System.debug('Debug : found Notnull');
System.debug('Debug : content document id ' + cdl.ContentDocumentId );
setParentId.add(cdl.LinkedEntityId);
}
}
Expenselst = [select Id , HasAttachment__c from Expense__c where Id IN :setParentId];
For(Expense__c e : Expenselst)
{
e.HasAttachment__c = True;
}
update Expenselst;
}
I'm trying to achieve something similiar where I need to update a record with the deleted attachment name and size. I'm still getting use to APEX, and had come across a few examples to help me with the following trigger. We're still utilizing the Attachment object as well. Any assistance would be appreciated. Currently I'm getting many errors on the SOQL query for TaskLst which I can't figure out at the moment. Thanks!
Sam
trigger AttachmentHCLTask on Attachment (before delete)
{
String tempParentId;
String tempAttName;
Integer tempAttSize;
Set<Id> setParentId = new Set<Id>();
List<BMCServiceDesk__Task__c> Tasklst = new List<BMCServiceDesk__Task__c>();
for (Attachment HCLTask : trigger.new ) {
tempParentId = HCLTask.Id;
tempAttName = HCLTask.Name;
tempAttSize = HCLTask.BodyLength;
if (tempParentId.left(10) =='a290H00000') {
System.debug('Debug : found a290H00000');
System.debug('Debug : Attachment id ' + HCLTask.Id );
setParentId.add(HCLTask.Id);
}
}
Tasklst = [select Id from BMCServiceDesk__Task__c where Id = setParentId AND HCL_Task_Creation_Sent__c = true];
For(BMCServiceDesk__Task__c e : Tasklst)
{
e.HCL_Attachment_Remove_File_Name__c = tempAttName;
e.HCL_Attachment_Remove_File_Size__c = tempAttSize;
}
update Tasklst;
}