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);

        }
    }
    }
}
  • I guess this is not happening in your trigger, but at the place, where you insert the record. Please also paste this code. – Basti Nov 7 '17 at 14:17
  • 2
    eh, DML inside a for loop is not bulkified and is also against best practices. – Raul Nov 7 '17 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. – Amit Nov 7 '17 at 14:23
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.

  • Thanks I will look at bulkifying it and getting it up to standard – Nebbyyy Nov 7 '17 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. ;) – Sergio Alcocer Nov 7 '17 at 14:44

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.