Trigger on Account to update Contact - triggers

Account and Contact both have Billing_Address__c field. Contact also have checkbox called active__c. If active__c is true and Account Billing_Address__c is update, then Contact's Billing_Address__c is updated . Here is the trigger. It is working fine. But I want to know if there is any problem or how can I optimize this in the terms of memory?
public static void updateContactBillingAddress(List<Account> lstNew, Map<Id,Account> mapOld){
Set<Id> accIds = new Set<Id>();
for(Account acc : lstNew){
if(acc.Billing_Address__c != mapOld.get(acc.Id).Billing_Address__c && acc.Billing_Address__c !=null){
accIds.add(acc.Id);
}
}
if(!accIds.isEmpty()){
List<Contact> lstContact = new List<Contact>([Select ID,active__c, Account.Billing_Address__c,Billing_Address__c FROM Contact where AccountID IN :accIds]);
List<Contact> lstUpdateCon = new List<Contact>();
for(Contact con : lstContact){
if(con.active__c == true){
if(con.Billing_Address__c != con.Account.Billing_Address__c){
con.Billing_Address__c = con.Account.Billing_Address__c;
lstUpdateCon.add(con);
}
}
else{
con.Billing_Address__c =null;
lstUpdateCon.add(con);
}
}
if(!lstUpdateCon.isEmpty()){
update lstUpdateCon;
}
}
}

Not really, it's semantics but i'd return a contact, 1 method, 1 thing. You're processing accounts and updating them, I'd return the List of contacts and not update them in the same method. If you need to update contacts down the road you will end up doing unnecessary DML statements, you also don't need to create a List just for that loop.
public static List<Contact> updateContactBillingAddress(List<Account> lstNew, Map<ID,Account> mapOld)
{
List<Contact> result = new List<Contact>();
Set<Id> accIds = new Set<Id>();
for(Account acc : lstNew)
{
if(acc.Billing_Address__c != null && acc.Billing_Address__c != mapOld.get(acc.Id).Billing_Address__c)
{
accIds.add(acc.Id);
}
}
if(!accIds.isEmpty())
{
for(Contact con : [Select ID,Active__c, Account.Billing_Address__c,Billing_Address__c FROM Contact where AccountID IN :accIds])
{
if(con.Active__c == true){
if(con.Billing_Address__c != con.Account.Billing_Address__c)
{
con.Billing_Address__c = con.Account.Billing_Address__c;
result.add(con);
}
}
else
{
con.Billing_Address__c = null;
result.add(con);
}
}
}
return result;
}

Related

Field Not Updated in Apex Class - Trigger

