## Full example

    // source: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_shopping_cart_example_code.htm

    trigger calculate on Item__c (after insert, after update, after delete) {

    // Use a map because it doesn't allow duplicate values

    Map<ID, Shipping_Invoice__C> updateMap = new Map<ID, Shipping_Invoice__C>();

    // Set this integer to -1 if we are deleting
    Integer subtract ;

    // Populate the list of items based on trigger type
    List<Item__c> itemList;
    	if(trigger.isInsert || trigger.isUpdate){
    		itemList = Trigger.new;
    		subtract = 1;
    	}
    	else if(trigger.isDelete)
    	{
    		// Note -- there is no trigger.new in delete
    		itemList = trigger.old;
    		subtract = -1;
    	}

    // Access all the information we need in a single query
    // rather than querying when we need it.
    // This is a best practice for bulkifying requests

    set<Id> AllItems = new set<id>();

    for(item__c i :itemList){
    // Assert numbers are not negative.
    // None of the fields would make sense with a negative value

    System.assert(i.quantity__c > 0, 'Quantity must be positive');
    System.assert(i.weight__c >= 0, 'Weight must be non-negative');
    System.assert(i.price__c >= 0, 'Price must be non-negative');

    // If there is a duplicate Id, it won't get added to a set
    AllItems.add(i.Shipping_Invoice__C);
    }

    // Accessing all shipping invoices associated with the items in the trigger
    List<Shipping_Invoice__C> AllShippingInvoices = [SELECT Id, ShippingDiscount__c,
                       SubTotal__c, TotalWeight__c, Tax__c, GrandTotal__c
                       FROM Shipping_Invoice__C WHERE Id IN :AllItems];

    // Take the list we just populated and put it into a Map.
    // This will make it easier to look up a shipping invoice
    // because you must iterate a list, but you can use lookup for a map,
    Map<ID, Shipping_Invoice__C> SIMap = new Map<ID, Shipping_Invoice__C>();

    for(Shipping_Invoice__C sc : AllShippingInvoices)
    {
    	SIMap.put(sc.id, sc);
    }

    // Process the list of items
    	if(Trigger.isUpdate)
    	{
    		// Treat updates like a removal of the old item and addition of the
    		// revised item rather than figuring out the differences of each field
    		// and acting accordingly.
    		// Note updates have both trigger.new and trigger.old
    		for(Integer x = 0; x < Trigger.old.size(); x++)
    		{
    			Shipping_Invoice__C myOrder;
    			myOrder = SIMap.get(trigger.old[x].Shipping_Invoice__C);

    			// Decrement the previous value from the subtotal and weight.
    			myOrder.SubTotal__c -= (trigger.old[x].price__c *
    			                        trigger.old[x].quantity__c);
    			myOrder.TotalWeight__c -= (trigger.old[x].weight__c *
    			                           trigger.old[x].quantity__c);

    			// Increment the new subtotal and weight.
    			myOrder.SubTotal__c += (trigger.new[x].price__c *
    			                        trigger.new[x].quantity__c);
    			myOrder.TotalWeight__c += (trigger.new[x].weight__c *
    			                           trigger.new[x].quantity__c);
    		}

    		for(Shipping_Invoice__C myOrder : AllShippingInvoices)
    		{

    			// Set tax rate to 9.25%  Please note, this is a simple example.
    			// Generally, you would never hard code values.
    			// Leveraging Custom Settings for tax rates is a best practice.
    			// See Custom Settings in the Apex Developer Guide
    			// for more information.
    			myOrder.Tax__c = myOrder.Subtotal__c * .0925;

    			// Reset the shipping discount
    			myOrder.ShippingDiscount__c = 0;

    			// Set shipping rate to 75 cents per pound.
    			// Generally, you would never hard code values.
    			// Leveraging Custom Settings for the shipping rate is a best practice.
    			// See Custom Settings in the Apex Developer Guide
    			// for more information.
    			myOrder.Shipping__c = (myOrder.totalWeight__c * .75);
    			myOrder.GrandTotal__c = myOrder.SubTotal__c + myOrder.tax__c +
    			                        myOrder.Shipping__c;
    			updateMap.put(myOrder.id, myOrder);
    		}
    	}
    	else
    	{
    		for(Item__c itemToProcess : itemList)
    		{
    			Shipping_Invoice__C myOrder;

    			// Look up the correct shipping invoice from the ones we got earlier
    			myOrder = SIMap.get(itemToProcess.Shipping_Invoice__C);
    			myOrder.SubTotal__c += (itemToProcess.price__c *
    			                        itemToProcess.quantity__c * subtract);
    			myOrder.TotalWeight__c += (itemToProcess.weight__c *
    			                           itemToProcess.quantity__c * subtract);
    		}

    		for(Shipping_Invoice__C myOrder : AllShippingInvoices)
    		{

    			// Set tax rate to 9.25%  Please note, this is a simple example.
    			// Generally, you would never hard code values.
    			// Leveraging Custom Settings for tax rates is a best practice.
    			// See Custom Settings in the Apex Developer Guide
    			// for more information.
    			myOrder.Tax__c = myOrder.Subtotal__c * .0925;

    			// Reset shipping discount
    			myOrder.ShippingDiscount__c = 0;

    			// Set shipping rate to 75 cents per pound.
    			// Generally, you would never hard code values.
    			// Leveraging Custom Settings for the shipping rate is a best practice.
    			// See Custom Settings in the Apex Developer Guide
    			// for more information.
    			myOrder.Shipping__c = (myOrder.totalWeight__c * .75);
    			myOrder.GrandTotal__c = myOrder.SubTotal__c + myOrder.tax__c +
    			                        myOrder.Shipping__c;

    			updateMap.put(myOrder.id, myOrder);

    		}
    	}

    	// Only use one DML update at the end.
    	// This minimizes the number of DML requests generated from this trigger.
    	update updateMap.values();
    }