-
ChatterFeed
-
0Best Answers
-
0Likes Received
-
0Likes Given
-
44Questions
-
67Replies
Copy Email to Case attachmnets from child case to Parent Case
Right now what ever I have developed I achieved copying emails from child to master case. But when an email is sent with attachments from child case then only email is getting copied to master case not the attachments.
Below is my trigger code
trigger CaseTrigger on Case (before insert, after insert, before update,after update, before delete,after delete) { CaseTriggerHandler csHandler = new CaseTriggerHandler(trigger.new,trigger.old,trigger.newMap,trigger.oldMap,trigger.isUpdate,trigger.isInsert); if (trigger.isAfter && trigger.isInsert) { csHandler.HandleAfterInsert(); } if (trigger.isAfter && trigger.isUpdate) { csHandler.HandleAfterUpdate(); } }
And Below is my trigger handler class(I have kept only useful method related to my question,rest I have omitted for better view and usefulness to my question)
public class CaseTriggerHandler { public static boolean run = true; public static boolean runOnce(){ if(run){ run=false; return true; }else{ return run; } } List<Case> listOfCase; List<Case> newCase; List<Case> oldCase; Map<Id,Case> newCaseMap; Map<Id,Case> oldCaseMap; boolean isUpdate; boolean isDelete; public CaseTriggerHandler (List<Case> newCase, List<Case> oldCase, Map<Id,Case> newCaseMap, Map<Id,Case> oldCaseMap, boolean isUpdate, boolean isDelete){ this.newCase = newCase; this.oldCase = oldCase; this.newCaseMap = newCaseMap; this.oldCaseMap = oldCaseMap; this.isUpdate = isUpdate; this.isDelete = isDelete; } public void HandleAfterUpdate(){ if(run){ handleemailattachment(); } } public void HandleAfterInsert(){ handleemailattachment(); } public void handleemailattachment(){ Map<Id, Id> parentCaseIdMap = new Map<Id, Id>(); for(Case c : newCase){ if(c.ParentId!=null)parentCaseIdMap.put(c.Id, c.ParentId); } // Fetch all the attachments related to the child case List<EmailMessage> EmailMessageList= new List<EmailMessage>(); List<EmailMessage> attachmentToBeCloned = new List<EmailMessage>(); EmailMessageList = [Select Id,Subject,ParentId,textBody From EmailMessage Where ParentId in:parentCaseIdMap.keySet()]; for(EmailMessage att : EmailMessageList){ EmailMessage a = att.clone(); if(parentCaseIdMap.containsKey(att.ParentId)){ a.ParentId = parentCaseIdMap.get(att.ParentId); attachmentToBeCloned.add(a); } } if(attachmentToBeCloned!=null && attachmentToBeCloned.size()>0){ insert attachmentToBeCloned; } } }
Illustration of my requirements:
Suppose I created one Email- to-Case which triggers a creation of cases in SF with 2 emails. Now I linked this case to other Case. Upon merging both of the cases emails are getting copied to master/parent case but if I attach any attachment while creating Email to Case then upon merging only emails are getting copied not attachments .
Kindly help.
Many thanks in advance
Thanks & Regards,
Harjeet
- Harjeet Singh 13
- April 10, 2018
- Like
- 0
How to copy attachments sent with an email from child case to master case
Right now what ever I have developed I achieved copying emails from child to master case. But when an email is sent with attachments from child case then only email is getting copied to master case not the attachments.
Below is my trigger code
trigger CaseTrigger on Case (before insert, after insert, before update,after update, before delete,after delete) { CaseTriggerHandler csHandler = new CaseTriggerHandler(trigger.new,trigger.old,trigger.newMap,trigger.oldMap,trigger.isUpdate,trigger.isInsert); if (trigger.isAfter && trigger.isInsert) { csHandler.HandleAfterInsert(); } if (trigger.isAfter && trigger.isUpdate) { csHandler.HandleAfterUpdate(); } }
And Below is my trigger handler class(I have kept only useful method related to my question,rest I have omitted for better view and usefulness to my question)
public class CaseTriggerHandler { public static boolean run = true; public static boolean runOnce(){ if(run){ run=false; return true; }else{ return run; } } List<Case> listOfCase; List<Case> newCase; List<Case> oldCase; Map<Id,Case> newCaseMap; Map<Id,Case> oldCaseMap; boolean isUpdate; boolean isDelete; public CaseTriggerHandler (List<Case> newCase, List<Case> oldCase, Map<Id,Case> newCaseMap, Map<Id,Case> oldCaseMap, boolean isUpdate, boolean isDelete){ this.newCase = newCase; this.oldCase = oldCase; this.newCaseMap = newCaseMap; this.oldCaseMap = oldCaseMap; this.isUpdate = isUpdate; this.isDelete = isDelete; } public void HandleAfterUpdate(){ if(run){ handleemailattachment(); } } public void HandleAfterInsert(){ handleemailattachment(); } public void handleemailattachment(){ Map<Id, Id> parentCaseIdMap = new Map<Id, Id>(); for(Case c : newCase){ if(c.ParentId!=null)parentCaseIdMap.put(c.Id, c.ParentId); } // Fetch all the attachments related to the child case List<EmailMessage> EmailMessageList= new List<EmailMessage>(); List<EmailMessage> attachmentToBeCloned = new List<EmailMessage>(); EmailMessageList = [Select Id,Subject,ParentId,textBody From EmailMessage Where ParentId in:parentCaseIdMap.keySet()]; for(EmailMessage att : EmailMessageList){ EmailMessage a = att.clone(); if(parentCaseIdMap.containsKey(att.ParentId)){ a.ParentId = parentCaseIdMap.get(att.ParentId); attachmentToBeCloned.add(a); } } if(attachmentToBeCloned!=null && attachmentToBeCloned.size()>0){ insert attachmentToBeCloned; } } }
Illustration of my requirements:
Suppose I created one Email- to-Case which triggers a creation of cases in SF with 2 emails. Now I linked this case to other Case. Upon merging both of the cases emails are getting copied to master/parent case but if I attach any attachment while creating Email to Case then upon merging only emails are getting copied not attachments .
Kindly help.
Many thanks in advance
Thanks & Regards,
Harjeet
- Harjeet Singh 13
- April 10, 2018
- Like
- 0
How to notify account owner when a non account owner logs a call
Kindly help to acheive above mentioned requirements.
Many thanks in advance
Thanks & Regards,
Harjeet
- Harjeet Singh 13
- February 16, 2018
- Like
- 0
How to resolve System.NullPointerException: Attempt to de-reference a null object error in Test Class Salesforce
I have developed a class which is calling standard REST API to determine Daily Apex Exceution Limits. I am getting error when I am running test class for the same.
Below is my Apex Class:
public class CurrentStorage{ public static void getStorage() { //fetch session od of user String sid = Userinfo.getSessionId(); //fetch Instance URL String baseURL = System.URL.getSalesforceBaseUrl().toExternalForm(); //Building call out to Standard Salesforce Rest API HttpRequest req = new HttpRequest(); req.setMethod('GET'); req.setEndpoint(baseURL+'/services/data/v41.0/limits'); req.setHeader('Authorization', 'OAuth '+ sid); Http http = new Http(); HTTPResponse res = http.send(req); Map<String, Object> m = (Map<String,Object>)JSON.deserializeUntyped(res.getBody()); Map<String, Object> dataStorage = (Map<String,Object>)m.get('DailyAsyncApexExecutions'); System.debug('Map: '+ dataStorage); System.debug('Current Storage: ' + dataStorage.get('Remaining')); If(Integer.valueof(dataStorage.get('Max'))*(0.8)<= (Integer.valueof(dataStorage.get('Max')) - Integer.valueof(dataStorage.get('Remaining')))){ Messaging.SingleEmailMessage message = new Messaging.SingleEmailMessage(); message.toAddresses = new String[] { 'abc@gmail.com','def@gmail.com'}; //message.optOutPolicy = 'FILTER'; message.subject = 'Async Apex Limits Threshold Warning'; message.plainTextBody = 'Your Org Limit of Daily Async Apex Execution reached 80% threshold for '+ baseURL; Messaging.SingleEmailMessage[] messages = new List<Messaging.SingleEmailMessage> {message}; Messaging.SendEmailResult[] results = Messaging.sendEmail(messages); if (results[0].success) { System.debug('The email was sent successfully.'); } else { System.debug('The email failed to send: ' + results[0].errors[0].message); } } // Send Mail to people } }
Below is my test class:
@isTest public class TestCurrentStorage { static testMethod void validateLocationCallouts() { RestRequest req = new RestRequest(); req.params.put('DailyAsyncApexExecutions', '250000'); //req.params.put('Max', '250000'); req.params.put('Remaining', '200000'); Test.startTest(); Test.setMock(HttpCalloutMock.class, new MockHttpResponse()); CurrentStorage.getStorage(); Test.stopTest(); } }
Below is my mock class:
@isTest global class mockHttpResponse implements HttpCalloutMock{ // Implement this interface method global HTTPResponse respond(HTTPRequest req) { System.assertEquals('GET', req.getMethod()); // Create a fake response HttpResponse res = new HttpResponse(); res.setHeader('Content-Type', 'application/json'); res.setBody('{"Max": "250000","Remaining": "200000"}'); res.setStatusCode(200); res.setStatus('OK'); return res; } }
When I am trying to run tess class I am getting below error trace logs:
Errors: System.NullPointerException: Attempt to de-reference a null object Stack Trace: Class.CurrentStorage.getStorage: Class.TestCurrentStorage.validateLocationCallouts:
Kindly help me to pass the test class and also test class showing 57% code coverage and singlemessaging code is not covering
Many thanks in advance
Thanks & Regards,
Harjeet
- Harjeet Singh 13
- February 15, 2018
- Like
- 0
Getting System.NullPointerException: Attempt to de-reference a null object error in Test Class
I have developed a class which is calling standard REST API to determine Daily Apex Exceution Limits. I am getting error when I am running test class for the same.
Below is my Apex Class:
public class CurrentStorage{ public static void getStorage() { //fetch session od of user String sid = Userinfo.getSessionId(); //fetch Instance URL String baseURL = System.URL.getSalesforceBaseUrl().toExternalForm(); //Building call out to Standard Salesforce Rest API HttpRequest req = new HttpRequest(); req.setMethod('GET'); req.setEndpoint(baseURL+'/services/data/v41.0/limits'); req.setHeader('Authorization', 'OAuth '+ sid); Http http = new Http(); HTTPResponse res = http.send(req); Map<String, Object> m = (Map<String,Object>)JSON.deserializeUntyped(res.getBody()); Map<String, Object> dataStorage = (Map<String,Object>)m.get('DailyAsyncApexExecutions'); System.debug('Map: '+ dataStorage); System.debug('Current Storage: ' + dataStorage.get('Remaining')); If(Integer.valueof(dataStorage.get('Max'))*(0.8)<= (Integer.valueof(dataStorage.get('Max')) - Integer.valueof(dataStorage.get('Remaining')))){ Messaging.SingleEmailMessage message = new Messaging.SingleEmailMessage(); message.toAddresses = new String[] { 'abc@gmail.com','def@gmail.com'}; //message.optOutPolicy = 'FILTER'; message.subject = 'Async Apex Limits Threshold Warning'; message.plainTextBody = 'Your Org Limit of Daily Async Apex Execution reached 80% threshold for '+ baseURL; Messaging.SingleEmailMessage[] messages = new List<Messaging.SingleEmailMessage> {message}; Messaging.SendEmailResult[] results = Messaging.sendEmail(messages); if (results[0].success) { System.debug('The email was sent successfully.'); } else { System.debug('The email failed to send: ' + results[0].errors[0].message); } } // Send Mail to people } }
Below is my test class:
@isTest public class TestCurrentStorage { static testMethod void validateLocationCallouts() { RestRequest req = new RestRequest(); req.params.put('DailyAsyncApexExecutions', '250000'); //req.params.put('Max', '250000'); req.params.put('Remaining', '200000'); Test.startTest(); Test.setMock(HttpCalloutMock.class, new MockHttpResponse()); CurrentStorage.getStorage(); Test.stopTest(); } }
Below is my mock class:
@isTest global class mockHttpResponse implements HttpCalloutMock{ // Implement this interface method global HTTPResponse respond(HTTPRequest req) { System.assertEquals('GET', req.getMethod()); // Create a fake response HttpResponse res = new HttpResponse(); res.setHeader('Content-Type', 'application/json'); res.setBody('{"Max": "250000","Remaining": "200000"}'); res.setStatusCode(200); res.setStatus('OK'); return res; } }
When I am trying to run tess class I am getting below error trace logs:
Errors: System.NullPointerException: Attempt to de-reference a null object Stack Trace: Class.CurrentStorage.getStorage: Class.TestCurrentStorage.validateLocationCallouts:
Kindly help me to pass the test class.
Many thanks in advance
Thanks & Regards,
Harjeet
- Harjeet Singh 13
- February 15, 2018
- Like
- 0
How to send a notification/alert/email when certain threshold of Daily Async Apex Execution reaches
I want to send an alert notification when overall organisation Async Apex Execution limit reached 70%of total limit(24hrs API Limit). Say if limit is 2500 and if system already exhausted 1750 of daily Async Apex Limit out of 2500 then any alert should be send to few persons notifying that your organisation limit of Async Apex Executions have reached 70% threshold.
I have done few research on the same but didn't get anything concrete. I saw blogs/documentation stating about Limit class and Limit methods but those are having limit method for future but no where I get any thing related to Async Apex Exceution Limits. In Limit Class I saw there are 2 mthods 'getAsyncCalls()' and 'getLimitAsyncCalls()' but both are related reserved for future use.
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_methods_system_limits.htm#apex_System_limits_getAsyncCalls
Kindly help me.
Any help will be greatly appreciated.
Many thanks in advance
Thanks & Regards,
Harjeet
- Harjeet Singh 13
- February 12, 2018
- Like
- 0
Notification alert for Async Apex Execution Limits
I have done few research on the same but didn't get anything concrete. I saw blogs/documentation stating about Limit class and Limit methods but those are having limit method for future but no where I get any thing related to Async Apex Exceution Limits. In Limit Class I saw there are 2 mthods 'getAsyncCalls()' and 'getLimitAsyncCalls()' but both are related reserved for future use.
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_methods_system_limits.htm#apex_System_limits_getAsyncCalls
Kindly help me.
Any help will be greatly appreciated.
Many thanks in advance
Thanks & Regards,
Harjeet
- Harjeet Singh 13
- February 12, 2018
- Like
- 0
Async Apex Execution Limits threshold limits notifications alert or email
Kindly help
Thanks & Regards,
Harjeet
- Harjeet Singh 13
- February 08, 2018
- Like
- 0
How to send an alert notification if Async Apex Execution Limits reached 70% of limit
Kindly help
Thanks
- Harjeet Singh 13
- February 08, 2018
- Like
- 0
After update triggers working everytime instead of after insert in geolocation triggers
I am immense need of help from all of you. After giving a much thought and so much brainstorming happened finally I turned up here for advise.
Requirement:
I need to fetch coordinates value of account based on Map address provided. Map addresses are new fields created on accounts object(map street,map city,map postal code,map countrymap state)
Solution approach
I create few fields on accounts like MapAddressCity,MapAddressState,MapAddressStreet,MapAddressPostalCode and MapAddresscountry on account. When an user enters values in Map fields and clicks on save button I am calling Google API. Google API will returns one coordinate value based on address filled in Map fields. I have created one field called "Location"(Data Type-Geolocation) which will stores coordinates and also I created 2 formula fields which stores the longitude and latitude values of coordinates in "LonField" and "LatField" respectively
If an user enters below in account:
MapAddressCity: San Francisco
MapAddressCountry: United States
MapAddressPostalCode: 94105
MapPostalState: CA
MapAddressStreet: One Market Street
and clicks on Save-Google API call will be made and below information wiull be stored on account:
Location-37°47'38''N 122°23'41''W
LongValue-122.3948
LatValue37.7939
My Question:
When I am trying to update an already existing account(update operation) then upon saving future method is called and coordinates are getting stored and in debug logs I can see "ta:coming in after UPDATE"(Kindly refer my trigger code) which is correct.But my worry point is when I am trying to insert a new account and provides map addresses and clicks on Save then also coordinates are getting stored which is also correct but in debug logs I cn still see "ta:coming in after UPDATE" instead of 'ta:coming in after insert' because its an insert not an update.
1.Why after trigger is not working and coordinates are getting populated correctly even for new insertion due to after update instead of after insert
2. When I am trying to insert account records through data loader some accounts have updated coordinates after insertion whereas some doesn't have coordinates inserted.
I tried inserting around 17K records upon which 5K records inserted succesfully and also their corresponding coordinates are updated. Rest 12K records also inserted succesfully but their coordinates are not updated.
Below is trigger which is written on account:
trigger geocodeAccountAddress on Account (after insert, after update) { Set<Id> li=new Set<Id>(); //bulkify trigger in case of multiple accounts // if(Trigger.isAfter && Trigger.isInsert){ System.debug('ta:coming in after insert'); for(Account acc:Trigger.New){ System.debug('ta:coming in after insert2'); if((acc.Location__Latitude__s == null) && (String.isNotBlank(acc.MapAddressCountry__c))){ System.debug('ta:coming in after insert1'); li.add(acc.id); System.debug('ta:coming in after insert4'); AccountGeocodeAddress.newAccmethod(li); } } } if(Trigger.isAfter && Trigger.isUpdate){ System.debug('ta:coming in after UPDATE'); for(Account acc:Trigger.New){ if((acc.Location__Latitude__s == null) &&(String.isNotBlank(acc.MapAddressCountry__c))){ System.debug('ta:coming in after UPDATE1'); li.add(acc.id); System.debug('ta:coming in after Update5'); AccountGeocodeAddress.newAccmethod(li); } } } }
My class code is as belows:
public class AccountGeocodeAddress { @future(callout=true) static public void newAccmethod(set<id> li){ for(Account a : [SELECT MapAddressCity__c,MapAddressCountry__c,MapAddressPostalCode__c,MapAddressStreet__c,MapPostalState__c FROM Account WHERE id =: li]){ String address = ' '; if (a.MapAddressStreet__c!= null) address += a.MapAddressStreet__c+', '; if (a.MapAddressCity__c != null) address += a.MapAddressCity__c +', '; if (a.MapPostalState__c!= null) address += a.MapPostalState__c+' '; if (a.MapAddressPostalCode__c!= null) address += a.MapAddressPostalCode__c+', '; if (a.MapAddressCountry__c!= null) address += a.MapAddressCountry__c; address = EncodingUtil.urlEncode(address, 'UTF-8'); // build callout Http h = new Http(); HttpRequest req = new HttpRequest(); //req.setEndpoint(‘http://maps.googleapis.com/maps/api/geocode/json?address=’+address+’&sensor=false’); req.setEndpoint('https://maps.googleapis.com/maps/api/geocode/json?address='+address + '&key='+ geocodingKey+ '&sensor=false'); req.setMethod('GET'); req.setTimeout(6000); try{ // callout HttpResponse res = h.send(req); // parse coordinates from response JSONParser parser = JSON.createParser(res.getBody()); system.debug('Harjeet:'+ res.getBody()); double lat = null; double lon = null; while (parser.nextToken() != null) { if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'location')){ parser.nextToken(); // object start while (parser.nextToken() != JSONToken.END_OBJECT){ String txt = parser.getText(); parser.nextToken(); if (txt == 'lat') lat = parser.getDoubleValue(); else if (txt == 'lng') lon = parser.getDoubleValue(); } } } // update coordinates if we get back if (lat != null){ system.debug(lat+' '+lon); a.Location__Latitude__s = lat; system.debug(a.Location__Latitude__s+'Location__Latitude__s'); a.Location__Longitude__s= lon; system.debug(a.Location__Longitude__s+'Location__Longitude__s'); update a; } } catch (Exception e) { system.debug(e); } } } }
Any help will be greatly appreciated!
Thanks in advance
Thanks & Regards,
Harjeet
- Harjeet Singh 13
- February 05, 2018
- Like
- 0
After insert triggers not working properly in geolocation triggers
I am immense need of help from all of you. After giving a much thought and so much brainstorming happened finally I turned up here for advise.
Requirement:
I need to fetch coordinates value of account based on Map address provided. Map addresses are new fields created on accounts object(map street,map city,map postal code,map countrymap state)
Solution approach
I create few fields on accounts like MapAddressCity,MapAddressState,MapAddressStreet,MapAddressPostalCode and MapAddresscountry on account. When an user enters values in Map fields and clicks on save button I am calling Google API. Google API will returns one coordinate value based on address filled in Map fields. I have created one field called "Location"(Data Type-Geolocation) which will stores coordinates and also I created 2 formula fields which stores the longitude and latitude values of coordinates in "LonField" and "LatField" respectively
If an user enters below in account:
MapAddressCity: San Francisco
MapAddressCountry: United States
MapAddressPostalCode: 94105
MapPostalState: CA
MapAddressStreet: One Market Street
and clicks on Save-Google API call will be made and below information wiull be stored on account:
Location-37°47'38''N 122°23'41''W
LongValue-122.3948
LatValue37.7939
My Question:
When I am trying to update an already existing account(update operation) then upon saving future method is called and coordinates are getting stored and in debug logs I can see "ta:coming in after UPDATE"(Kindly refer my trigger code) which is correct.But my worry point is when I am trying to insert a new account and provides map addresses and clicks on Save then also coordinates are getting stored which is also correct but in debug logs I cn still see "ta:coming in after UPDATE" instead of 'ta:coming in after insert' because its an insert not an update.
1.Why after trigger is not working and coordinates are getting populated correctly even for new insertion due to after update instead of after insert
2. When I am trying to insert account records through data loader some accounts have updated coordinates after insertion whereas some doesn't have coordinates inserted.
I tried inserting around 17K records upon which 5K records inserted succesfully and also their corresponding coordinates are updated. Rest 12K records also inserted succesfully but their coordinates are not updated.
Below is trigger which is written on account:
trigger geocodeAccountAddress on Account (after insert, after update) { Set<Id> li=new Set<Id>(); //bulkify trigger in case of multiple accounts // if(Trigger.isAfter && Trigger.isInsert){ System.debug('ta:coming in after insert'); for(Account acc:Trigger.New){ System.debug('ta:coming in after insert2'); if((acc.Location__Latitude__s == null) && (String.isNotBlank(acc.MapAddressCountry__c))){ System.debug('ta:coming in after insert1'); li.add(acc.id); System.debug('ta:coming in after insert4'); AccountGeocodeAddress.newAccmethod(li); } } } if(Trigger.isAfter && Trigger.isUpdate){ System.debug('ta:coming in after UPDATE'); for(Account acc:Trigger.New){ if((acc.Location__Latitude__s == null) && (String.isNotBlank(acc.MapAddressCountry__c))){ System.debug('ta:coming in after UPDATE1'); li.add(acc.id); System.debug('ta:coming in after Update5'); AccountGeocodeAddress.newAccmethod(li); } } } }
My class code is as belows:
public class AccountGeocodeAddress { @future(callout=true) static public void newAccmethod(set<id> li){ String geocodingKey ='AIzaSyD6DLnewg4y0Casi0-iFFjoenLJmmayt8c'; for(Account a : [SELECT MapAddressCity__c,MapAddressCountry__c,MapAddressPostalCode__c,MapAddressStreet__c,MapPostalState__c FROM Account WHERE id =: li]){ String address = ' '; if (a.MapAddressStreet__c!= null) address += a.MapAddressStreet__c+', '; if (a.MapAddressCity__c != null) address += a.MapAddressCity__c +', '; if (a.MapPostalState__c!= null) address += a.MapPostalState__c+' '; if (a.MapAddressPostalCode__c!= null) address += a.MapAddressPostalCode__c+', '; if (a.MapAddressCountry__c!= null) address += a.MapAddressCountry__c; address = EncodingUtil.urlEncode(address, 'UTF-8'); // build callout Http h = new Http(); HttpRequest req = new HttpRequest(); //req.setEndpoint(‘http://maps.googleapis.com/maps/api/geocode/json?address=’+address+’&sensor=false’); req.setEndpoint('https://maps.googleapis.com/maps/api/geocode/json?address='+address + '&key='+ geocodingKey+ '&sensor=false'); req.setMethod('GET'); req.setTimeout(6000); try{ // callout HttpResponse res = h.send(req); // parse coordinates from response JSONParser parser = JSON.createParser(res.getBody()); system.debug('Harjeet:'+ res.getBody()); double lat = null; double lon = null; while (parser.nextToken() != null) { if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'location')){ parser.nextToken(); // object start while (parser.nextToken() != JSONToken.END_OBJECT){ String txt = parser.getText(); parser.nextToken(); if (txt == 'lat') lat = parser.getDoubleValue(); else if (txt == 'lng') lon = parser.getDoubleValue(); } } } // update coordinates if we get back if (lat != null){ system.debug(lat+' '+lon); a.Location__Latitude__s = lat; system.debug(a.Location__Latitude__s+'Location__Latitude__s'); a.Location__Longitude__s= lon; system.debug(a.Location__Longitude__s+'Location__Longitude__s'); update a; } } catch (Exception e) { system.debug(e); } } } }
Any help will be greatly appreciated!
Thanks in advance
Thanks & Regards,
Harjeet
- Harjeet Singh 13
- February 05, 2018
- Like
- 0
Coordinates of few accounts are not updating on bulk insert and update through data loader
I am immense need of help from all of you. After giving a much thought and so much brainstorming happened finally I turned up here for advise.
Requirement:
I need to fetch coordinates value of account based on Map address provided. Map addresses are new fields created on accounts object(map street,map city,map postal code,map countrymap state)
Solution approach
I create few fields on accounts like MapAddressCity,MapAddressState,MapAddressStreet,MapAddressPostalCode and MapAddresscountry on account. When an user enters values in Map fields and clicks on save button I am calling Google API. Google API will returns one coordinate value based on address filled in Map fields. I have created one field called "Location"(Data Type-Geolocation) which will stores coordinates and also I created 2 formula fields which stores the longitude and latitude values of coordinates in "LonField" and "LatField" respectively
If an user enters below in account:
MapAddressCity: San Francisco
MapAddressCountry: United States
MapAddressPostalCode: 94105
MapPostalState: CA
MapAddressStreet: One Market Street
and clicks on Save-Google API call will be made and below information wiull be stored on account:
Location-37°47'38''N 122°23'41''W
LongValue-122.3948
LatValue37.7939
My Question:
In our org there is already one trigger written on account and there is already one accounthandler class and we always follow best practices so I didnt write a separate trigger and class to achieve above mentioned requirement. I am reusing same accounttriggerhandler class and apex trigger which is written on account.
When I am trying to insert account records through data loader some accounts have updated coordinates after insertion whereas some doesn't have coordinates inserted.
I tried inserting around 17K records upon which 5K records inserted succesfully and also their corresponding coordinates are updated. Rest 12K records also inserted succesfully but their coordinates are not updated.
Kindly help me. Below is trigger which is already existing on account:
//Single Master Trigger on Account using Handlers for each individual actions trigger AccountTrigger on Account (before delete, before insert, before update, after insert, after update,after delete) { checkRecursive.isRunOnce = true; // ToDo : Need to change the recursive handling logic AccountTriggerHandler accHandler = new AccountTriggerHandler(trigger.new,trigger.old,trigger.newMap,trigger.oldMap,trigger.isUpdate); if(trigger.isBefore && trigger.isInsert){ accHandler.HandleBeforeInsert(); } if(trigger.isBefore && trigger.isUpdate){ accHandler.HandleBeforeUpdate(); } if(trigger.isAfter && trigger.isInsert) { accHandler.HandleAfterInsert(); } if(trigger.isAfter && trigger.isUpdate){ accHandler.HandleAfterUpdate(); } if(trigger.isBefore && trigger.isDelete) accHandler.HandleBeforeDelete(); if(trigger.isAfter && trigger.isDelete) accHandler.HandleAfterDelete(); }
My class code is as belows:
//Handler Class to handle Account Trigger public class AccountTriggerHandler { public static Boolean runAccountTriggerHandler = true; private static Boolean geocodingCalled = false; //recursive variables public static boolean run = true; public static boolean runOnce(){ if(run){ run=false; return true; }else{ return run; } } //trigger variables List<Account> newAccs; List<Account> oldAccs; Map<Id,Account> newAccMap; Map<Id,Account> oldAccMap; Id accountId; boolean isUpdate; //constructor public AccountTriggerHandler(List<Account> newAccs, List<Account> oldAccs, Map<Id,Account> newAccMap, Map<Id,Account> oldAccMap, boolean isUpdate){ this.newAccs = newAccs; this.oldAccs = oldAccs; this.newAccMap = newAccMap; this.oldAccMap = oldAccMap; this.isUpdate = isUpdate; this.accountId= accountId; this.consentService = new ConsentManagementService(Account.sObjectType); } public void HandleAfterInsert(){ system.debug(LoggingLevel.DEBUG, '***Inside after insert- ' ); for(Account account : newAccs) { //check if Map Address has been updated Boolean addressChangedFlag = false; if(Trigger.isInsert) { Account newAccount = (Account)Trigger.newMap.get(account.Id); if((account.MapAddressStreet__c != newAccount.MapAddressStreet__c) || (account.MapAddressCity__c != newAccount.MapAddressCity__c) || (account.MapPostalState__c!= newAccount.MapPostalState__c) || (account.MapAddressPostalCode__c!= newAccount.MapAddressPostalCode__c) || (account.MapAddressCountry__c!= newAccount.MapAddressCountry__c)) { addressChangedFlag = true; System.debug(LoggingLevel.DEBUG, '***Address changed for - ' +newAccount.Name); } } if(((account.Location__Latitude__s == null) || (addressChangedFlag == true)) && (String.isNotBlank(account.MapAddressCountry__c))){ System.debug(LoggingLevel.DEBUG,'***Geocoding Account - ' + account.Name); AccountTriggerHandler.DoAddressGeocode(account.id); } } } public void HandleAfterUpdate(){ system.debug(LoggingLevel.DEBUG, '***Inside after update- ' ); for(Account account : newAccs) { //check if Map Address has been updated Boolean addressChangedFlag = false; if(Trigger.isUpdate) { Account oldAccount = (Account)Trigger.oldMap.get(account.Id); if((account.MapAddressStreet__c != oldAccount.MapAddressStreet__c) || (account.MapAddressCity__c != oldAccount.MapAddressCity__c) || (account.MapPostalState__c!= oldAccount.MapPostalState__c) || (account.MapAddressPostalCode__c!= oldAccount.MapAddressPostalCode__c) || (account.MapAddressCountry__c!= oldAccount.MapAddressCountry__c)) { addressChangedFlag = true; System.debug(LoggingLevel.DEBUG, '***Address changed for - ' +oldAccount.Name); } } if(((account.Location__Latitude__s == null) || (addressChangedFlag == true)) && (String.isNotBlank(account.MapAddressCountry__c))) { System.debug(LoggingLevel.DEBUG,'***Geocoding Account - ' + account.Name); AccountTriggerHandler.DoAddressGeocode(account.id); } } } public void HandleBeforeDelete(){ } public void HandleAfterDelete(){ } // wrapper method to prevent calling futuremethods from an existing future context public static void DoAddressGeocode(id accountId) { if(geocodingCalled || System.isFuture()) { System.debug(LoggingLevel.WARN,'***Address Geocoding Future Method Already Called - Aborting...'); return; } // if not being called from future context, geocode the address geocodingCalled= true; getLocation(accountId); } @future (callout=true) // future method needed to run callouts from Triggers static public void getLocation( id accountId){ String geocodingKey ='AIzaSyD6DLnewg4y0Casi0-iFFjoenLJmmayt8c'; Account a = new Account(); if(!Test.isRunningTest()) // gather account info a= [SELECT id, MapAddressCity__c,MapAddressCountry__c,MapAddressPostalCode__c,MapAddressStreet__c,MapPostalState__c FROM Account WHERE id =: accountId]; // create an address string String address = ''; if (a.MapAddressStreet__c!= null) address += a.MapAddressStreet__c+', '; if (a.MapAddressCity__c != null) address += a.MapAddressCity__c +', '; if (a.MapPostalState__c!= null) address += a.MapPostalState__c+' '; if (a.MapAddressPostalCode__c!= null) address += a.MapAddressPostalCode__c+', '; if (a.MapAddressCountry__c!= null) address += a.MapAddressCountry__c; address = EncodingUtil.urlEncode(address, 'UTF-8'); // build callout Http h = new Http(); HttpRequest req = new HttpRequest(); req.setEndpoint('https://maps.googleapis.com/maps/api/geocode/json?address='+address + '&key='+ geocodingKey+ '&sensor=false'); req.setMethod('GET'); req.setTimeout(60000); try{ // callout HttpResponse res = h.send(req); // parse coordinates from response JSONParser parser = JSON.createParser(res.getBody()); system.debug('Harjeet:'+ res.getBody()); double lat = null; double lon = null; while (parser.nextToken() != null) { if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'location')){ parser.nextToken(); // object start while (parser.nextToken() != JSONToken.END_OBJECT){ String txt = parser.getText(); parser.nextToken(); if (txt == 'lat') lat = parser.getDoubleValue(); else if (txt == 'lng') lon = parser.getDoubleValue(); } } } // update coordinates if we get back if (lat != null){ a.Location__Latitude__s = lat; a.Location__Longitude__s = lon; update a; } } catch (Exception e) { } } }
I have removed all the extra codes and methods from class and only kept my method in class to have a better visibility for code to all of you.
I am calling "DoAddressGeocode" method on HandleAfterInsert and HandleAfterUpdate.
Kindly help me why few thousand records inserted/updated succesfully using data loader with long/lat and coordinate values and other few thousand records are only inserting/updating but not lat/ong and coordinates are updating.
Any help will be greatly appreciated!
Thanks in advance
Thanks & Regards,
Harjeet
- Harjeet Singh 13
- February 02, 2018
- Like
- 0
Coordinates are not updating on bulk insert/update
I am immense need of help from all of you. After giving a much thought and so much brainstorming happened finally I turned up here for advise.
Requirement:
I need to fetch coordinates value of account based on Map address provided. Map addresses are new fields created on accounts object(map street,map city,map postal code,map countrymap state)
Solution approach
I create few fields on accounts like MapAddressCity,MapAddressState,MapAddressStreet,MapAddressPostalCode and MapAddresscountry on account. When an user enters values in Map fields and clicks on save button I am calling Google API. Google API will returns one coordinate value based on address filled in Map fields. I have created one field called "Location"(Data Type-Geolocation) which will stores coordinates and also I created 2 formula fields which stores the longitude and latitude values of coordinates in "LonField" and "LatField" respectively
If an user enters below in account:
MapAddressCity: San Francisco
MapAddressCountry: United States
MapAddressPostalCode: 94105
MapPostalState: CA
MapAddressStreet: One Market Street
and clicks on Save-Google API call will be made and below information wiull be stored on account:
Location-37°47'38''N 122°23'41''W
LongValue-122.3948
LatValue37.7939
My Question:
In our org there is already one trigger written on account and there is already one accounthandler class and we always follow best practices so I didnt write a separate trigger and class to achieve above mentioned requirement. I am reusing same accounttriggerhandler class and apex trigger which is written on account.
When I am trying to insert account records through data loader some accounts have updated coordinates after insertion whereas some doesn't have coordinates inserted.
I tried inserting around 17K records upon which 5K records inserted succesfully and also their corresponding coordinates are updated. Rest 12K records also inserted succesfully but their coordinates are not updated.
Kindly help me. Below is trigger which is already existing on account:
//Single Master Trigger on Account using Handlers for each individual actions trigger AccountTrigger on Account (before delete, before insert, before update, after insert, after update,after delete) { checkRecursive.isRunOnce = true; // ToDo : Need to change the recursive handling logic AccountTriggerHandler accHandler = new AccountTriggerHandler(trigger.new,trigger.old,trigger.newMap,trigger.oldMap,trigger.isUpdate); if(trigger.isBefore && trigger.isInsert){ accHandler.HandleBeforeInsert(); } if(trigger.isBefore && trigger.isUpdate){ accHandler.HandleBeforeUpdate(); } if(trigger.isAfter && trigger.isInsert) { accHandler.HandleAfterInsert(); } if(trigger.isAfter && trigger.isUpdate){ accHandler.HandleAfterUpdate(); } if(trigger.isBefore && trigger.isDelete) accHandler.HandleBeforeDelete(); if(trigger.isAfter && trigger.isDelete) accHandler.HandleAfterDelete(); }
My class code is as belows:
//Handler Class to handle Account Trigger public class AccountTriggerHandler { public static Boolean runAccountTriggerHandler = true; private static Boolean geocodingCalled = false; //recursive variables public static boolean run = true; public static boolean runOnce(){ if(run){ run=false; return true; }else{ return run; } } //trigger variables List<Account> newAccs; List<Account> oldAccs; Map<Id,Account> newAccMap; Map<Id,Account> oldAccMap; Id accountId; boolean isUpdate; //constructor public AccountTriggerHandler(List<Account> newAccs, List<Account> oldAccs, Map<Id,Account> newAccMap, Map<Id,Account> oldAccMap, boolean isUpdate){ this.newAccs = newAccs; this.oldAccs = oldAccs; this.newAccMap = newAccMap; this.oldAccMap = oldAccMap; this.isUpdate = isUpdate; this.accountId= accountId; this.consentService = new ConsentManagementService(Account.sObjectType); } public void HandleAfterInsert(){ system.debug(LoggingLevel.DEBUG, '***Inside after insert- ' ); for(Account account : newAccs) { //check if Map Address has been updated Boolean addressChangedFlag = false; if(Trigger.isInsert) { Account newAccount = (Account)Trigger.newMap.get(account.Id); if((account.MapAddressStreet__c != newAccount.MapAddressStreet__c) || (account.MapAddressCity__c != newAccount.MapAddressCity__c) || (account.MapPostalState__c!= newAccount.MapPostalState__c) || (account.MapAddressPostalCode__c!= newAccount.MapAddressPostalCode__c) || (account.MapAddressCountry__c!= newAccount.MapAddressCountry__c)) { addressChangedFlag = true; System.debug(LoggingLevel.DEBUG, '***Address changed for - ' +newAccount.Name); } } if(((account.Location__Latitude__s == null) || (addressChangedFlag == true)) && (String.isNotBlank(account.MapAddressCountry__c))){ System.debug(LoggingLevel.DEBUG,'***Geocoding Account - ' + account.Name); AccountTriggerHandler.DoAddressGeocode(account.id); } } } public void HandleAfterUpdate(){ system.debug(LoggingLevel.DEBUG, '***Inside after update- ' ); for(Account account : newAccs) { //check if Map Address has been updated Boolean addressChangedFlag = false; if(Trigger.isUpdate) { Account oldAccount = (Account)Trigger.oldMap.get(account.Id); if((account.MapAddressStreet__c != oldAccount.MapAddressStreet__c) || (account.MapAddressCity__c != oldAccount.MapAddressCity__c) || (account.MapPostalState__c!= oldAccount.MapPostalState__c) || (account.MapAddressPostalCode__c!= oldAccount.MapAddressPostalCode__c) || (account.MapAddressCountry__c!= oldAccount.MapAddressCountry__c)) { addressChangedFlag = true; System.debug(LoggingLevel.DEBUG, '***Address changed for - ' +oldAccount.Name); } } if(((account.Location__Latitude__s == null) || (addressChangedFlag == true)) && (String.isNotBlank(account.MapAddressCountry__c))) { System.debug(LoggingLevel.DEBUG,'***Geocoding Account - ' + account.Name); AccountTriggerHandler.DoAddressGeocode(account.id); } } } public void HandleBeforeDelete(){ } public void HandleAfterDelete(){ } // wrapper method to prevent calling futuremethods from an existing future context public static void DoAddressGeocode(id accountId) { if(geocodingCalled || System.isFuture()) { System.debug(LoggingLevel.WARN,'***Address Geocoding Future Method Already Called - Aborting...'); return; } // if not being called from future context, geocode the address geocodingCalled= true; getLocation(accountId); } @future (callout=true) // future method needed to run callouts from Triggers static public void getLocation( id accountId){ String geocodingKey ='AIzaSyD6DLnewg4y0Casi0-iFFjoenLJmmayt8c'; Account a = new Account(); if(!Test.isRunningTest()) // gather account info a= [SELECT id, MapAddressCity__c,MapAddressCountry__c,MapAddressPostalCode__c,MapAddressStreet__c,MapPostalState__c FROM Account WHERE id =: accountId]; // create an address string String address = ''; if (a.MapAddressStreet__c!= null) address += a.MapAddressStreet__c+', '; if (a.MapAddressCity__c != null) address += a.MapAddressCity__c +', '; if (a.MapPostalState__c!= null) address += a.MapPostalState__c+' '; if (a.MapAddressPostalCode__c!= null) address += a.MapAddressPostalCode__c+', '; if (a.MapAddressCountry__c!= null) address += a.MapAddressCountry__c; address = EncodingUtil.urlEncode(address, 'UTF-8'); // build callout Http h = new Http(); HttpRequest req = new HttpRequest(); req.setEndpoint('https://maps.googleapis.com/maps/api/geocode/json?address='+address + '&key='+ geocodingKey+ '&sensor=false'); req.setMethod('GET'); req.setTimeout(60000); try{ // callout HttpResponse res = h.send(req); // parse coordinates from response JSONParser parser = JSON.createParser(res.getBody()); system.debug('Harjeet:'+ res.getBody()); double lat = null; double lon = null; while (parser.nextToken() != null) { if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'location')){ parser.nextToken(); // object start while (parser.nextToken() != JSONToken.END_OBJECT){ String txt = parser.getText(); parser.nextToken(); if (txt == 'lat') lat = parser.getDoubleValue(); else if (txt == 'lng') lon = parser.getDoubleValue(); } } } // update coordinates if we get back if (lat != null){ a.Location__Latitude__s = lat; a.Location__Longitude__s = lon; update a; } } catch (Exception e) { } } }
I have removed all the extra codes and methods from class and only kept my method in class to have a better visibility for code to all of you.
I am calling "DoAddressGeocode" method on HandleAfterInsert and HandleAfterUpdate.
Kindly help me why few thousand records inserted/updated succesfully using data loader with long/lat and coordinate values and other few thousand records are only inserting/updating but not lat/ong and coordinates are updating.
Any help will be greatly appreciated!
Thanks in advance
Thanks & Regards,
Harjeet
- Harjeet Singh 13
- February 02, 2018
- Like
- 0
How can I bulkify my code to store coordinates for multiple accounts
I am immense need of help from all of you. After giving a much thought and so much brainstorming happened finally I turned up here for advise.
Requirement:
I need to fetch coordinates value of account based on Map address provided
Solution approach
I create few fields on accounts like MapAddressCity,MapAddressState,MapAddressStreet,MapAddressPostalCode and MapAddresscountry on account. When an user enters values in Map fields and clicks on save button I am calling Google API. Google API will returns one coordinate value based on address filled in Map fields. I have created one field called "Location"(Data Type-Geolocation) which will stores coordinates and also I created 2 formula fields which stores the longitude and latitude values of coordinates in "LonField" and "LatField" respectively
If an user enters below in account:
MapAddressCity: San Francisco
MapAddressCountry: United States
MapAddressPostalCode: 94105
MapPostalState: CA
MapAddressStreet: One Market Street
and clicks on Save-Google API call will be made and below information wiull be stored on account:
Location-37°47'38''N 122°23'41''W
LongValue-122.3948
LatValue37.7939
My Question:
In our org there is already one trigger written on account and there is already one accounthandler class and we always follow best practices so I didnt write a separate trigger and class to achieve above mentioned requirement. I am reusing same accounttriggerhandler class and apex trigger which is written on account.
If I write separate class and trigger to achieve above mentioned functionality then I have no issue everything works smoothly but when I am trying to include my code in already existing account trigger handler then I am not able to make my code bulkify. I am calling my class method on after insert and after update and coordinates fields are updating perfectly but only for single account because I am not able to make my code bulkify and runs for multiple accounts.
Kindly help me. Below is trigger which is already existing on account:
//Single Master Trigger on Account using Handlers for each individual actions trigger AccountTrigger on Account (before delete, before insert, before update, after insert, after update,after delete) { checkRecursive.isRunOnce = true; // ToDo : Need to change the recursive handling logic AccountTriggerHandler accHandler = new AccountTriggerHandler(trigger.new,trigger.old,trigger.newMap,trigger.oldMap,trigger.isUpdate); if(trigger.isBefore && trigger.isInsert){ accHandler.HandleBeforeInsert(); } if(trigger.isBefore && trigger.isUpdate){ accHandler.HandleBeforeUpdate(); } if(trigger.isAfter && trigger.isInsert) { accHandler.HandleAfterInsert(); } if(trigger.isAfter && trigger.isUpdate){ accHandler.HandleAfterUpdate(); } if(trigger.isBefore && trigger.isDelete) accHandler.HandleBeforeDelete(); if(trigger.isAfter && trigger.isDelete) accHandler.HandleAfterDelete(); }
My class code is as belows:
//Handler Class to handle Account Trigger public class AccountTriggerHandler { public static Boolean runAccountTriggerHandler = true; private static Boolean geocodingCalled = false; public static boolean run = true; public static boolean runOnce(){ if(run){ run=false; return true; }else{ return run; } } //trigger variables List<Account> newAccs; List<Account> oldAccs; Map<Id,Account> newAccMap; Map<Id,Account> oldAccMap; Id accountId; boolean isUpdate; //constructor public AccountTriggerHandler(List<Account> newAccs, List<Account> oldAccs, Map<Id,Account> newAccMap, Map<Id,Account> oldAccMap, boolean isUpdate){ this.newAccs = newAccs; this.oldAccs = oldAccs; this.newAccMap = newAccMap; this.oldAccMap = oldAccMap; this.isUpdate = isUpdate; this.accountId= accountId; this.consentService = new ConsentManagementService(Account.sObjectType); } public void HandleAfterInsert(){ //if(!System.isFuture()) //getLocation(newAccs[0].Id); DoAddressGeocode(newAccs[0].id); } } public void HandleAfterUpdate(){ //if(!System.isFuture()) //getLocation(newAccs[0].Id); DoAddressGeocode(newAccs[0].id); } } } public void HandleBeforeDelete(){ } public void HandleAfterDelete(){ } // wrapper method to prevent calling futuremethods from an existing future context public static void DoAddressGeocode(id accountId) { if(geocodingCalled || System.isFuture()) { System.debug(LoggingLevel.WARN,'***Address Geocoding Future Method Already Called - Aborting...'); return; } // if not being called from future context, geocode the address geocodingCalled= true; getLocation(accountId); } @future (callout=true) // future method needed to run callouts from Triggers static public void getLocation( id accountId){ // gather account info Account a =[SELECT MapAddressCity__c,MapAddressCountry__c,MapAddressPostalCode__c,MapAddressStreet__c,MapPostalState__c FROM Account WHERE id =: accountId]; //List<Account> a= new List<Account>(); //a= [SELECT id, MapAddressCity__c,MapAddressCountry__c,MapAddressPostalCode__c,MapAddressStreet__c,MapPostalState__c FROM Account WHERE id =: accountId]; // create an address string String address = ''; if (a.MapAddressStreet__c!= null) address += a.MapAddressStreet__c+', '; if (a.MapAddressCity__c != null) address += a.MapAddressCity__c +', '; if (a.MapPostalState__c!= null) address += a.MapPostalState__c+' '; if (a.MapAddressPostalCode__c!= null) address += a.MapAddressPostalCode__c+', '; if (a.MapAddressCountry__c!= null) address += a.MapAddressCountry__c; address = EncodingUtil.urlEncode(address, 'UTF-8'); // build callout Http h = new Http(); HttpRequest req = new HttpRequest(); req.setEndpoint('http://maps.googleapis.com/maps/api/geocode/json?address='+address+'&sensor=false'); req.setMethod('GET'); req.setTimeout(60000); try{ // callout HttpResponse res = h.send(req); // parse coordinates from response JSONParser parser = JSON.createParser(res.getBody()); double lat = null; double lon = null; while (parser.nextToken() != null) { if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'location')){ parser.nextToken(); // object start while (parser.nextToken() != JSONToken.END_OBJECT){ String txt = parser.getText(); parser.nextToken(); if (txt == 'lat') lat = parser.getDoubleValue(); else if (txt == 'lng') lon = parser.getDoubleValue(); } } } // update coordinates if we get back if (lat != null){ a.Location__Latitude__s = lat; a.Location__Longitude__s = lon; update a; } } catch (Exception e) { } } }
I have removed all the extra codes and methods from class and only kept my method in class to have a better visibility for code to all of you.
I am calling "DoAddressGeocode" method on HandleAfterInsert and HandleAfterUpdate.
Right now I am not able to do bulkification of my code and wrote only for 1 accounts like DoAddressGeocode(newAccs[0].id)
Any help would be greatly appreciated.
Thanks in advance!
Kindly help
- Harjeet Singh 13
- January 23, 2018
- Like
- 0
How to bulkify triggers
I am immense need of help from all of you. After giving a much thought and so much brainstorming happened finally I turned up here for advise.
Requirement:
I need to fetch coordinates value of account based on Map address provided
Solution approach
I create few fields on accounts like MapAddressCity,MapAddressState,MapAddressStreet,MapAddressPostalCode and MapAddresscountry on account. When an user enters values in Map fields and clicks on save button I am calling Google API. Google API will returns one coordinate value based on address filled in Map fields. I have created one field called "Location"(Data Type-Geolocation) which will stores coordinates and also I created 2 formula fields which stores the longitude and latitude values of coordinates in "LonField" and "LatField" respectively
If an user enters below in account:
MapAddressCity: San Francisco
MapAddressCountry: United States
MapAddressPostalCode: 94105
MapPostalState: CA
MapAddressStreet: One Market Street
and clicks on Save-Google API call will be made and below information wiull be stored on account:
Location-37°47'38''N 122°23'41''W
LongValue-122.3948
LatValue37.7939
My Question:
In our org there is already one trigger written on account and there is already one accounthandler class and we always follow best practices so I didnt write a separate trigger and class to achieve above mentioned requirement. I am reusing same accounttriggerhandler class and apex trigger which is written on account.
If I write separate class and trigger to achieve above mentioned functionality then I have no issue everything works smoothly but when I am trying to include my code in already existing account trigger handler then I am not able to make my code bulkify. I am calling my class method on after insert and after update and coordinates fields are updating perfectly but only for single account because I am not able to make my code bulkify and runs for multiple accounts.
Kindly help me. Below is trigger which is already existing on account:
//Single Master Trigger on Account using Handlers for each individual actions trigger AccountTrigger on Account (before delete, before insert, before update, after insert, after update,after delete) { checkRecursive.isRunOnce = true; // ToDo : Need to change the recursive handling logic AccountTriggerHandler accHandler = new AccountTriggerHandler(trigger.new,trigger.old,trigger.newMap,trigger.oldMap,trigger.isUpdate); if(trigger.isBefore && trigger.isInsert){ accHandler.HandleBeforeInsert(); } if(trigger.isBefore && trigger.isUpdate){ accHandler.HandleBeforeUpdate(); } if(trigger.isAfter && trigger.isInsert) { accHandler.HandleAfterInsert(); } if(trigger.isAfter && trigger.isUpdate){ accHandler.HandleAfterUpdate(); } if(trigger.isBefore && trigger.isDelete) accHandler.HandleBeforeDelete(); if(trigger.isAfter && trigger.isDelete) accHandler.HandleAfterDelete(); }
My class code is as belows:
//Handler Class to handle Account Trigger public class AccountTriggerHandler { public static Boolean runAccountTriggerHandler = true; private static Boolean geocodingCalled = false; public static boolean run = true; public static boolean runOnce(){ if(run){ run=false; return true; }else{ return run; } } //trigger variables List<Account> newAccs; List<Account> oldAccs; Map<Id,Account> newAccMap; Map<Id,Account> oldAccMap; Id accountId; boolean isUpdate; //constructor public AccountTriggerHandler(List<Account> newAccs, List<Account> oldAccs, Map<Id,Account> newAccMap, Map<Id,Account> oldAccMap, boolean isUpdate){ this.newAccs = newAccs; this.oldAccs = oldAccs; this.newAccMap = newAccMap; this.oldAccMap = oldAccMap; this.isUpdate = isUpdate; this.accountId= accountId; this.consentService = new ConsentManagementService(Account.sObjectType); } public void HandleAfterInsert(){ //if(!System.isFuture()) //getLocation(newAccs[0].Id); DoAddressGeocode(newAccs[0].id); } } public void HandleAfterUpdate(){ //if(!System.isFuture()) //getLocation(newAccs[0].Id); DoAddressGeocode(newAccs[0].id); } } } public void HandleBeforeDelete(){ } public void HandleAfterDelete(){ } // wrapper method to prevent calling futuremethods from an existing future context public static void DoAddressGeocode(id accountId) { if(geocodingCalled || System.isFuture()) { System.debug(LoggingLevel.WARN,'***Address Geocoding Future Method Already Called - Aborting...'); return; } // if not being called from future context, geocode the address geocodingCalled= true; getLocation(accountId); } @future (callout=true) // future method needed to run callouts from Triggers static public void getLocation( id accountId){ // gather account info Account a =[SELECT MapAddressCity__c,MapAddressCountry__c,MapAddressPostalCode__c,MapAddressStreet__c,MapPostalState__c FROM Account WHERE id =: accountId]; //List<Account> a= new List<Account>(); //a= [SELECT id, MapAddressCity__c,MapAddressCountry__c,MapAddressPostalCode__c,MapAddressStreet__c,MapPostalState__c FROM Account WHERE id =: accountId]; // create an address string String address = ''; if (a.MapAddressStreet__c!= null) address += a.MapAddressStreet__c+', '; if (a.MapAddressCity__c != null) address += a.MapAddressCity__c +', '; if (a.MapPostalState__c!= null) address += a.MapPostalState__c+' '; if (a.MapAddressPostalCode__c!= null) address += a.MapAddressPostalCode__c+', '; if (a.MapAddressCountry__c!= null) address += a.MapAddressCountry__c; address = EncodingUtil.urlEncode(address, 'UTF-8'); // build callout Http h = new Http(); HttpRequest req = new HttpRequest(); req.setEndpoint('http://maps.googleapis.com/maps/api/geocode/json?address='+address+'&sensor=false'); req.setMethod('GET'); req.setTimeout(60000); try{ // callout HttpResponse res = h.send(req); // parse coordinates from response JSONParser parser = JSON.createParser(res.getBody()); double lat = null; double lon = null; while (parser.nextToken() != null) { if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'location')){ parser.nextToken(); // object start while (parser.nextToken() != JSONToken.END_OBJECT){ String txt = parser.getText(); parser.nextToken(); if (txt == 'lat') lat = parser.getDoubleValue(); else if (txt == 'lng') lon = parser.getDoubleValue(); } } } // update coordinates if we get back if (lat != null){ a.Location__Latitude__s = lat; a.Location__Longitude__s = lon; update a; } } catch (Exception e) { } } }
I have removed all the extra codes and methods from class and only kept my method in class to have a better visibility for code to all of you.
I am calling "DoAddressGeocode" method on HandleAfterInsert and HandleAfterUpdate.
Right now I am not able to do bulkification of my code and wrote only for 1 accounts like DoAddressGeocode(newAccs[0].id)
Any help would be greatly appreciated.
Thanks in advance!
Kindly help
- Harjeet Singh 13
- January 23, 2018
- Like
- 0
How can I calculate and store hash value based on multliple picklist field value
I am working on a requiremnts which states something as belows:
Craete a new field on Account object which will calculate and store hash value based on a multiple picklist field field "Products" (Products__c)on account object.
Products(Products__c) field have below mentioned values:
- Baha
- Vistafix
- Codacs
- Hybrid
- Nucleus
- CI
- Acoustic
I have craeted 1 numer field on Aaccount Object as ProductsHash__c and created 1 trigger as below:
trigger CalculateHash on Account (before insert,before update) { public void beforeInsert(Account newAcct){ AccountPopulator.populateProductsHash(null, newAcct); } public void beforeUpdate(Account oldAcc, Account newAcc){ AccountPopulator.populateProductsHash(oldAcc, newAcc); } }Below is my class:
public class AccountPopulator{ public static void populateProductsHash(Account oldAcct, Account newAcct){ if(oldAcct == null || oldAcct.Products__c != oldAcct.Products__c){ newAcct.ProductsHash__c=System.hashCode(Account.Products__c); } } }
Problem Encouter:
Nothing is happening. The newly created field Products_Hash__c on account object is calculating nothing and storing nothing based on the Paroducts__c field on Account.
Kindly help me what I am doing wrong or what I am missing.
Any help will be greatly appreciated!
Thanks in advance
Thanks & Regards,
Harjeet
- Harjeet Singh 13
- December 27, 2017
- Like
- 0
Create a field which calculate hash value based on multiple picklist field value same object
I have one field called "Products" in account object which is a multi select picklist field with value: Baha,Vistafix,Codacs,Hybrid,Nucleus,CI ,Acoustic
Kindly help me how to achieve the same. I have no idea about hash and dont know how to proceed.
Any help would be greatly appreciated!
Thanks
- Harjeet Singh 13
- December 27, 2017
- Like
- 0
How to create a field to calculate hash value based on multiple picklist field value on same object
I have one field called "Products" in account object which is a multi select picklist field with value: Baha,Vistafix,Codacs,Hybrid,Nucleus,CI ,Acoustic
Kindly help me how to achieve the same. I have no idea about hash and dont know how to proceed.
Any help would be greatly appreciated!
Thanks
- Harjeet Singh 13
- December 26, 2017
- Like
- 0
Create a field to calculate hash value based on multiple picklist field value on object
I have one field called "Products" in account object which is a multi select picklist field with value: Baha,Vistafix,Codacs,Hybrid,Nucleus,CI ,Acoustic
Kindly help me how to achieve the same. I have no idea about hash and dont know how to proceed.
Any help would be greatly appreciated!
Thanks
- Harjeet Singh 13
- December 26, 2017
- Like
- 0
Create a field to calculate hash value based on multiple picklist field value
I have one field called "Products" in account object which is a multi select picklist field with value: Baha,Vistafix,Codacs,Hybrid,Nucleus,CI ,Acoustic
Kindly help me how to achieve the same. I have no idea about hash and dont know how to proceed.
Any help would be greatly appreciated!
Thanks
- Harjeet Singh 13
- December 26, 2017
- Like
- 0
How to copy attachments sent with an email from child case to master case
Right now what ever I have developed I achieved copying emails from child to master case. But when an email is sent with attachments from child case then only email is getting copied to master case not the attachments.
Below is my trigger code
trigger CaseTrigger on Case (before insert, after insert, before update,after update, before delete,after delete) { CaseTriggerHandler csHandler = new CaseTriggerHandler(trigger.new,trigger.old,trigger.newMap,trigger.oldMap,trigger.isUpdate,trigger.isInsert); if (trigger.isAfter && trigger.isInsert) { csHandler.HandleAfterInsert(); } if (trigger.isAfter && trigger.isUpdate) { csHandler.HandleAfterUpdate(); } }
And Below is my trigger handler class(I have kept only useful method related to my question,rest I have omitted for better view and usefulness to my question)
public class CaseTriggerHandler { public static boolean run = true; public static boolean runOnce(){ if(run){ run=false; return true; }else{ return run; } } List<Case> listOfCase; List<Case> newCase; List<Case> oldCase; Map<Id,Case> newCaseMap; Map<Id,Case> oldCaseMap; boolean isUpdate; boolean isDelete; public CaseTriggerHandler (List<Case> newCase, List<Case> oldCase, Map<Id,Case> newCaseMap, Map<Id,Case> oldCaseMap, boolean isUpdate, boolean isDelete){ this.newCase = newCase; this.oldCase = oldCase; this.newCaseMap = newCaseMap; this.oldCaseMap = oldCaseMap; this.isUpdate = isUpdate; this.isDelete = isDelete; } public void HandleAfterUpdate(){ if(run){ handleemailattachment(); } } public void HandleAfterInsert(){ handleemailattachment(); } public void handleemailattachment(){ Map<Id, Id> parentCaseIdMap = new Map<Id, Id>(); for(Case c : newCase){ if(c.ParentId!=null)parentCaseIdMap.put(c.Id, c.ParentId); } // Fetch all the attachments related to the child case List<EmailMessage> EmailMessageList= new List<EmailMessage>(); List<EmailMessage> attachmentToBeCloned = new List<EmailMessage>(); EmailMessageList = [Select Id,Subject,ParentId,textBody From EmailMessage Where ParentId in:parentCaseIdMap.keySet()]; for(EmailMessage att : EmailMessageList){ EmailMessage a = att.clone(); if(parentCaseIdMap.containsKey(att.ParentId)){ a.ParentId = parentCaseIdMap.get(att.ParentId); attachmentToBeCloned.add(a); } } if(attachmentToBeCloned!=null && attachmentToBeCloned.size()>0){ insert attachmentToBeCloned; } } }
Illustration of my requirements:
Suppose I created one Email- to-Case which triggers a creation of cases in SF with 2 emails. Now I linked this case to other Case. Upon merging both of the cases emails are getting copied to master/parent case but if I attach any attachment while creating Email to Case then upon merging only emails are getting copied not attachments .
Kindly help.
Many thanks in advance
Thanks & Regards,
Harjeet
- Harjeet Singh 13
- April 10, 2018
- Like
- 0
How to notify account owner when a non account owner logs a call
Kindly help to acheive above mentioned requirements.
Many thanks in advance
Thanks & Regards,
Harjeet
- Harjeet Singh 13
- February 16, 2018
- Like
- 0
Getting System.NullPointerException: Attempt to de-reference a null object error in Test Class
I have developed a class which is calling standard REST API to determine Daily Apex Exceution Limits. I am getting error when I am running test class for the same.
Below is my Apex Class:
public class CurrentStorage{ public static void getStorage() { //fetch session od of user String sid = Userinfo.getSessionId(); //fetch Instance URL String baseURL = System.URL.getSalesforceBaseUrl().toExternalForm(); //Building call out to Standard Salesforce Rest API HttpRequest req = new HttpRequest(); req.setMethod('GET'); req.setEndpoint(baseURL+'/services/data/v41.0/limits'); req.setHeader('Authorization', 'OAuth '+ sid); Http http = new Http(); HTTPResponse res = http.send(req); Map<String, Object> m = (Map<String,Object>)JSON.deserializeUntyped(res.getBody()); Map<String, Object> dataStorage = (Map<String,Object>)m.get('DailyAsyncApexExecutions'); System.debug('Map: '+ dataStorage); System.debug('Current Storage: ' + dataStorage.get('Remaining')); If(Integer.valueof(dataStorage.get('Max'))*(0.8)<= (Integer.valueof(dataStorage.get('Max')) - Integer.valueof(dataStorage.get('Remaining')))){ Messaging.SingleEmailMessage message = new Messaging.SingleEmailMessage(); message.toAddresses = new String[] { 'abc@gmail.com','def@gmail.com'}; //message.optOutPolicy = 'FILTER'; message.subject = 'Async Apex Limits Threshold Warning'; message.plainTextBody = 'Your Org Limit of Daily Async Apex Execution reached 80% threshold for '+ baseURL; Messaging.SingleEmailMessage[] messages = new List<Messaging.SingleEmailMessage> {message}; Messaging.SendEmailResult[] results = Messaging.sendEmail(messages); if (results[0].success) { System.debug('The email was sent successfully.'); } else { System.debug('The email failed to send: ' + results[0].errors[0].message); } } // Send Mail to people } }
Below is my test class:
@isTest public class TestCurrentStorage { static testMethod void validateLocationCallouts() { RestRequest req = new RestRequest(); req.params.put('DailyAsyncApexExecutions', '250000'); //req.params.put('Max', '250000'); req.params.put('Remaining', '200000'); Test.startTest(); Test.setMock(HttpCalloutMock.class, new MockHttpResponse()); CurrentStorage.getStorage(); Test.stopTest(); } }
Below is my mock class:
@isTest global class mockHttpResponse implements HttpCalloutMock{ // Implement this interface method global HTTPResponse respond(HTTPRequest req) { System.assertEquals('GET', req.getMethod()); // Create a fake response HttpResponse res = new HttpResponse(); res.setHeader('Content-Type', 'application/json'); res.setBody('{"Max": "250000","Remaining": "200000"}'); res.setStatusCode(200); res.setStatus('OK'); return res; } }
When I am trying to run tess class I am getting below error trace logs:
Errors: System.NullPointerException: Attempt to de-reference a null object Stack Trace: Class.CurrentStorage.getStorage: Class.TestCurrentStorage.validateLocationCallouts:
Kindly help me to pass the test class.
Many thanks in advance
Thanks & Regards,
Harjeet
- Harjeet Singh 13
- February 15, 2018
- Like
- 0
How to send a notification/alert/email when certain threshold of Daily Async Apex Execution reaches
I want to send an alert notification when overall organisation Async Apex Execution limit reached 70%of total limit(24hrs API Limit). Say if limit is 2500 and if system already exhausted 1750 of daily Async Apex Limit out of 2500 then any alert should be send to few persons notifying that your organisation limit of Async Apex Executions have reached 70% threshold.
I have done few research on the same but didn't get anything concrete. I saw blogs/documentation stating about Limit class and Limit methods but those are having limit method for future but no where I get any thing related to Async Apex Exceution Limits. In Limit Class I saw there are 2 mthods 'getAsyncCalls()' and 'getLimitAsyncCalls()' but both are related reserved for future use.
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_methods_system_limits.htm#apex_System_limits_getAsyncCalls
Kindly help me.
Any help will be greatly appreciated.
Many thanks in advance
Thanks & Regards,
Harjeet
- Harjeet Singh 13
- February 12, 2018
- Like
- 0
Notification alert for Async Apex Execution Limits
I have done few research on the same but didn't get anything concrete. I saw blogs/documentation stating about Limit class and Limit methods but those are having limit method for future but no where I get any thing related to Async Apex Exceution Limits. In Limit Class I saw there are 2 mthods 'getAsyncCalls()' and 'getLimitAsyncCalls()' but both are related reserved for future use.
https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_methods_system_limits.htm#apex_System_limits_getAsyncCalls
Kindly help me.
Any help will be greatly appreciated.
Many thanks in advance
Thanks & Regards,
Harjeet
- Harjeet Singh 13
- February 12, 2018
- Like
- 0
Async Apex Execution Limits threshold limits notifications alert or email
Kindly help
Thanks & Regards,
Harjeet
- Harjeet Singh 13
- February 08, 2018
- Like
- 0
How to send an alert notification if Async Apex Execution Limits reached 70% of limit
Kindly help
Thanks
- Harjeet Singh 13
- February 08, 2018
- Like
- 0
After update triggers working everytime instead of after insert in geolocation triggers
I am immense need of help from all of you. After giving a much thought and so much brainstorming happened finally I turned up here for advise.
Requirement:
I need to fetch coordinates value of account based on Map address provided. Map addresses are new fields created on accounts object(map street,map city,map postal code,map countrymap state)
Solution approach
I create few fields on accounts like MapAddressCity,MapAddressState,MapAddressStreet,MapAddressPostalCode and MapAddresscountry on account. When an user enters values in Map fields and clicks on save button I am calling Google API. Google API will returns one coordinate value based on address filled in Map fields. I have created one field called "Location"(Data Type-Geolocation) which will stores coordinates and also I created 2 formula fields which stores the longitude and latitude values of coordinates in "LonField" and "LatField" respectively
If an user enters below in account:
MapAddressCity: San Francisco
MapAddressCountry: United States
MapAddressPostalCode: 94105
MapPostalState: CA
MapAddressStreet: One Market Street
and clicks on Save-Google API call will be made and below information wiull be stored on account:
Location-37°47'38''N 122°23'41''W
LongValue-122.3948
LatValue37.7939
My Question:
When I am trying to update an already existing account(update operation) then upon saving future method is called and coordinates are getting stored and in debug logs I can see "ta:coming in after UPDATE"(Kindly refer my trigger code) which is correct.But my worry point is when I am trying to insert a new account and provides map addresses and clicks on Save then also coordinates are getting stored which is also correct but in debug logs I cn still see "ta:coming in after UPDATE" instead of 'ta:coming in after insert' because its an insert not an update.
1.Why after trigger is not working and coordinates are getting populated correctly even for new insertion due to after update instead of after insert
2. When I am trying to insert account records through data loader some accounts have updated coordinates after insertion whereas some doesn't have coordinates inserted.
I tried inserting around 17K records upon which 5K records inserted succesfully and also their corresponding coordinates are updated. Rest 12K records also inserted succesfully but their coordinates are not updated.
Below is trigger which is written on account:
trigger geocodeAccountAddress on Account (after insert, after update) { Set<Id> li=new Set<Id>(); //bulkify trigger in case of multiple accounts // if(Trigger.isAfter && Trigger.isInsert){ System.debug('ta:coming in after insert'); for(Account acc:Trigger.New){ System.debug('ta:coming in after insert2'); if((acc.Location__Latitude__s == null) && (String.isNotBlank(acc.MapAddressCountry__c))){ System.debug('ta:coming in after insert1'); li.add(acc.id); System.debug('ta:coming in after insert4'); AccountGeocodeAddress.newAccmethod(li); } } } if(Trigger.isAfter && Trigger.isUpdate){ System.debug('ta:coming in after UPDATE'); for(Account acc:Trigger.New){ if((acc.Location__Latitude__s == null) &&(String.isNotBlank(acc.MapAddressCountry__c))){ System.debug('ta:coming in after UPDATE1'); li.add(acc.id); System.debug('ta:coming in after Update5'); AccountGeocodeAddress.newAccmethod(li); } } } }
My class code is as belows:
public class AccountGeocodeAddress { @future(callout=true) static public void newAccmethod(set<id> li){ for(Account a : [SELECT MapAddressCity__c,MapAddressCountry__c,MapAddressPostalCode__c,MapAddressStreet__c,MapPostalState__c FROM Account WHERE id =: li]){ String address = ' '; if (a.MapAddressStreet__c!= null) address += a.MapAddressStreet__c+', '; if (a.MapAddressCity__c != null) address += a.MapAddressCity__c +', '; if (a.MapPostalState__c!= null) address += a.MapPostalState__c+' '; if (a.MapAddressPostalCode__c!= null) address += a.MapAddressPostalCode__c+', '; if (a.MapAddressCountry__c!= null) address += a.MapAddressCountry__c; address = EncodingUtil.urlEncode(address, 'UTF-8'); // build callout Http h = new Http(); HttpRequest req = new HttpRequest(); //req.setEndpoint(‘http://maps.googleapis.com/maps/api/geocode/json?address=’+address+’&sensor=false’); req.setEndpoint('https://maps.googleapis.com/maps/api/geocode/json?address='+address + '&key='+ geocodingKey+ '&sensor=false'); req.setMethod('GET'); req.setTimeout(6000); try{ // callout HttpResponse res = h.send(req); // parse coordinates from response JSONParser parser = JSON.createParser(res.getBody()); system.debug('Harjeet:'+ res.getBody()); double lat = null; double lon = null; while (parser.nextToken() != null) { if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'location')){ parser.nextToken(); // object start while (parser.nextToken() != JSONToken.END_OBJECT){ String txt = parser.getText(); parser.nextToken(); if (txt == 'lat') lat = parser.getDoubleValue(); else if (txt == 'lng') lon = parser.getDoubleValue(); } } } // update coordinates if we get back if (lat != null){ system.debug(lat+' '+lon); a.Location__Latitude__s = lat; system.debug(a.Location__Latitude__s+'Location__Latitude__s'); a.Location__Longitude__s= lon; system.debug(a.Location__Longitude__s+'Location__Longitude__s'); update a; } } catch (Exception e) { system.debug(e); } } } }
Any help will be greatly appreciated!
Thanks in advance
Thanks & Regards,
Harjeet
- Harjeet Singh 13
- February 05, 2018
- Like
- 0
Coordinates of few accounts are not updating on bulk insert and update through data loader
I am immense need of help from all of you. After giving a much thought and so much brainstorming happened finally I turned up here for advise.
Requirement:
I need to fetch coordinates value of account based on Map address provided. Map addresses are new fields created on accounts object(map street,map city,map postal code,map countrymap state)
Solution approach
I create few fields on accounts like MapAddressCity,MapAddressState,MapAddressStreet,MapAddressPostalCode and MapAddresscountry on account. When an user enters values in Map fields and clicks on save button I am calling Google API. Google API will returns one coordinate value based on address filled in Map fields. I have created one field called "Location"(Data Type-Geolocation) which will stores coordinates and also I created 2 formula fields which stores the longitude and latitude values of coordinates in "LonField" and "LatField" respectively
If an user enters below in account:
MapAddressCity: San Francisco
MapAddressCountry: United States
MapAddressPostalCode: 94105
MapPostalState: CA
MapAddressStreet: One Market Street
and clicks on Save-Google API call will be made and below information wiull be stored on account:
Location-37°47'38''N 122°23'41''W
LongValue-122.3948
LatValue37.7939
My Question:
In our org there is already one trigger written on account and there is already one accounthandler class and we always follow best practices so I didnt write a separate trigger and class to achieve above mentioned requirement. I am reusing same accounttriggerhandler class and apex trigger which is written on account.
When I am trying to insert account records through data loader some accounts have updated coordinates after insertion whereas some doesn't have coordinates inserted.
I tried inserting around 17K records upon which 5K records inserted succesfully and also their corresponding coordinates are updated. Rest 12K records also inserted succesfully but their coordinates are not updated.
Kindly help me. Below is trigger which is already existing on account:
//Single Master Trigger on Account using Handlers for each individual actions trigger AccountTrigger on Account (before delete, before insert, before update, after insert, after update,after delete) { checkRecursive.isRunOnce = true; // ToDo : Need to change the recursive handling logic AccountTriggerHandler accHandler = new AccountTriggerHandler(trigger.new,trigger.old,trigger.newMap,trigger.oldMap,trigger.isUpdate); if(trigger.isBefore && trigger.isInsert){ accHandler.HandleBeforeInsert(); } if(trigger.isBefore && trigger.isUpdate){ accHandler.HandleBeforeUpdate(); } if(trigger.isAfter && trigger.isInsert) { accHandler.HandleAfterInsert(); } if(trigger.isAfter && trigger.isUpdate){ accHandler.HandleAfterUpdate(); } if(trigger.isBefore && trigger.isDelete) accHandler.HandleBeforeDelete(); if(trigger.isAfter && trigger.isDelete) accHandler.HandleAfterDelete(); }
My class code is as belows:
//Handler Class to handle Account Trigger public class AccountTriggerHandler { public static Boolean runAccountTriggerHandler = true; private static Boolean geocodingCalled = false; //recursive variables public static boolean run = true; public static boolean runOnce(){ if(run){ run=false; return true; }else{ return run; } } //trigger variables List<Account> newAccs; List<Account> oldAccs; Map<Id,Account> newAccMap; Map<Id,Account> oldAccMap; Id accountId; boolean isUpdate; //constructor public AccountTriggerHandler(List<Account> newAccs, List<Account> oldAccs, Map<Id,Account> newAccMap, Map<Id,Account> oldAccMap, boolean isUpdate){ this.newAccs = newAccs; this.oldAccs = oldAccs; this.newAccMap = newAccMap; this.oldAccMap = oldAccMap; this.isUpdate = isUpdate; this.accountId= accountId; this.consentService = new ConsentManagementService(Account.sObjectType); } public void HandleAfterInsert(){ system.debug(LoggingLevel.DEBUG, '***Inside after insert- ' ); for(Account account : newAccs) { //check if Map Address has been updated Boolean addressChangedFlag = false; if(Trigger.isInsert) { Account newAccount = (Account)Trigger.newMap.get(account.Id); if((account.MapAddressStreet__c != newAccount.MapAddressStreet__c) || (account.MapAddressCity__c != newAccount.MapAddressCity__c) || (account.MapPostalState__c!= newAccount.MapPostalState__c) || (account.MapAddressPostalCode__c!= newAccount.MapAddressPostalCode__c) || (account.MapAddressCountry__c!= newAccount.MapAddressCountry__c)) { addressChangedFlag = true; System.debug(LoggingLevel.DEBUG, '***Address changed for - ' +newAccount.Name); } } if(((account.Location__Latitude__s == null) || (addressChangedFlag == true)) && (String.isNotBlank(account.MapAddressCountry__c))){ System.debug(LoggingLevel.DEBUG,'***Geocoding Account - ' + account.Name); AccountTriggerHandler.DoAddressGeocode(account.id); } } } public void HandleAfterUpdate(){ system.debug(LoggingLevel.DEBUG, '***Inside after update- ' ); for(Account account : newAccs) { //check if Map Address has been updated Boolean addressChangedFlag = false; if(Trigger.isUpdate) { Account oldAccount = (Account)Trigger.oldMap.get(account.Id); if((account.MapAddressStreet__c != oldAccount.MapAddressStreet__c) || (account.MapAddressCity__c != oldAccount.MapAddressCity__c) || (account.MapPostalState__c!= oldAccount.MapPostalState__c) || (account.MapAddressPostalCode__c!= oldAccount.MapAddressPostalCode__c) || (account.MapAddressCountry__c!= oldAccount.MapAddressCountry__c)) { addressChangedFlag = true; System.debug(LoggingLevel.DEBUG, '***Address changed for - ' +oldAccount.Name); } } if(((account.Location__Latitude__s == null) || (addressChangedFlag == true)) && (String.isNotBlank(account.MapAddressCountry__c))) { System.debug(LoggingLevel.DEBUG,'***Geocoding Account - ' + account.Name); AccountTriggerHandler.DoAddressGeocode(account.id); } } } public void HandleBeforeDelete(){ } public void HandleAfterDelete(){ } // wrapper method to prevent calling futuremethods from an existing future context public static void DoAddressGeocode(id accountId) { if(geocodingCalled || System.isFuture()) { System.debug(LoggingLevel.WARN,'***Address Geocoding Future Method Already Called - Aborting...'); return; } // if not being called from future context, geocode the address geocodingCalled= true; getLocation(accountId); } @future (callout=true) // future method needed to run callouts from Triggers static public void getLocation( id accountId){ String geocodingKey ='AIzaSyD6DLnewg4y0Casi0-iFFjoenLJmmayt8c'; Account a = new Account(); if(!Test.isRunningTest()) // gather account info a= [SELECT id, MapAddressCity__c,MapAddressCountry__c,MapAddressPostalCode__c,MapAddressStreet__c,MapPostalState__c FROM Account WHERE id =: accountId]; // create an address string String address = ''; if (a.MapAddressStreet__c!= null) address += a.MapAddressStreet__c+', '; if (a.MapAddressCity__c != null) address += a.MapAddressCity__c +', '; if (a.MapPostalState__c!= null) address += a.MapPostalState__c+' '; if (a.MapAddressPostalCode__c!= null) address += a.MapAddressPostalCode__c+', '; if (a.MapAddressCountry__c!= null) address += a.MapAddressCountry__c; address = EncodingUtil.urlEncode(address, 'UTF-8'); // build callout Http h = new Http(); HttpRequest req = new HttpRequest(); req.setEndpoint('https://maps.googleapis.com/maps/api/geocode/json?address='+address + '&key='+ geocodingKey+ '&sensor=false'); req.setMethod('GET'); req.setTimeout(60000); try{ // callout HttpResponse res = h.send(req); // parse coordinates from response JSONParser parser = JSON.createParser(res.getBody()); system.debug('Harjeet:'+ res.getBody()); double lat = null; double lon = null; while (parser.nextToken() != null) { if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'location')){ parser.nextToken(); // object start while (parser.nextToken() != JSONToken.END_OBJECT){ String txt = parser.getText(); parser.nextToken(); if (txt == 'lat') lat = parser.getDoubleValue(); else if (txt == 'lng') lon = parser.getDoubleValue(); } } } // update coordinates if we get back if (lat != null){ a.Location__Latitude__s = lat; a.Location__Longitude__s = lon; update a; } } catch (Exception e) { } } }
I have removed all the extra codes and methods from class and only kept my method in class to have a better visibility for code to all of you.
I am calling "DoAddressGeocode" method on HandleAfterInsert and HandleAfterUpdate.
Kindly help me why few thousand records inserted/updated succesfully using data loader with long/lat and coordinate values and other few thousand records are only inserting/updating but not lat/ong and coordinates are updating.
Any help will be greatly appreciated!
Thanks in advance
Thanks & Regards,
Harjeet
- Harjeet Singh 13
- February 02, 2018
- Like
- 0
How to bulkify triggers
I am immense need of help from all of you. After giving a much thought and so much brainstorming happened finally I turned up here for advise.
Requirement:
I need to fetch coordinates value of account based on Map address provided
Solution approach
I create few fields on accounts like MapAddressCity,MapAddressState,MapAddressStreet,MapAddressPostalCode and MapAddresscountry on account. When an user enters values in Map fields and clicks on save button I am calling Google API. Google API will returns one coordinate value based on address filled in Map fields. I have created one field called "Location"(Data Type-Geolocation) which will stores coordinates and also I created 2 formula fields which stores the longitude and latitude values of coordinates in "LonField" and "LatField" respectively
If an user enters below in account:
MapAddressCity: San Francisco
MapAddressCountry: United States
MapAddressPostalCode: 94105
MapPostalState: CA
MapAddressStreet: One Market Street
and clicks on Save-Google API call will be made and below information wiull be stored on account:
Location-37°47'38''N 122°23'41''W
LongValue-122.3948
LatValue37.7939
My Question:
In our org there is already one trigger written on account and there is already one accounthandler class and we always follow best practices so I didnt write a separate trigger and class to achieve above mentioned requirement. I am reusing same accounttriggerhandler class and apex trigger which is written on account.
If I write separate class and trigger to achieve above mentioned functionality then I have no issue everything works smoothly but when I am trying to include my code in already existing account trigger handler then I am not able to make my code bulkify. I am calling my class method on after insert and after update and coordinates fields are updating perfectly but only for single account because I am not able to make my code bulkify and runs for multiple accounts.
Kindly help me. Below is trigger which is already existing on account:
//Single Master Trigger on Account using Handlers for each individual actions trigger AccountTrigger on Account (before delete, before insert, before update, after insert, after update,after delete) { checkRecursive.isRunOnce = true; // ToDo : Need to change the recursive handling logic AccountTriggerHandler accHandler = new AccountTriggerHandler(trigger.new,trigger.old,trigger.newMap,trigger.oldMap,trigger.isUpdate); if(trigger.isBefore && trigger.isInsert){ accHandler.HandleBeforeInsert(); } if(trigger.isBefore && trigger.isUpdate){ accHandler.HandleBeforeUpdate(); } if(trigger.isAfter && trigger.isInsert) { accHandler.HandleAfterInsert(); } if(trigger.isAfter && trigger.isUpdate){ accHandler.HandleAfterUpdate(); } if(trigger.isBefore && trigger.isDelete) accHandler.HandleBeforeDelete(); if(trigger.isAfter && trigger.isDelete) accHandler.HandleAfterDelete(); }
My class code is as belows:
//Handler Class to handle Account Trigger public class AccountTriggerHandler { public static Boolean runAccountTriggerHandler = true; private static Boolean geocodingCalled = false; public static boolean run = true; public static boolean runOnce(){ if(run){ run=false; return true; }else{ return run; } } //trigger variables List<Account> newAccs; List<Account> oldAccs; Map<Id,Account> newAccMap; Map<Id,Account> oldAccMap; Id accountId; boolean isUpdate; //constructor public AccountTriggerHandler(List<Account> newAccs, List<Account> oldAccs, Map<Id,Account> newAccMap, Map<Id,Account> oldAccMap, boolean isUpdate){ this.newAccs = newAccs; this.oldAccs = oldAccs; this.newAccMap = newAccMap; this.oldAccMap = oldAccMap; this.isUpdate = isUpdate; this.accountId= accountId; this.consentService = new ConsentManagementService(Account.sObjectType); } public void HandleAfterInsert(){ //if(!System.isFuture()) //getLocation(newAccs[0].Id); DoAddressGeocode(newAccs[0].id); } } public void HandleAfterUpdate(){ //if(!System.isFuture()) //getLocation(newAccs[0].Id); DoAddressGeocode(newAccs[0].id); } } } public void HandleBeforeDelete(){ } public void HandleAfterDelete(){ } // wrapper method to prevent calling futuremethods from an existing future context public static void DoAddressGeocode(id accountId) { if(geocodingCalled || System.isFuture()) { System.debug(LoggingLevel.WARN,'***Address Geocoding Future Method Already Called - Aborting...'); return; } // if not being called from future context, geocode the address geocodingCalled= true; getLocation(accountId); } @future (callout=true) // future method needed to run callouts from Triggers static public void getLocation( id accountId){ // gather account info Account a =[SELECT MapAddressCity__c,MapAddressCountry__c,MapAddressPostalCode__c,MapAddressStreet__c,MapPostalState__c FROM Account WHERE id =: accountId]; //List<Account> a= new List<Account>(); //a= [SELECT id, MapAddressCity__c,MapAddressCountry__c,MapAddressPostalCode__c,MapAddressStreet__c,MapPostalState__c FROM Account WHERE id =: accountId]; // create an address string String address = ''; if (a.MapAddressStreet__c!= null) address += a.MapAddressStreet__c+', '; if (a.MapAddressCity__c != null) address += a.MapAddressCity__c +', '; if (a.MapPostalState__c!= null) address += a.MapPostalState__c+' '; if (a.MapAddressPostalCode__c!= null) address += a.MapAddressPostalCode__c+', '; if (a.MapAddressCountry__c!= null) address += a.MapAddressCountry__c; address = EncodingUtil.urlEncode(address, 'UTF-8'); // build callout Http h = new Http(); HttpRequest req = new HttpRequest(); req.setEndpoint('http://maps.googleapis.com/maps/api/geocode/json?address='+address+'&sensor=false'); req.setMethod('GET'); req.setTimeout(60000); try{ // callout HttpResponse res = h.send(req); // parse coordinates from response JSONParser parser = JSON.createParser(res.getBody()); double lat = null; double lon = null; while (parser.nextToken() != null) { if ((parser.getCurrentToken() == JSONToken.FIELD_NAME) && (parser.getText() == 'location')){ parser.nextToken(); // object start while (parser.nextToken() != JSONToken.END_OBJECT){ String txt = parser.getText(); parser.nextToken(); if (txt == 'lat') lat = parser.getDoubleValue(); else if (txt == 'lng') lon = parser.getDoubleValue(); } } } // update coordinates if we get back if (lat != null){ a.Location__Latitude__s = lat; a.Location__Longitude__s = lon; update a; } } catch (Exception e) { } } }
I have removed all the extra codes and methods from class and only kept my method in class to have a better visibility for code to all of you.
I am calling "DoAddressGeocode" method on HandleAfterInsert and HandleAfterUpdate.
Right now I am not able to do bulkification of my code and wrote only for 1 accounts like DoAddressGeocode(newAccs[0].id)
Any help would be greatly appreciated.
Thanks in advance!
Kindly help
- Harjeet Singh 13
- January 23, 2018
- Like
- 0
How can I calculate and store hash value based on multliple picklist field value
I am working on a requiremnts which states something as belows:
Craete a new field on Account object which will calculate and store hash value based on a multiple picklist field field "Products" (Products__c)on account object.
Products(Products__c) field have below mentioned values:
- Baha
- Vistafix
- Codacs
- Hybrid
- Nucleus
- CI
- Acoustic
I have craeted 1 numer field on Aaccount Object as ProductsHash__c and created 1 trigger as below:
trigger CalculateHash on Account (before insert,before update) { public void beforeInsert(Account newAcct){ AccountPopulator.populateProductsHash(null, newAcct); } public void beforeUpdate(Account oldAcc, Account newAcc){ AccountPopulator.populateProductsHash(oldAcc, newAcc); } }Below is my class:
public class AccountPopulator{ public static void populateProductsHash(Account oldAcct, Account newAcct){ if(oldAcct == null || oldAcct.Products__c != oldAcct.Products__c){ newAcct.ProductsHash__c=System.hashCode(Account.Products__c); } } }
Problem Encouter:
Nothing is happening. The newly created field Products_Hash__c on account object is calculating nothing and storing nothing based on the Paroducts__c field on Account.
Kindly help me what I am doing wrong or what I am missing.
Any help will be greatly appreciated!
Thanks in advance
Thanks & Regards,
Harjeet
- Harjeet Singh 13
- December 27, 2017
- Like
- 0
Can you retrieve the Async limits from a class?
I can see there is a REST API that can be called so we can see where we are currently with all of the Salesforce limits. https://instance.salesforce.com/services/data/v37.0/limits/
We would like to be able to track the limits periodically using a trigger. Inside this trigger we would like to view the Daily Async Apex Executions, and do something if the number left is below a threshold
The only method that I can see of grabbing this number real time is with that REST API. Is there another way to grab that number? e.g. is there an object that I can query using SOQL? Alternatively, am I wrong in thinking it's impossible to grab the results from that REST API in a trigger?
I have searched for all resources on the topic and have come up blank. If someone could shine a light on this it would be greatly appreciated
Thanks
Mark
- Mark Mulholland 3
- June 22, 2017
- Like
- 0
2 Quick Questions RE: Governor Limit Max # of Asynchronous Apex Method Executions
"The maximum number of asynchronous Apex method executions (batch Apex, future methods, Queueable Apex, and scheduled Apex) per a 24-hour period: 250,000 or the number of user licenses in your organization multiplied by 200, whichever is greater"
When we're talking about batch Apex, for example, are we just talking about start(), execute(), finish() methods being applied to that limit or are all methods - even custom methods - also included in that figure as well?
Also is there a way to see how close we are getting to that limit every day? I looked at the Limits class but didn't see any direct methods there. We have a couple of huge batch classes that run once a week and I want to make sure we're not getting too close to that limit.
- BroncoBoy
- December 09, 2016
- Like
- 0
Monitoring APEX Async Operation requests?
We are experiencing issues with our APEX components where we are routinely running into issues with exceeding our API AsyncOperations. The errorrs we get are the following:
caused by: System.AsyncException: Rate Limiting Exception : AsyncApexExecutions Limit exceeded.
Are there any tools out there that would allow us to see who and what is making all these Async calls. I've tried using the Apex Jobs monitoring tool in SFDC but I think the Async jobs that are listed in this tool are the Async jobs that have been successfully submitted to the system AND NOT the total # of requests that have been made. If we were able to see how many total requests are being made, then I think we should be able zero in on the offending class and object.
Any suggestions?
- jbarraza@rocketlawyer
- July 10, 2013
- Like
- 0