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
Seth PartridgeSeth Partridge 

Can't Insert ContentVersion in Apex Trigger Test Class ERROR: System.DmlException: Insert failed. First exception on row 0; first error: INVALID_ARGUMENT_TYPE, The argument is null or invalid.: []

I keep getting this error, and don't know why - help! :
System.DmlException: Insert failed. First exception on row 0; first error: INVALID_ARGUMENT_TYPE, The argument is null or invalid.: []

when I run this test:
@istest 
public class UpdateCheckboxAgreementContentDocTest {
    @isTest static void testcheckboxaddPDFcd() {
        // Insert Company
        Account acc=new Account(name='testing');
        insert acc;
        // Insert Contact
        Contact con=new contact(lastname='testinggvs',accountid=acc.id,leadsource='Walk In');
        insert con;
        // Insert Pricebook
        Pricebook2 pb = new Pricebook2(name='test',IsActive = true);
        insert pb;
        // Get Standard Pricebook
        Pricebook2 standardPB = new Pricebook2(
            Id = Test.getStandardPricebookId(),
            IsActive = true
        );
        // Insert Product Agreement Terms
        Product_Agreement_Terms__c pat = new Product_Agreement_Terms__c(name = 'MAP');
        insert pat;
        // Insert Product
        Product2 p = new Product2(Name='MAP Build',Productcode='MACP',Product_Agreement_Terms__c=pat.Id,IsActive = true);
        insert p;
        // Insert Standard Pricebook Entry
        PricebookEntry standardPBE = new PricebookEntry(Product2Id = p.Id,Pricebook2Id = standardPB.Id,UnitPrice = 0,IsActive = true);
        insert standardPBE;
        // Insert Pricebook Entry
        PricebookEntry pbe = new PricebookEntry(Product2Id = p.Id,Pricebook2Id = pb.Id,UnitPrice = 0,IsActive = true);
        insert pbe;
        // Insert Opportunity
        Opportunity opp = new Opportunity(Name='AAA Test',StageName='Agreement Sent', CloseDate=date.parse('02/02/2018'),MAP_Start_Date__c=date.parse('02/02/2018'),MAP_End_Date__c=date.parse('02/02/2018'),Pricebook2Id = pb.Id,Payment_Method__c='Interac',Signing_Contact__c=con.id,accountid=acc.id);
        insert opp; 
        // Insert Opportunity Line Item
        OpportunityLineItem oli = new OpportunityLineItem(OpportunityId = opp.Id,UnitPrice = 1,Quantity = 1,Product2Id = p.Id);
        insert oli;
        // Insert CD to opportunity
        ContentVersion contentVersion1 = new ContentVersion(Title = 'ContentAgreement0',PathOnClient = 'ContentAgreement0.pdf',VersionData = Blob.valueOf('Test Content'),IsMajorVersion = true,ContentLocation='S ');
        system.debug('contentVersion Value equals: '+ contentVersion1);
        insert contentVersion1;
    }
    @isTest static void testcheckboxremovePDFcd() {
        // Insert Company
        Account acc=new Account(name='testing');
        insert acc;
        // Insert Contact
        Contact con=new contact(lastname='testinggvs',accountid=acc.id,leadsource='Walk In');
        insert con;
        // Insert Pricebook
        Pricebook2 pb = new Pricebook2(name='test',IsActive = true);
        insert pb;
        // Get Standard Pricebook
        Pricebook2 standardPB = new Pricebook2(
            Id = Test.getStandardPricebookId(),
            IsActive = true
        );
        // Insert Product Agreement Terms
        Product_Agreement_Terms__c pat = new Product_Agreement_Terms__c(name = 'MAP');
        insert pat;
        // Insert Product
        Product2 p = new Product2(Name='MAP Build',Productcode='MACP',Product_Agreement_Terms__c=pat.Id,IsActive = true);
        insert p;
        // Insert Standard Pricebook Entry
        PricebookEntry standardPBE = new PricebookEntry(Product2Id = p.Id,Pricebook2Id = standardPB.Id,UnitPrice = 0,IsActive = true);
        insert standardPBE;
        // Insert Pricebook Entry
        PricebookEntry pbe = new PricebookEntry(Product2Id = p.Id,Pricebook2Id = pb.Id,UnitPrice = 0,IsActive = true);
        insert pbe;
        // Insert Opportunity
        Opportunity opp = new Opportunity(Name='AAA Test',StageName='Agreement Sent', CloseDate=date.parse('02/02/2018'),MAP_Start_Date__c=date.parse('02/02/2018'),MAP_End_Date__c=date.parse('02/02/2018'),Pricebook2Id = pb.Id,Payment_Method__c='Interac',Signing_Contact__c=con.id,accountid=acc.id);
        insert opp; 
        // Insert Opportunity Line Item
        OpportunityLineItem oli = new OpportunityLineItem(OpportunityId = opp.Id,UnitPrice = 1,Quantity = 1,Product2Id = p.Id);
        insert oli;
        // Insert ContentVersion to opportunity       
 	    ContentVersion contentVersion = new ContentVersion(
            Title = 'ContentAgreement1',
            PathOnClient = 'ContentAgreement1.pdf',
            VersionData = Blob.valueOf('Test Content'),
            IsMajorVersion = true
        );
        insert contentVersion;
        contentVersion = [Select ContentDocumentId from contentVersion where Title= 'ContentAgreement1'];
        ContentDocument cd = new ContentDocument(id=contentVersion.ContentDocumentId);
        // Insert ContentVersion2 to opportunity       
        ContentVersion contentVersion2 = new ContentVersion(
            Title = 'ContentAgreement2',
            PathOnClient = 'ContentAgreement2.jpg',
            VersionData = Blob.valueOf('Test Content'),
            IsMajorVersion = true
        );
        insert contentVersion2;
        contentVersion2 = [Select ContentDocumentId from contentVersion where Title= 'ContentAgreement2'];
        ContentDocument cd2 = new ContentDocument(id=contentVersion2.ContentDocumentId);
        //Create and populate review opportunity record
        Opportunity oppReview =  new Opportunity();
        oppReview = [Select Id,Agreement_Attached_as_Content_Document__c from Opportunity where ID=:opp.Id];
        system.debug('Content Added, oppReview.Agreement_Attached_as_Content_Document__c Value equals: '+ oppReview.Agreement_Attached_as_Content_Document__c);
        System.Assert(oppReview.Agreement_Attached_as_Content_Document__c==True);
        // Delete ContentDocument
        delete cd;
        //Populate review opportunity record
        oppReview = [Select Id,Agreement_Attached_as_Content_Document__c from Opportunity where ID=:opp.Id];
        system.debug('cd deleted, oppReview.Agreement_Attached_as_Content_Document__c Value equals: '+ oppReview.Agreement_Attached_as_Content_Document__c);
        System.Assert(oppReview.Agreement_Attached_as_Content_Document__c==False);
        // Delete ContentDocument2
        delete cd2;
        //Populate review opportunity record
        oppReview = [Select Id,Agreement_Attached_as_Content_Document__c from Opportunity where ID=:opp.Id];
        system.debug('cd2 deleted, oppReview.Agreement_Attached_as_Content_Document__c Value equals: '+ oppReview.Agreement_Attached_as_Content_Document__c);
        System.Assert(oppReview.Agreement_Attached_as_Content_Document__c==False);
    }
}


for this trigger:
trigger UpdateCheckboxAgreementContentDocument on ContentDocument (after insert, after delete) {
    Set<Id> setOpportunityId = new Set<Id>();
    List<Opportunity> lstOpp = new List<Opportunity>();
    if (Trigger.isInsert) {
        for(ContentDocument cd: trigger.new){
            // this 006 check was in the sample code I found
            if(String.valueOf(cd.ParentId).startsWith('006')) {
                setOpportunityId.add(cd.ParentId); 
            }
            // Check ContentDocument to see if PDF
            if(cd.FileExtension.endsWithIgnoreCase('pdf')) {
                for(Opportunity opp: [Select Id, Agreement_Attached_as_Content_Document__c from opportunity where Id IN:setOpportunityId]){
                    // check the box on the opportunity
                    opp.Agreement_Attached_as_Content_Document__c = True;
                    // add the opportunity to the list variable to update
                    lstOpp.add(opp);
                }
            }
        }
    }
    else if (Trigger.isDelete) {
        //new id variable for checking in delete scenario
        id oppId = null;
        boolean PDFStillAttached = null;
        for(ContentDocument cd: trigger.old){
            // this 006 check was in the sample code I found
            if(String.valueOf(cd.ParentId).startsWith('006')) {
                oppId = cd.ParentId; 
            }
            // Check other ContentDocuments to see if there are any other PDFs attached
            List<ContentDocument> lstCds = ([SELECT ID, FileExtension From ContentDocument where ParentId=:oppId]);
            if (lstCds.size()>0) {
                for (ContentDocument lstCd: lstCds) {
                    if(lstCd.FileExtension.endsWithIgnoreCase('pdf')) {
                        PDFStillAttached = True;
                    }
                }
                for(Opportunity opp: [Select Id, Agreement_Attached_as_Content_Document__c from opportunity where Id IN:setOpportunityId]){
                    // check the box on the opportunity
                    If(PDFStillAttached=True){
                        opp.Agreement_Attached_as_Content_Document__c = True;
                    }
                    else {
                        opp.Agreement_Attached_as_Content_Document__c = False;
                    }
                    // add the opportunity to the list variable to update
                    lstOpp.add(opp);
                }
            }
            else {
                Opportunity opp= [Select Id, Agreement_Attached_as_Content_Document__c from opportunity where Id=:oppId];
                    opp.Agreement_Attached_as_Content_Document__c = False;
                // add the opportunity to the list variable to update
                lstOpp.add(opp);
                system.debug('lstOpp equals: '+ lstOpp);
            }
        }
    }
    // Update opportunity if opportunity list size greater than 0
    if(lstOpp.size()>0) {
        update lstOpp;
                system.debug('lstOpp updated: '+ lstOpp);
    }
}

 
SabrentSabrent
On which line are you getting that error? 

Put some Debug logs in your trigger, that will pin point exactly which value is null.
MariuszMariusz
I think the problem is that the cd.ParentId is the ID of the library that owns the document. So it's not populated. If you want to find the connection between an Opportunity and ContentDocument you should look for a junction object named ContentDocumentLink and it's field LinkedEntityId.

When your trigger fires then this record is probably not yet available (I'm not sure, you can check it with soql and system.debug in your trigger). So I think that the best solution would be trying to build a new trigger on ContentDocumentLink. Be aware that this trigger will fire twice. First time for the User currently uploading the document and second time for the opportunity record (they only differ in LinkedEntityId).

Let me know if you need more help or you get stuck.
Seth PartridgeSeth Partridge
@rov Good point  - lines 39 and 81 in the test code (chunk of code in the middle)

 
MariuszMariusz
Could you check if the code below solves the problem? (I modified only the part for Trigger.isInsert; Trigger.isDelete can be done analogically, unfortunately I had run out of time).
Trigger:
trigger UpdateCheckboxAgreementContentDocumentLink on ContentDocumentLink (after insert, after delete) {
	List<Opportunity> oppList = new List<Opportunity>();
    // Get ContentDocumentLink list
    Set<Id> setOppId = new Set<Id>();
    for (ContentDocumentLink cdlt : trigger.new) {
        setOppId.add(cdlt.LinkedEntityId);
    }
    List<ContentDocumentLink> cdlList = [SELECT Id, LinkedEntityId, ContentDocumentId FROM ContentDocumentLink where LinkedEntityId =:setOppId];
    // Create Maps with ContentDocument and Opportunity
    Set<Id> cdId = new Set<Id>();
    for (ContentDocumentLink cdl : cdlList) {
        cdId.add(cdl.ContentDocumentId);
    }
    Map<Id, ContentDocument> mapCd = new Map<Id, ContentDocument>([SELECT FileExtension FROM ContentDocument WHERE Id IN :cdId]);
    Map<Id, Opportunity> mapOpp = new Map<Id, Opportunity>([SELECT Agreement_Attached_as_Content_Document__c FROM Opportunity WHERE Id IN :setOppId]);
    // IsInsert Trigger
    if (Trigger.isInsert) {
        for(ContentDocumentLink cdl: trigger.new){
            // Check if opportunity and if file extension is PDF
            if(String.valueOf(cdl.LinkedEntityId).startsWith('006') && mapCd.get(cdl.ContentDocumentId).FileExtension.endsWithIgnoreCase('pdf')) {
            	Opportunity opp = mapOpp.get(cdl.LinkedEntityId);
                opp.Agreement_Attached_as_Content_Document__c = true;
                oppList.add(opp);
            }
        }
    }
    if(oppList.size()>0) {
        update oppList;
                system.debug('oppList updated: '+ oppList);
    }
}
TestClass
@istest 
public class UpdateCheckboxAgreementContentDocTest {
    @isTest static void testcheckboxaddPDFcd() {
        // Insert Company
        Account acc=new Account(name='testing');
        insert acc;
        // Insert Contact
        Contact con=new contact(lastname='testinggvs',accountid=acc.id,leadsource='Walk In');
        insert con;
        // Insert Pricebook
        Pricebook2 pb = new Pricebook2(name='test',IsActive = true);
        insert pb;
        // Get Standard Pricebook
        Pricebook2 standardPB = new Pricebook2(
            Id = Test.getStandardPricebookId(),
            IsActive = true
        );
        // Insert Product Agreement Terms
        Product_Agreement_Terms__c pat = new Product_Agreement_Terms__c(name = 'MAP');
        insert pat;
        // Insert Product
        Product2 p = new Product2(Name='MAP Build',Productcode='MACP',Product_Agreement_Terms__c=pat.Id,IsActive = true);
        insert p;
        // Insert Standard Pricebook Entry
        PricebookEntry standardPBE = new PricebookEntry(Product2Id = p.Id,Pricebook2Id = standardPB.Id,UnitPrice = 0,IsActive = true);
        insert standardPBE;
        // Insert Pricebook Entry
        PricebookEntry pbe = new PricebookEntry(Product2Id = p.Id,Pricebook2Id = pb.Id,UnitPrice = 0,IsActive = true);
        insert pbe;
        // Insert Opportunity
        Opportunity opp = new Opportunity(Name='AAA Test',StageName='Agreement Sent', CloseDate=date.parse('02/02/2018'),MAP_Start_Date__c=date.parse('02/02/2018'),MAP_End_Date__c=date.parse('02/02/2018'),Pricebook2Id = pb.Id,Payment_Method__c='Interac',Signing_Contact__c=con.id,accountid=acc.id);
        insert opp; 
        // Insert Opportunity Line Item
        OpportunityLineItem oli = new OpportunityLineItem(OpportunityId = opp.Id,UnitPrice = 1,Quantity = 1,Product2Id = p.Id);
        insert oli;
        // Insert CD to opportunity
        ContentVersion contentVersion1 = new ContentVersion(Title = 'ContentAgreement0',PathOnClient = 'ContentAgreement0.pdf',VersionData = Blob.valueOf('Test Content'),IsMajorVersion = true,ContentLocation='S ');
        insert contentVersion1;
        // Insert CDL
        ContentVersion cv = [SELECT id, ContentDocumentId FROM ContentVersion where Id = :contentVersion1.Id];
        ContentDocumentLink cdl = new ContentDocumentLink(ContentDocumentId = cv.ContentDocumentId, LinkedEntityId = opp.Id, ShareType= 'V');
        insert cdl;
    }
}
I left all the code in the trigger, although it's better to put it in a separate class.
Seth PartridgeSeth Partridge
This is looking great so far, Mariusz. Just checking to see if I can get it to work for the isDelete case. Thank you sir!
MariuszMariusz
Happy to help. If you get any problem with the rest, let me know.