Generating an Email-to-Case thread id using Apex

How to generate Email-to-Case thread id inside template:

Generate the thread Id

public static String getThreadId(String caseId){
public static String getThreadId(String caseId){
  return '[ ref:_'
     + UserInfo.getOrganizationId().left(5)
     + UserInfo.getOrganizationId().mid(11,4) + '._'
     + caseId.left(5)
     + caseId.mid(10,5) + ':ref ]';
}

Send customEmail and Add ThreadId

public void sendCustomEmail(User selectedUser, Contact selectedContact, String templateName, Map<String, String> customVariables){
    EmailTemplate emailTemplate = [select Id, Subject, HtmlValue, Body from EmailTemplate where DeveloperName=:templateName];

    if (selectedContact==null){
       selectedContact =  selectedUser.Contact;
    }

    String customSubject = emailTemplate.Subject;

    if (customVariables.containsKey('joinContactName')){
      customSubject = customSubject.replace('{!JointContactName}', customVariables.get('joinContactName'));
    }
    //Add ThreadId to the Subject
    if (customVariables.containsKey('ThreadId')) {
      customSubject = customSubject.replace('{!ThreadId}', customVariables.get('ThreadId'));
    }

    String htmlBody = emailTemplate.HtmlValue;
    htmlBody = htmlBody.replace('{!Contact.FirstName}',selectedContact.FirstName);
    htmlBody = htmlBody.replace('{!Contact.Email}', selectedContact.Email);
    if (customVariables.containsKey('Link')){
      htmlBody = htmlBody.replace('{!CustomUrl}', customVariables.get('Link'));
    } else if (customVariables.containsKey('link')){
      htmlBody = htmlBody.replace('{!CustomUrl}', customVariables.get('link'));
    } else if (customVariables.containsKey('joinContactName')){
      htmlBody = htmlBody.replace('{!JointContactName}', customVariables.get('joinContactName'));
    }

    //Add ThreadId to the htmlBody
    if (customVariables.containsKey('ThreadId')){
      htmlBody = htmlBody.replace('{!ThreadId}', customVariables.get('ThreadId'));
    }

    String plainBody = emailTemplate.Body;
    plainBody = plainBody.replace('{!Contact.FirstName}',selectedContact.FirstName);
    plainBody = plainBody.replace('{!Contact.Email}', selectedContact.Email);
    if (customVariables.containsKey('Link')){
      plainBody = plainBody.replace('{!CustomUrl}', customVariables.get('Link'));
    } else if (customVariables.containsKey('link')){
      plainBody = plainBody.replace('{!CustomUrl}', customVariables.get('link'));
    } else if (customVariables.containsKey('joinContactName')){
      plainBody = plainBody.replace('{!JointContactName}', customVariables.get('joinContactName'));
    }

    //Add the threadId to the plainBody
    if (customVariables.containsKey('ThreadId')){
      plainBody = plainBody.replace('{!ThreadId}', customVariables.get('ThreadId'));
    }

    Messaging.Singleemailmessage email = new Messaging.Singleemailmessage();
    List<OrgWideEmailAddress> orgWideEmailAddress = [Select Id, Address from OrgWideEmailAddress where DisplayName=:ORGWIDEEMAILADDRESSNAME];
    //Set ReplyTo as the Email-to-Case email address
    if (customVariables.containsKey('ThreadId')){
      List<EmailServicesAddress> emailServicesAddress = [SELECT Id,AuthorizedSenders,EmailDomainName,IsActive,LocalPart FROM EmailServicesAddress where IsActive=true and (LocalPart like '%service%' or LocalPart like '%support%')];
      if (!emailServicesAddress.isEmpty()){
        EmailServicesAddress emailToCase = emailServicesAddress.get(0);
        email.setReplyTo(emailToCase.LocalPart +'@'+ emailToCase.EmailDomainName);
        email.setSenderDisplayName('Client Support');
      } else {
        email.setReplyTo('customer-service@gmail.com');
        email.setSenderDisplayName('Client Support');
      }
    }

    email.setTargetObjectId(selectedContact.Id);
    email.setSaveAsActivity(true);

    email.setSubject(customSubject);

    email.setHtmlBody(htmlBody);
    email.setPlainTextBody(plainBody);

    if (customVariables.containsKey('WhatId')){
      email.setWhatId(customVariables.get('WhatId'));
    }

    Messaging.sendEmail(new Messaging.SingleEmailmessage[] {email});
}

Putting it all together

Map<String, String> mappingOfCaseFields = new Map<String, String>();
mappingOfCaseFields.put('ThreadId', App_Service.getThreadId(paymentCaseId));
App_Service.instance.sendCustomEmail(null, contact, 'App_Support_Template', mappingOfCaseFields);

Apex Trigger for Sales Rep Scoring

This trigger is used to track and score sales rep activities as they complete Account fields.

Account Trigger Handler to Track specific field updates by sales rep and give points for based on which field was completed.

trigger AccountTrigger on Account (after delete, after insert, after undelete, after update, before delete, before insert, before update) {
    
    if (!System.isFuture() && !System.isBatch()){
      AccountTriggerHandler handler = new AccountTriggerHandler(Trigger.isExecuting, Trigger.size);

      if(Trigger.isUpdate && Trigger.isBefore){
          handler.OnBeforeUpdate(Trigger.old, Trigger.new, Trigger.newMap);
          AccountTriggerHandler.firstRun=false;
      }
}

Account Trigger Handler calls the SalesRepActivityScoring class to loop through all the accounts see which fields have been completed and assign points accordingly.

public with sharing class AccountTriggerHandler {
	
 	public static boolean firstRun = true; 

	private Boolean m_isExecuting = false;
    private Integer batchSize = 0;

	public AccountTriggerHandler(boolean isExecuting, integer size) {
		this.m_isExecuting = isExecuting;
        this.batchSize = size;
	}

	public void onBeforeUpdate(List<Account> oldAccounts, List<Account> updatedAccounts, Map<Id, Account> accountMap){
		SalesRepActivityScoring salesRepScoring = new SalesRepActivityScoring();
		salesRepScoring.insertSalesRepActivity(oldAccounts, updatedAccounts, accountMap);
	}
}

SalesRepActivityScoring class loops through accounts and checks if field not null and assign score. If field goes from filled in to null we subtract or points.

public with sharing class SalesRepActivityScoring {
	
	private static final Integer POTENTIALTOINVEST=4;
	private static final Integer LIQUIDASSETS=1;
	private static final Integer CONTEXTOFLC=1;
	private static final Integer GOALFORFUNDS=1;
	private static final Integer OCCUPATION=1;
	private static final Integer ACCREDIDTEDINVESTOR=1;
	private static final Integer HEADABOUTUS =1;

	private static final String ExecWithDialerProfileId = [Select Id from Profile where Name='Exec Standard user with dialer'].Id;
	private static final String AssociateWithDialerProfileId = [Select Id from Profile where Name='Associate Standard User With Dialer'].Id;

	public void insertSalesRepActivity(List<Account> oldAccounts, List<Account> updatedAccounts, Map<Id, Account> accountMap){
		List<SalesRep_Scoring__c> updateSalesRepScoringRecords = new List<SalesRep_Scoring__c>();

		Integer counter = 0;
		for (Account updatedAccount : updatedAccounts){
			if (updatedAccount.Account_Actor_ID__c!=null){
				if (UserInfo.getUserId().equals(updatedAccount.Lead_Assigned_To__c) && (UserInfo.getProfileId().equals(ExecWithDialerProfileId)) || UserInfo.getProfileId().equals(AssociateWithDialerProfileId)){
			
					SalesRep_Scoring__c salesRepScoring = new SalesRep_Scoring__c();
					salesRepScoring.Account__c = updatedAccount.Id;
					salesRepScoring.Account_Number__c = updatedAccount.Account_Actor_ID__c;
					salesRepScoring.Sales_Rep__c = UserInfo.getUserId();

					Boolean flag = false;

					if (updatedAccount.Accredited_Investor__c!=null){
						salesRepScoring.Accredited_Investor__c = ACCREDIDTEDINVESTOR;
						flag=true;
					} else if (oldAccounts.get(counter).Accredited_Investor__c!=null && updatedAccount.Accredited_Investor__c==null){
						salesRepScoring.Accredited_Investor__c = 0;
						flag=true;
					}

					if (updatedAccount.Context_of_LC_in_portfolio__c!=null){
						salesRepScoring.Context_of_LC__c = CONTEXTOFLC;
						flag=true;
					}else if (oldAccounts.get(counter).Context_of_LC_in_portfolio__c!=null && updatedAccount.Context_of_LC_in_portfolio__c==null) {
						salesRepScoring.Context_of_LC__c = 0;
						flag=true;
					}

					if (updatedAccount.Goal_for_Funds_at_LC__c!=null){
						salesRepScoring.Goal_for_funds__c = GOALFORFUNDS;
						flag=true;
					} else if (oldAccounts.get(counter).Context_of_LC_in_portfolio__c!=null && updatedAccount.Goal_for_Funds_at_LC__c==null){
						salesRepScoring.Goal_for_funds__c = 0;
						flag=true;
					}

					if (updatedAccount.How_did_you_hear_about_us__c!=null){
						salesRepScoring.How_did_you_hear_about_us__c = HEADABOUTUS;
						flag=true;
					} else if (oldAccounts.get(counter).How_did_you_hear_about_us__c!=null && updatedAccount.How_did_you_hear_about_us__c==null) {
						salesRepScoring.How_did_you_hear_about_us__c = 0;
						flag=true;
					}

					if (updatedAccount.Liquid_assets_client_stated__c!=null){
						salesRepScoring.Liquid_Assets__c = LIQUIDASSETS;
						flag=true;
					} else if (oldAccounts.get(counter).Liquid_assets_client_stated__c!=null && updatedAccount.Liquid_assets_client_stated__c==null){
						salesRepScoring.Liquid_Assets__c = 0;
						flag=true;
					}

					if (updatedAccount.Head_of_household_Occupation__c!=null){
						salesRepScoring.Occupation__c=OCCUPATION;
						flag=true;
					} else if (oldAccounts.get(counter).Head_of_household_Occupation__c!=null && updatedAccount.Head_of_household_Occupation__c==null){
						salesRepScoring.Occupation__c=0;
						flag=true;
					}

					if (updatedAccount.Potential_to_invest__c!=null){
						salesRepScoring.Potential_to_Invest__c=POTENTIALTOINVEST;
						flag=true;
					} else if (oldAccounts.get(counter).Potential_to_invest__c!=null && updatedAccount.Potential_to_invest__c==null) {
						salesRepScoring.Potential_to_Invest__c=0;
						flag=true;
					}

					if (flag){
						updateSalesRepScoringRecords.add(salesRepScoring);
					}
				}	
			}
			counter++;
		}
		upsert updateSalesRepScoringRecords Account_Number__c;
	}
}

SalesRepActivityScoringTest Class (100% code coverage). The first test method will test that the scoring only works for specific profiles. Second and third test method test scoring when fields completed for selected profiles. The last method will test if the scores is subtracted when fields goes from filled in to blank.

@isTest
private class SalesRepActivityScoringTest {
	

	public Id refProfileIdByName(String profileName){
        Profile getprofileId = [SELECT id FROM Profile WHERE name= :profileName];
        return getProfileId.id;
    }
    public User createAssociateSalesRepByProfile(String profileName){   
        User toUser = new User(alias = 'lcrep', 
        email='salesrep@lendingclub.com', 
        emailencodingkey='UTF-8',
        firstname='Associate', 
        lastname='Rep', 
        languagelocalekey='en_US', 
        localesidkey='en_US', 
        profileid = refProfileIdByName(profileName), 
        timezonesidkey='America/Los_Angeles', 
        username='assosciatesalesrep@lendingclub.com',
        Record_Count__c = 0,
        Assigned_Record_Count__c=10,
        Record_Tier__c='1;2;3;4;5;6;7;8;9;10',
        isActive=true);
        
        return toUser;
    }

    private Account createDummyAccount(User newUser, Decimal actorId){
    	Account newAccount = new Account();
		newAccount.Name='[TEST]AccountRepActivity';
		newAccount.Lead_Assigned_To__c=newUser.Id;
		newAccount.OwnerId= newUser.Id;
		newAccount.Account_Actor_ID__c=actorId;
		insert newAccount;

	
		return newAccount;
    }

	@isTest(SeeAllData=true) static void testSalesRepActivityScoringNotAddingForStandardRep() {
		SalesRepActivityScoringTest sra = new SalesRepActivityScoringTest();
		User standardUser = sra.createAssociateSalesRepByProfile('Standard User');
		insert standardUser;
		Account newAccount = sra.createDummyAccount(standardUser, 1111.0);

		Test.startTest();
			update newAccount;
		Test.stopTest();

		System.assertEquals([Select id from SalesRep_Scoring__c where Account__c=:newAccount.Id].size(), 0);
	}
	
	@isTest static void testSalesRepActivityScoringAddingForExecRep() {
		SalesRepActivityScoringTest sra = new SalesRepActivityScoringTest();
		User execUser = sra.createAssociateSalesRepByProfile('Exec Standard user with dialer');
		insert execUser;
		System.runAs(execUser){
			Account newAccount = sra.createDummyAccount(execUser, 1234.0);

			newAccount.Account_Actor_ID__c=1234.0;
			newAccount.Accredited_Investor__c='Not Accredited';
			newAccount.Context_of_LC_in_portfolio__c='a';
			newAccount.Goal_for_Funds_at_LC__c='a';
			newAccount.How_did_you_hear_about_us__c='a';
			newAccount.Liquid_assets_client_stated__c='a';
			newAccount.Head_of_household_Occupation__c='a';
			newAccount.Potential_to_invest__c='a';

			Test.startTest();
				update newAccount;
			Test.stopTest();

			SalesRep_Scoring__c salesRepScoring = [select Goal_for_funds__c,Account__c, Account_Number__c, Accredited_Investor__c, Context_of_LC__c, CreatedById, CreatedDate, How_did_you_hear_about_us__c, Id, IsDeleted, LastActivityDate, LastModifiedById, LastModifiedDate, Liquid_Assets__c, Name, Occupation__c, OwnerId, Potential_to_Invest__c, Sales_Rep__c, SystemModstamp from SalesRep_Scoring__c where Account__c=:newAccount.Id][0];

			System.assertEquals(salesRepScoring.Account__c, newAccount.Id);
			System.assertEquals(salesRepScoring.Sales_Rep__c, execUser.Id);
			System.assertEquals(salesRepScoring.Accredited_Investor__c, 1);
			System.assertEquals(salesRepScoring.Context_of_LC__c, 1);
			System.assertEquals(salesRepScoring.Goal_for_funds__c, 1);
			System.assertEquals(salesRepScoring.How_did_you_hear_about_us__c, 1);
			System.assertEquals(salesRepScoring.Liquid_Assets__c, 1);
			System.assertEquals(salesRepScoring.Occupation__c, 1);
			System.assertEquals(salesRepScoring.Potential_to_Invest__c, 4);
		}
	}

	@isTest(SeeAllData=true) static void testSalesRepActivityScoringAddingForAssociateRep() {
		SalesRepActivityScoringTest sra = new SalesRepActivityScoringTest();
		User associate = sra.createAssociateSalesRepByProfile('Associate Standard User With Dialer');
		insert associate;
		System.runAs(associate){
			
			Account newAccount = sra.createDummyAccount(associate, 1235.0);

			newAccount.Account_Actor_ID__c=1235.0;
			newAccount.Accredited_Investor__c='Not Accredited';
			newAccount.Context_of_LC_in_portfolio__c='a';
			newAccount.Goal_for_Funds_at_LC__c='a';
			newAccount.How_did_you_hear_about_us__c='a';
			newAccount.Liquid_assets_client_stated__c='a';
			newAccount.Head_of_household_Occupation__c='a';
			newAccount.Potential_to_invest__c='a';

			Test.startTest();
				update newAccount;
			Test.stopTest();

			SalesRep_Scoring__c salesRepScoring = [select Goal_for_funds__c,Account__c, Account_Number__c, Accredited_Investor__c, Context_of_LC__c, CreatedById, CreatedDate, How_did_you_hear_about_us__c, Id, IsDeleted, LastActivityDate, LastModifiedById, LastModifiedDate, Liquid_Assets__c, Name, Occupation__c, OwnerId, Potential_to_Invest__c, Sales_Rep__c, SystemModstamp from SalesRep_Scoring__c where Account__c=:newAccount.Id][0];

			System.assertEquals(salesRepScoring.Account__c, newAccount.Id);
			System.assertEquals(salesRepScoring.Sales_Rep__c, associate.Id);
			System.assertEquals(salesRepScoring.Accredited_Investor__c, 1);
			System.assertEquals(salesRepScoring.Context_of_LC__c, 1);
			System.assertEquals(salesRepScoring.Goal_for_funds__c, 1);
			System.assertEquals(salesRepScoring.How_did_you_hear_about_us__c, 1);
			System.assertEquals(salesRepScoring.Liquid_Assets__c, 1);
			System.assertEquals(salesRepScoring.Occupation__c, 1);
			System.assertEquals(salesRepScoring.Potential_to_Invest__c, 4);

		}
	}

	@isTest(SeeAllData=true)  static void testSalesRepActivityResetNullResetScore(){
		SalesRepActivityScoringTest sra = new SalesRepActivityScoringTest();
		User execUser = sra.createAssociateSalesRepByProfile('Exec Standard user with dialer');
		insert execUser;
		System.runAs(execUser){
			Account newAccount = sra.createDummyAccount(execUser, 1234.0);

			newAccount.Account_Actor_ID__c=1234.0;
			newAccount.Accredited_Investor__c='Not Accredited';
			newAccount.Context_of_LC_in_portfolio__c='a';
			newAccount.Goal_for_Funds_at_LC__c='a';
			newAccount.How_did_you_hear_about_us__c='a';
			newAccount.Liquid_assets_client_stated__c='a';
			newAccount.Head_of_household_Occupation__c='a';
			newAccount.Potential_to_invest__c='a';

			update newAccount;

			SalesRep_Scoring__c salesRepScoring = [select Goal_for_funds__c,Account__c, Account_Number__c, Accredited_Investor__c, Context_of_LC__c, CreatedById, CreatedDate, How_did_you_hear_about_us__c, Id, IsDeleted, LastActivityDate, LastModifiedById, LastModifiedDate, Liquid_Assets__c, Name, Occupation__c, OwnerId, Potential_to_Invest__c, Sales_Rep__c, SystemModstamp from SalesRep_Scoring__c where Account__c=:newAccount.Id][0];

			System.assertEquals(salesRepScoring.Account__c, newAccount.Id);
			System.assertEquals(salesRepScoring.Sales_Rep__c, execUser.Id);
			System.assertEquals(salesRepScoring.Accredited_Investor__c, 1);
			System.assertEquals(salesRepScoring.Context_of_LC__c, 1);
			System.assertEquals(salesRepScoring.Goal_for_funds__c, 1);
			System.assertEquals(salesRepScoring.How_did_you_hear_about_us__c, 1);
			System.assertEquals(salesRepScoring.Liquid_Assets__c, 1);
			System.assertEquals(salesRepScoring.Occupation__c, 1);
			System.assertEquals(salesRepScoring.Potential_to_Invest__c, 4);

			newAccount.Accredited_Investor__c=null;
			newAccount.Context_of_LC_in_portfolio__c=null;
			newAccount.Goal_for_Funds_at_LC__c=null;
			newAccount.How_did_you_hear_about_us__c=null;
			newAccount.Liquid_assets_client_stated__c=null;
			newAccount.Head_of_household_Occupation__c=null;
			newAccount.Potential_to_invest__c=null;

			Test.startTest();
				update newAccount;
			Test.stopTest();

			SalesRep_Scoring__c salesRepScoringReset = [select Goal_for_funds__c,Account__c, Account_Number__c, Accredited_Investor__c, Context_of_LC__c, CreatedById, CreatedDate, How_did_you_hear_about_us__c, Id, IsDeleted, LastActivityDate, LastModifiedById, LastModifiedDate, Liquid_Assets__c, Name, Occupation__c, OwnerId, Potential_to_Invest__c, Sales_Rep__c, SystemModstamp from SalesRep_Scoring__c where Account__c=:newAccount.Id][0];

			System.assertEquals(salesRepScoringReset.Account__c, newAccount.Id);
			System.assertEquals(salesRepScoringReset.Sales_Rep__c, execUser.Id);
			System.assertEquals(salesRepScoringReset.Accredited_Investor__c, 0);
			System.assertEquals(salesRepScoringReset.Context_of_LC__c, 0);
			System.assertEquals(salesRepScoringReset.Goal_for_funds__c, 0);
			System.assertEquals(salesRepScoringReset.How_did_you_hear_about_us__c, 0);
			System.assertEquals(salesRepScoringReset.Liquid_Assets__c, 0);
			System.assertEquals(salesRepScoringReset.Occupation__c, 0);
			System.assertEquals(salesRepScoringReset.Potential_to_Invest__c, 0);
		}
	}
}

Apex Code: Track Sales Rep Tasks and Set Follow Up Dates

public with sharing class SalesRepActivity  {
	
	public void updateSalesRepActivity(Set<Id> taskIds){
		try{
		
		for (Task task : [Select Id, Type, Subject, Status, AccountId, Account.Owner.Id, OwnerId, Detailed_Type__c from Task where Id IN : taskIds]){
			if (task.AccountId != null){
				if (task.Account.Owner.Id == task.OwnerId){
					Account accountToUpdate = new Account(Id=task.AccountId);

					if (task.type.equals('Sent Email') && task.subject.containsIgnoreCase('Mass Email:')){
						accountToUpdate.Last_Mass_Email__c = Date.today();
					}
					else if ((task.type.equals('Sent Email') || task.type.equals('Clearslide Email Pitch')) && task.subject.containsIgnoreCase('Email:')){
						accountToUpdate.Last_Non_Mass_Email__c = Date.today();
					}
					else if ((task.type.equals('Sent Email') && task.subject.containsIgnoreCase('re:')) && (task.Detailed_Type__c.equals('Connected') || task.Detailed_Type__c.equals('Meet') || task.Detailed_Type__c.equals('Meet outside'))){
						accountToUpdate.Last_Email_Connect__c = Date.today();
						accountToUpdate.Last_connected_date__c = Date.today();
					}
					else if (task.type.equals('Outbound Call') && task.status.equals('Completed') && task.Detailed_Type__c.equals('Connected')){
						accountToUpdate.Last_Call_Connect__c = Date.today();
						accountToUpdate.Last_connected_date__c = Date.today();
						accountToUpdate.Last_Call_attempt__c = Date.today();
					}
					else if (task.type.equals('Outbound Call')){
						accountToUpdate.Last_Call_attempt__c = Date.today();
					}
					else if (task.type.equals('Inbound Call')){
						accountToUpdate.Last_Call_attempt__c = Date.today();
						accountToUpdate.Last_connected_date__c = Date.today();
						accountToUpdate.Last_Call_Connect__c = Date.today();
					}

					update accountToUpdate;
				}
			}
		}

		}catch(Exception e){
			System.debug(e.getMessage());
		}
	}
}

Apex Update Case Priority when Bad Words in Incoming Email

Updating a case priority of a case when you receive a email with some words in the body that will make it more important. By looking at the words you can update the priority to high so Support reps can faster attend to those cases

public with sharing class CaseMatchIncomingEmail {
	public enum badWords {
		Frustrated,
		Frustrating,
		Angry,
		Mad,
		Annoyed,
		Annoying,
		Complain,
		Complaint,
		Lost,
		Upset,
		Awful,
		Bad,
		Mislead,
		Misleading,
		Fraud,
		Scam,
		request,
		SEC,
		transfer,
		Broken,
		Problem,
		Issue,
		Disappoint,
		Disappointing,
		Prosper,
		Lawsuit,
		Sue,
		Hate,
		Attorney,
		Discrepancy,
		Pissed,
		ridiculous,
		immediate,
		immediately,
		kidding,
		joking,
		joke}

	public void mathIncomingCaseEmail(List<Case> casesToUpdate) {
		List<Case> caseToUpdateList = new List<Case>();

		for (Case caseToUpdate : casesToUpdate){
			for (badWords badword : badWords.values()){
				if (caseToUpdate.Subject!=null){
					if (caseToUpdate.Subject.containsIgnoreCase(badword.name())){
						caseToUpdate.Priority = 'High';
					}
				}
				if (caseToUpdate.Description!=null){
					if (caseToUpdate.Description.containsIgnoreCase('disclaimer')){
						if (caseToUpdate.Description.lastIndexOf('disclaimer')>0){
							if (caseToUpdate.Description.substring(0,caseToUpdate.Description.lastIndexOf('disclaimer')).containsIgnoreCase(badword.name())){
							caseToUpdate.Priority = 'High';
							}
						}
					}
					else if (caseToUpdate.Description.containsIgnoreCase(badword.name())){
						caseToUpdate.Priority = 'High';
					}
				}
			}

			if (caseToUpdate.SuppliedEmail != null){
				List<List<SObject>> searchList = searchByField(caseToUpdate.SuppliedEmail);
				List<Contact> contactSearchList =  ((List<Contact>)searchList[0]);
				List<Admin_Member_ID_Account__c> adminMemberSearchList =  ((List<Admin_Member_ID_Account__c>)searchList[1]);

				if (contactSearchList.size() > 0){
					for (Contact contactSearchResult:contactSearchList){
						if (contactSearchResult.Email == caseToUpdate.SuppliedEmail){
							caseToUpdate.ContactId = contactSearchList.get(0).Id;
							caseToUpdate.AccountId = contactSearchList.get(0).AccountId;
						}
					}
				}
				if (adminMemberSearchList.size() > 0){
					for (Admin_Member_ID_Account__c adminMemberIdAccount : adminMemberSearchList){
						if (adminMemberIdAccount.AM_ID_Email__c == caseToUpdate.SuppliedEmail)
							caseToUpdate.AM_Member_ID__c = adminMemberSearchList.get(0).Id;
					}
				}
			}
		}
	}
}

Salesforce Export Database Records to CSV for Batch Upload

Exporting of Database records to csv can be done using:

1. OpenCSV CSVWriter
2. FileWriter

1. OpenCSV CSVWriter


	@Inject
    private Environment environment;

	@Inject @Named("proddataSource") DataSource dataSource;

	private FileWriter writer;
	
	@Override
	public ResultSet getDWRecords(String queryName) {
		try {
			java.sql.PreparedStatement ps = dataSource.getConnection().prepareStatement(environment.getProperty(queryName));
			ps.setMaxRows(10000);
			ResultSet rs = ps.executeQuery();
			return rs;
		} catch (SQLException e) {
			logger.error("CreateCSVDWDumpFileImpl.getDWRecords(): " + e.getMessage());
		}
      return null;
	}

	@Override
	public void createCSVDumpFromQuery(ResultSet resultSet, String[] salesforceColumnNames, String fileName) {
		if (resultSet!=null){
			try {
				CSVWriter writer = new CSVWriter(new FileWriter(fileName), ',', CSVWriter.NO_QUOTE_CHARACTER);
				writer.writeNext(salesforceColumnNames);
				writer.writeAll(resultSet, false);
	            writer.close();
			} catch (IOException e) {
				logger.error("CreateCSVDWDumpFileImpl.createCSVDumpFromQuery(): " + e.getMessage());
			} catch (SQLException e) {
				logger.error("CreateCSVDWDumpFileImpl.createCSVDumpFromQuery(): " + e.getMessage());
			}
		}
	}

2. FileWriter

private FileWriter writer;
public void writeToCSVFileAccount(Collection<SObject> sObjects, String[] salesforceColumnNames, String fileName) {
	try {
		writer = new FileWriter(fileName);
		for (int firstCol = 0; firstCol < salesforceColumnNames.length; firstCol++){
			 writer.append(salesforceColumnNames[firstCol]);
			 if (firstCol < salesforceColumnNames.length-1)
				 writer.append(',');
		}
		writer.append('\n');
		
		for (SObject sAccount : sObjects){
			for (int k = 0; k < salesforceColumnNames.length; k++){
				writer.append(sAccount.getField(salesforceColumnNames[k])!=null ? salesforceColumnNames[k].contains("Date") || salesforceColumnNames[k].contains("date") ?  String.format("%1$tF", sAccount.getField(salesforceColumnNames[k])) : sAccount.getField(salesforceColumnNames[k]).toString() : "");
				if (k < salesforceColumnNames.length-1)
					writer.append(',');
			}
			writer.append('\n');
		}
		
		writer.flush();
		writer.close();
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
		}
	}

Salesforce WSC Partner Connection Session Renew when Session Timeout

Implement SessionRenewer

package com.sforce.authentication;

import javax.inject.Inject;
import javax.xml.namespace.QName;


import org.slf4j.Logger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;

import com.sforce.async.AsyncApiException;
import com.sforce.async.BulkConnection;
import com.sforce.soap.partner.Connector;
import com.sforce.soap.partner.PartnerConnection;
import com.sforce.ws.ConnectionException;
import com.sforce.ws.ConnectorConfig;
import com.sforce.ws.SessionRenewer;

/**
 * @author tmichels
 */
@PropertySource("classpath:salesforcesync.properties")
@Configuration
public class SalesforceAuthenticationConfigImpl implements SalesforceAuthenticationConfig {

	private static final Logger logger = org.slf4j.LoggerFactory.getLogger(SalesforceAuthenticationConfigImpl.class);
	
	@Inject private Environment environment;
		    
	private PartnerConnection partnerConnection = null;
	private BulkConnection bulkConnection = null;
	
	public ConnectorConfig productionConnectionConfig(){
		ConnectorConfig config = new ConnectorConfig();
		config.setUsername("username");
		config.setPassword("passwordtoken");
		config.setCompression(true);
		return config;
	}
	
    @Bean(name="loginToProductionSalesforce")
	public PartnerConnection loginToProductionSalesforce() {
    	try {
    		ConnectorConfig config = productionConnectionConfig();
    		config.setSessionRenewer(new productionSessionRenewer());
        	partnerConnection = Connector.newConnection(config);
		} catch (ConnectionException e) {
			logger.error("SalesforceAuthenticationConfigImpl.loginToProductionSalesforce(): " + e.getMessage());
			e.printStackTrace();
		}
		return partnerConnection;
	}
    
    public class productionSessionRenewer implements SessionRenewer {
		@Override
		public SessionRenewalHeader renewSession(ConnectorConfig config) throws ConnectionException {
			ConnectorConfig conConfig = productionConnectionConfig();
			partnerConnection = Connector.newConnection(conConfig);
            SessionRenewalHeader header = new SessionRenewalHeader();
            header.name = new QName("urn:partner.soap.sforce.com", "SessionHeader");
            header.headerElement = partnerConnection.getSessionHeader();
            return header;
		}
    }
}

Test SessionRenewer

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader=AnnotationConfigContextLoader.class, classes={SalesforceAuthenticationConfigImpl.class})
public class SalesforceAuthenticationServiceTest {

	@Inject @Named("loginToProductionSalesforce") PartnerConnection loginToProductionPartner;
	
	@Test
	public void testLoginToProductionSalesforce() {
		assertNotNull(loginToProductionPartner.getConfig().getSessionId());
		try {
			loginToProductionPartner.logout();
                        assertNotNull(loginToProductionPartner.getConfig().getSessionId());
		} catch (ConnectionException e) {
			e.printStackTrace();
		}
	}
}

UNABLE_TO_LOCK_ROW solution using Rerun method

I have been reading a few blogs and posts of the forums on how to solve the database locking error I sometime get when running @future methods. The reason for the error is that some other system or user has already locked the record and now you want access to the record. This is denied and an error is thrown.

There is some solution when doing updated by specifying FOR UPDATE in your SOQL expression. But even with this I still got locking errors. I worked on a solution to run a batch apex job to redo the method later using Batch Apex.

Catch the error by writing the following:

catch (System.DMLException ex) 
{
    if (StatusCode.UNABLE_TO_LOCK_ROW==ex.getDmlType(0)) 
       Debugger.createDebugRecord(ex, 'methodName');
}

What I did was overload the Exception class and created a custom Debugger Object. In this object I have the record Id and method name. With this I created a rerun button to rerun this method with this Id.

I created a managed package to install the Debugger Object.

public static void createDebugRecord(handlerException exceptionObject, String methodName)
     {
         Database.insert(new Debugger__c
            (   
                    Message__c = exceptionObject.getMessage(),
                    Line_Number__c = exceptionObject.getLineNumber(),
                    Stack_Trace__c = exceptionObject.getStackTraceString(),
                    Method_Name__c=methodName
            ), false);
     }
     public static void createDebugRecord(DMLException dmlexceptionObject, String methodName)
     {
         Database.insert(new Debugger__c
            (       
                    DML_Record_Id__c = dmlexceptionObject.getDmlId(0),
                    DML_Type__c = dmlexceptionObject.getTypeName(),
                    Message__c = dmlexceptionObject.getDmlMessage(0),
                    Line_Number__c = dmlexceptionObject.getDmlIndex(0),
                    Stack_Trace__c = dmlexceptionObject.getDmlStatusCode(0),
                    Method_Name__c=methodName
            ),false);
     }

My handleException extends Exception

     public class handlerException extends Exception{}

Run a Batch Apex/Batch Java to retry all the failed records.

Force.com Tooling API IDE

Cloudsole Developer is an easy way to develop Salesforce apex classes, triggers, components and visualforce pages. It uses the salesforce API to access your code in a safe and secure way.

Some of the functionality of the IDE:

  • Create new Apex Triggers Classes, Visualforce Pages & Components
  • Select from a list of predefined templates to create class stubs
  • Code debugger
  • Run Anonymous Apex Code
  • Run SOQL queries
  • Run Batch queries
  • Metadata viewer and download
  • Code Metrics Dashboard

Force.com API Used:

  • Force.com OAuth
  • Force.com Tooling API
  • Force.com REST API
  • Force.com Batch API
  • Force.com Metadata API

Create new Triggers, Apex Classes, Visualforce Pages and Components:

CloudSoleApexClasses

Code Editor:

CloudSoleCodeEditor

Run Anonymous Apex Code:

CloudSoleAnonApex

Code Dashboard:

CloudSoleDashboard

Run SOQL Queries:

CloudSoleDataManagement

Create Force.com Batch Jobs:

CloudSoleBatchJob

My Dreamforce 2013 Developer Theater Presentation

Exposing Force.com RESTful Services using Swagger.

Try it live:
http://force-com-rest-swagger.herokuapp.com

Fork my project
https://github.com/thysmichels/force.com-swagger-rest-spring-mvc

Here are some photos from the event:

photo 1

photo 2

Presentation attached:
DF13_Exposing Salesforce REST Service using Swagger

Youtube video: