• Hermann Ouré
  • NEWBIE
  • 190 Points
  • Member since 2019

  • Chatter
    Feed
  • 1
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 69
    Questions
  • 54
    Replies
Hello,
I have a batch making reference to an history record and I am struggling to get above 75% in my test class.
Could someone help?
Thanks
I have attached the code coverageUser-added image

Here is the batch
public class BatchHealthcareJourneyLastSyncedDate implements Schedulable, Database.Batchable<sObject>{
    
    public void execute(SchedulableContext sc) {
        Id batchProcessId = Database.executeBatch(this);
    }
    
    public Database.QueryLocator start(Database.BatchableContext bc) {
        Map<Id, HealthCare_Journey_Template__c> hcjTempMap = new Map<Id, HealthCare_Journey_Template__c>(
            [SELECT Name, Template_Last_Modified__c, 
            (SELECT Field, NewValue, OldValue, ParentId FROM Histories WHERE Field = 'Template_Last_Modified__c')
             FROM HealthCare_Journey_Template__c]);
        
        Set<Id> hcjTempIds = new Set<Id>();
        for(HealthCare_Journey_Template__c hcjTmp : hcjTempMap.values()) {
            for(HealthCare_Journey_Template__History hcjhist : hcjTmp.Histories) {
                if(hcjhist.Field == 'Template_Last_Modified__c' 
                   && (hcjhist.OldValue != hcjhist.NewValue) && (hcjhist.ParentId == hcjTmp.Id)) {
                    hcjTempIds.add(hcjTmp.Id);
                }
            }
        }
        System.debug('hcjTempIds ' +hcjTempIds);
        return Database.getQueryLocator([SELECT Name, Healthcare_Journey_Template__c, Last_Synced_Date__c FROM HealthCare_Journey__c 
                                         WHERE Journey_out_of_date__c = true AND Healthcare_Journey_Template__c IN :hcjTempIds]); 
        
        
    }
    
    public void execute(Database.BatchableContext bc, List<HealthCare_Journey__c> scope) {
        System.debug('#### UPDATED Scope Size ' + scope.size());

        List<HealthCare_Journey__c> hcjToUpdate = new List<HealthCare_Journey__c>();        
        for(HealthCare_Journey__c hcj : scope) {
            hcj.Last_Synced_Date__c = System.now();
            hcjToUpdate.add(hcj);
        }
        if(hcjToUpdate.size() > 0) {
            update hcjToUpdate;
        }
        
        
    }
    
    public void finish(Database.BatchableContext info) {
        System.debug('Done'); 
    }

}
here is my test class: 
@isTest
public class BatchHealthcareJourneyLastSyncedDateTest {
    
    @testSetup
    static void setup() {
        Indication__c ind = new Indication__c(Name = 'test Indication');
        insert ind;
        
        Account acc = new Account(Name = 'test Account');
        insert acc;
       
        Healthcare_Journey_Template__c hcjTemp = new Healthcare_Journey_Template__c(Name = 'testHcjTemplate', 
                                                                                    Template_Last_Modified__c = System.now().addDays(-1),                                                              
                                                                                    Indication__c = ind.Id);
        insert hcjTemp;
        
        Step_Master__c stpMaster = new Step_Master__c(Name = 'test Step Master');
        insert stpMaster;
        
        Sub_Step_Master__c subStpMaster = new Sub_Step_Master__c(Name = 'Bilan sanguin',
                                                                 Step_Master__c = stpMaster.Id);
        insert subStpMaster;
        
        Template_Step__c tstep = new Template_Step__c(Name = 'testTemplateStep', 
                                                      Step_Number__c = 1,
                                                      Step_Master__c = stpMaster.Id,
                                                      HealthCare_Journey_Template__c = hcjTemp.Id);
        insert tstep;
        
        Template_Sub_Step__c tsubstep = new Template_Sub_Step__c(Name = 'sub Step',
                                                                 Sub_Step_Number__c = 1,
                                                                 Sub_Step_Master__c = subStpMaster.Id,
                                                                 Template_Step__c = tstep.Id);
        insert tsubstep;
        
        List<Healthcare_Journey__c> hcjList = new List<Healthcare_Journey__c>();
        for(Integer i=0; i<200; i++) {
            hcjList.add(new Healthcare_Journey__c(Name = 'test journey ' +i, Last_Synced_Date__c = System.now().addDays(-1),
                                                  Healthcare_Journey_Template__c = hcjTemp.Id));
        }
        insert hcjList;
        
        List<Healthcare_Journey__c> hcjToUpdate = new List<Healthcare_Journey__c>();
        for(Healthcare_Journey__c hcj : hcjList) {
            hcj.Last_Synced_Date__c = System.now();
            hcjToUpdate.add(hcj);
        }
        update hcjToUpdate;
        
        Test.startTest();
        BatchHealthcareJourneyLastSyncedDateTest batchClass = new BatchHealthcareJourneyLastSyncedDateTest();
        batchClass.processTemplateUpdate(hcjTemp.Id);
        
       
        HealthCare_Journey_Template__History[] hcjHist = batchClass.retrieveTemplateHistory(hcjTemp.Id);
        Test.stopTest();
        System.debug('hcjHist History ' +hcjHist);
        System.assertEquals(1, hcjHist.size());
        
    }
    
    public void processTemplateUpdate(Id hcjTempId) {
        Healthcare_Journey_Template__c hcjTemp = new Healthcare_Journey_Template__c(Id = hcjTempId, Template_Last_Modified__c = System.now());
        update hcjTemp;
    }
    
    public HealthCare_Journey_Template__History[] retrieveTemplateHistory(Id hcjTempId) {
        List<HealthCare_Journey_Template__History> hcjHist;
        if(Test.isRunningTest()) {
            hcjHist = new List<HealthCare_Journey_Template__History>{}; //OldValue, NewValue not writeable
            hcjHist.add(new HealthCare_Journey_Template__History(ParentId = hcjTempId, Field = 'Template_Last_Modified__c'));
        } else 
            hcjHist = [SELECT ParentId, Field, NewValue, OldValue FROM HealthCare_Journey_Template__History
                       WHERE ParentId = :hcjTempId];
        
        return hcjHist;
    }
    
    @isTest static void test() {
        Test.startTest();
        BatchHealthcareJourneyLastSyncedDate hcj = new BatchHealthcareJourneyLastSyncedDate();
        Id batchId = Database.executeBatch(hcj);
        Test.stopTest();
    }


}




 
Hello I have a batch calling a queueable class. But when running the batch, I have an error Too many callout 101.
I know I need to reduce the size of the callout but not sure how to implement it in my code
Could someone help?
Thanks

Queueable class
public class QueueableSubStepMaster implements Queueable, Database.AllowsCallouts {
    
    //class variable of type List
    private List<Sub_Step_Master__c> subStepMasterList;
    
    //Constructor
	public QueueableSubStepMaster(List<Sub_Step_Master__c> listSubStepMaster){
		this.subStepMasterList = listSubStepMaster;
	}
	
	public void execute(QueueableContext qc){
		for(Sub_Step_Master__c subStepMaster : subStepMasterList){
            //Map<String,String> layoutFieldMap = new Map<String,String>{'Sub_Step__c'=> 'String'}; to test batch (batch seems to work OK)!!!
			Map<String,String> layoutFieldMap = getFieldsOnLayoutForRecordType('Sub_Step__c',subStepMaster.RecordTypeName__c);
            subStepMaster.Layout_Field__c = prettyPrintLayoutFields(layoutFieldMap);
		}
		update subStepMasterList;
	}
    
    private String prettyPrintLayoutFields(Map<String,String> layoutFieldMap){
        
        //Print Map Key-Value pairs using toString();
        String result;
        result = layoutFieldMap.toString();
        
        //Print keys from Map using String.join(); //string.join(map.keyset(),',');
        /*String result = '';
        set<string> strSet = layoutFieldMap.keySet();
        List<String> StrList = new List<String>();
        StrList.addall(strSet);
        result = String.join(StrList , ',');*/
	
        System.debug('String result ' +result);
        return result;
    }
    
