Newer Version Available

This content describes an older version of this product. View Latest

Shipping Invoice Example Code

The following triggers and test class make up the shipping invoice example application:

Calculate Trigger

1swfobject.registerObject("clippy.codeblock-0", "9");
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17trigger calculate on Item__c (after insert, after update, after delete) {
18
19// Use a map because it doesn't allow duplicate values
20
21Map<ID, Shipping_Invoice__C> updateMap = new Map<ID, Shipping_Invoice__C>();
22
23// Set this integer to -1 if we are deleting
24Integer subtract ;
25
26// Populate the list of items based on trigger type
27List<Item__c> itemList;
28    if(trigger.isInsert || trigger.isUpdate){
29        itemList = Trigger.new;
30        subtract = 1;
31    }
32    else if(trigger.isDelete)
33    {
34        // Note -- there is no trigger.new in delete
35        itemList = trigger.old;
36        subtract = -1;
37    }
38
39// Access all the information we need in a single query 
40// rather than querying when we need it.
41// This is a best practice for bulkifying requests
42
43set<Id> AllItems = new set<id>();
44
45for(item__c i :itemList){
46// Assert numbers are not negative.  
47// None of the fields would make sense with a negative value
48
49System.assert(i.quantity__c > 0, 'Quantity must be positive');
50System.assert(i.weight__c >= 0, 'Weight must be non-negative');
51System.assert(i.price__c >= 0, 'Price must be non-negative');
52
53// If there is a duplicate Id, it won't get added to a set
54AllItems.add(i.Shipping_Invoice__C);
55}
56
57// Accessing all shipping invoices associated with the items in the trigger
58List<Shipping_Invoice__C> AllShippingInvoices = [SELECT Id, ShippingDiscount__c, 
59                   SubTotal__c, TotalWeight__c, Tax__c, GrandTotal__c 
60                   FROM Shipping_Invoice__C WHERE Id IN :AllItems];
61                   
62// Take the list we just populated and put it into a Map.  
63// This will make it easier to look up a shipping invoice
64// because you must iterate a list, but you can use lookup for a map, 
65Map<ID, Shipping_Invoice__C> SIMap = new Map<ID, Shipping_Invoice__C>();
66
67for(Shipping_Invoice__C sc : AllShippingInvoices)
68{
69    SIMap.put(sc.id, sc);
70}
71
72// Process the list of items
73    if(Trigger.isUpdate)
74    {
75        // Treat updates like a removal of the old item and addition of the         
76        // revised item rather than figuring out the differences of each field 
77        // and acting accordingly.
78        // Note updates have both trigger.new and trigger.old
79        for(Integer x = 0; x < Trigger.old.size(); x++)
80        {
81            Shipping_Invoice__C myOrder;
82            myOrder = SIMap.get(trigger.old[x].Shipping_Invoice__C);
83
84            // Decrement the previous value from the subtotal and weight.
85            myOrder.SubTotal__c -= (trigger.old[x].price__c * 
86                                    trigger.old[x].quantity__c);
87            myOrder.TotalWeight__c -= (trigger.old[x].weight__c * 
88                                       trigger.old[x].quantity__c);
89                
90            // Increment the new subtotal and weight.
91            myOrder.SubTotal__c += (trigger.new[x].price__c * 
92                                    trigger.new[x].quantity__c);
93            myOrder.TotalWeight__c += (trigger.new[x].weight__c * 
94                                       trigger.new[x].quantity__c);
95        }
96        
97        for(Shipping_Invoice__C myOrder : AllShippingInvoices)
98        {
99            
100            // Set tax rate to 9.25%  Please note, this is a simple example.  
101            // Generally, you would never hard code values.
102            // Leveraging Custom Settings for tax rates is a best practice.  
103            // See Custom Settings in the Apex Developer's guide 
104            // for more information.
105            myOrder.Tax__c = myOrder.Subtotal__c * .0925;
106            
107            // Reset the shipping discount
108            myOrder.ShippingDiscount__c = 0;
109    
110            // Set shipping rate to 75 cents per pound.  
111            // Generally, you would never hard code values.
112            // Leveraging Custom Settings for the shipping rate is a best practice.
113            // See Custom Settings in the Apex Developer's guide 
114            // for more information.
115            myOrder.Shipping__c = (myOrder.totalWeight__c * .75);
116            myOrder.GrandTotal__c = myOrder.SubTotal__c + myOrder.tax__c + 
117                                    myOrder.Shipping__c;
118            updateMap.put(myOrder.id, myOrder);
119         }
120    }
121    else
122    { 
123        for(Item__c itemToProcess : itemList)
124        {
125            Shipping_Invoice__C myOrder;
126    
127            // Look up the correct shipping invoice from the ones we got earlier
128            myOrder = SIMap.get(itemToProcess.Shipping_Invoice__C);
129            myOrder.SubTotal__c += (itemToProcess.price__c * 
130                                    itemToProcess.quantity__c * subtract);
131            myOrder.TotalWeight__c += (itemToProcess.weight__c * 
132                                       itemToProcess.quantity__c * subtract);
133        }
134        
135        for(Shipping_Invoice__C myOrder : AllShippingInvoices)
136        {
137            
138             // Set tax rate to 9.25%  Please note, this is a simple example.  
139             // Generally, you would never hard code values.
140             // Leveraging Custom Settings for tax rates is a best practice.  
141             // See Custom Settings in the Apex Developer's guide 
142             // for more information.
143             myOrder.Tax__c = myOrder.Subtotal__c * .0925;
144             
145             // Reset shipping discount
146             myOrder.ShippingDiscount__c = 0;
147    
148            // Set shipping rate to 75 cents per pound.  
149            // Generally, you would never hard code values.
150            // Leveraging Custom Settings for the shipping rate is a best practice.
151            // See Custom Settings in the Apex Developer's guide 
152            // for more information.
153            myOrder.Shipping__c = (myOrder.totalWeight__c * .75);
154            myOrder.GrandTotal__c = myOrder.SubTotal__c + myOrder.tax__c + 
155                                    myOrder.Shipping__c;
156                                       
157            updateMap.put(myOrder.id, myOrder);
158    
159         }
160     }    
161     
162     // Only use one DML update at the end.
163     // This minimizes the number of DML requests generated from this trigger.
164     update updateMap.values();
165}
166

