0

Sales Invoices are a custom child object of Opportunity. I'm trying to write a class that throws an error if the total of all sales invoices for a given opp goes above the opp's amount.

Currently it won't fire the first time you go over the opp amount, but then on subsequent edits to the invoice I get the following error:

MasterSalesInvoiceTrigger: execution of BeforeInsert caused by: System.FinalException: SObject row does not allow errors Class.SalesInvoice_InvoiceTotalValidation.validateTotals: line 30, column 1 Trigger.MasterSalesInvoiceTrigger: line 10, column 1

There are two issues:

  1. Error doesn't fire at all the first time the total goes over the opp amount and
  2. I get that error on subsequent edits.

I know its possible to do this with validation rules however to do so I would need to set one up that would fire on any edit to the opp and not just when the Sales Invoices are being inserted or the Total is changing. I'd prefer not to do that.

Here's my class:

public class SalesInvoice_InvoiceTotalValidation {

    List<Sales_Invoice__c> sInvoices = new List<Sales_Invoice__c>();
    public SalesInvoice_InvoiceTotalValidation(List<Sales_Invoice__c> trigSI){
        sInvoices = trigSI;
    }

    public void validateTotals (){
        Decimal siAmount = 0;
        Decimal oppTotal = 0;     
        Set<Id> oppSet = new Set<Id>();

        for(Sales_Invoice__c si : sInvoices){
            oppSet.add(si.Opportunity__c);
        }       

        List<Sales_Invoice__c> siList = [SELECT Total__c, Id, Opportunity__r.Amount
                                        FROM Sales_Invoice__c
                                        WHERE Opportunity__c =: oppSet];

        if(siList.size() > 0){
            for(Sales_Invoice__c si2 : siList){
                if(si2.Total__c == null){
                siAmount = siAmount + 0;
                } else {
                    siAmount = siAmount + si2.Total__c;
                }
                //Need error to fire if total is greater than opp amount
                if(siAmount > si2.Opportunity__r.Amount){
                si2.addError('Sales Invoice total cannot be greater than Opportunity Amount. Adjust opp amount and then adjust Sales Invoices.');
            }
            }


    }
    }
}

Here's the trigger calling it:

trigger MasterSalesInvoiceTrigger on Sales_Invoice__c (
  before insert, after insert, 
  before update, after update, 
  before delete, after delete,
  after undelete) {

  if (Trigger.isBefore) {
    if (Trigger.isInsert) {
        SalesInvoice_InvoiceTotalValidation itv = new SalesInvoice_InvoiceTotalValidation(Trigger.new);
        itv.validateTotals();

    } 
    if (Trigger.isUpdate) {
        SalesInvoice_InvoiceTotalValidation itv = new SalesInvoice_InvoiceTotalValidation(Trigger.new);
        itv.validateTotals();
            }
    if (Trigger.isDelete) {

    }
  }

  if (Trigger.IsAfter) {
    if (Trigger.isInsert) {

    } 
    if (Trigger.isUpdate) {

    }
    if (Trigger.isDelete) {

    }
    if (Trigger.isUndelete){

      }
  }
}

1 Answer 1

2

you can use addError method in trigger for records, that are in context in current trigger:

Usage

When used on Trigger.new in before insert and before update triggers, and on Trigger.old in before delete triggers, the error message is displayed in the application interface.


I suggest you to create container to store Sales Invoice context records by Opportunity__c. Before throwing an error get trigger context record from this map by Opportunity__c Id. Instead of line

si2.addError('Sales Invoice total cannot be greater than Opportunity Amount. Adjust opp amount and then adjust Sales Invoices.');

it will be

contextInvoicesByOppId.get(si2.Opportunity__c).addError('Sales Invoice total cannot be greater than Opportunity Amount. Adjust opp amount and then adjust Sales Invoices.');

whole your class will look like:

public class SalesInvoice_InvoiceTotalValidation {
    private List<Sales_Invoice__c> sInvoices = new List<Sales_Invoice__c>();
    private Map<Id, Sales_Invoice__c> contextInvoicesByOppId = new Map<Id, Sales_Invoice__c>();

    public SalesInvoice_InvoiceTotalValidation(List<Sales_Invoice__c> trigSI){
        sInvoices = trigSI;
        for(Sales_Invoice__c invoice :trigSI){
            if(invoice.Opportunity__c != null){
                contextInvoicesByOppId.put(invoice.Opportunity__c, invoice);
            }
        }
    }

    public void validateTotals (){
        Decimal siAmount = 0;
        Decimal oppTotal = 0;     
        Set<Id> oppSet = new Set<Id>();

        for(Sales_Invoice__c si : sInvoices){
            oppSet.add(si.Opportunity__c);
        }       

        List<Sales_Invoice__c> siList = [SELECT Total__c, Id, Opportunity__r.Amount, Opportunity__c
                                        FROM Sales_Invoice__c
                                        WHERE Opportunity__c =: oppSet];

        for(Sales_Invoice__c si2 : siList){
            if(si2.Total__c == null){
                siAmount = siAmount + 0;
            } else {
                siAmount = siAmount + si2.Total__c;
            }
            //Need error to fire if total is greater than opp amount
            if(siAmount > si2.Opportunity__r.Amount){
                contextInvoicesByOppId.get(si2.Opportunity__c).addError('Sales Invoice total cannot be greater than Opportunity Amount. Adjust opp amount and then adjust Sales Invoices.');
            }
        }
    }
}
1
  • Thank you very much Oleksandr. That seems to be doing the trick. Appreciate your help.
    – J. Rodden
    Commented Oct 25, 2018 at 11:01

You must log in to answer this question.

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