	private static Map<String,String> getFieldsOnLayoutForRecordType(String sobjectName, String recordTypeName){
		Map<String,String> result = new Map<String,String>();
		
		String url = system.URL.getSalesforceBaseUrl().toExternalForm() 
				   + '/services/data/v52.0/sobjects/'
				   + sObjectName
				   + '/describe/layouts/' 
				   + getRecordTypeId(sobjectName, recordTypeName);
        system.debug(url);
		httprequest req = buildRequest(url);
		try{
			http h = new http();
			httpresponse res = h.send(req);
			if(res.getStatusCode() == 200){
				result = getFieldsFromLayoutString(res.getBody());
			}
		}catch(exception ex){
			system.debug('ERROR: ' + ex.getMessage());
		}
		return result;
	}
	private static Map<String,String> getFieldsFromLayoutString(String jsonString){
		Map<String,String> result = new Map<String,String>();
        
        Map<String,Object> layoutMap = (Map<String,Object>)JSON.deserializeUntyped(jsonString);
        
        List<Map<String, Object>> data = new List<Map<String, Object>>();
        
		List<Object> detailSectionList = (List<Object>)layoutMap.get('detailLayoutSections'); //added H.O
        
		for(Object section : detailSectionList){
			Map<String,Object> sectionMap = (Map<String,Object>)section;
			for(Object sectionLayoutRow : (List<Object>)sectionMap.get('layoutRows')){
				Map<String,Object> sectionLayoutRowMap = (Map<String,Object>)sectionLayoutRow;
				for(Object liObject : (List<Object>)sectionLayoutRowMap.get('layoutItems')){
                    LayoutItem li = new LayoutItem((Map<String,Object>)liObject);
					String label = li.label;
					if(label != null && label != ''){
                        for(Object lc : li.layoutComponents){
                            Map<String,Object> lcMap = (Map<String,Object>)lc;
                            if((String)lcMap.get('type') == 'field'){
                            	String field = (String)lcMap.get('value');
                                result.put(field,label);
                            }
                        }
					}
				}
			}
		}
		return result;
	}
    
	private static String getRecordTypeId(String sobjectName, String recordTypeName){
        //use condition to avoid RecordType returning null
        if(Schema.getGlobalDescribe().get(sObjectName).getDescribe().getRecordTypeInfosByName().get(recordTypeName) != null) {
            return Schema.getGlobalDescribe().get(sObjectName).getDescribe().getRecordTypeInfosByName().get(recordTypeName).getRecordTypeId();

        } else {
            return null;
        }
	}

	private static HttpRequest buildRequest(String url){
		HttpRequest result = new HttpRequest();
		system.debug(url);
		result.setendpoint(url);
		result.setmethod('GET');
		result.setHeader('Authorization', 'OAuth ' + UserInfo.getSessionId());       
		result.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionID());
		return result;
	}
	
	private class LayoutItem{
		public boolean editableForNew;
		public boolean editableForUpdate;
		public string label;
		public List<Object> layoutComponents;
		public boolean placeholder;
		public boolean required;
        
        public LayoutItem(Map<String,Object> liMap){
            editableForNew = (Boolean)liMap.get('editableForNew');
            editableForUpdate = (Boolean)liMap.get('editableForUpdate');
            label = (String)liMap.get('label');
            layoutComponents = (List<Object>)liMap.get('layoutComponents');
            placeholder = (Boolean)liMap.get('placeholder');
            required = (Boolean)liMap.get('required');
        }
	}
	
}

Batch Class
public class BatchSubStepMasterProcessor implements Schedulable, Database.Batchable<sObject> {
    
    public void execute(SchedulableContext sc) {
        Id batchProcessId = Database.executeBatch(this);
    }
    
    public Database.QueryLocator start(Database.BatchableContext bc) {
        return Database.getQueryLocator('SELECT Id, Name, Layout_Field__c, RecordTypeName__c FROM Sub_Step_Master__c');  
    }
    
    public void execute(Database.BatchableContext bc, List<Sub_Step_Master__c > scope) {
        System.enqueueJob(new QueueableSubStepMaster(new List<Sub_Step_Master__c>(scope)));
        System.debug('#### UPDATED Scope Size ' + scope.size());
    }
    
    public void finish(Database.BatchableContext info) {
       System.debug('Done'); 
    }

}

//Database.executeBatch(new BatchSubStepMasterProcessor());

​​​​​​​
 
Hello,
I have an aura component to show / hide field depending on checkbox values. What I'm trying to do is to when the checkbox for the current user is checked, to show the field on the component. But if the current user profile name is different from the record owner, to make the field on the component disabled.
The problem is that 2 fields on my component is showing when I only want to display one.

aura markup
How do I change my markup to apply the logic on the same lightning textarea so only 1 is shown
 
<aura:component controller="ActionDescriptionFieldShowHideController" implements="flexipage:availableForRecordHome,force:hasRecordId" access="global" >
    
    <aura:attribute name="recordId" type="String"/>
    <aura:attribute name="actionRec" type="Action__c" default="{'sObjectType':'Action__c'}"/>
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    <lightning:spinner alternativeText="Loading" size="large" aura:id="spinner" class="slds-hide" />
    
    <aura:attribute name="CurrentUser" type="Object"/>
    <force:recordData recordId="{!$SObjectType.CurrentUser.Id}"
                      fields="Profile.Name"
                      targetFields="{!v.CurrentUser}"/>
    
    
    <form class="slds-form_stacked">
    
        
    <aura:if isTrue="{!and(v.actionRec.Commercial__c == true, v.CurrentUser.Profile.Name == 'Sales')}">
        <lightning:textarea label="Description" name="desc" value="{!v.actionRec.Description__c }"/>  
        <aura:set attribute="else">
            <aura:if isTrue="{!and(v.actionRec.Commercial__c == true, v.CurrentUser.Profile.Name != 'Sales')}">
                <lightning:textarea label="Description" name="desc" disabled="true" value="{!v.actionRec.Description__c }"/> 
            </aura:if>
        </aura:set>  
    </aura:if>
        
    <footer class="slds-modal__footer">
        <lightning:button variant="brand"
                          label="Save"
                          title="Save"
                          onclick="{! c.actionSave}" />
    </footer>
    </form>
</aura:component>

 
Hello,
I have created a batch with a method that returns a json in a specific format (key-value pair)
 
private String prettyPrintLayoutFields(Map<String,String> layoutFieldMap){
        String result;
        result = layoutFieldMap.toString(); 
        System.debug('String result ' +result);
        return result;
    }
The value parsed into the field looks like this:
{Performance_Level__c=Performance Level, CreatedById=Created By, CreatedDate=Created By, LastModifiedById=Last Modified By, LastModifiedDate=Last Modified By, Name=Sub-Step Name, Level_of_details__c=Level of details, OwnerId=Owner, RecordTypeId=Record Type, ...}
How can I update this method to only print the key separated by a comma.
It looks like that I should use something like that:
string.join(map.keyset(),',');
But not quite on how to write it in my method
Could someone help?
Thanks

 

Hello,
I am getting a System null pointer because of the RecordTypeId.
Could someone help me understand why I can't insert the record.
Thanks

 

List<Sub_Step__c> subStepList = new List<Sub_Step__c>();
        for(List<Template_Step__c> tStepList : hcJvsTempStepMap.values()) {
            for(Template_Step__c tStep : tStepList ){
                for(Template_Sub_Step__c temSubStepInst : tstep.Template_Sub_Steps__r){
                    subStepList.add(new Sub_Step__c(Name=temSubStepInst.Sub_Step_Master__r.Name,
                                                    RecordTypeId = Schema.SObjectType.Sub_Step__c.getRecordTypeInfosByName().get(temSubStepInst.Sub_Step_Master__r.Name).getRecordTypeId(),
                                                    Sub_Step_Number__c = temSubStepInst.Sub_Step_Number__c,
                                                    Step__c =tempStepIdvsStepMap.get(tStep.id).Id,
                                                    Template_Sub_Step__c = temSubStepInst.Id));
                }

            }
        }
        
        if(!subStepList.isEmpty())
           insert subStepList;
Hello,
I am using a standard object (Action Plan) and I would like to give access to records for a specific profile once I have updated a checkbox.
The org does not use 'Role' so using criteria based sharing rule is not an option.
I could probably use a trigger but I am not quite sure how to give visibility to the record once I have ticked the checkbox.
Does anyone have a sample code?
Thanks
 
Hello, 
I wrote a trigger to prevent duplicate records but now I am not even able to create new records.

Anytime I try to create a new record, I have the following error
[AccountRelationsTrigger: execution of AfterInsert caused by: System.DmlException: Insert failed. First exception on row 0; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, A relation already exists between the 2 Accounts: [Related_Account__c] Class.AccountRelationHandler.createAccountRelation: line 20, column 1 Trigger.AccountRelationsTrigger: line 6, column 1]

here is the trigger
trigger AccountRelationsTrigger on Account_Relation__c (before insert, after insert) {
    
    
    if(Trigger.isAfter) {
       if(!AccountRelationHandler.isRecursion)
    	AccountRelationHandler.createAccountRelation(Trigger.New); 
    }
    
    if(Trigger.isBefore && Trigger.isInsert) {
        Set<Id> relatedAccIds = new Set<Id>();
        for(Account_Relation__c ar : Trigger.New) {
            relatedAccIds.add(ar.Related_Account__c);
        }
        List<Account_Relation__c> arList = [SELECT Related_Account__c FROM Account_Relation__c WHERE Related_Account__c = :relatedAccIds];
                                           
        
        for(Account_Relation__c relAcc : Trigger.New) {
            if(arList.size() > 0) {
                relAcc.Related_Account__c.addError('A relation already exists between the 2 Accounts');
            }
        }
     	
    }
    
}



here is the class:
public class AccountRelationHandler {
    
    public static Boolean isRecursion = false;
    public static void createAccountRelation(List<Account_Relation__c> accRelationList) {
        // We are creating the inverse records, so return now
        if(isRecursion) {
            return;
        }
        isRecursion = true;
        
        Map<Id, Account> accRelatedToAccount = new Map<Id, Account>(
        [SELECT Id, Name, (SELECT Account__c, Related_Account__c FROM Account_Relations__r) 
         FROM Account]);
        
        Account_Relation__c[] newRelations = new Account_Relation__c[0];
        for(Account_Relation__c acc : accRelationList) {
            newRelations.add(new Account_Relation__c(Name=acc.Name, Account__c=acc.Related_Account__c, Related_Account__c=acc.Account__c));
        
        }
        insert newRelations;
        isRecursion = false;
        
    }
}
Thanks for any help
 

Hello,
I am trying to write a trigger to stop user creating contact with the same email address. But I keep getting an error
 System.NullPointerException: Attempt to de-reference a null object
on line 8 for:

conMap.get(c.Id).Email
How can I fix this error
Thanks
 
trigger ContactDuplicate on Contact (before insert) {
    
    Map<Id, Contact> conMap = new Map<Id, Contact>([SELECT Id, Email FROM Contact WHERE Email != null]);
    System.debug('Map ' +conMap);
      
    if(Trigger.isBefore && Trigger.isInsert) {
        for(Contact c : Trigger.New) {
            if(c.Email != null && c.Email == conMap.get(c.Id).Email) {
                c.Email.addError('Duplicate Contact');
            }
        }
    }
}

 

Hello,
I wrote a batch and I am trying to reference a Set<Id> in the WHERE clause but I have an error:
System.QueryException: expecting a colon, found '{kA09E0000005mCySAI}'

How can I fix the error and reference my Set kesIds in the Dynamic SOQL?
Thanks

