function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
ExpertNOTExpertNOT 

Apex to copy files from one record to another

I have a process where an email service (custom) cretes a CASE with attachments converted to files. I then using Visual Flow create a custom record Purchase_Order__c and fill out some fielsd. I would like to attach the FILES to the new Purchase_Order__c record with in the Visual Flow. Can someone point me on how to copy files from one record to another. I was thinking of calling APEX in the Visual flow. Thanks
SalesFORCE_enFORCErSalesFORCE_enFORCEr
You have to write a class to copy files to Purchase Order record and then call it from your flow.
ExpertNOTExpertNOT
Ok I wrote the following Class with an invocable method so I can use it in a Flow. I input a Case id  as SourceID and the find the Purchase_Order__c ID on the Case. 

It compiles OK but no Attachments from the Case are copied. 
 
Public class CopyAttachments {

    @InvocableMethod (label='Copy attachments from Soruce to Destination' description='Copy attachments from SourceID to DestID')
     
            
        public static void   SourceIDs (List<id> SourceID )   {
        String DestID;
           
                      
            List<Case> cs = [Select Id, Purchase_Order__c from Case where Id=:SourceID]; 
           
            DestID = cs[0].Purchase_Order__c;
            
        Purchase_Order__c po = [Select Id, Name from Purchase_Order__c where Id = :DestID]; 
            
            Attachment[] attList = [SELECT Body,BodyLength,ContentType,Description,Id,Name,ParentId FROM Attachment where ParentId =: cs[0].Id];
            Attachment[] insertAttList = new Attachment[]{};
    
 
    System.debug('==========================attList:'+attList);   
        
             for(Attachment a: attList)
         {
               Attachment att = new Attachment(name = a.name, body = a.body, parentid = DestId);
               insertAttList.add(att);
         }
            
       if(insertAttList.size() > 0)
       {
            insert insertAttList;
            
            
           }
    
        }
    
}

 
SalesFORCE_enFORCErSalesFORCE_enFORCEr
The way you are querying Case using SourceId is wrong. It should be like this
List<Case> cs = [Select Id, Purchase_Order__c from Case where Id IN:SourceID];

SourceId is a list so you have to use IN
ExpertNOTExpertNOT
Thanks enFORCEr. I made the changes but no luck. Does my Flow variable need to be a list? 
SalesFORCE_enFORCErSalesFORCE_enFORCEr
I have not see your flow so you have to decide whether you wnat to send a list of records or just one record. If your invocable method accepts list then you have to pass a list from your flow
ExpertNOTExpertNOT
I want to pass one record id (the case id) Since my Invocable Method requires a List should the Flow be a Collection Varible?????
 
Public class CopyAttachments {

    @InvocableMethod (label='Copy attachments from Soruce to Destination' description='Copy attachments from SourceID to DestID')
     
            
        public static void   CopyFile (List<id> SourceID )   {
        String DestID;
           
                      
            List<Case> cs = [Select Id, Purchase_Order__c from Case where Id IN:SourceID]; 
           
            DestID = cs[0].Purchase_Order__c;
            
        Purchase_Order__c po = [Select Id, Name from Purchase_Order__c where Id = :DestID]; 
            
            Attachment[] attList = [SELECT Body,BodyLength,ContentType,Description,Id,Name FROM Attachment where ParentId =:cs[0].Id];
            Attachment[] insertAttList = new Attachment[]{};
    
 
    System.debug('==========================attList:'+attList);   
        
             for(Attachment a: attList)
         {
               Attachment att = new Attachment(name = a.name, ContentType = a.ContentType, body = a.body, ParentId = DestId);
               insertAttList.add(att);
         }
            
       if(insertAttList.size() > 0)
       {
            insert insertAttList;
            
            
           }
    
        }
    
}

 
ExpertNOTExpertNOT
I tryed creating a Collection Variable in the Flow but it will not allow me to assign it to SourceID.  ???????
SalesFORCE_enFORCErSalesFORCE_enFORCEr
It is not mandatory that your invocable method will accept a list. You can pass the record id and take in a String
ExpertNOTExpertNOT
OK I thought so. I think there is a simple mistake I am making as my test class is comming up with "Method does not exist or incorrect signature: CopyAttachments.CopyFile(List<Case>) line 91. 

Here is my test
@isTest

