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
bohemianguy100bohemianguy100 

bulk update failed: duplicate id

I was testing my trigger in dataloader and received the following error:

 

Error:

SalesInvoiceTotalsToOpportunity: execution of AfterUpdate

caused by: System.ListException: Duplicate id in list: 006S0000003fw8pIAA

Trigger.SalesInvoiceTotalsToOpportunity: line 55, column 2

 

trigger SalesInvoiceTotalsToOpportunity on Sales_Invoice__c (after insert, after update) {

	Set<Id> opIds = new Set<Id>();
	for (Sales_Invoice__c si : Trigger.new) {
		opIds.add(si.Opportunity__c);
	}
	
	List<Sales_Invoice__c> salesInvoiceList = [Select Opportunity__c, Date__c, Payment_Posting_Date__c, Subtotal__c, Amount_Paid__c From Sales_Invoice__c Where Opportunity__c in: opIds];
	
	Map<Id, List<Sales_Invoice__c>> oppyToSalesInvoiceMap = new Map<Id, List<Sales_Invoice__c>>();
	
	for (Sales_Invoice__c salesInvoice : salesInvoiceList) {
		
		List<Sales_Invoice__c> salesInvoices = oppyToSalesInvoiceMap.get(salesInvoice.Opportunity__c);
		if (salesInvoices == null) { 
			
			salesInvoices = new List<Sales_Invoice__c>();
			oppyToSalesInvoiceMap.put(salesInvoice.Opportunity__c, salesInvoices);
		}
		salesInvoices.add(salesInvoice);
	}
	
	List<Opportunity> opps = [Select Date_Paid__c, Date_Invoiced__c, Total_Invoiced_Amt__c, Total_Paid_Amt__c From Opportunity Where Id in: opIds];

	List<Opportunity> oppsToUpdate = new List<Opportunity>();
	
	for (Id oppyId : oppyToSalesInvoiceMap.keySet()) {
		Decimal invoicedAmt = 0;
		Decimal totalPaid = 0;
		List<Sales_Invoice__c> salesInvoices = oppyToSalesInvoiceMap.get(oppyId);
		for (Sales_Invoice__c salesInvoice : salesInvoices) {
			invoicedAmt =  invoicedAmt + salesInvoice.Subtotal__c;
			totalPaid = totalPaid + salesInvoice.Amount_Paid__c;
		}
		
		for (Opportunity o : opps) {
		o.Total_Invoiced_Amt__c = invoicedAmt;
		o.Total_Paid_Amt__c = totalPaid;
		oppsToUpdate.add(o);
		}
	}
	
	
	update oppsToUpdate;

}

 

How can I correct the trigger so it will work in bulk mode? 

Thanks.

SurekaSureka

Hi,

 

Instead of storing in the List, store the values in the "Set". Duplicate errors will be avoided automatically.

 

Thanks

bohemianguy100bohemianguy100

I'm not quite sure I understand.  A set of opportunities is not allowed:

 

Set<Opportunity> oppsToUpdate = new Set<Opportunity>();

 

I assume you mean to use the set elsewhere.  Can you explain?

 

Thanks.

frederic baudaxfrederic baudax

Hi,

 

I would simply replace the list by a map, maps don't store duplicate Id(s). Bear in mind that the latest record will be kept in the map so if  there are differences between the 2 (or more) opportunity occurances you will not keep track of the changes.

 

Hope this helps.

 

Kr,

Fred

bohemianguy100bohemianguy100

I changed to using a map as suggested and I'm not getting an error when updating using dataloader, but my invoice totals are incorrrect.  However, if I just update one record the invoice totals are correct.  Not sure why the totals are off when run in batch.

 

trigger SalesInvoiceTotalsToOpportunity on Sales_Invoice__c (after insert, after update) {

	Set<Id> opIds = new Set<Id>();
	for (Sales_Invoice__c si : Trigger.new) {
		opIds.add(si.Opportunity__c);
	}
	
	List<Sales_Invoice__c> salesInvoiceList = [Select Opportunity__c, Date__c, Payment_Posting_Date__c, Subtotal__c, Amount_Paid__c From Sales_Invoice__c Where Opportunity__c in: opIds];
	
	Map<Id, List<Sales_Invoice__c>> oppyToSalesInvoiceMap = new Map<Id, List<Sales_Invoice__c>>();
	
	for (Sales_Invoice__c salesInvoice : salesInvoiceList) {
		
		List<Sales_Invoice__c> salesInvoices = oppyToSalesInvoiceMap.get(salesInvoice.Opportunity​__c);
		if (salesInvoices == null) { 
			
			salesInvoices = new List<Sales_Invoice__c>();
			oppyToSalesInvoiceMap.put(salesInvoice.Opportunity​__c, salesInvoices);
		}
		salesInvoices.add(salesInvoice);
	}
	
	List<Opportunity> opps = [Select Date_Paid__c, Date_Invoiced__c, Total_Invoiced_Amt__c, Total_Paid_Amt__c From Opportunity Where Id in: opIds];

	Map<Id, Opportunity> oppsToUpdate = new List<Id, Opportunity>();
	
	for (Id oppyId : oppyToSalesInvoiceMap.keySet()) {
		Decimal invoicedAmt = 0;
		Decimal totalPaid = 0;
		List<Sales_Invoice__c> salesInvoices = oppyToSalesInvoiceMap.get(oppyId);
		for (Sales_Invoice__c salesInvoice : salesInvoices) {
			invoicedAmt =  invoicedAmt + salesInvoice.Subtotal__c;
			totalPaid = totalPaid + salesInvoice.Amount_Paid__c;
		}
		
		for (Opportunity o : opps) {
		o.Total_Invoiced_Amt__c = invoicedAmt;
		o.Total_Paid_Amt__c = totalPaid;
		oppsToUpdate.put(o.Id, o);
		}
	}
	
	
	update oppsToUpdate.values();

}

 

I'm totally all the invoices for a specific opportunity.  So, if there are three invoices for Opportunity A, I add the totals for the 3 invoices and update the total into the opportunity.  Again, this works for a single opportunity, but when I am running in batch for multiple opportunities, the summations are not correct.  Do you see where the error is occurring in my code?

 

Thanks.

frederic baudaxfrederic baudax

Strange, everything looks good but I’m not used with inner maps so I might be missing something.

 

One thought, if Opportunity has a master child relationship with Sales_Invoice__c  you could use a roll-up summary field on opportunity instead of using a trigger.

 

Kr,

Fred.