ShippingDiscount Trigger

1swfobject.registerObject("clippy.codeblock-1", "9");
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17trigger ShippingDiscount on Shipping_Invoice__C (before update) {
18    // Free shipping on all orders greater than $100
19    
20    for(Shipping_Invoice__C myShippingInvoice : Trigger.new)
21    {
22        if((myShippingInvoice.subtotal__c >= 100.00) && 
23           (myShippingInvoice.ShippingDiscount__c == 0))
24        {
25            myShippingInvoice.ShippingDiscount__c = 
26                         myShippingInvoice.Shipping__c * -1;
27            myShippingInvoice.GrandTotal__c += myShippingInvoice.ShippingDiscount__c;
28        }
29    }
30}
31

Shipping Invoice Test

1swfobject.registerObject("clippy.codeblock-2", "9");
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17@IsTest
18private class TestShippingInvoice{
19
20    // Test for inserting three items at once
21    public static testmethod void testBulkItemInsert(){
22        // Create the shipping invoice. It's a best practice to either use defaults
23        // or to explicitly set all values to zero so as to avoid having
24        // extraneous data in your test.
25        Shipping_Invoice__C order1 = new Shipping_Invoice__C(subtotal__c = 0, 
26                          totalweight__c = 0, grandtotal__c = 0, 
27                          ShippingDiscount__c = 0, Shipping__c = 0, tax__c = 0);
28
29        // Insert the order and populate with items
30        insert Order1;
31        List<Item__c> list1 = new List<Item__c>();
32        Item__c item1 = new Item__C(Price__c = 10, weight__c = 1, quantity__c = 1, 
33                                    Shipping_Invoice__C = order1.id);
34        Item__c item2 = new Item__C(Price__c = 25, weight__c = 2, quantity__c = 1, 
35                                    Shipping_Invoice__C = order1.id);
36        Item__c item3 = new Item__C(Price__c = 40, weight__c = 3, quantity__c = 1, 
37                                    Shipping_Invoice__C = order1.id);
38        list1.add(item1);
39        list1.add(item2);
40        list1.add(item3);
41        insert list1;
42        
43        // Retrieve the order, then do assertions
44        order1 = [SELECT id, subtotal__c, tax__c, shipping__c, totalweight__c, 
45                  grandtotal__c, shippingdiscount__c 
46                  FROM Shipping_Invoice__C 
47                  WHERE id = :order1.id];
48        
49        System.assert(order1.subtotal__c == 75, 
50                'Order subtotal was not $75, but was '+ order1.subtotal__c);
51        System.assert(order1.tax__c == 6.9375, 
52                'Order tax was not $6.9375, but was ' + order1.tax__c);
53        System.assert(order1.shipping__c == 4.50, 
54                'Order shipping was not $4.50, but was ' + order1.shipping__c);
55        System.assert(order1.totalweight__c == 6.00, 
56                'Order weight was not 6 but was ' + order1.totalweight__c);
57        System.assert(order1.grandtotal__c == 86.4375, 
58                'Order grand total was not $86.4375 but was ' 
59                 + order1.grandtotal__c);
60        System.assert(order1.shippingdiscount__c == 0, 
61                'Order shipping discount was not $0 but was ' 
62                + order1.shippingdiscount__c);
63    }
64    
65    // Test for updating three items at once
66    public static testmethod void testBulkItemUpdate(){
67
68        // Create the shipping invoice. It's a best practice to either use defaults
69        // or to explicitly set all values to zero so as to avoid having
70        // extraneous data in your test.
71        Shipping_Invoice__C order1 = new Shipping_Invoice__C(subtotal__c = 0, 
72                          totalweight__c = 0, grandtotal__c = 0, 
73                          ShippingDiscount__c = 0, Shipping__c = 0, tax__c = 0);
74
75        // Insert the order and populate with items.
76        insert Order1;
77        List<Item__c> list1 = new List<Item__c>();
78        Item__c item1 = new Item__C(Price__c = 1, weight__c = 1, quantity__c = 1, 
79                                    Shipping_Invoice__C = order1.id);
80        Item__c item2 = new Item__C(Price__c = 2, weight__c = 2, quantity__c = 1, 
81                                    Shipping_Invoice__C = order1.id);
82        Item__c item3 = new Item__C(Price__c = 4, weight__c = 3, quantity__c = 1, 
83                                    Shipping_Invoice__C = order1.id);
84        list1.add(item1);
85        list1.add(item2);
86        list1.add(item3);
87        insert list1;
88        
89        // Update the prices on the 3 items
90        list1[0].price__c = 10;
91        list1[1].price__c = 25;
92        list1[2].price__c = 40;
93        update list1;
94        
95        // Access the order and assert items updated
96        order1 = [SELECT id, subtotal__c, tax__c, shipping__c, totalweight__c, 
97                  grandtotal__c, shippingdiscount__c 
98                  FROM Shipping_Invoice__C 
99                  WHERE Id = :order1.Id];
100
101        System.assert(order1.subtotal__c == 75, 
102                       'Order subtotal was not $75, but was '+ order1.subtotal__c);
103        System.assert(order1.tax__c == 6.9375, 
104                       'Order tax was not $6.9375, but was ' + order1.tax__c);
105        System.assert(order1.shipping__c == 4.50, 
106                       'Order shipping was not $4.50, but was ' 
107                       + order1.shipping__c);
108        System.assert(order1.totalweight__c == 6.00, 
109                       'Order weight was not 6 but was ' + order1.totalweight__c);
110        System.assert(order1.grandtotal__c == 86.4375, 
111                       'Order grand total was not $86.4375 but was ' 
112                       + order1.grandtotal__c);
113        System.assert(order1.shippingdiscount__c == 0, 
114                       'Order shipping discount was not $0 but was ' 
115                       + order1.shippingdiscount__c);
116    
117    }
118    
119    // Test for deleting items
120    public static testmethod void testBulkItemDelete(){
121
122        // Create the shipping invoice. It's a best practice to either use defaults
123        // or to explicitly set all values to zero so as to avoid having
124        // extraneous data in your test.
125        Shipping_Invoice__C order1 = new Shipping_Invoice__C(subtotal__c = 0, 
126                          totalweight__c = 0, grandtotal__c = 0, 
127                          ShippingDiscount__c = 0, Shipping__c = 0, tax__c = 0);
128
129        // Insert the order and populate with items
130        insert Order1;
131        List<Item__c> list1 = new List<Item__c>();
132        Item__c item1 = new Item__C(Price__c = 10, weight__c = 1, quantity__c = 1, 
133                                    Shipping_Invoice__C = order1.id);
134        Item__c item2 = new Item__C(Price__c = 25, weight__c = 2, quantity__c = 1, 
135                                    Shipping_Invoice__C = order1.id);
136        Item__c item3 = new Item__C(Price__c = 40, weight__c = 3, quantity__c = 1, 
137                                    Shipping_Invoice__C = order1.id);
138        Item__c itemA = new Item__C(Price__c = 1, weight__c = 3, quantity__c = 1, 
139                                    Shipping_Invoice__C = order1.id);
140        Item__c itemB = new Item__C(Price__c = 1, weight__c = 3, quantity__c = 1, 
141                                    Shipping_Invoice__C = order1.id);
142        Item__c itemC = new Item__C(Price__c = 1, weight__c = 3, quantity__c = 1, 
143                                    Shipping_Invoice__C = order1.id);
144        Item__c itemD = new Item__C(Price__c = 1, weight__c = 3, quantity__c = 1, 
145                                    Shipping_Invoice__C = order1.id);
146        list1.add(item1);
147        list1.add(item2);
148        list1.add(item3);
149        list1.add(itemA);
150        list1.add(itemB);
151        list1.add(itemC);
152        list1.add(itemD);
153        insert list1;
154        
155        // Seven items are now in the shipping invoice. 
156       // The following deletes four of them.
157        List<Item__c> list2 = new List<Item__c>();
158        list2.add(itemA);
159        list2.add(itemB);
160        list2.add(itemC);
161        list2.add(itemD);
162        delete list2;
163        
164        // Retrieve the order and verify the deletion
165        order1 = [SELECT id, subtotal__c, tax__c, shipping__c, totalweight__c, 
166                  grandtotal__c, shippingdiscount__c 
167                  FROM Shipping_Invoice__C 
168                  WHERE Id = :order1.Id];
169        
170        System.assert(order1.subtotal__c == 75, 
171                      'Order subtotal was not $75, but was '+ order1.subtotal__c);
172        System.assert(order1.tax__c == 6.9375, 
173                      'Order tax was not $6.9375, but was ' + order1.tax__c);
174        System.assert(order1.shipping__c == 4.50, 
175                      'Order shipping was not $4.50, but was ' + order1.shipping__c);
176        System.assert(order1.totalweight__c == 6.00, 
177                      'Order weight was not 6 but was ' + order1.totalweight__c);
178        System.assert(order1.grandtotal__c == 86.4375, 
179                      'Order grand total was not $86.4375 but was ' 
180                      + order1.grandtotal__c);
181        System.assert(order1.shippingdiscount__c == 0, 
182                      'Order shipping discount was not $0 but was ' 
183                      + order1.shippingdiscount__c);
184    }
185    // Testing free shipping
186    public static testmethod void testFreeShipping(){
187
188        // Create the shipping invoice. It's a best practice to either use defaults
189        // or to explicitly set all values to zero so as to avoid having
190        // extraneous data in your test.
191        Shipping_Invoice__C order1 = new Shipping_Invoice__C(subtotal__c = 0, 
192                          totalweight__c = 0, grandtotal__c = 0, 
193                          ShippingDiscount__c = 0, Shipping__c = 0, tax__c = 0);
194
195        // Insert the order and populate with items.
196        insert Order1;
197        List<Item__c> list1 = new List<Item__c>();
198        Item__c item1 = new Item__C(Price__c = 10, weight__c = 1, 
199                                 quantity__c = 1, Shipping_Invoice__C = order1.id);
200        Item__c item2 = new Item__C(Price__c = 25, weight__c = 2, 
201                                 quantity__c = 1, Shipping_Invoice__C = order1.id);
202        Item__c item3 = new Item__C(Price__c = 40, weight__c = 3, 
203                                 quantity__c = 1, Shipping_Invoice__C = order1.id);
204        list1.add(item1);
205        list1.add(item2);
206        list1.add(item3);
207        insert list1;
208        
209        // Retrieve the order and verify free shipping not applicable
210        order1 = [SELECT id, subtotal__c, tax__c, shipping__c, totalweight__c, 
211                  grandtotal__c, shippingdiscount__c 
212                  FROM Shipping_Invoice__C 
213                  WHERE Id = :order1.Id];
214        
215        // Free shipping not available on $75 orders
216        System.assert(order1.subtotal__c == 75, 
217                      'Order subtotal was not $75, but was '+ order1.subtotal__c);
218        System.assert(order1.tax__c == 6.9375, 
219                      'Order tax was not $6.9375, but was ' + order1.tax__c);
220        System.assert(order1.shipping__c == 4.50, 
221                      'Order shipping was not $4.50, but was ' + order1.shipping__c);
222        System.assert(order1.totalweight__c == 6.00, 
223                      'Order weight was not 6 but was ' + order1.totalweight__c);
224        System.assert(order1.grandtotal__c == 86.4375, 
225                      'Order grand total was not $86.4375 but was ' 
226                      + order1.grandtotal__c);
227        System.assert(order1.shippingdiscount__c == 0, 
228                      'Order shipping discount was not $0 but was ' 
229                      + order1.shippingdiscount__c);
230        
231        // Add items to increase subtotal
232        item1 = new Item__C(Price__c = 25, weight__c = 20, quantity__c = 1, 
233                            Shipping_Invoice__C = order1.id);       
234        insert item1;
235
236        // Retrieve the order and verify free shipping is applicable
237        order1 = [SELECT id, subtotal__c, tax__c, shipping__c, totalweight__c, 
238                  grandtotal__c, shippingdiscount__c 
239                  FROM Shipping_Invoice__C 
240                  WHERE Id = :order1.Id];
241        
242        // Order total is now at $100, so free shipping should be enabled
243        System.assert(order1.subtotal__c == 100, 
244                      'Order subtotal was not $100, but was '+ order1.subtotal__c);
245        System.assert(order1.tax__c == 9.25, 
246                      'Order tax was not $9.25, but was ' + order1.tax__c);
247        System.assert(order1.shipping__c == 19.50, 
248                      'Order shipping was not $19.50, but was ' 
249                      + order1.shipping__c);
250        System.assert(order1.totalweight__c == 26.00, 
251                      'Order weight was not 26 but was ' + order1.totalweight__c);
252        System.assert(order1.grandtotal__c == 109.25, 
253                      'Order grand total was not $86.4375 but was ' 
254                      + order1.grandtotal__c);
255        System.assert(order1.shippingdiscount__c == -19.50, 
256                      'Order shipping discount was not -$19.50 but was ' 
257                      + order1.shippingdiscount__c);
258    }
259    
260     // Negative testing for inserting bad input
261    public static testmethod void testNegativeTests(){
262
263        // Create the shipping invoice. It's a best practice to either use defaults
264        // or to explicitly set all values to zero so as to avoid having
265        // extraneous data in your test.
266        Shipping_Invoice__C order1 = new Shipping_Invoice__C(subtotal__c = 0, 
267                          totalweight__c = 0, grandtotal__c = 0, 
268                          ShippingDiscount__c = 0, Shipping__c = 0, tax__c = 0);
269
270        // Insert the order and populate with items. 
271        insert Order1;
272        Item__c item1 = new Item__C(Price__c = -10, weight__c = 1, quantity__c = 1, 
273                                    Shipping_Invoice__C = order1.id);
274        Item__c item2 = new Item__C(Price__c = 25, weight__c = -2, quantity__c = 1, 
275                                    Shipping_Invoice__C = order1.id);
276        Item__c item3 = new Item__C(Price__c = 40, weight__c = 3, quantity__c = -1, 
277                                    Shipping_Invoice__C = order1.id);
278        Item__c item4 = new Item__C(Price__c = 40, weight__c = 3, quantity__c = 0, 
279                                    Shipping_Invoice__C = order1.id);
280
281        try{
282            insert item1;
283        }
284        catch(Exception e)
285        {
286            system.assert(e.getMessage().contains('Price must be non-negative'), 
287                         'Price was negative but was not caught');
288        }
289        
290        try{
291            insert item2;
292        }
293        catch(Exception e)
294        {
295            system.assert(e.getMessage().contains('Weight must be non-negative'), 
296                         'Weight was negative but was not caught');
297        }
298
299        try{
300            insert item3;
301        }
302        catch(Exception e)
303        {
304            system.assert(e.getMessage().contains('Quantity must be positive'), 
305                         'Quantity was negative but was not caught');
306        }
307        
308        try{
309            insert item4;
310        }
311        catch(Exception e)
312        {
313            system.assert(e.getMessage().contains('Quantity must be positive'), 
314                         'Quantity was zero but was not caught');
315        }
316    }
317}
318