I Have Apex class that will fill value of field Eksternal ID, there is no error i got, when i tried to update data that have same mobilephone with different account, the Eksternal ID will not be changed, even though,in System.debug('FinalList2 :' +finalList) the value is correct (Changed). But, when i klik button save there is no changes in Eksternal ID.
If i update data that have different mobile phone and account, it will be okay, the eksternal ID will changed perfectly.
what should i do? or where is my fault? thank you guys
Here is APex Manager
public class UT_MDM_EksternalKey_Manager {
final Integer MAX_TEXT_LENGTH = 255;
Set<Id> S_ContactIds = new Set<Id>();
public List <String> S_Lastname = new List<String>();
public List <String> S_Phone = new List<String>();
public List <String> S_Account = new List<String>();
public List <String> S_Title = new List<String>();
public List <String> S_Email = new List<String>();
public void preProcessingForInsert(List<Contact> newContact){
for(Contact cont : newContact){
if(cont.MobilePhone != null && cont.LastName != null && cont.AccountId != null && cont.Title != null ){
S_ContactIds.add(cont.Id);
S_Lastname.add(cont.LastName);
S_Phone.add(cont.MobilePhone);
S_Account.add(cont.AccountId);
S_Title.add(cont.Title);
S_Email.add(cont.Email);
}else{
cont.adderror('Please Check Your MobilePhone, LastName, Account and Title Data First!! ');
}
}
if(S_ContactIds.size() > 0){
UT_MDM_CreateEksternalKey ck = new UT_MDM_CreateEksternalKey();
ck.validateDuplicate(S_ContactIds,S_Phone,newContact);
}
}
public void preProcessingForUpdate(List<Contact> newContact){
for(Contact cont : newContact){
if(cont.MobilePhone != null && cont.LastName != null && cont.AccountId != null && cont.Title != null ){
S_ContactIds.add(cont.Id);
S_Phone.add(cont.MobilePhone);
S_Account.add(cont.AccountId);
}else{
cont.adderror('Please Check Your MobilePhone, LastName, Account and Title Data First!! ');
}
}
if(S_ContactIds.size() > 0){
UT_MDM_CreateEksternalKey ck = new UT_MDM_CreateEksternalKey();
ck.validateDuplicate(S_ContactIds,S_Phone,newContact);
}
}
public void postProcessingForUpdate(List<Contact> newContact){
}
}
And Here is UT_MDM_CreateEksternalkey Class
public class UT_MDM_CreateEksternalKey {
final Integer MAX_TEXT_LENGTH = 255;
public void validateDuplicate(Set<Id> S_ContactIds,List <String> S_Phone,List<Contact> newContact){
List<Contact> contractorList = [SELECT Id,AccountId, MobilePhone FROM Contact WHERE MobilePhone =:S_Phone AND ID NOT IN :S_ContactIds]; //duplicate
List<Id> contIds = new List<Id>();
List<Contact> finalList = new List<Contact>();
if(S_ContactIds.size() > 0){
if(contractorList.size() > 0 ){
for(Contact contactVal : newContact){
for(Contact contList: contractorList){
if (contactVal.MobilePhone == contList.MobilePhone && contactVal.AccountId == contList.AccountId){
contactVal.adderror('Duplicate Contact: Already Exist in '+contactVal.AccountId );
}
else{
contIds.add(contactVal.Id);
Contact FinalContact = new Contact();
FinalContact.Id= contactVal.Id;
FinalContact.AccountId= contactVal.AccountId;
FinalContact.MobilePhone = contactVal.MobilePhone;
FinalContact.LastName = contactVal.LastName;
FinalContact.Title = contactVal.Title;
finalList.add(FinalContact);
}
}
}
}
//List<Contact> finalList = new List<Contact> ([SELECT Id, Account.SAP_Account_Id__c, LastName, Title, MobilePhone FROM Contact WHERE Id IN :contIds]); //
if (contIds.size() > 0){
System.debug('FinalList2 :' +finalList);
UT_MDM_CreateEksternalKey ck = new UT_MDM_CreateEksternalKey();
ck.CreateContactEksternalID(finalList);
}
else if (contractorList.size() == 0 ){
UT_MDM_CreateEksternalKey ck = new UT_MDM_CreateEksternalKey();
ck.CreateContactEksternalID(newContact);
}
}
}
public void CreateContactEksternalID(List<Contact> listContact){
List<Id> accountIds = new List<ID>();
for(Contact cont : listContact){
accountIds.add(cont.AccountId);
}
Map<Id,Account> accountMap = new Map<Id,Account>([SELECT ID,SAP_Account_Id__c FROM ACCOUNT
WHERE ID IN:accountIds]);
Account tempAccount = null;
for(Contact cont : listContact){
if(accountMap.containsKey(cont.AccountId)){
String mobile = cont.MobilePhone.replaceAll('\\D','');
tempAccount = accountMap.get(cont.AccountId);
if(tempAccount.SAP_Account_Id__c != null){
cont.Eksternal_ID__c = cont.LastName + '_' + tempAccount.SAP_Account_Id__c + '_'+ cont.Title + '_' + mobile ;
// Ensure that the search text does not exceed max length:
cont.Eksternal_ID__c = cont.Eksternal_ID__c.left(MAX_TEXT_LENGTH);
}
else{
cont.adderror('There is no SAP ID in Account selected ');
}
}
}
}
}

Not able to do re parenting in this question. If an opportunity is removed from an account then it should be removed from the Account lookup field

issue in re parenting, In this question i have to find the largest opportunity by amount and put into the Account lookup field which is working but when i am changing the account of an opportunity then it remains in the account look up field. can someone please correct it, if i am wrong
public class TopOpportunityClass{
public static boolean flag = true;
public static void onTopOpportunity(List<Opportunity> opport){
if(flag==true){
List<Opportunity> uptOpp = new List<Opportunity>();
Set<Id> accIds = new Set<Id>();
for(Opportunity opp : opport){
if(opp.AccountId != null){
accIds.add(opp.AccountId);
}
}
Map<Id, List<Opportunity>> accOpportMap = new Map<Id, List<Opportunity>>();
List<Account> accUpdateList = new List<Account>();
for(Opportunity obj : [SELECT id,name, amount,accountId
FROM Opportunity
WHERE accountId IN :accIds ORDER BY amount DESC nulls last]){
List<Opportunity> oppList;
if(accOpportMap.containsKey(obj.accountId)){
oppList = accOpportMap.get(obj.accountId);
}else{
oppList = new List<Opportunity>();
}
oppList.add(obj);
accOpportMap.put(obj.accountId, oppList);
}
for(Id accId : accOpportMap.keySet()){
if(accOpportMap.get(accId).size() > 1 ){
opportunity opp1 = new opportunity(id = accOpportMap.get(accId)[1].id , isTopOpportunityCheck__c = false);
uptOpp.add(opp1);
accUpdateList.add(new Account(id = accId, isTopOpportunity__c = accOpportMap.get(accId)[0].id));
opportunity opp = new opportunity(id = accOpportMap.get(accId)[0].id , isTopOpportunityCheck__c = true);
uptOpp.add(opp);
}else if(accOpportMap.get(accId).size() == 1 ){
accUpdateList.add(new Account(id = accId, isTopOpportunity__c = accOpportMap.get(accId)[0].id));
opportunity opp = new opportunity(id = accOpportMap.get(accId)[0].id , isTopOpportunityCheck__c = true);
uptOpp.add(opp);
}else if(accOpportMap.get(accId).size() == 0){
accUpdateList.add(new Account(isTopOpportunity__c = NULL, id = NULL));
}
flag = false;
}
if(!accUpdateList.isEmpty()){
update accUpdateList;
update uptOpp;
}
}
}
}
//trigger
trigger OpportunityTrigger on Opportunity (after insert, after update){
if(Trigger.isAfter){
TopOpportunityClass.onTopOpportunity(Trigger.new);
}
}
You are running after update, so you're getting the new values in each sObject. If you want to affect the old Account assigned to some reparented Opportunity, you need to also look at the value in Trigger.old or Trigger.oldMap.
The way to do this would be to add a check here:
for(Opportunity opp : opport){
if(opp.AccountId != null){
accIds.add(opp.AccountId);
}
}
to find a reparented Opportunity (opp.AccountId != Trigger.oldMap.get(opp.Id).AccountId) and affect that Account as well.
There's a separate issue further below: this logical branch is clearly wrong.
}else if(accOpportMap.get(accId).size() == 0){
accUpdateList.add(new Account(isTopOpportunity__c = NULL, id = NULL));
}
You can't update an Account whose Id is null, and that will produce an exception.
You also need to reset flag to true after performing updates, or your trigger will have some very confusing and difficult-to-debug edge cases when multiple DML operations are performed in a single transaction.

Trigger on contentdocumentlink on insert, makes checkbox true on account

Trying to write a trigger on contentdocumentlink, which fires on insert and check a check box to true on account, but code doesn't seems to work.
Also getting compile error.
public with sharing class contentDocumentLinkTriggerHandler {
public static void processOnInsert(list<ContentDocumentLink> newList) {
list<ContentDocumentLink> contentList = new list<ContentDocumentLink>();
set<id> accId = new set<id>();
map<id,list<ContentDocumentLink>> parentContentMap = new map<id,list<ContentDocumentLink>>();
set<id> contId = new set<id>();
for(ContentDocumentLink nt : newList){
if(nt.linkedentityid.getSobjectType() == Account.SObjectType){
accId.add(nt.linkedentityid);
}
if(nt.linkedentityid.getSobjectType() == Contact.SObjectType){
contId.add(nt.linkedentityid);
}
if(parentContentMap.containsKey(nt.linkedentityid))
parentContentMap.get(nt.linkedentityid).add(nt);
else
parentContentMap.put(nt.linkedentityid,new list<ContentDocumentLink>{nt});
}
if(!accId.isEmpty()){
//login for acc
for(Account acc : [SELECT id,checkFiles__c FROM Account WHERE id IN : accId]){
if(parentContentMap.containsKey(acc.id)){
acc.checkFiles__c == true;// compile error
}
}
}
}
}

AutoCompleteTextField list does not always scroll to top?

The AutoCompleteTextField seems to work exactly as intended until I start backspacing in the TextField. I am not sure what the difference is, but if I type in something like "123 M" then I get values that start with "123 M". If I backspace and delete the M leaving "123 " in the field, the list changes, but it does not scroll to the top of the list.
I should note that everything works fine on the simulator and that I am experiencing this behavior when running a debug build on my iPhone.
EDIT: So this does not only seem to happen when backspacing. This image shows the results I have when typing in an address key by key. In any of the pictures where the list isn't viewable or is clipped, I am able to drag down on the list to get it to then display properly. I have not tried this on an Android device.
EDIT2:
public class CodenameOneTest {
private Form current;
private Resources theme;
private WaitingClass w;
private String[] properties = {"1 MAIN STREET", "123 E MAIN STREET", "12 EASTER ROAD", "24 MAIN STREET"};
public void init(Object context) {
theme = UIManager.initFirstTheme("/theme");
// Enable Toolbar on all Forms by default
Toolbar.setGlobalToolbar(true);
}
public void start() {
if(current != null) {
current.show();
return;
}
Form form = new Form("AutoCompleteTextField");
form.setLayout(new BorderLayout());
final DefaultListModel<String> options = new DefaultListModel<>();
AutoCompleteTextField ac = new AutoCompleteTextField(options) {
protected boolean filter(String text) {
if(text.length() == 0) {
options.removeAll();
return false;
}
String[] l = searchLocations(text);
if(l == null || l.length == 0) {
return false;
}
options.removeAll();
for(String s : l) {
options.addItem(s);
}
return true;
};
};
Container container = new Container(BoxLayout.y());
container.setScrollableY(true); // If you comment this out then the field works fine
container.add(ac);
form.addComponent(BorderLayout.CENTER, container);
form.show();
}
String[] searchLocations(String text) {
try {
if(text.length() > 0) {
if(w != null) {
w.actionPerformed(null);
}
w = new WaitingClass();
String[] properties = getProperties(text);
if(Display.getInstance().isEdt()) {
Display.getInstance().invokeAndBlock(w);
}
else {
w.run();
}
return properties;
}
}
catch(Exception e) {
Log.e(e);
}
return null;
}
private String[] getProperties(String text) {
List<String> returnList = new ArrayList<>();
List<String> propertyList = Arrays.asList(properties);
for(String property : propertyList) {
if(property.startsWith(text)) {
returnList.add(property);
}
}
w.actionPerformed(null);
return returnList.toArray(new String[returnList.size()]);
}
class WaitingClass implements Runnable, ActionListener<ActionEvent> {
private boolean finishedWaiting;
public void run() {
while(!finishedWaiting) {
try {
Thread.sleep(30);
}
catch(InterruptedException ex) {
ex.printStackTrace();
}
}
}
public void actionPerformed(ActionEvent e) {
finishedWaiting = true;
return;
}
}
public void stop() {
current = Display.getInstance().getCurrent();
if(current instanceof Dialog) {
((Dialog)current).dispose();
current = Display.getInstance().getCurrent();
}
}
public void destroy() {
}
}
I used this code on an iPhone 4s:
public void start() {
if(current != null){
current.show();
return;
}
Form hi = new Form("AutoComplete", new BorderLayout());
if(apiKey == null) {
hi.add(new SpanLabel("This demo requires a valid google API key to be set in the constant apiKey, "
+ "you can get this key for the webservice (not the native key) by following the instructions here: "
+ "https://developers.google.com/places/web-service/get-api-key"));
hi.getToolbar().addCommandToRightBar("Get Key", null, e -> Display.getInstance().execute("https://developers.google.com/places/web-service/get-api-key"));
hi.show();
return;
}
Container box = new Container(new BoxLayout(BoxLayout.Y_AXIS));
box.setScrollableY(true);
for(int iter = 0 ; iter < 30 ; iter++) {
box.add(createAutoComplete());
}
hi.add(BorderLayout.CENTER, box);
hi.show();
}
private AutoCompleteTextField createAutoComplete() {
final DefaultListModel<String> options = new DefaultListModel<>();
AutoCompleteTextField ac = new AutoCompleteTextField(options) {
#Override
protected boolean filter(String text) {
if(text.length() == 0) {
return false;
}
String[] l = searchLocations(text);
if(l == null || l.length == 0) {
return false;
}
options.removeAll();
for(String s : l) {
options.addItem(s);
}
return true;
}
};
ac.setMinimumElementsShownInPopup(5);
return ac;
}
String[] searchLocations(String text) {
try {
if(text.length() > 0) {
ConnectionRequest r = new ConnectionRequest();
r.setPost(false);
r.setUrl("https://maps.googleapis.com/maps/api/place/autocomplete/json");
r.addArgument("key", apiKey);
r.addArgument("input", text);
NetworkManager.getInstance().addToQueueAndWait(r);
Map<String,Object> result = new JSONParser().parseJSON(new InputStreamReader(new ByteArrayInputStream(r.getResponseData()), "UTF-8"));
String[] res = Result.fromContent(result).getAsStringArray("//description");
return res;
}
} catch(Exception err) {
Log.e(err);
}
return null;
}
I was able to create this issue but not the issue you describe.