public class CopyAttachmentTEST {

    private static testMethod void myTest(){
        
        
      test.startTest();
        Profile pf = [Select Id from Profile where Name = 'System Administrator'];
        User u = new User();
        u.FirstName = 'Test';
        u.LastName = 'User';
        u.Email = 'testuser@test123456789.com';
        u.CompanyName = 'test.com';
        u.Title = 'Test User';
        u.Username = 'friend@quadrantsoftware.com';
        u.Alias = 'testuser';
        u.CommunityNickname = 'Test User';
        u.TimeZoneSidKey = 'America/Mexico_City';
        u.LocaleSidKey = 'en_US';
        u.EmailEncodingKey = 'ISO-8859-1';
        u.ProfileId = pf.Id;
        u.LanguageLocaleKey = 'en_US';
        insert u;
        system.runAs(u){
        u=[Select Id,Name FROM User WHERE Id= :u.Id];
            // Create an Account          
       Account a = new Account();
            a.Name = 'Test';
            a.Site = 'Home';
     
            insert a; 
            a=[Select Id,Name FROM Account WHERE Id= :a.Id];
       
        
            //Create Master Opportunity
        
        Opportunity oppMas = new Opportunity();
            
            oppMas.name='MasterTest';
            oppMas.accountId =a.id;
            oppMas.stageName='Qualified';
            oppMas.CloseDate=System.today();
            oppMas.Segue_Customer_Service_Rep__c = u.Id;
              
            insert oppMas;
            
            // Get Opportunity ID
            
          oppMas=[Select Id,Name FROM Opportunity WHERE Id= :oppMas.Id];
       
                   
            // Create New CASE
        
            Case cas =new Case();

            cas.Build_Location__c='Lowell';
            cas.RFQ_Opportunity__c = oppMas.id;
            cas.Status = 'RFQ Initiated';
            
            insert cas;
             // Get Case ID
            
            cas=[Select Id,CaseNumber FROM Case WHERE Id= :cas.Id];  

            
            // Create Purchase Order
            Purchase_Order__C po = new Purchase_Order__c();
            po.Account__c = a.Id;
            po.Customer_PO_Number__c = '1234';
            po.Purchase_Order_Value__c= 34;
            po.Purchase_Order_Date__c =System.today();
            po.Master_Opportunity__c = oppMas.id;
            insert po;
            
            po = [Select Id, Name FROM Purchase_Order__c WHERE Id= :po.Id];
            
            String oppid = oppMas.Id;
            String casid = cas.Id;
            String poID = po.Id;
        
        Attachment attachment=new Attachment();   	
     	attachment.Name='Unit Test Attachment';
    	Blob bodyBlob=Blob.valueOf('Unit Test Attachment Body');
    	attachment.Body=bodyBlob;
        attachment.parentId=casid;
            
        attachment attach;
                    
      // excute method
            CopyAttachments.CopyFile(New Case[]{cas});  
            
    }
    
        
    }    
        
}

 
SalesFORCE_enFORCErSalesFORCE_enFORCEr
If you have not changed your method to accept a single record Id then it still accepts a list<Id> but in the test class you are passing an array of Case records. You need to create a list of Id and then add the case id in it.
ExpertNOTExpertNOT
I thought Incovable Methods will only take a List. I am (trying) to use this method in my flow therefore it needs to be Invocable. Thanks for the advice!!!
SalesFORCE_enFORCErSalesFORCE_enFORCEr
Actually, you are right. Invocable methods accept list. So you can just pass the case id to SourceID. Also, in your test class, create a list of Ids and populate it with case id
ExpertNOTExpertNOT
OK I got the test case working by creating a list of Ids. But my Method is still not working. I have narrowed it down to line 22 where the Attachments from the Source (Cases) is not found. Can anybody see my issue. I have starred at it too long....
 
