background

Create a FedEx shipment from a trigger on the Account object

Published on 08 March 2017 in salesforce fedex 

Today’s blog post explains how to create a FedEx shipment directly from a trigger on a standard Salesforce Account object. You will need our FedEx app and our Bulk Shipping package (sandbox install link, production install link, please be aware there are extra licensing costs for using the bulk package.) Contact us if you need any further information.

 

Firstly, create a checkbox on your account object. Let’s call it Create_Fedex__c. We will run the shipment creation process when this gets set to TRUE.

To store any validation errors (such as incorrect addresses), you need to create a custom object called Zenkraft_Validation_Error__c. Fill in the fields as you see here:

Custom Object Zenkraft Validation Error Salesforce Enterprise Edition

Next, create the trigger on the Account object. You can see the code below:

 

trigger AccountTrigger on Account(after delete, after insert, after undelete, after update,
before delete, before insert, before update) {
if (AccountTriggerHandler.enableTrigger) {
if (Trigger.isAfter && Trigger.isUpdate) {
AccountTriggerHandler.createShipments(Trigger.oldMap, Trigger.newMap);
}
}
}

 

The trigger calls the AccountTriggerHandler that determines whether the checkbox has been set to TRUE, and if so, creates the shipment.

Lines 13-20: Get the address information from the account object that is needed to create the shipment.

Lines 25-33: Create the queued shipment.

Lines 35-43: Create the package, including the weight and declared value.

Lines 45-47: If the above have been generated successfully we use the processShipments method to start the creation process

 

public class AccountTriggerHandler {
public static Boolean enableTrigger = true;
public static void createShipments(Map<Id, Account> oldMap, Map<Id, Account> newMap) {
Set<Id> AccountsToProcessFedexSet = new Set<Id>();
for (Account currentAccount : newMap.values()) {
if (currentAccount.Create_FedEx__c == true &&
currentAccount.Create_FedEx__c != oldMap.get(currentAccount.Id).Create_FedEx__c) {
AccountsToProcessFedexSet.add(currentAccount.Id);
}
}
Map<Id, Account> AccountsToProcessFedexMap = new Map<Id, Account>([
SELECT Name, Phone, Email__c,
ShippingStreet, ShippingCity,
ShippingState, ShippingPostalCode,
ShippingCountry
FROM Account
WHERE Id IN :AccountsToProcessFedexSet
LIMIT 10000]);
if ( ! AccountsToProcessFedexMap.isEmpty() ) {
FedexShipmentService.settings = BulkShipmentSettings__c.getInstance('FedEx');
FedexShipmentService.shipmatePreference = FedexShipmentService.getShipmatePreference();
List<zkfedex__QueuedShipment__c> queuedShipmentsList = new List<zkfedex__QueuedShipment__c>();
String bulkShipmentId = FedexShipmentService.createBulkShipment();
for (Account currentAccount : AccountsToProcessFedexMap.values()) {
zkfedex__QueuedShipment__c queuedShipment = FedexShipmentService.createQueuedShipment(
bulkShipmentId,
currentAccount);
queuedShipmentsList.add(queuedShipment);
}
insert queuedShipmentsList;
List<zkfedex__QueuedPackage__c> packagesList = new List<zkfedex__QueuedPackage__c>();
for (zkfedex__QueuedShipment__c queuedShipment : queuedShipmentsList) {
zkfedex__QueuedPackage__c queuedPackage = new zkfedex__QueuedPackage__c(
zkfedex__QueuedShipment__c = queuedShipment.Id,
zkfedex__DeclaredValue__c = 0,
zkfedex__Weight__c = 1);
packagesList.add(queuedPackage);
}
insert packagesList;
if ( ! queuedShipmentsList.isEmpty() ) {
FedexShipmentService.processShipments(bulkShipmentId);
}
}
}
}

 

FedexShipmentService is the class that allows the easy creation of the QueuedShipments, it gets the account details from the FedEx account that you have set up, and creates the BulkShipment where we store all the shipment information before we actually send it to be processed.

