1

so basically I ripped off http://www.iterativelogic.com/using-invocable-methods-with-skuid/ in order to integrate an automatic Lead Convert Method that can be called from Skuid and I'm unable to test it.

The InvocableMethod is:

global class LeadConvertAction {  
    @InvocableMethod(label='Convert Leads')
    global static List<ConvertLeadActionResult> convertLeads(List<ConvertLeadActionRequest> requests) {
        List<ConvertLeadActionResult> results = new List<ConvertLeadActionResult>();

    try {
      for (ConvertLeadActionRequest request : requests) {
        results.add(convertLead(request));
      }
    }
    catch(Exception ex) {
      System.debug(ex);
    }

    System.debug(results);
    return results;
  }

  public static ConvertLeadActionResult convertLead(ConvertLeadActionRequest request) {
    Database.LeadConvert lc = new Database.LeadConvert();
    lc.setLeadId(request.leadId);
    lc.setConvertedStatus(request.convertedStatus);

    if (request.accountId != null) {
        lc.setAccountId(request.accountId);
    }

    if (request.contactId != null) {
      lc.setContactId(request.contactId);
    }

    if (request.overWriteLeadSource != null && request.overWriteLeadSource) {
      lc.setOverwriteLeadSource(request.overWriteLeadSource);
    }

    if (request.createOpportunity != null && !request.createOpportunity) {
      lc.setDoNotCreateOpportunity(!request.createOpportunity);
    }

    if (request.opportunityName != null) {
      lc.setOpportunityName(request.opportunityName);
    }

    if (request.ownerId != null) {
      lc.setOwnerId(request.ownerId);
    }

    if (request.sendEmailToOwner != null && request.sendEmailToOwner) {
      lc.setSendNotificationEmail(request.sendEmailToOwner);
    }

    try {
      Database.LeadConvertResult lcr = Database.convertLead(lc, true);
      if (lcr.isSuccess()) {
        ConvertLeadActionResult result = new ConvertLeadActionResult();
        result.accountId = lcr.getAccountId();
        result.contactId = lcr.getContactId();
        result.opportunityId = lcr.getOpportunityId();
        return result;
      } else {
        throw new ConvertLeadActionException(lcr.getErrors()[0].getMessage());
      }
    }
    catch(Exception ex) {
      ConvertLeadActionResult result = new ConvertLeadActionResult();
      result.error = ex.getMessage();
      return result;
    }
  }

  global class ConvertLeadActionRequest {
    @InvocableVariable(required=true)
    public ID leadId;

    @InvocableVariable(required=true)
    public String convertedStatus;

    @InvocableVariable
    public ID accountId;

    @InvocableVariable
    public ID contactId;

    @InvocableVariable
    public Boolean overWriteLeadSource;

    @InvocableVariable
    public Boolean createOpportunity;

    @InvocableVariable
    public String opportunityName;

    @InvocableVariable
    public ID ownerId;

    @InvocableVariable
    public Boolean sendEmailToOwner;
  }

  global class ConvertLeadActionResult {
    @InvocableVariable
    public ID accountId;

    @InvocableVariable
    public ID contactId;

    @InvocableVariable
    public ID opportunityId;

    @InvocableVariable
    public String error;
  }

  class ConvertLeadActionException extends Exception {}
}

And then my testClass as of now is:

@isTest
global class LeadConvertActionTest {

    private static testMethod void doTest() {

        Test.startTest();

        Lead l = new Lead(FirstName = 'TestFirst',
            LastName = 'TestLast',
            Street = 'Somewhere',
            City = 'Around',
            State = 'CA',
            PostalCode = '90002',
            Phone = '3103081233',
            Email = '[email protected]',
            Existing_PV_System__c = 'Yes',
            Utility__c = 'Other');

        insert l;

        //String jsonInput = '{"leadId": "' + l.Id + '", "convertedStatus": "Closed - Converted"}';
    //String jsonInput = '{"inputs":[{"leadId": "' + l.Id + '", "convertedStatus": "Closed - Converted"}]}';
    //Map<String, Object> leadObj = (Map<String, Object>)JSON.deserializeUntyped(jsonInput);
    //Map<String, Object> leadObj = (Map<String, Object>)JSON.deserializeStrict(jsonInput, String.class);
    //Map<String, String> MyStrings = new Map<String, String>{'leadId' => l.Id, 'convertedStatus' => 'Closed - Converted'};
    //new Object { 'leadId' => l.Id, 'convertedStatus' => 'Closed - Converted' }

    List<LeadConvertAction.ConvertLeadActionRequest> leadC = New List<LeadConvertAction.ConvertLeadActionRequest>();

    //leadC.leadId = new ID l.Id;

    leadC.leadId = l.Id;
    leadC.convertedStatus = 'Closed - Converted';
    List<LeadConvertAction.ConvertLeadActionResult> converted = LeadConvertAction.convertLeads(leadC);
    Test.stopTest();

    Account a = [Select FirstName, LastName, Id From Account where ID = :converted.accountId];
    Contact c = [Select FirstName, LastName, Id From Contact where ID = :converted.contactId];
    Opportunity o = [Select Account.FirstName, Account.LastName, Id From Opportunity where ID = :converted.opportunityId];

    system.assertEquals(a.FirstName, l.FirstName);
    system.assertEquals(c.LastName, l.LastName);
    system.assertEquals(o.Account.LastName, l.LastName);
  }
}

The different json strings and maps were my futile attempts at making the object correct but I keep getting:

I've tried many solutions but can solve it. The last errors I'm getting are:

Error: Compile Error: Initial term of field expression must be a concrete SObject: List<LeadConvertAction.ConvertLeadActionRequest> at line 28 column 9

Now the error is quite obvious, but I'm not sure why it's happening. I've also try to create the leadC.leadId field as a new ID but a whole different range of errors appear, from cannot be initiated as an ID etc. Before I tried simply parsing, encoding, creating a List, and passing that directly to the function Call, but was always getting type mismatches so decided to initialize the variables with News and try to set their values and then pass it...

In the real usage, it will be called from a JS snippet as:

var request = '{"inputs":[{"leadId": "' + row.Id + '", "convertedStatus": "Closed - Converted"}]}';
    console.log(request);

    $.ajax('/services/data/v33.0/actions/custom/apex/LeadConvertAction', {
        data: request,
        type: 'POST',
        crossDomain: true,
        dataType: "json",
        beforeSend: function(xhr) {
            xhr.setRequestHeader('Authorization', 'Bearer ' + sforce.connection.sessionId);
            xhr.setRequestHeader('Content-Type', 'application/json');
        },
...

If anyone can help would be greatly appreciated! Thanks Micael

4
  • Even if that's where you found the resource initially, they took it directly from the horse's mouth.
    – Adrian Larson
    May 24, 2016 at 0:04
  • @AdrianLarson. Yup. The Salesforce article is where I got the code from. I re-used it to illustrate using Invocable Methods from Skuid which they now directly support but at the time was an experiment I had done to see what was possible. I gave proper credit and a link to the source but also included it in my post for the benefit of the reader. May 24, 2016 at 2:02
  • Ah, you authored the post. No accusation intended, I just skimmed the article peripherally. Cheers!
    – Adrian Larson
    May 24, 2016 at 2:08
  • Yes, but John mentioned it that's why I didn't feel so bad about ripping it - although the JS code to call it from Skuid/VF would take me surely a lot more to come up with as well :) May 24, 2016 at 12:51

1 Answer 1

1

The message is somewhat opaque, but your problem is that you are trying to set instance properties on a collection. Think about it, List<ConvertLeadActionRequest> does not have a property named leadId, and if it did, what would it mean? You need to construct an individual instance and set the properties there.

List<LeadConvertAction.ConvertLeadActionRequest> requests =
    new List<LeadConvertAction.ConvertLeadActionRequest>();
// the above does not have a property named leadId

LeadConvertAction.ConvertLeadActionRequest request =
    new LeadConvertAction.ConvertLeadActionRequest();
// the above does have a property named leadId

request.leadId = l.Id;
request.convertedStatus = 'Closed - Converted';
requests.add(request);
3
  • This should resolve your issue. Noticed as well that you were modifying the list object rather than a instance and then adding that instance to the list. May 24, 2016 at 1:54
  • Thank you so much Adrian! I did first try to assign to the Obj instead of list, but then forgot to add it to a list of these objects and when passing to the method I was getting a mismatch - duh! Can't give you a vote yet. But thanks! May 24, 2016 at 12:33
  • Thanks John, as of now it's going but I still need to increase the test coverage! May 24, 2016 at 12:52

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .