-1

I am new to salesforce, and I am getting an error :

INVALID_FIELD_FOR_INSERT_UPDATE, cannot specify Id in an insert call

I am trying to test my Trigger

My Trigger

trigger invoiceTrigger on Invoice_Line_Item__c (before insert , after insert) 
{
    
    if(Trigger.isbefore)
    {
        String invoiceId;
        Invoice__c newInvoice = new Invoice__c();
        insert newInvoice;
        decimal sum = 0 ;
        invoiceId = newInvoice.id;
        for(Invoice_Line_Item__c invL : Trigger.new)
        {
            invL.parent_id__c = invoiceId;
            sum = invL.Amount_Item_One__c + invL.Amount_Item_Two__c + invL.Amount_Item_Three__c;
            newInvoice.Total_Amount__c = sum ;
            update newInvoice;
        }
    }
}

And My Test Class is:

@isTest
public class TestInvoice
{
    @isTest
    public static void invoiceTest()
    {
        List<invoice_line_item__c> lst = Test.loadData(invoice_line_item__c.sobjectType, 'upload');
        
        
        for(invoice_line_item__c c :lst)
        {
            insert c;
        }
    }
}

If I create a new invoice__c in test class it works fine.

*Error I am getting : * INVALID_FIELD_FOR_INSERT_UPDATE, cannot specify Id in an insert call.

I am new to salesforce if someone can help it would be really helpful.

1
  • Your 'upload' csv file might be containing value in id column. can you please check and remove it. Oct 6 '20 at 16:55
3

The error itself is pretty straightforward. If your record has an Id already, then it cannot be inserted. Inserting a record is what gives it an Id in the first place. So trying to insert a record that already has an Id is not a valid operation.

Test.loadData() itself doesn't cause records to be inserted, so that means the static resource you're passing into Test.loadData() contains Id values. Modify your static resource file appropriately (so you don't have an Id column or Id values), re-upload it, and things should work better.

...but!

Your code (and test code) has some issues you should address.

Bad variable names are going to haunt you later

what is "lst"? what is "c"?

It's easy enough to see what they are now, when the amount of code you have is so small, but being more descriptive with your variable names will help you (and whoever inherits your code after you).

testInvoiceLineItems and invoiceLineItem are much better variable names (in your test class).

It's also helpful to have a convention for naming things. Something like:

  • Make class names TitleCase
  • Method names start with a lowercase letter, and then useCamelCase
  • Indicate a collection by using the plural (e.g. invoiceLineItems)

It doesn't matter what you settle on, just pick something, stick to it, and be consistent

DML inside of a loop

DML and Queries are things that should practically never appear inside of a loop. Salesforce only gives us so many of each for any given transaction, and putting queries or DML inside of a loop is a ticket on the express train to a governor limit exception.

The key to working on the Salesforce platform is to use collections (lists, sets, and maps) as much as you can.

You should remove the loop in your test class and just simply insert the list of records insert lst;

For the SUT (system under test, i.e. the trigger you're trying to test here), you also have DML inside of a loop. Generally, the appropriate way to do this is to add your records to a list (done inside of your loop). Then, once you're done looping, you perform dml on the entire list at once (as opposed to one at a time).

It's not very clear what your trigger is trying to do (are you trying to sum all invoice line items on a given invoice? are you trying to sum all line items and put them under a single invoice?), so it's hard to tell you what you should do specifically here.

You'll either want to create a list, or just keep adding to sum and set/update the invoice once. In both cases, you do not want to have DML inside of a loop.

Also, in both cases, this trigger is unlikely to do what you want it to.

If any of your Amount_Item_* fields are null, you'll run into an error

Math operators don't handle null values. You could do manual null checking (Amount_Item_One__c == null ? 0 : Amount_Item_One__c will return 0 if null, and the given amount if not null), but honestly, there's a better way to do this...

Sometimes, code isn't the best approach

You can do the work of summing your three Amount fields by creating a formula field on your Invoice_Line_Item__c SObject. Even better, you can tell formula fields how to handle null values ("treat blanks as zeroes" is the setting you'd want).

If you only want to sum up those values on each line item (and not roll the total up to the parent Invoice__c record), then your work would be done (no need for a trigger and no need for a test).

If you're trying to roll up data from child records to a parent record, you should consider making Invoice_Line_Item__c part of a master-detail relationship (Invoice is the parent/master, Invoice Line Item is the child/detail). That would allow you to create rollup summary field(s) on Invoice__c to do this work automatically (and without the need for a test).

If you combine both of these (formula field on Invoice Line Item, rollup summary on Invoice), then your work would be done.

If that's not a possibility, then you should look into Andrew Fawcett's Declarative Lookup Rollup Summary tool before trying to write your own trigger to do field roll-ups.

0

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.