global class BatchArticleEmail implements Schedulable, Database.Batchable<SObject> {
    
    global string query;
    
    // To schedule batch 
    global void execute(SchedulableContext sc) {
		Id batchProcessId = Database.executeBatch(this);
	}

    // Constructor to query articles
    global BatchArticleEmail() {
        
        Set<Id> kesIds = new Set<Id>();
       
        List<Known_Error_Subscription__c> kesList = [SELECT KnowledgeKA__c FROM Known_Error_Subscription__c];
        for(Known_Error_Subscription__c kes : kesList) {
            kesIds.add(kes.KnowledgeKA__c);
        }
        
        query = 'Select Id, KnowledgeArticleId, Known_Error_Status__c FROM Knowledge__kav WHERE PublishStatus=\'Online\'' + 
                ' AND KnowledgeArticleId IN \''+kesIds+'\'';     
        System.debug('query BatchArticleEmail ' +query);
    }
Hello,

I have a child object called Known_Error_Subscription__c and anytime a client subscribe to an Article (parent object : Knowledge__kav), a record is automatically created on the child object Known_Error_Subscription__c
When the Article is archived, meaning when the PublishStatus is updated to 'Archived' on the parent object Knowledge__kav, I would like the related record on Known_Error_Subscription__c to be deleted.

I have created a Trigger but can't figure out what I am doing wrong.
Thanks
 
trigger Knowledge_kavTrigger on Knowledge__kav (after update) {
    
    List<Known_Error_Subscription__c> kesListToDelete = new List<Known_Error_Subscription__c>();
    
    for(Knowledge__kav kav : [SELECT KnowledgeArticleId, PublishStatus, (SELECT Knowledge__c FROM Known_Errors_Subscriptions__r) FROM Knowledge__kav 
             WHERE PublishStatus = 'Archived' AND Id IN :Trigger.New]) {
                 
        kesListToDelete.add(kav.Known_Errors_Subscriptions__r);
       
    }
    delete kesListToDelete;
    
}

 
Hello,
I am unable to fix the error 
System.NullPointerException: Attempt to de-reference a null object on my trigger.

Could someone help?
Thanks
 
trigger Knowledge_kavKnownErrorSubscription on Knowledge__kav (after insert, after update) {
    
    List<Known_Error_Subscription__c> kesList = new List<Known_Error_Subscription__c>();
    
    for(Knowledge__kav kav : [SELECT KnowledgeArticleId, Known_Error_Status__c, VersionNumber, (SELECT Knowledge__c FROM Known_Errors_Subscriptions__r)
                              FROM Knowledge__kav WHERE Id IN :Trigger.New]) {
                                                                              
            if(kav.KnowledgeArticleId != null && (Trigger.oldMap.get(kav.Id).LastPublishedDate != Trigger.newMap.get(kav.Id).LastPublishedDate)) {
            Known_Error_Subscription__c kes = kav.Known_Errors_Subscriptions__r;
            kes.Knowledge__c = kav.KnowledgeArticleId;
            kesList.add(kes);
            
        }
                                  
    }
    if(kesList.size() > 0) {
        update kesList;
    }
    

}

 
Hello,
I have created an aura component to allow client to follow /subscribe to an article.
When a user click on the button subscribe, a record is created in Salesforce
User-added image.
Until there the code behaves as expected.
The problem is when the user has subscribed, he needs to be able to unsubscribe by click on the same button
User-added imageBut when clicking the button I am not able to unsubscribe, the button remains to subscribed
User-added imageEven worst, anytime I click the button, a new record is created in salesforce.
The idea is to stop the client for subscribing more than once to the same article and be able to unsubscribe when clicking on the button

here is my code:
KnownErrorSubscription.comp
<aura:component controller="KnownErrorSubscriptionController" implements="forceCommunity:availableForAllPageTypes,flexipage:availableForAllPageTypes,force:hasRecordId" access="global">

<aura:attribute name="recordId" type="String"/>
    <aura:attribute name="isFollowed" type="Boolean" default="false"/>
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    
    <lightning:buttonStateful
        labelWhenOff="Subscribe"
        labelWhenOn="Subscribed"
        labelWhenHover="Unsubscribe"
        iconNameWhenOff="utility:add"
        iconNameWhenOn="utility:check"
        iconNameWhenHover="utility:close"
        state="{! v.isFollowed }"
        onclick="{! c.handleClick }"/>
	
</aura:component>
KnownErrorSubscriptionController.js
 
({
       doInit: function(component, event, helper) {
             let search = window.location.pathname;
             let result = search.substring(search.lastIndexOf("/") + 1);
             let action = component.get("c.isRecordExist");

             action.setParams({
                     urlNames : result
              });
              action.setCallback(this, function(data) {
                    let result = data.getReturnValue();
                     if(result){
                         component.set('v.isFollowed', 'true');
                      }
             });
             $A.enqueueAction(action);
         },

         handleClick : function(component, event, helper) {

              let search = window.location.pathname;
              let result = search.substring(search.lastIndexOf("/") + 1);
              let action = component.get("c.saveKnownIssue");
              
             action.setParams({
                  urlNames : result
             });

             action.setCallback(this, function(data) {
                  let result = data.getReturnValue();
                  if(result){
                        component.set('v.isFollowed', 'true');
                    }
              });
             $A.enqueueAction(action);
       }
})

KnownErrorSubscriptionController.apxc
 
public class KnownErrorSubscriptionController {
    
    @AuraEnabled
    public static Boolean isRecordExist(String urlNames) {
        List<User> userList = [SELECT Id, Name, ContactId, Contact.Name FROM User WHERE Id = :UserInfo.getUserId()];
        List<Knowledge__kav> kavList = new List<Knowledge__kav>();
        if(urlNames != null) {
            kavList = [SELECT Id, LastPublishedDate, Title, ArticleBody__c FROM Knowledge__kav WHERE UrlName =:urlNames];
        }
        
        if(userList.size() > 0 && kavList.size() > 0) {
        	List<Known_Error_Subscription__c> kESubscriptionList = [SELECT Contact__c, Knowledge__c FROM Known_Error_Subscription__c
                                                                    WHERE Contact__c =:userList[0].ContactId AND Knowledge__c =:kavList[0].Id];
            if(kESubscriptionList.size() > 0) {
            	return true;
            } else {
            	return false;
            }
                
        } else {
        	return false;
        }        
    } 
    
    @AuraEnabled
    public static Boolean saveKnownIssue(String urlNames, Boolean isFollowed) {
        List<User> userList = [SELECT Id, Name, ContactId, Contact.Name FROM User WHERE Id =:UserInfo.getUserId()];
        List<Knowledge__kav> kavList = new List<Knowledge__kav>();
        
        if(urlNames != null) {
            kavList = [SELECT Id, LastPublishedDate, Title, ArticleBody__c FROM Knowledge__kav WHERE UrlName =:urlNames];
        }
        Known_Error_Subscription__c kes = new Known_Error_Subscription__c();
        if(userList.size() > 0 && userList[0].ContactId != null) {
            kes.Contact__c = userList[0].ContactId;
        }
        
        if(kavList.size() > 0) {
            kes.Knowledge__c = kavList[0].Id;
            kes.Subscribed__c = true;
        }
        
        insert kes;
        return true;
        
    }
    

}





 
Hello,
I am trying to use the Ids that I store in a Set; in a String variable but I am unable to do so.
I have obviously an error: Variable Id does not exist. But I don't j=know how to fix it.
Could someone help?
Thanks

here is what I wrote:
public static String setSlackUserNickName(String businessUnit) {
        String channelName;
        Set<ID> headOfService_ids = new Set<ID>();
        
        Map<Id, Application_Parameters__c> headOfService = New Map<Id, Application_Parameters__c>(
            [SELECT Id, Head_of_Service__c FROM Application_Parameters__c WHERE Business_Unit__c = :businessUnit]);
     
        for(Application_Parameters__c app : headOfService.values()) {
            headOfService_ids.add(app.Head_of_Service__c);
        }
       
         
        channelName = ''+headOfService_ids.get(Id).CommunityNickname+'';

 
Hello,

I have an Apex class sending slack notification to a channel and I would like to update the code to send the notification to multiple slack channels.

Is Anyone familiar with Slack integration?

Here is my code
public without sharing class SlackNotificationSupport{
       
    public class slackRequest { 
        @InvocableVariable(label='caseNumber')
        public String caseNumber;
        @InvocableVariable(label='status')
        public String status;
        @InvocableVariable(label='nickName')
        public String nickname;
        @InvocableVariable(label='queue')
        public String queue;
        @InvocableVariable(label='accountTier')
        public String accountTier;
        @InvocableVariable(label='accountName')
        public String accountName;
        @InvocableVariable(label='subject')
        public String subject;
        @InvocableVariable(label='businessUnit')
    	public String businessUnit;
    } 
    

    public static String setChannelName(String queue) {

        String channelName;

        channelName = '#'+queue;
        channelName = channelName.toLowerCase('en');
        channelName = channelName.replaceAll('queue', 'bot');
        channelName = channelName.replaceAll('[_]', '-');
        return channelName;
    }

    @InvocableMethod(label='Publish to Slack')
    public static void publishToSlack(List<slackRequest> requests) {

        String webhookURL = system.label.Param_Slack_Token;
        String msg;
        String channelName;

        for(slackRequest r:requests){

            if (r.queue == 'internal'){
                System.debug('### SlackNotificationSupport new internal case');
                channelName = '#'+Label.Slack_Internal_Case_Channel;
                msg = 'A new internal case has been created : *'+r.caseNumber+'* - By User : (*'+r.accountName+'*) - Subject : (*'+r.subject+'*)';                
            }
            else if (r.queue == 'caseconcern'){
                System.debug('### SlackNotificationSupport new case concern');
                channelName = '#'+Label.Slack_Case_Concern_Channel;
                
                msg = 'A new Case Concern has been created : *'+r.caseNumber+'* - By User : (*'+r.nickName+' '+r.accountName+'* From *'+r.accountTier+'*) - Category : (*'+r.subject+'*)';
				msg += '\nLink to Case Concern : '+URL.getOrgDomainUrl().toExternalForm()+'/'+r.status;
                
            }
            // Team Leads
            else if (r.queue == 'Queue Team Leads') {
                channelName = setChannelName(r.queue);
                msg = 'A customer has opened a new case.\n>>>*'+
                    r.caseNumber+'* - '+r.subject;
                    System.debug('### SlackNotificationSupport Queue Team Leads');
            } // New Tier 1 Ticker
            else if (r.accountTier == 'Tier 1' && r.accountName != null && r.queue != null) {
                System.debug('### SlackNotificationSupport New Tier 1');
                channelName = setChannelName(r.queue);
                msg = 'The customer '+r.accountTier+' - *'+r.accountName+'* has opened a new case.\n>>>*'+
                    r.caseNumber+'* - '+r.subject;
            }// Assigned ticket, status to Open - Internal notification for awaiting feedback cases
            else if (r.nickname != null && r.status != null && r.caseNumber != null) {
                System.debug('### SlackNotificationSupport  Status x to Open');
                channelName = '@'+r.nickname;
                if(r.queue == 'internal_notification')msg = 'Salesforce Internal Case number *'+r.caseNumber+'* related to : *'+r.subject+'* - Status changed to : *'+r.status+'*.';
                else msg = 'Case number *'+r.caseNumber+'* has become '+r.status+'.';
            }

            // Generate JSON for request
            try {
                if (r.queue != null || r.nickname != null) {
                    System.debug('### SlackNotificationSupport Sending message');
                    JSONGenerator gen = JSON.createGenerator(true);
                    gen.writeStartObject(); //Inserts {
                    gen.writeStringField('text', msg);
                    gen.writeStringField('channel', channelName);
                    gen.writeStringField('username', 'bot-support');
                    gen.writeStringField('icon_emoji', ':smartplus:');
                    gen.writeEndObject(); //Inserts }
                    String body = gen.getAsString(); //Translates JSONGenerator to string to be passed to callout
                    System.debug('### SlackNotificationSupport body: '+ body);
                    System.enqueueJob(new qCallOut(webhookURL, 'POST', body)); // Send request
                }
                else {
                    System.debug('### SlackNotificationSupport Queue = '+ r.queue);
                    return;
                }
            } // try    
            catch (exception e){
                system.debug('### SlackNotificationSupport error:' + e);
            }
        } 
    }
   

    public class qCallOut implements System.Queueable, Database.AllowsCallouts {
         
        private final String url;
        private final String method;
        private final String body;
         
        public qCallOut(String url, String method, String body) {
            this.url = url;
            this.method = method;
            this.body = body;
        }
         
        public void execute(System.QueueableContext ctx) {
            HttpRequest req = new HttpRequest();
            req.setEndpoint(url);
            req.setMethod(method);
            req.setBody(body);
            Http http = new Http();
            // to pass when process builder is invoked by another test class
            if(!Test.isRunningTest()){  
              HttpResponse res = http.send(req);
            }
        }
    }
}

 

Hello,
I am trying to include a Case Number of an email template for an email-to-case.
Basically, when a client sent an email to a closed case, he received an automatic email reply.
On the template I have added the merge field value {!Case.CaseNumber}
User-added imagebut the Case Number does not appear on the email reply sent to the client

User-added image

I believe that, to add the Case Number in the automatic email reply, I need to reference the CaseId somewhere in my code. But I have figured out how.
The tried to do 

mail.setTargetObjectId(c.Id);
But that does not work.
Here is my full code:
Apex class:
public class EmailManager {
    @future
    public static void sendEmailToCaseDeactivated(Set<Id> caseIds){
    
        List<Messaging.SingleEmailMessage> allmsg = new List<Messaging.SingleEmailMessage>();
        List<Case> lstCase = [SELECT Id, Status,ContactEmail FROM Case WHERE 
                              Status = 'Closed' AND
                              ContactEmail != Null AND
                              Id IN: caseIds];
        EmailTemplate templateId = [SELECT Id FROM EmailTemplate WHERE DeveloperName =:'Email_to_Case_Closed'];
       
        for(Case c : lstCase) {
            Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
            mail.setTargetObjectId(UserInfo.getUserId());
            mail.setTemplateId(templateId.Id);
            String[] sendingTo = new String[]{c.ContactEmail}; 
            mail.setToAddresses(sendingTo); 
            mail.setSaveAsActivity(false);
            allmsg.add(mail);
        }               
        Messaging.sendEmail(allmsg, false);
    }
    
}
Apex Trigger: 
trigger IncomingEmailClosedCase on EmailMessage (before insert,after insert) {
    
    if(trigger.isBefore) { 
        Set<Id> sCaseIds = new Set<Id>();
        for(EmailMessage em: Trigger.New) {
            if (em.Incoming)
                 sCaseIds.add(em.parentId);   
        }
        if(!sCaseIds.isEmpty())
            EmailManager.sendEmailToCaseDeactivated(sCaseIds);
    }
    if(trigger.isAfter){
        Map<Id,Id> caseIdsToEmailMessageIds = new Map<Id,Id>();
        for(EmailMessage em: Trigger.New) {
            if (em.Incoming)
                caseIdsToEmailMessageIds.put(em.parentId,em.Id);   
        }
        set<Id> sMessageIdsToDelete = new Set<Id>();
        if(caseIdsToEmailMessageIds.isEmpty()) return;
        for(Case lstCase : [SELECT Id, Status,ContactEmail FROM Case WHERE 
                          Status = 'Closed' AND
                          ContactEmail != Null AND
                          Id IN: caseIdsToEmailMessageIds.keyset()]){
            if(caseIdsToEmailMessageIds.containsKey(lstCase.Id)){
                Id emId = caseIdsToEmailMessageIds.get(lstCase.Id);
                sMessageIdsToDelete.add(emId);
            } 
        } 
        if(!sMessageIdsToDelete.isEmpty())   delete [ select Id from EmailMessage where id in :sMessageIdsToDelete];
    }
}

 
Hello,
I have created a class and a trigger to be able to stop clients from sending email message on Closed Cases.
The code works as intended. We tend to communicate with Clients using the quick action Email under the Case Feed tab. But sometimes, clients try to communicate to us about new issues using an old email reply of a closed case.
Now, with the code I wrote, they receive an email informing them that the case is closed & that we are not communicating on the case anymore.
The code works as intended... But since I am still learning on the platform, I have the feeling that my code is cumbersome.
How can I optimise and make my code more efficient?
Thanks

Apex class:
 
public class EmailManager {
@future
public static void sendEmailToCaseDeactivated(Set<Id> caseIds){

    List<Messaging.SingleEmailMessage> allmsg = new List<Messaging.SingleEmailMessage>();
    List<Case> lstCase = [SELECT Id, Status,ContactEmail FROM Case WHERE 
                          Status = 'Closed' AND
                          ContactEmail != Null AND
                          Id IN: caseIds];
    EmailTemplate templateId = [SELECT Id FROM EmailTemplate WHERE DeveloperName =:'Smart_Community_Email_to_Case_Deactivated'];
   
    for(Case cas :  lstCase) {
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        mail.setTargetObjectId(UserInfo.getUserId());
        mail.setTemplateId(templateId.Id);
        String[] sendingTo = new String[]{cas.ContactEmail}; 
        mail.setToAddresses(sendingTo); 
        mail.setSaveAsActivity(false);
        allmsg.add(mail);
    }               
    Messaging.sendEmail(allmsg, false);
}

}

Apex Trigger: 
 
trigger IncomingEmailClosedCase on EmailMessage (before insert,after insert) {

if(trigger.isBefore) { 
    Set<Id> caseIds = new Set<Id>();
    for(EmailMessage em: Trigger.New) {
        if (em.Incoming)
             caseIds.add(em.parentId);   
    }
    if(!caseIds.isEmpty())
        EmailManager.sendEmailToCaseDeactivated(caseIds);
}
if(trigger.isAfter){
    Map<Id,Id> mapOfCaseVsEM = new Map<Id,Id>();
    for(EmailMessage em: Trigger.New) {
        if (em.Incoming)
            mapOfCaseVsEM.put(em.parentId,em.Id);   
    }
    set<Id> todeleteEM = new Set<Id>();
    if(mapOfCaseVsEM.isEmpty()) return;
    for(Case lstCase : [SELECT Id, Status,ContactEmail FROM Case WHERE 
                      Status = 'Closed' AND
                      ContactEmail != Null AND
                      Id IN: mapOfCaseVsEM.keyset()]){
        if(mapOfCaseVsEM.containsKey(lstCase.Id)){
            Id emId = mapOfCaseVsEM.get(lstCase.Id);
            todeleteEM.add(emId);
        } 
    } 
    if(!todeleteEM.isEmpty())   delete [ select Id from EmailMessage where id in :todeleteEM];
}
}

 
Hello,
I have created an aura component to be able to display the value of an account field (Tip To Smarties) on the related Case.
User-added imageBut the value of the field do not display when I put the component on the case page. It does work when I put the component on the Account page but that's not what I am looking for.

How can I display the value when putting the aura component on the Case page?
Thanks

aura component:
<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId" access="global" >
    
    <aura:attribute name="recordId" type="Id"/>
    
    
     <lightning:recordViewForm recordId="{!v.recordId}" objectApiName="Account">
        <div class="slds-box slds-theme_default">
            <lightning:outputField fieldName="Tip_To_Smarties__c" />
        </div>
    </lightning:recordViewForm>
    
</aura:component>

 

Hello, 
I am trying to create a trigger to stop clients from sending emails on Case closed. But it doesn't work.
Could someone help?
Thanks,

Apex Class:

public class EmailManager {
    
    public static void sendEmailToCaseDeactivated(){
        
        //Use classic email template
        EmailTemplate templateId = [SELECT Id FROM EmailTemplate WHERE DeveloperName =:'Smart_Community_Email_to_Case_Deactivated'];
        List<Messaging.SingleEmailMessage> allmsg = new List<Messaging.SingleEmailMessage>();
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        
        mail.setTargetObjectId(UserInfo.getUserId());
        mail.setTemplateId(templateId.Id);
        mail.setSaveAsActivity(false);
        allmsg.add(mail);
        
        Messaging.sendEmail(allmsg, false);
        
    }
        
}
Apex Trigger:
trigger IncomingEmailClosedCase on EmailMessage (before insert) {
   
    Set<Id> caseIds = new Set<Id>();
    
    for(EmailMessage em: Trigger.New) {
        if (em.Incoming == true) caseIds.add(em.Id);   
    }
    
    List<Case> lstCase = new List<Case>([SELECT Id, Status FROM Case WHERE Status = 'Closed' AND Id In: caseIds]);
    
    if(lstCase.size() > 0) {
        EmailManager.sendEmailToCaseDeactivated();
    }
   
}


 

Hello,
I am trying to query Articles on the Knowledge__kav object related to Cases. But I have the following error
Didn't understand relationship 'Knowledge__kavs' in FROM part of query call. 
How can I make a subquery on Knowledge__kav?
Map<Id, Case> caseMap = new Map<Id, Case>([SELECT Id, First_JIRA_Issue_Number__c, (SELECT Id FROM Knowledge__kavs) FROM Case WHERE Id IN :caseIdJiraIssueId.keyset()]);


 

Hello,

I have a lookup field (First_JIRA_Issue_Number__c) on Case object that needs to be updated with the Jira Number when the related issue is created.

Basically from a Case, I have the possibility to create a Jira Issue (object: JIRA_Issue__c).
User-added image

When the Jira Issue is created, the field First_JIRA_Issue_Number__c needs to be updated with the Jira Number. In this example the field First Jira Issue Number on Case is updated with JIRA000692
User-added image

I have created a class and a trigger but it does work.
Could someone help.
Thanks

Apex Class

public class CaseManager {
    
    public static void updateJiraIssue(List<JIRA_Issue__c> lstJira) {
        Set<Id> jiraIds = new Set<Id>();
       
        for(JIRA_Issue__c jissue : lstJira){
            if(jissue.Case__c != null){
                jiraIds.add(jissue.Id);  
            }
        }
        
        List<Case> lstCase = new List<Case>([SELECT Id, First_JIRA_Issue_Number__c,(SELECT Id, Case__c FROM JIRA_Issues__r) FROM Case WHERE First_JIRA_Issue_Number__c IN: jiraIds]);
        System.debug('##### lstCase ' + lstCase.Size());
        
        if(lstCase.size()>0){
            for(Case c: lstCase){
                List<JIRA_Issue__c> lstJiraIssue = new List<JIRA_Issue__c>();
                lstJiraIssue = c.JIRA_Issues__r;
                if(lstJiraIssue.size() > 0){
                    for(JIRA_Issue__c ji: lstJiraIssue){
                        if(ji.Case__c == c.Id){
                            c.First_JIRA_Issue_Number__c = ji.Id;
                        }
                        
                    }
                    
                }
    
       		}
            update lstCase;
        }
        
      
    }

}
Apex Trigger:
 
trigger CaseJiraIssueNumber on JIRA_Issue__c (after insert) {
    if(trigger.isAfter){
        CaseManager.updateJiraIssue(Trigger.New);
    }

}

 
Hello I have a batch calling a queueable class. But when running the batch, I have an error Too many callout 101.
I know I need to reduce the size of the callout but not sure how to implement it in my code
Could someone help?
Thanks

Queueable class
public class QueueableSubStepMaster implements Queueable, Database.AllowsCallouts {
    
    //class variable of type List
    private List<Sub_Step_Master__c> subStepMasterList;
    
    //Constructor
	public QueueableSubStepMaster(List<Sub_Step_Master__c> listSubStepMaster){
		this.subStepMasterList = listSubStepMaster;
	}
	
	public void execute(QueueableContext qc){
		for(Sub_Step_Master__c subStepMaster : subStepMasterList){
            //Map<String,String> layoutFieldMap = new Map<String,String>{'Sub_Step__c'=> 'String'}; to test batch (batch seems to work OK)!!!
			Map<String,String> layoutFieldMap = getFieldsOnLayoutForRecordType('Sub_Step__c',subStepMaster.RecordTypeName__c);
            subStepMaster.Layout_Field__c = prettyPrintLayoutFields(layoutFieldMap);
		}
		update subStepMasterList;
	}
    
    private String prettyPrintLayoutFields(Map<String,String> layoutFieldMap){
        
        //Print Map Key-Value pairs using toString();
        String result;
        result = layoutFieldMap.toString();
        
        //Print keys from Map using String.join(); //string.join(map.keyset(),',');
        /*String result = '';
        set<string> strSet = layoutFieldMap.keySet();
        List<String> StrList = new List<String>();
        StrList.addall(strSet);
        result = String.join(StrList , ',');*/
	
        System.debug('String result ' +result);
        return result;
    }
    
	private static Map<String,String> getFieldsOnLayoutForRecordType(String sobjectName, String recordTypeName){
		Map<String,String> result = new Map<String,String>();
		
		String url = system.URL.getSalesforceBaseUrl().toExternalForm() 
				   + '/services/data/v52.0/sobjects/'
				   + sObjectName
				   + '/describe/layouts/' 
				   + getRecordTypeId(sobjectName, recordTypeName);
        system.debug(url);
		httprequest req = buildRequest(url);
		try{
			http h = new http();
			httpresponse res = h.send(req);
			if(res.getStatusCode() == 200){
				result = getFieldsFromLayoutString(res.getBody());
			}
		}catch(exception ex){
			system.debug('ERROR: ' + ex.getMessage());
		}
		return result;
	}
	private static Map<String,String> getFieldsFromLayoutString(String jsonString){
		Map<String,String> result = new Map<String,String>();
        
        Map<String,Object> layoutMap = (Map<String,Object>)JSON.deserializeUntyped(jsonString);
        
        List<Map<String, Object>> data = new List<Map<String, Object>>();
        
		List<Object> detailSectionList = (List<Object>)layoutMap.get('detailLayoutSections'); //added H.O
        
		for(Object section : detailSectionList){
			Map<String,Object> sectionMap = (Map<String,Object>)section;
			for(Object sectionLayoutRow : (List<Object>)sectionMap.get('layoutRows')){
				Map<String,Object> sectionLayoutRowMap = (Map<String,Object>)sectionLayoutRow;
				for(Object liObject : (List<Object>)sectionLayoutRowMap.get('layoutItems')){
                    LayoutItem li = new LayoutItem((Map<String,Object>)liObject);
					String label = li.label;
					if(label != null && label != ''){
                        for(Object lc : li.layoutComponents){
                            Map<String,Object> lcMap = (Map<String,Object>)lc;
                            if((String)lcMap.get('type') == 'field'){
                            	String field = (String)lcMap.get('value');
                                result.put(field,label);
                            }
                        }
					}
				}
			}
		}
		return result;
	}
    
	private static String getRecordTypeId(String sobjectName, String recordTypeName){
        //use condition to avoid RecordType returning null
        if(Schema.getGlobalDescribe().get(sObjectName).getDescribe().getRecordTypeInfosByName().get(recordTypeName) != null) {
            return Schema.getGlobalDescribe().get(sObjectName).getDescribe().getRecordTypeInfosByName().get(recordTypeName).getRecordTypeId();

        } else {
            return null;
        }
	}

	private static HttpRequest buildRequest(String url){
		HttpRequest result = new HttpRequest();
		system.debug(url);
		result.setendpoint(url);
		result.setmethod('GET');
		result.setHeader('Authorization', 'OAuth ' + UserInfo.getSessionId());       
		result.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionID());
		return result;
	}
	
	private class LayoutItem{
		public boolean editableForNew;
		public boolean editableForUpdate;
		public string label;
		public List<Object> layoutComponents;
		public boolean placeholder;
		public boolean required;
        
        public LayoutItem(Map<String,Object> liMap){
            editableForNew = (Boolean)liMap.get('editableForNew');
            editableForUpdate = (Boolean)liMap.get('editableForUpdate');
            label = (String)liMap.get('label');
            layoutComponents = (List<Object>)liMap.get('layoutComponents');
            placeholder = (Boolean)liMap.get('placeholder');
            required = (Boolean)liMap.get('required');
        }
	}
	
}

Batch Class
public class BatchSubStepMasterProcessor implements Schedulable, Database.Batchable<sObject> {
    
    public void execute(SchedulableContext sc) {
        Id batchProcessId = Database.executeBatch(this);
    }
    
    public Database.QueryLocator start(Database.BatchableContext bc) {
        return Database.getQueryLocator('SELECT Id, Name, Layout_Field__c, RecordTypeName__c FROM Sub_Step_Master__c');  
    }
    
    public void execute(Database.BatchableContext bc, List<Sub_Step_Master__c > scope) {
        System.enqueueJob(new QueueableSubStepMaster(new List<Sub_Step_Master__c>(scope)));
        System.debug('#### UPDATED Scope Size ' + scope.size());
    }
    
    public void finish(Database.BatchableContext info) {
       System.debug('Done'); 
    }

}

//Database.executeBatch(new BatchSubStepMasterProcessor());

​​​​​​​
 
Hello,
I have an aura component to show / hide field depending on checkbox values. What I'm trying to do is to when the checkbox for the current user is checked, to show the field on the component. But if the current user profile name is different from the record owner, to make the field on the component disabled.
The problem is that 2 fields on my component is showing when I only want to display one.

aura markup
How do I change my markup to apply the logic on the same lightning textarea so only 1 is shown
 
<aura:component controller="ActionDescriptionFieldShowHideController" implements="flexipage:availableForRecordHome,force:hasRecordId" access="global" >
    
    <aura:attribute name="recordId" type="String"/>
    <aura:attribute name="actionRec" type="Action__c" default="{'sObjectType':'Action__c'}"/>
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    <lightning:spinner alternativeText="Loading" size="large" aura:id="spinner" class="slds-hide" />
    
    <aura:attribute name="CurrentUser" type="Object"/>
    <force:recordData recordId="{!$SObjectType.CurrentUser.Id}"
                      fields="Profile.Name"
                      targetFields="{!v.CurrentUser}"/>
    
    
    <form class="slds-form_stacked">
    
        
    <aura:if isTrue="{!and(v.actionRec.Commercial__c == true, v.CurrentUser.Profile.Name == 'Sales')}">
        <lightning:textarea label="Description" name="desc" value="{!v.actionRec.Description__c }"/>  
        <aura:set attribute="else">
            <aura:if isTrue="{!and(v.actionRec.Commercial__c == true, v.CurrentUser.Profile.Name != 'Sales')}">
                <lightning:textarea label="Description" name="desc" disabled="true" value="{!v.actionRec.Description__c }"/> 
            </aura:if>
        </aura:set>  
    </aura:if>
        
    <footer class="slds-modal__footer">
        <lightning:button variant="brand"
                          label="Save"
                          title="Save"
                          onclick="{! c.actionSave}" />
    </footer>
    </form>
</aura:component>

 
Hello, 
I wrote a trigger to prevent duplicate records but now I am not even able to create new records.

Anytime I try to create a new record, I have the following error
[AccountRelationsTrigger: execution of AfterInsert caused by: System.DmlException: Insert failed. First exception on row 0; first error: FIELD_CUSTOM_VALIDATION_EXCEPTION, A relation already exists between the 2 Accounts: [Related_Account__c] Class.AccountRelationHandler.createAccountRelation: line 20, column 1 Trigger.AccountRelationsTrigger: line 6, column 1]

here is the trigger
trigger AccountRelationsTrigger on Account_Relation__c (before insert, after insert) {
    
    
    if(Trigger.isAfter) {
       if(!AccountRelationHandler.isRecursion)
    	AccountRelationHandler.createAccountRelation(Trigger.New); 
    }
    
    if(Trigger.isBefore && Trigger.isInsert) {
        Set<Id> relatedAccIds = new Set<Id>();
        for(Account_Relation__c ar : Trigger.New) {
            relatedAccIds.add(ar.Related_Account__c);
        }
        List<Account_Relation__c> arList = [SELECT Related_Account__c FROM Account_Relation__c WHERE Related_Account__c = :relatedAccIds];
                                           
        
        for(Account_Relation__c relAcc : Trigger.New) {
            if(arList.size() > 0) {
                relAcc.Related_Account__c.addError('A relation already exists between the 2 Accounts');
            }
        }
     	
    }
    
}



here is the class:
public class AccountRelationHandler {
    
    public static Boolean isRecursion = false;
    public static void createAccountRelation(List<Account_Relation__c> accRelationList) {
        // We are creating the inverse records, so return now
        if(isRecursion) {
            return;
        }
        isRecursion = true;
        
        Map<Id, Account> accRelatedToAccount = new Map<Id, Account>(
        [SELECT Id, Name, (SELECT Account__c, Related_Account__c FROM Account_Relations__r) 
         FROM Account]);
        
        Account_Relation__c[] newRelations = new Account_Relation__c[0];
        for(Account_Relation__c acc : accRelationList) {
            newRelations.add(new Account_Relation__c(Name=acc.Name, Account__c=acc.Related_Account__c, Related_Account__c=acc.Account__c));
        
        }
        insert newRelations;
        isRecursion = false;
        
    }
}
Thanks for any help
 

Hello,
I wrote a batch and I am trying to reference a Set<Id> in the WHERE clause but I have an error:
System.QueryException: expecting a colon, found '{kA09E0000005mCySAI}'

How can I fix the error and reference my Set kesIds in the Dynamic SOQL?
Thanks

global class BatchArticleEmail implements Schedulable, Database.Batchable<SObject> {
    
    global string query;
    
    // To schedule batch 
    global void execute(SchedulableContext sc) {
		Id batchProcessId = Database.executeBatch(this);
	}

    // Constructor to query articles
    global BatchArticleEmail() {
        
        Set<Id> kesIds = new Set<Id>();
       
        List<Known_Error_Subscription__c> kesList = [SELECT KnowledgeKA__c FROM Known_Error_Subscription__c];
        for(Known_Error_Subscription__c kes : kesList) {
            kesIds.add(kes.KnowledgeKA__c);
        }
        
        query = 'Select Id, KnowledgeArticleId, Known_Error_Status__c FROM Knowledge__kav WHERE PublishStatus=\'Online\'' + 
                ' AND KnowledgeArticleId IN \''+kesIds+'\'';     
        System.debug('query BatchArticleEmail ' +query);
    }
Hello,

I have a child object called Known_Error_Subscription__c and anytime a client subscribe to an Article (parent object : Knowledge__kav), a record is automatically created on the child object Known_Error_Subscription__c
When the Article is archived, meaning when the PublishStatus is updated to 'Archived' on the parent object Knowledge__kav, I would like the related record on Known_Error_Subscription__c to be deleted.

I have created a Trigger but can't figure out what I am doing wrong.
Thanks
 
trigger Knowledge_kavTrigger on Knowledge__kav (after update) {
    
    List<Known_Error_Subscription__c> kesListToDelete = new List<Known_Error_Subscription__c>();
    
    for(Knowledge__kav kav : [SELECT KnowledgeArticleId, PublishStatus, (SELECT Knowledge__c FROM Known_Errors_Subscriptions__r) FROM Knowledge__kav 
             WHERE PublishStatus = 'Archived' AND Id IN :Trigger.New]) {
                 
        kesListToDelete.add(kav.Known_Errors_Subscriptions__r);
       
    }
    delete kesListToDelete;
    
}

 
Hello,
I am unable to fix the error 
System.NullPointerException: Attempt to de-reference a null object on my trigger.

Could someone help?
Thanks
 
trigger Knowledge_kavKnownErrorSubscription on Knowledge__kav (after insert, after update) {
    
    List<Known_Error_Subscription__c> kesList = new List<Known_Error_Subscription__c>();
    
    for(Knowledge__kav kav : [SELECT KnowledgeArticleId, Known_Error_Status__c, VersionNumber, (SELECT Knowledge__c FROM Known_Errors_Subscriptions__r)
                              FROM Knowledge__kav WHERE Id IN :Trigger.New]) {
                                                                              
            if(kav.KnowledgeArticleId != null && (Trigger.oldMap.get(kav.Id).LastPublishedDate != Trigger.newMap.get(kav.Id).LastPublishedDate)) {
            Known_Error_Subscription__c kes = kav.Known_Errors_Subscriptions__r;
            kes.Knowledge__c = kav.KnowledgeArticleId;
            kesList.add(kes);
            
        }
                                  
    }
    if(kesList.size() > 0) {
        update kesList;
    }
    

}

 
Hello,
I have created an aura component to be able to display the value of an account field (Tip To Smarties) on the related Case.
User-added imageBut the value of the field do not display when I put the component on the case page. It does work when I put the component on the Account page but that's not what I am looking for.

How can I display the value when putting the aura component on the Case page?
Thanks

aura component:
<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId" access="global" >
    
    <aura:attribute name="recordId" type="Id"/>
    
    
     <lightning:recordViewForm recordId="{!v.recordId}" objectApiName="Account">
        <div class="slds-box slds-theme_default">
            <lightning:outputField fieldName="Tip_To_Smarties__c" />
        </div>
    </lightning:recordViewForm>
    
</aura:component>

 

Hello,

I have a lookup field (First_JIRA_Issue_Number__c) on Case object that needs to be updated with the Jira Number when the related issue is created.

Basically from a Case, I have the possibility to create a Jira Issue (object: JIRA_Issue__c).
User-added image

When the Jira Issue is created, the field First_JIRA_Issue_Number__c needs to be updated with the Jira Number. In this example the field First Jira Issue Number on Case is updated with JIRA000692
User-added image

I have created a class and a trigger but it does work.
Could someone help.
Thanks

Apex Class

public class CaseManager {
    
    public static void updateJiraIssue(List<JIRA_Issue__c> lstJira) {
        Set<Id> jiraIds = new Set<Id>();
       
        for(JIRA_Issue__c jissue : lstJira){
            if(jissue.Case__c != null){
                jiraIds.add(jissue.Id);  
            }
        }
        
        List<Case> lstCase = new List<Case>([SELECT Id, First_JIRA_Issue_Number__c,(SELECT Id, Case__c FROM JIRA_Issues__r) FROM Case WHERE First_JIRA_Issue_Number__c IN: jiraIds]);
        System.debug('##### lstCase ' + lstCase.Size());
        
        if(lstCase.size()>0){
            for(Case c: lstCase){
                List<JIRA_Issue__c> lstJiraIssue = new List<JIRA_Issue__c>();
                lstJiraIssue = c.JIRA_Issues__r;
                if(lstJiraIssue.size() > 0){
                    for(JIRA_Issue__c ji: lstJiraIssue){
                        if(ji.Case__c == c.Id){
                            c.First_JIRA_Issue_Number__c = ji.Id;
                        }
                        
                    }
                    
                }
    
       		}
            update lstCase;
        }
        
      
    }

}
Apex Trigger:
 
trigger CaseJiraIssueNumber on JIRA_Issue__c (after insert) {
    if(trigger.isAfter){
        CaseManager.updateJiraIssue(Trigger.New);
    }

}

 
Hello,
For a particular case, I have the possibility to create a Jira issue (in custom object: JIRA_Issue__c)  and an Article for Known Errors (in object Knowledge__kav)

Jira Issue:
User-added image

known error Article:

User-added image


In this example I have create a Jira Issue (JIRA000659) and an Article for the case 00161455.

What I am struggling with is that the lookup field Jira Issue on the article (Knowledge__kav object) needs to be update with the Jira Number (JIRA000659). Only a Jira Issue can be created before an article is created. Alternatively a Jira Issue can also be created after an article has been created. In both case the field Jira Issue  on Knowledge has to be updated with the Jira Issue Number JIRA000659 associated to the case (00161455)

I have written a class and created a trigger on the custom object JIRA_Issue__c.
But nothing happens, I can't get the right logic.

Could someone help?
Thanks

Apex class
public class KnowledgeKavManager {
    
    public static void updateJiraIssue(List<JIRA_Issue__c> lstJira) {
        Set<Id> kavIds = new Set<Id>();
        //Id KnownErrorRecordTypeId = schema.SObjectType.Knowledge__kav.getRecordTypeInfosByName().get('Known_Error').getRecordTypeId();
        
        for(JIRA_Issue__c jissue : lstJira){
            if(jissue.Case__c != null){
                kavIds.add(jissue.Id);      
            }
        }
        
        //Get Articles where related problem Id = Jira case__c Id
        //Map<Id,Knowledge__kav> KavMap = new Map<Id,Knowledge__kav>([SELECT Id FROM Knowledge__kav WHERE Related_Problem__c IN: kavIds AND RecordTypeId =:KnownErrorRecordTypeId]);
        Map<Id,Knowledge__kav> KavMap = new Map<Id,Knowledge__kav>([SELECT Id FROM Knowledge__kav WHERE Related_Problem__c IN: kavIds]);
        
        List<Knowledge__kav> lstKav = new List<Knowledge__kav>();
        
        for(Knowledge__kav kav: KavMap.values()){
            System.debug('##### KavMap.values ' + KavMap.values() );
            
        	if(KavMap != null && KavMap.containskey(kav.Related_Problem__c)) {
            
                List<JIRA_Issue__c> lstJiraIssue = new List<JIRA_Issue__c>();
                for(JIRA_Issue__c ji: lstJiraIssue){
                    
                    if(ji.Case__c == kav.Related_Problem__c){
                        kav.JIRA_Issue__c = ji.Id;
                   		lstKav.add(kav);
                    }
                    
                }
            }
            update lstKav;           
        }
      
    }

}

Apex Trigger
trigger JiraLinkKnownErrorArticle on JIRA_Issue__c (after insert, after update) {
    if(trigger.isAfter){
        KnowledgeKavManager.updateJiraIssue(Trigger.New);
    }

}



 

Hello,
I have an approval process on on Custom object. And I would like to update a custom field "Approver Name" with the name of the "Actual Approver"
So let's say the name the of Actual Approver is "Frank Karl" I would like the custom field "Approver Name" to be automatically updated with "Frank Karl"
User-added image
How can I do it with out of the box functionnality?
Thanks
 

Hello,
How can I calclulate a Due Date / target date excluding business Days and Holidays?
I have a date/time field called "First_Reply_Date__c" and when its filled, I would like the "Target_Date__c" field to be updated with the next working day.
For example, let's say the "First_Reply_Date__c" field is filled on a Friday
First_Reply_Date__c : 25/10/2020 1:00 pm;
Then "Target_Date__c" will be on the Monday 28/10/2020 1:00pm

How could I do it using a code? 
Thanks,

Hello,
I am trying to stop clients from commenting on Closed Cases in client portal.

I am using a trigger on CaseComment. But the trigger does not work as clients can still comments on closed case.
Alternatively if someone has another suggestion that would stop clients from commenting on Closed Cases.
Please suggest alternatives.

Thanks
 

trigger ClosedCaseComment on CaseComment (before insert) {
    
    Set<Id> parentCase=new Set<Id>();
    
	Map<Id,Case> mapCase=new Map<Id,Case>();
	for (CaseComment t: Trigger.new) {
		parentCase.add(t.ParentId);
	}
    
	List<Case> lstCase=[Select Id,Status from case where Id in :parentCase ];
	for(case c: lstCase){
		mapCase.put(c.Id,c);
	}

	for (CaseComment t: Trigger.new){
		if(mapCase.containskey(t.ParentId)) {
        
			if(mapCase.get(t.ParentId).Status=='Closed' && System.Userinfo.getUserType() == 'Standard'){
				t.addError('You cannot add comments to closed cases.');		
			}
		}
	}

}
 



 

Hi,

I have created a lightning button called "Raise a concern" but I would like to change the color of the text and the Icon, but when using Style in the component style, I am unale to change the color.

Here is the bit of code 
</aura:if>
        <aura:if isTrue="{!v.currentCaseRecordType=='Incident'}"> 
             
            <lightning:button variant="destructive"
                              label="Raise a Concern" class="concern"
                              iconName="utility:priority"
                              iconPosition="left"
                              title="Raise a Concern"
                              onclick="{! c.concernModalOpen }" 
                              disabled="{!if(v.currentCaseCaseConcern>0,'true','false')}"/>
        </aura:if>      

Could someone Help?
ThanksUser-added image