Today's blog post we will show you how to add an externally created FedEx tracking numbers to an object. Updating tracking is the most common use case, that you are then able to query using the standard Salesforce reporting. We’ll be using the Order object in our demo here.
The code is made up of 3 parts.
- Trigger on the Order Object:
Line 3: For when a brand new order is added with a tracking number
Line 7: For when the tracking number field is updated
trigger Add_Shipment_Manually on Order (after update, after insert) { | |
if (AddShipmentManuallyHandler.enablesTrigger) { | |
if (Trigger.isAfter && Trigger.isInsert) { | |
AddShipmentManuallyHandler.createOrderShipments(Trigger.new, null); | |
} | |
if (Trigger.isAfter && Trigger.isUpdate) { | |
AddShipmentManuallyHandler.createOrderShipments(Trigger.new, Trigger.old); | |
} | |
} | |
} |
1. The trigger Handler class:
This is where the work gets done.
Line 4: Here you will need to contact us to get the ModKey value that allows the creation of a Shipment Object (without actually going through our package for the shipment creation process).
Line 8: You need to create a custom setting to store the ID of the preference, so that when you move this code from your sandbox org to your production org, its easy to update the custom setting to your saved UPS preference.

Line 19-30: For any new Orders, add the new record to the createFedExShipment method.
Line 30-47: If you are just updating the tracking number field (FB_Tracking_Numbers__c) on your Order, these lines take care of the shipment creation.
Line 67-75: For each shipment we create we also need to create a shipment package (zkfedex__ShipmentPackage__c) associated with it.
public class AddShipmentManuallyHandler { | |
public static Boolean enablesTrigger = true; | |
private static final String FEDEX_ZKMODKEY = 'CONTACT US AT SUPPORT@ZENKRAFT.COM'; | |
private static final String KEY_FEDEX = 'FedEx'; | |
private static zkfedex__ShipmatePreference__c fedexShipmatePreference; | |
public static void createOrderShipments(List<Order> newRecords, List<Order> oldRecords) { | |
initPreferences(); | |
if (!canCreateShipment(KEY_FEDEX)) { | |
return; | |
} | |
List<zkfedex__Shipment__c> fedexShipmentsForInsert = new List<zkfedex__Shipment__c>(); | |
// collect ids | |
if (oldRecords == null) { // insert, undelete | |
for (Order newRecord: newRecords) { | |
// logic for insert and undelete | |
if (String.isNotBlank(newRecord.FB_Tracking_Numbers__c)) { | |
if(isOrderForFedEx(newRecord) | |
&& canCreateShipment(KEY_FEDEX) | |
&& newRecord.EffectiveDate != null) { | |
fedexShipmentsForInsert.add(createFedExShipment(newRecord)); | |
} | |
} | |
} | |
} else { | |
if (newRecords != null) { // update | |
for (Integer i = 0; i < newRecords.size(); i++) { | |
Order oldRecord = oldRecords.get(i); | |
Order newRecord = newRecords.get(i); | |
// logic for update | |
if (String.isNotBlank(newRecord.FB_Tracking_Numbers__c) | |
&& newRecord.FB_Tracking_Numbers__c != oldRecord.FB_Tracking_Numbers__c) { | |
if(isOrderForFedEx(newRecord) | |
&& canCreateShipment(KEY_FEDEX) | |
&& newRecord.EffectiveDate != null) { | |
fedexShipmentsForInsert.add(createFedExShipment(newRecord)); | |
} | |
} | |
} | |
} else { // delete | |
// for (Order detail: oldRecords) { | |
// logic for delete | |
// } | |
} | |
} | |
if (fedexShipmentsForInsert != null && !fedexShipmentsForInsert.isEmpty()) { | |
insert fedexShipmentsForInsert; | |
Map<Id, zkfedex__Package__c> shipmentIdPackageMap = new Map<Id, zkfedex__Package__c>(); | |
for (zkfedex__Shipment__c fedexShipment : fedexShipmentsForInsert) { | |
shipmentIdPackageMap.put(fedexShipment.Id, new zkfedex__Package__c()); | |
} | |
insert shipmentIdPackageMap.values(); | |
List<zkfedex__ShipmentPackage__c> shipPackages = new List<zkfedex__ShipmentPackage__c>(); | |
zkfedex__ShipmentPackage__c shipPackage; | |
for (zkfedex__Shipment__c fedexShipment : fedexShipmentsForInsert) { | |
shipPackage = new zkfedex__ShipmentPackage__c(); | |
shipPackage.zkfedex__Shipment__c = fedexShipment.Id; | |
shipPackage.zkfedex__TrackingId__c = fedexShipment.zkfedex__MasterTrackingId__c; | |
// shipPackage.zkfedex__TrackingIdType__c | |
shipPackage.zkfedex__Package__c = shipmentIdPackageMap.get(fedexShipment.Id).Id; | |
shipPackages.add(shipPackage); | |
} | |
insert shipPackages; | |
} | |
} | |
private static zkfedex__Shipment__c createFedExShipment(Order order) { | |
zkfedex__Shipment__c shipment = new zkfedex__Shipment__c(); | |
shipment.zkfedex__MasterTrackingId__c = order.FB_Tracking_Numbers__c; | |
shipment.zkfedex__ShipDate__c = order.EffectiveDate; | |
shipment.zkfedex__ShipmatePreference__c = fedexShipmatePreference.Id; | |
// shipment.zkfedex__RecipientCountry__c = 'US'; | |
shipment.zkfedex__ModKey__c = FEDEX_ZKMODKEY; | |
shipment.Order__c = order.Id; | |
return shipment; | |
} | |
private static Boolean isOrderForFedEx(Order order) { | |
return order.FB_Carrier__c == 'FedEx'; | |
} | |
private static Boolean canCreateShipment(String carrier) { | |
if (carrier == KEY_FEDEX) { | |
return (fedexShipmatePreference != null); | |
} | |
return false; | |
} | |
private static void initPreferences() { | |
ShipmentSettings__c shipmentFedExSettings = ShipmentSettings__c.getInstance(KEY_FEDEX); | |
if (shipmentFedExSettings != null | |
&& String.isNotBlank(shipmentFedExSettings.Shipment_Preference_Id__c)) { | |
List<zkfedex__ShipmatePreference__c> fedexPreferences = [ | |
SELECT Id, Name | |
FROM zkfedex__ShipmatePreference__c | |
WHERE Id =: shipmentFedExSettings.Shipment_Preference_Id__c | |
LIMIT 1]; | |
if (fedexPreferences != null | |
&& !fedexPreferences.isEmpty()) { | |
AddShipmentManuallyHandler.fedexShipmatePreference = fedexPreferences[0]; | |
} | |
} | |
} | |
} |
1. The @Test class, is needed for the code coverage to be able to deploy into production.
@isTest | |
private class AddShipmentManuallyHandlerTest { | |
static testMethod void test_createFedExShipments() { | |
zkfedex__ShipmatePreference__c preference = new zkfedex__ShipmatePreference__c(); | |
insert preference; | |
ShipmentSettings__c shipmentSettings = new ShipmentSettings__c(); | |
shipmentSettings.Name = 'FedEx'; | |
shipmentSettings.Shipment_Preference_Id__c = preference.Id; | |
insert shipmentSettings; | |
String trackNumber = 'trackNumber'; | |
Account acc = new Account(); | |
acc.Name = 'Account'; | |
insert acc; | |
Order ord = new Order(); | |
ord.FB_Tracking_Numbers__c = trackNumber; | |
ord.AccountId = acc.Id; | |
ord.Status = 'Draft'; | |
ord.EffectiveDate = Date.today(); | |
ord.FB_Carrier__c = 'FedEx'; | |
Test.startTest(); | |
insert ord; | |
checkFedExShipmentExists(trackNumber, ord.EffectiveDate); | |
ord.FB_Tracking_Numbers__c = trackNumber + '1'; | |
update ord; | |
checkFedExShipmentExists(trackNumber + '1', ord.EffectiveDate); | |
Test.stopTest(); | |
} | |
private static void checkFedExShipmentExists(String trackNumber, Date shipDate){ | |
List<zkfedex__Shipment__c> shipments = [ | |
SELECT Id, zkfedex__MasterTrackingId__c, zkfedex__ShipDate__c | |
FROM zkfedex__Shipment__c | |
WHERE zkfedex__MasterTrackingId__c = :trackNumber | |
AND zkfedex__ShipDate__c =: shipDate | |
LIMIT 1 | |
]; | |
System.assertEquals(1, shipments.size()); | |
} | |
} |
Any questions, please do not hesitate to contact us!