When a Lead is converted into an Account, Contact, and Opportunity not much of any of its related data comes along for the ride. In fact, I’ve previously blogged about some of those shortcomings and workarounds regarding Chatter comments and related objects.

In this post, I’m focusing on preserving Chatter Files through the lead conversion process. To do so I developed a simple trigger to demonstrate how to preserve and carry over the Chatter Files to the lead’s converted Account, Contact, and Opportunity.

You can get the apex trigger code from my GitHub repo at https://github.com/DouglasCAyers/sfdc-preserve-chatter-files-on-lead-conversion

Enhanced Notes Oddity

As of this writing, Salesforce does not share to the converted Account, Contact, or Opportunity any of the Lead’s related Files after the lead conversion operation. Oddly enough, Salesforce does bring over Enhanced Notes to the converted Account and Contact, but the Files are left orphaned. I consider this odd since Enhanced Notes (ContentNote object) is built on Chatter Files (ContentVersion object) and so if one is supported why isn’t the other? If you’re curious, you may want to follow or chime in to the conversation on the Success Community.

The Struggle is Real

You can contribute to our struggle by voting on the IdeaExchange for these ideas:

How Does this Code Work?

When a lead is converted, the code queries for all the Files currently shared with the Lead then shares them to the converted Account, Contact, and Lead by inserting new ContentDocumentLink records. However, the SOQL query filters out any documents whose FileType is SNOTE as those are Enhanced Notes which Salesforce does bring over during the conversion. If we were not to filter them out then we’d get an error that the document was already shared with the converted Account.

public void handleConvertedLeads( List convertedLeads ) {

  Map<ID, Lead> convertedLeadsMap = new Map<ID, Lead>( convertedLeads );
  Set convertedLeadIds = convertedLeadsMap.keySet();
  List linksToInsert = new List();

  List fileLinks = new List([
    SELECT
      id, linkedEntityId, contentDocumentId, shareType
    FROM
      ContentDocumentLink
    WHERE
      linkedEntityId IN :convertedLeadIds
    AND
      contentDocument.fileType != 'SNOTE'
  ]);

  for ( ContentDocumentLink fileLink : fileLinks ) {

    Lead convertedLead = convertedLeadsMap.get( fileLink.linkedEntityId );

    if ( convertedLead != null ) {

      // share file to account
      if ( String.isNotBlank( convertedLead.convertedAccountId ) ) {
        linksToInsert.add( new ContentDocumentLink(
          linkedEntityId = convertedLead.convertedAccountId,
          contentDocumentId = fileLink.contentDocumentId,
          shareType = fileLink.shareType
        ));
      }

      // share file to contact
      if ( String.isNotBlank( convertedLead.convertedContactId ) ) {
        linksToInsert.add( new ContentDocumentLink(
          linkedEntityId = convertedLead.convertedContactId,
          contentDocumentId = fileLink.contentDocumentId,
          shareType = fileLink.shareType
        ));
      }

      // share file to opportunity
      if ( String.isNotBlank( convertedLead.convertedOpportunityId ) ) {
        linksToInsert.add( new ContentDocumentLink(
          linkedEntityId = convertedLead.convertedOpportunityId,
          contentDocumentId = fileLink.contentDocumentId,
          shareType = fileLink.shareType
        ));
      }

    }

  }

  if ( linksToInsert.size() > 0 ) {
    insert linksToInsert;
  }

}