Public class CopyAttachments {

    @InvocableMethod (label='Copy attachments from Soruce to Destination' description='Copy attachments from SourceID to DestID')
     
            
        public static List<String>   CopyFile (List<id> SourceID )   {
        String DestID;
                         
            List<Case> cs = [Select Id from Case where Id IN:SourceID]; 
            List<Case> cspo = [Select Id, Purchase_Order__c from Case where Id IN:SourceID];
            DestID = cspo[0].Purchase_Order__c;
 
            
            List<Purchase_Order__c> poList = [Select Id, Name from Purchase_Order__c where Id = :DestID]; 
         
            //Create a list for Returning results 
            List<String> ResultList =  new List<String> ();
            
                        
    
            // PROBLEM NOT FINDING ATTACHMENTS ON THE CASE
            Attachment[] CaseList = [SELECT  ID, Name, Body, ContentType from Attachment where ParentId  IN :SourceID];
          
            Attachment[] insertAttList = new Attachment[]{};
    
                        
    System.debug('==========================attList:'+CaseList);   
        
             for(Attachment a: CaseList)
         {
               Attachment att = new Attachment(name = a.Name, ContentType = a.ContentType, Body = a.Body, ParentId = DestID);
               insertAttList.add(att);
         }
            
       if(insertAttList.size() > 0)
      {
            insert insertAttList;
           
             ResultList.add('Files Copied Insert');
                Return ResultList;         
           }
    
            
            else
            {
                ResultList.add(DestID);
                Return ResultList;
                }
        }
    
}

 
ExpertNOTExpertNOT
And here is the Test 
 
@isTest

public class CopyAttachmentTEST {

    private static testMethod void myTest(){
        
        
      test.startTest();
        Profile pf = [Select Id from Profile where Name = 'System Administrator'];
        User u = new User();
        u.FirstName = 'Test';
        u.LastName = 'User';
        u.Email = 'testuser@test123456789.com';
        u.CompanyName = 'test.com';
        u.Title = 'Test User';
        u.Username = 'friend@quadrantsoftware.com';
        u.Alias = 'testuser';
        u.CommunityNickname = 'Test User';
        u.TimeZoneSidKey = 'America/Mexico_City';
        u.LocaleSidKey = 'en_US';
        u.EmailEncodingKey = 'ISO-8859-1';
        u.ProfileId = pf.Id;
        u.LanguageLocaleKey = 'en_US';
        insert u;
        system.runAs(u){
        u=[Select Id,Name FROM User WHERE Id= :u.Id];
            // Create an Account          
       Account a = new Account();
            a.Name = 'Test';
            a.Site = 'Home';
     
            insert a; 
            a=[Select Id,Name FROM Account WHERE Id= :a.Id];
       
        
            //Create Master Opportunity
        
        Opportunity oppMas = new Opportunity();
            
            oppMas.name='MasterTest';
            oppMas.accountId =a.id;
            oppMas.stageName='Qualified';
            oppMas.CloseDate=System.today();
            oppMas.Segue_Customer_Service_Rep__c = u.Id;
              
            insert oppMas;
            
            // Get Opportunity ID
            
          oppMas=[Select Id,Name FROM Opportunity WHERE Id= :oppMas.Id];
       
                   
            // Create New CASE
        
            Case cas = new Case();

            cas.Build_Location__c='Lowell';
            cas.RFQ_Opportunity__c = oppMas.id;
            cas.Status = 'RFQ Initiated';
            
            insert cas;
             // Get Case ID
            
            cas=[Select Id,CaseNumber FROM Case WHERE Id= :cas.Id];  

            
            // Create Purchase Order
            Purchase_Order__C po = new Purchase_Order__c();
            po.Account__c = a.Id;
            po.Customer_PO_Number__c = '1234';
            po.Purchase_Order_Value__c= 34;
            po.Purchase_Order_Date__c =System.today();
            po.Master_Opportunity__c = oppMas.id;
            insert po;
            
            po = [Select Id, Name FROM Purchase_Order__c WHERE Id= :po.Id];
          
            
            String oppid = oppMas.Id;
            String casid = cas.Id;
            String poID = po.Id;
           

            //Create a List of Case IDs. Needed to test the method as it takes a List
         
            List<String> CaseIds =  new List<String> ();
            CaseIds.add(casid);
            
        Attachment attachment=new Attachment();   	
     	attachment.Name='Unit Test Attachment';
    	Blob bodyBlob=Blob.valueOf('Unit Test Attachment Body');
    	attachment.Body=bodyBlob;
        attachment.parentId=casid;
            
        attachment attach;
		insert attachment;
            
      // excute method
            CopyAttachments.CopyFile(CaseIds);  
            
    }



 
Sowmya C M 18Sowmya C M 18
How to write apex method to copy status value from order to case ?
can anyone help me