2

I am trying to write a trigger that will transfer attachments from a Task object to the related Opportunity object from emails & attachments using Salesforce for Outlook. I have the basic trigger code written to do the transfer. But after some research I found that the WhatId is not available after insert when created from SFO. I found that you can call a @future method to then complete the transfer if the WhatId is Null.

The problem is that in the @future method I am looping through the list of tasks collected from the Ids passed to it. I am then querying to find the attachments linked to the task. I know I should not put SOQL inside the loop but a subquery would not allow the select of the body of the attachments. I will clean it up later. But I still do not understand why the reference to the task iteration variable in the select statement will not return any results. The exact same loop structure and select are in the base trigger and work fine.

Like I said I will clean this up to be better code, but I am trying to finish this for a demo that will show we can modify the default actions of Salesforce for Outlook as far as the attachments go.

I will include both the trigger code and class code along with a sample of the log.

        trigger Task_Transfer_Attachments on Task (after insert, after undelete) {
    //Create a List to store the Ids of Attachments to be deleted
    List<Id> forDeletionIds = new List<Id>();
    List<Id> tasks = new List<Id>();
    //List<Attachment> AttachToUpdate = new List<Attachment>();
    for (Task t : trigger.new){
        String taskWhatId = String.valueof(t.WhatId);
        if (taskWhatId == null){
             tasks.add(t.Id);
             System.debug('~~~~~~ WhatId String =' + t.WhatId ); 
             Continue;
        }
        //Get the attachments for the task
            System.debug('~~~~~~ Parent String =' + t.WhatId ); 
        for(Attachment AttachToUpdate :  [select id,name,body from Attachment where parentid = :t.Id ]){
            //Check if the task is related to an opportunity
            if (taskWhatId.substring(0,3) == '006' ){   
                    Attachment newA = New Attachment(
                        Name = AttachToUpdate.Name,
                        Body = AttachToUpdate.Body,
                        //ContentType = 'image/jpeg',
                        //Description = 'Account Photo',
                        OwnerId = t.OwnerId,
                        ParentId = t.WhatId
                    );
                    //Insert the new Attachment
                    insert newA;
                    //Add the now duplicate Attachment ID to a list
                    forDeletionIds.add(AttachToUpdate.Id); 
                //}
            }
        }
    }
    //Call a @future method to transfer attchments created by SFO
    if (tasks.size() > 0) {
        System.debug('~~~~~~ Call Future Method =' + tasks ); 
        Task_Transfer_Future.FutureTransferAttachMethod(tasks);
    }
    //List and then delete all duplicate Attachments
    List<Attachment> forDeletion = [SELECT Id FROM Attachment WHERE Id IN :forDeletionIds];
    delete forDeletion;
    }

public with sharing class Task_Transfer_Future {
 @future
    public static void FutureTransferAttachMethod(List<id> taskIds){
        List<Id> forDeletionIds = new List<Id>();
        list <id> tasks = taskIds;
        //list <Attachment> AttachToUpdate = new list <Attachment>();
        list <task> theTasks  = [select Id, WhatId, OwnerId from task  where ID IN :tasks];
        for (task t : theTasks){
            String taskWhatId = String.valueof(t.WhatId);
            //Get the attachments for the task
                System.debug('~~~~~~ What ID = ' + t.WhatId + ' t.Id = ' + t.id ); 
            list <Attachment> AttachToUpdate = [select id,name,body from Attachment where parentid = :t.id ];
            for(Attachment a : AttachToUpdate ){
                if (taskWhatId.substring(0,3) == '006' ){ 
                    System.debug('~~~~~~ Loop Attach  =' + a.Id );   
                        Attachment newA = New Attachment(
                            Name = a.Name,
                            Body = a.Body,
                            OwnerId = t.OwnerId,
                            ParentId = t.WhatId
                        );
                        //Insert the new Attachment
                        insert newA;
                        //Add the now duplicate Attachment ID to a list
                        forDeletionIds.add(a.Id); 
                }
            }
        }
        //List and then delete all duplicate Attachments
        List<Attachment> forDeletion = [SELECT Id FROM Attachment WHERE Id IN :forDeletionIds];
        delete forDeletion;
    }
}

Log sample:

    |USER_DEBUG|[11]|DEBUG|~~~~~~ What ID = 0067000000azvv8AAA t.Id = 00TV0000008DqwuMAC
    SYSTEM_METHOD_EXIT|[11]|System.debug(ANY)
    SOQL_EXECUTE_BEGIN|[12]|Aggregations:0|SELECT id, name, body FROM Attachment WHERE parentid = :tmpVar1
    SOQL_EXECUTE_END|[12]|Rows:0
  • did you check apex jobs to see if something is queued related to this trigger? – Rao Sep 24 '14 at 18:40
  • Your trigger is an after insert trigger. As such, how could there be any Attachments whose parent is the task being inserted? Attachments can't be added to any object until the object has been committed. – cropredy Sep 24 '14 at 19:13
  • Your code would look nicer if you used taskWhatId.startsWith(Opportunity.sObjectType.getDescribe().getKeyPrefix()). Except of course you would cache that prefix outside your for loop! – Adrian Larson Sep 24 '14 at 19:17
  • The after insert trigger work great when a task is created from SFDC with an attachment. The problem is only when the task is created from SFO. I am still unsure why the WhatId is not available, but I don't think that has anything to do with why this code will not work. The WhatId and T.Id are both displayed in the debug statement. But the SOQL select does not return any rows. If I hard code a taskID into the @future code instead of t.Id it does work. So the Functionality of the code is good. – James Allen Sep 24 '14 at 19:33
  • crop1645 I re-wrote this as an after insert trigger on the attachment object. I still don't understand why it works from the task object except when from SFO. I also used this thread as a big help and basis for the code. link – James Allen Sep 24 '14 at 20:33
1

It seems like your list<Id> tasks will always be a list of null values if there are any at all. I think this line in your trigger:

if (taskWhatId == null){

Should be changed to

if (taskWhatId != null){

Now it will be gathering the Tasks that have WhatIds. Currently it is only gathering if the Task has no WhatId, then sending such a Task to the future method.

0

You have to modify your trigger. Attached is a child object and task is parent object like account & Opportunity where account is parent. Since trigger is on Task which is insert event. So it not make any difference if it is before or after, Task insertation will be completed only after it executed & stopped. In the 1st debug you see task id as it is inserted but as trigger after event not completeled till now, so salesforce have not committed it in database. And when you query in database it will be null there. Attached can be inserted after trigger is committed. And when you pass hardcoded task id it shows value as you are passing id of already inserted Task.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.