How do I convert a trigger to an Apex class

I need to transfer the below trigger logic to an apex class. But in apex class I cant use Trigger.New as it will give error. Once I give the logic in apex call, I can call the method in trigger so, Can anybody please tell me that how can I convert this trigger to an apex class?
trigger updatecontactrolecount on Opportunity(before insert, before update) {
Boolean isPrimary;
Integer iCount;
Map < String, Opportunity > oppty_con = new Map < String, Opportunity > (); //check if the contact role is needed and add it to the oppty_con map
for (Integer i = 0; i < Trigger.new.size(); i++) {
oppty_con.put(Trigger.new[i].id,
Trigger.new[i]);
}
isPrimary = False;
for (List < OpportunityContactRole > oppcntctrle: [select OpportunityId from OpportunityContactRole where(OpportunityContactRole.IsPrimary = True and OpportunityContactRole.OpportunityId in : oppty_con.keySet())]) {
if (oppcntctrle.Size() > 0) {
isPrimary = True;
}
}
iCount = 0;
for (List < OpportunityContactRole > oppcntctrle2: [select OpportunityId from OpportunityContactRole where(OpportunityContactRole.OpportunityId in : oppty_con.keySet())]) //Query for Contact Roles
{
if (oppcntctrle2.Size() > 0) {
iCount = oppcntctrle2.Size();
}
}
for (Opportunity Oppty: system.trigger.new) //Check if roles exist in the map or contact role isn't required
{
Oppty.Number_of_Contacts_Roles_Assigned__c = iCount;
Oppty.Primary_Contact_Assigned__c = isPrimary;
}
}
You can use a TriggerHandler Class to manage your all your triggerred events in the same place:
https://developer.salesforce.com/page/Trigger_Frameworks_and_Apex_Trigger_Best_Practices
In your trigger call your unique class :
trigger OpportunityTrigger on Opportunity (before insert,after insert,before update,after update, before delete,after delete) {
try {
new OpportunityTriggerHandler().run();
}
catch(Exception e) {
System.debug(e);
}
Then do all the logic in the TriggerHandler :
public with sharing class OpportunityTriggerHandler extends TriggerHandler {
private Map<Id, Opportunity> newOpportunityMap;
private Map<Id, Opportunity> oldOpportunityMap;
private List<Opportunity> newOpportunity;
private List<Opportunity> oldOpportunity;
public OpportunityTriggerHandler() {
this.newOpportunityMap = (Map<Id, Opportunity>) Trigger.newMap;
this.oldOpportunityMap = (Map<Id, Opportunity>) Trigger.oldMap;
this.newOpportunity = (List<Opportunity>) Trigger.new;
this.oldOpportunity = (List<Opportunity>) Trigger.old;
}
public override void beforeInsert() {
for (Opportunity o : this.newOpportunity) {
if (o.Name == '...') {
//do your stuff
}
}
}
public override void afterInsert() {
//...
}
}