3

We are using Live Agents for a service implementation, but due to implementation decisions made, cant use Profiles to assign Skills for the Live Agents, and need to assign individual users to their skills in order for the Live Agent functionality to work.

Is there a way to insert SkillUsers from Apex? It seems to not allow DML operations on the object, but I wasn't sure if there would be another way to create the object. We are planning on automating this via a trigger on user creation, much the same as for permission sets, and queue membership.

We can create the object using DataLoader, but this would be impractical due to the holiday season where 100-200 users would be added each day, each having multiple skills.

  • 1
    If DataLoader can create the SObject but Apex can't, then that means it can be created by the API. Hence, your Apex code can invoke the SFDC REST API upon the same org and do the insert that way – cropredy Jun 22 '15 at 22:24
4

You can use REST to create these records as well. I find it a much simpler approach.

public static HttpResponse postSkillUser(SkillUser record)
{
    String endpoint = URL.getSalesforceBaseUrl().toExternalForm() +
        '/services/data/v40.0/sobjects/SkillUser';
    String authHeader = 'Bearer ' + UserInfo.getSessionId();

    HttpRequest request = new HttpRequest();
    request.setHeader('Content-Type', 'application/json');
    request.setHeader('Authorization', authHeader);
    request.setBody(JSON.serialize(record));
    request.setEndpoint(endpoint);
    request.setMethod('POST');

    return new Http().send(request);
}
  • the above code returns 401. This is json of skillUser record SkillUser:{SkillId=0C51h000000005ZCAQ, UserId=0051h000000G1h0AAC} – user2815826 Feb 14 '18 at 20:42
  • Nice solution. It was a version issue. Try below version 30 on sites :) – user2815826 Feb 14 '18 at 21:14
1

So after much research and fiddling around, I have found the answer. It involves creating a SOAP request to insert the Skill Users. I've posted the code below as I couldn't find any examples when I was searching for information on this topic before.

public static void AddUserSkills(Map<Id, User> userMap){
   String soapbody;  
   //use same soapHeader as above and place in a GlobalConstants later
   String soapHeader='<?xml version="1.0" encoding="utf-8"?>' +
                      '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:sobject.partner.soap.sforce.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns2="urn:partner.soap.sforce.com">'+
                      '<SOAP-ENV:Header>'+
                      '<ns2:SessionHeader>'+
                      '<ns2:sessionId>' + UserInfo.getSessionId() + 
                      '</ns2:sessionId>'+
                      '</ns2:SessionHeader>'+
                      '</SOAP-ENV:Header>'+
                       '<SOAP-ENV:Body>'+
                      '<ns2:create>';

    String soapFooter ='</ns2:create>' +
                '</SOAP-ENV:Body>'+
                '</SOAP-ENV:Envelope>';    

    Set<String> skillsToGet = new Set<String>();
    Map<String, Skill> skillNameToSkill = new Map<String, Skill>();       
    Map<String, String> skillUserMap = new Map<String, String>();   

   //Put this in a method later that can be reused between RemoveUserSkills and AddUserSkills
    for(user u: userMap.values()){
        if(u.Skills__c != null){
           String[] tmpGroups =  u.Skills__c.split(';');                        
           if(u.IsActive){
              for(String q : tmpGroups){
                  if(!skillsToGet.contains(q)){
                      skillsToGet.add(q);
                 }
             }
          } 
        }
    } 

 List<Skill> skills = [SELECT Id,DeveloperName 
                       FROM Skill WHERE 
                       DeveloperName in: skillsToGet];

 for(Skill s : skills){
            if(!skillNameToSkill.containsKey(s.DeveloperName)){
                skillNameToSkill.put(s.DeveloperName, s);
            }
     }

  for(user u : userMap.values()){
        if(u.Skills__c != null){
            List<String> tmpSkills =  u.Skills__c.split(';');
            Set<String> skillsSet = new Set<String>();                
            if(u.IsActive){
                skillsSet.addAll(tmpSkills);
                for(String s : tmpSkills){
                    soapbody +='<ns2:sObjects>'+
                    '<ns1:type>SkillUser</ns1:type>'+
                    '<ns1:Id xsi:nil="true"/>'+
                    '<SkillId>' + skillNameToSkill.get(s).Id+'</SkillId>'+
                    '<UserId>' + + u.Id +'</UserId>'+                                                          
                    '</ns2:sObjects>';                                
                }
            }                
    }
}

System.debug('Soap Body: ' + soapbody);
//tune batch set size accordingly later for optimization within @future call time out limit. Depends if 200 records can be created within 120 seconds      
ApexWebServiceProxy.HttpRequest(GlobalConstants.partnerSoapEndPoint, 'POST', '"', 'text/xml', soapHeader + soapbody + soapFooter);}

Hope this helps other individuals trying to accomplish the same task via Apex.

And for completeness, here's the ApexWebServiceProxy class.

public with sharing class ApexWebServiceProxy {
@Future(callout=true)
public static void HttpRequest(String uri, String httpMethod, String soapAction, String contentType, String body ) {   
    Http h = new Http();
    HttpRequest req = new HttpRequest();
    req.setEndpoint(uri);
    req.setMethod(httpMethod); 
    req.setHeader('SOAPAction',soapAction); 
    req.setHeader('Content-Type', contentType);
    req.setBody(body);    
    HttpResponse res = h.send(req);  
}}

And finally the Global Constants class

public class GlobalConstants {
    public static final String partnerSoapEndPoint =    System.URL.getSalesforceBaseUrl().toExternalForm()+'/services/Soap/u/33.0';
}
  • I have been looking for a similar solution (in my case its about deleting records from the skilluser object). I am using the code from the previous answer, but I do not know what goes in the GlobalConstants.partnerSoapEndPoint variable, could you include this declaration? Thanks! – user22313 Jul 31 '15 at 15:56
  • does the rest API not work? – cropredy Jul 31 '15 at 20:52
  • @crop1645 we couldn't get the rest API to work correctly for the SkillUser object. That's not to say it won't work, we just gave up on the rest API and decided on the Soap API since it took less effort. – sevargdcg Aug 6 '15 at 17:15

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.