Lines 6-41: We set the zkfedex__ServiceType__c , zkfedex__PackagingType__c for the shipment along with the sender and recipient addresses.

 

public class FedexShipmentService {
public static zkfedex__ShipmatePreference__c shipmatePreference {
get;
set;
}
public static BulkShipmentSettings__c settings {
get;
set;
}
public static zkfedex__QueuedShipment__c createQueuedShipment(String bulkShipmentId, Account currentAccount) {
zkfedex__QueuedShipment__c queuedShipment = new zkfedex__QueuedShipment__c();
queuedShipment.zkfedex__BulkShipment__c = bulkShipmentId;
queuedShipment.zkfedex__ShipDate__c = Date.today();
queuedShipment.zkfedex__DropoffType__c = dropoffTypeMap.get(shipmatePreference.zkfedex__DropoffTypeDefault__c);
queuedShipment.zkfedex__LabelImageType__c = shipmatePreference.zkfedex__LabelImageTypeDefault__c;
queuedShipment.zkfedex__Account__c = currentAccount.Id;
queuedShipment.zkfedex__ServiceType__c = 'Domestic: FedEx Ground';
queuedShipment.zkfedex__PackagingType__c = 'Your Packaging';
queuedShipment.zkfedex__WeightDimensionUnits__c = 'LB / IN';
queuedShipment.zkfedex__PaymentType__c = 'Sender'; // Sender queuedShipment.zkfedex__SenderName__c = shipmatePreference.zkfedex__SenderNameDefault__c; queuedShipment.zkfedex__SenderCompany__c = shipmatePreference.zkfedex__CompanyName__c; queuedShipment.zkfedex__SenderPhone__c = shipmatePreference.zkfedex__SenderPhoneDefault__c; queuedShipment.zkfedex__SenderEmail__c = shipmatePreference.zkfedex__SenderEMailDefault__c; queuedShipment.zkfedex__SenderStreet__c = shipmatePreference.zkfedex__ShippingStreet__c; queuedShipment.zkfedex__SenderCity__c = shipmatePreference.zkfedex__ShippingCity__c; queuedShipment.zkfedex__SenderState__c = shipmatePreference.zkfedex__ShippingState__c; queuedShipment.zkfedex__SenderPostalCode__c = shipmatePreference.zkfedex__ShippingPostalCode__c; queuedShipment.zkfedex__SenderCountry__c = shipmatePreference.zkfedex__ShippingCountry__c; // Recipient queuedShipment.zkfedex__RecipientName__c = currentAccount.Name; queuedShipment.zkfedex__RecipientCompany__c = currentAccount.Name; queuedShipment.zkfedex__RecipientPhone__c = currentAccount.Phone; queuedShipment.zkfedex__RecipientEmail__c = currentAccount.Email__c; queuedShipment.zkfedex__RecipientStreet__c = currentAccount.ShippingStreet; queuedShipment.zkfedex__RecipientCity__c = currentAccount.ShippingCity; queuedShipment.zkfedex__RecipientState__c = currentAccount.ShippingState; queuedShipment.zkfedex__RecipientPostalCode__c = currentAccount.ShippingPostalCode; queuedShipment.zkfedex__RecipientCountry__c = currentAccount.ShippingCountry; return queuedShipment; } public static zkfedex__ShipmatePreference__c getShipmatePreference() { return [ SELECT Id, Name, zkfedex__FedExAccountNumber__c, zkfedex__FedExMeterNumber__c, zkfedex__EncryptedFedExMeterNumber__c, zkfedex__SubscriptionDataEncrypted__c, zkfedex__GenericFedExEndUserKey__c, zkfedex__GenericFedExEndUserPassword__c, zkfedex__EncryptedGenericFedExEndUserKey__c, zkfedex__EncryptedGenericFedExEndUserPasswd__c, zkfedex__GenericCredentialsEncrypted__c, zkfedex__CompanyName__c, zkfedex__ShippingStreet__c, zkfedex__ShippingCity__c, zkfedex__ShippingState__c, zkfedex__ShippingPostalCode__c, zkfedex__ShippingCountry__c, zkfedex__ShippingIsResidential__c, zkfedex__BillingStreet__c, zkfedex__BillingCity__c, zkfedex__BillingState__c, zkfedex__BillingPostalCode__c, zkfedex__BillingCountry__c, zkfedex__LabelImageTypeDefault__c, zkfedex__EMailMessageDefault__c, zkfedex__SendEMailNotificationToShipper__c, zkfedex__SendEMailNotificationToRecipient__c, zkfedex__EMailNotifyOnExceptionDefault__c, zkfedex__EMailNotifyOnDeliveryDefault__c, zkfedex__SenderNameDefault__c, zkfedex__SenderEMailDefault__c, zkfedex__SenderPhoneDefault__c, zkfedex__DetailedViewShipmatePreferenceList__c, zkfedex__DetailedViewReUsePackageList__c, zkfedex__AccountIsSetupForSmartPostOutbound__c, zkfedex__AccountIsSetupForSmartPostReturns__c, zkfedex__SmartPostHubId__c, zkfedex__DropoffTypeDefault__c FROM zkfedex__ShipmatePreference__c WHERE Name = :settings.Preference_Name__c LIMIT 1]; } public static Id createBulkShipment() { zkfedex__BulkShipment__c shipment = new zkfedex__BulkShipment__c(); shipment.zkfedex__ShipmatePreference__c = shipmatePreference.Id; insert shipment; return shipment.Id; } public static String processShipments(Id bulkShipmentId) { return zkfedex.BulkShipmentInterface.processBulkShipment(bulkShipmentId); } private static Map<String,String> dropoffTypeMap = new Map<String,String> { 'BUSINESS_SERVICE_CENTER' => 'Business Service Center', 'DROP_BOX' => 'Drop Box', 'REGULAR_PICKUP' => 'Regular Pickup', 'REQUEST_COURIER' => 'Request Courier', 'STATION' => 'Station' };}

 

To handle any errors, create another trigger. This time put it on the Queued Shipment Status object.

 

trigger FedexQueuedShipmentStatusTrigger on zkfedex__QueuedShipmentStatus__c(after delete, after insert, after undelete, after update,
before delete, before insert, before update) {
if (FedexQueuedShipmentStatusTriggerHandler.enableTrigger) {
if (Trigger.isAfter && Trigger.isInsert) {
FedexQueuedShipmentStatusTriggerHandler.updateValidationIfError(Trigger.newMap);
}
}
}

 

And the respective trigger handler code is below:

 

public class FedexQueuedShipmentStatusTriggerHandler {
public static Boolean enableTrigger = true;
public static void updateValidationIfError(Map<Id, zkfedex__QueuedShipmentStatus__c> newMap) {
Set<Id> errorsSet = new Set<Id>();
Boolean isContinue = false;
for (zkfedex__QueuedShipmentStatus__c qss : newMap.values()) {
if (qss.zkfedex__Status__c == 'ERROR') {
errorsSet.add(qss.Id);
}
}
Map<Id, zkfedex__QueuedShipmentStatus__c> errorsMap = new Map<Id, zkfedex__QueuedShipmentStatus__c>([
SELECT zkfedex__StatusMessage__c, zkfedex__QueuedShipment__r.zkfedex__Account__c
FROM zkfedex__QueuedShipmentStatus__c
WHERE Id IN :errorsSet]);
List<Zenkraft_Validation_Error__c> validationList = new List<Zenkraft_Validation_Error__c>();
for (zkfedex__QueuedShipmentStatus__c qss : errorsMap.values()) {
Id accountId = Id.valueOf(qss.zkfedex__QueuedShipment__r.zkfedex__Account__c);
validationList.add(
new Zenkraft_Validation_Error__c(
Error_Text__c = 'FedEx: ' + qss.zkfedex__StatusMessage__c,
Account__c = accountId));
}
if ( ! validationList.isEmpty()) {
insert validationList;
}
}
}

 

Happy coding.