0

I have a trigger which seems to be working when I insert transactions one at a time but when trying to insert multiple records I recieve the error:

FATAL_ERROR System.DmlException: Insert failed. First exception on row 0 with id a1C4E000000Cz8NUAS; first error: INVALID_FIELD_FOR_INSERT_UPDATE, cannot specify Id in an insert call: [Id]

How should I restructure my trigger to account for multiple inserts. I understand I should be inserting my payment outside the loop but how do I call back the id after its inserted to use to update my tranaction prior to insert.

trigger TransactionInsertedTrigger on Transaction__c (before insert) {
    List<Asset> AssetList = new List<Asset>();
    List<asp04__authorisation__c> AuthList = new List<asp04__authorisation__c>();
    asp04__payment__c p = new asp04__payment__c();
    contract C = new contract();
    merchant_Account__c ma = new Merchant_Account__c();
    Contact mc = new Contact();

    for(Transaction__c t : trigger.new){
        if(Trigger.isInsert){
        AssetList = AsperatoController.findAssets(t.Contract__c);
        C = [SELECT Id, Name, Merchant_Account__c, Status, billingStreet, BillingCity, BillingPostalCode, BillingState, BillingCountry From Contract WHERE Id=:t.Contract__c];
        AuthList = AsperatoController.getAuth(C.Merchant_Account__c);
        ma = [select id, Main_Contact__c, Billing_Contact__c FROM Merchant_Account__c WHERE id=:c.Merchant_Account__c];
        mc = [SELECT FirstName, LastName, Email, Phone, MobilePhone FROM Contact Where id=:ma.Main_Contact__c];
        //Contact bc = [SELECT FirstName, LastName, Email, Phone, MobilePhone FROM Contact Where id=:ma.Billing_Contact__c];
        Decimal price=0.00;
        for(integer i = 0; i < AssetList.size(); i++) {
            if(AssetList[i].Name!='Additonal Fees - Gateway'){
            price = price + (((AssetList[i].Unit_Price__c) + ((t.Number_of_Transactions__c - AssetList[i].Inclusive_Transactions__c) * AssetList[i].Cost_for_non_exclusive_transactions__c)) * 1.20);
            System.debug('Check Values, Price =' + AssetList[i].Unit_Price__c + ' no of trans ' + t.Number_of_Transactions__c + 'inclusive ' + AssetList[i].Inclusive_Transactions__c + 'cost per ' + AssetList[i].Cost_for_non_exclusive_transactions__c);
            System.debug('total =' + price);
            }
        }
        //Generate payment with relevant info
        //After payment is inserted attach payment id to transaction obj
        //update trans obj
        if(t.payment_generated__c==false && C.status=='Activated'){
            p.asp04__Amount__c=price;
            p.asp04__Billing_Address_Street__c=c.BillingStreet;
            p.asp04__Billing_Address_City__c=c.BillingCity;
            p.asp04__Billing_Address_Country__c=c.BillingCountry;
            p.asp04__Billing_Address_PostalCode__c=c.BillingPostalCode;
            p.asp04__Billing_Address_State__c=c.BillingState;
            if(mc.LastName!=null){
                p.asp04__First_Name__c=mc.FirstName;
                p.asp04__Last_Name__c=mc.LastName;
            }
            //}
            p.asp04__Company_Name__c=c.Merchant_Account__c;
            p.asp04__Payment_Route_Options__c='Direct Debit';
            Date d = Date.newInstance(t.Billable_Month__c.year(), t.Billable_Month__c.month(),15);            
            p.asp04__Due_Date__c=d;
            p.Contract__c=t.Contract__c;
            p.Transaction_Payment__c=true;
            p.asp04__Authorisation__c=AuthList[0].Id;
            insert p;
            t.payment_generated__c=true;
            t.Related_Payment__c=p.id;
            System.debug('payment details : ' + p);

        }
    }
    }
}
3
  • I guess this is not happening in your trigger, but at the place, where you insert the record. Please also paste this code.
    – itsmebasti
    Nov 7, 2017 at 14:17
  • 2
    eh, DML inside a for loop is not bulkified and is also against best practices.
    – Raul
    Nov 7, 2017 at 14:19
  • declaring asp04__payment__c p = new asp04__payment__c(); inside for loop will resolve the issue temporarily. but to your trigger will fail for more records as you are using 3 soql and 1 dml in for loop try to get it out of loop. Nov 7, 2017 at 14:23

1 Answer 1

1

There are many things to improve in your code,

  1. You should NOT make queries inside a loop.
  2. You should NOT make DML statements in a loop.

An easy quick fix is to move

asp04__payment__c p = new asp04__payment__c();

inside the loop, for example after

if(t.payment_generated__c==false && C.status=='Activated'){

BUT what you should really use maps to keep the data, and only make queries once and use a List to add all your asp04__payment__c so you only do one insert.

2
  • Thanks I will look at bulkifying it and getting it up to standard
    – Nebbyyy
    Nov 7, 2017 at 14:42
  • Your problem was that the insert was putting the Id into p, so the second time it was going through it already had an Id. ;) Nov 7, 2017 at 14:44

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .