Flow

Flow Builder 允许管理员构建应用程序(称为),这些应用程序通过收集来自动执行业务流程 数据并在您的 Salesforce 组织或外部系统中执行某些操作。

例如,您可以创建一个流来编写客户支持中心或 为销售团队生成实时报价。您可以在 Visualforce 页面或 Aura 组件中嵌入流程,然后 在 Apex 控制器中访问它。

  • 获取流变量
    您可以在 Apex 中检索特定流的流变量。
  • 从可调用操作向外部系统发出标注 当您定义在屏幕流中作为可调用操作
    运行并向外部系统发出标注的方法时,请使用修饰符。callout
  • 使用 Process.Plugin 接口将数据传递到流是一个内置接口
    ,可用于处理组织内的数据并将其传递给指定的流。该接口将 Apex 公开为服务,该服务接受输入值并将输出返回给流。Process.Plugin

获取流变量

您可以在 Apex 中检索特定流的流变量。

Apex 类提供用于检索流变量的方法, 它可以位于 Visualforce 页面中嵌入的流程中,也可以位于 由 subflow 元素调用。此示例演示如何使用此方法获取痕迹导航 (导航)来自 Visualforce 页面中嵌入的流程的信息。如果那流动 包含子流元素,并且每个引用的流还包含一个变量,Visualforce 页面可以为用户提供 面包屑,无论面试运行哪个流程。Flow.InterviewgetVariableValuevaBreadCrumb

public class SampleContoller {

   // Instance of the flow
   public Flow.Interview.Flow_Template_Gallery myFlow {get; set;}

   public String getBreadCrumb() {
      String aBreadCrumb;
      if (myFlow==null) { return 'Home';}
      else aBreadCrumb = (String) myFlow.getVariableValue('vaBreadCrumb');

      return(aBreadCrumb==null ? 'Home': aBreadCrumb);

   }
}

从可调用操作向外部系统发出标注

当您定义一个方法,该方法在屏幕流中作为可调用操作运行,并使 标注到外部系统时,请使用修饰符。

callout

当该方法作为可调用操作执行时,屏幕流使用此修饰符来确定 该操作是否可以在当前事务中安全执行。流管理员可以配置 让 Flow 决定是在新事务中执行该操作还是在当前事务中执行该操作的操作 一。当满足以下所有条件时,流将提交当前事务,开始 一个新事务,并安全地调用外部系统:

  • 该方法的标注修饰符是 。true
  • 屏幕流中操作的“事务控制”设置配置为允许流 决定。
  • 当前事务具有未提交的工作。

如果满足以下任一条件,则流将在当前事务中执行操作:

  • 标注修饰符为 。false
  • 该操作由非屏幕流执行。
  • 当前事务没有未提交的工作。

使用 Process.Plugin 接口将数据传递到流

Process.Plugin 是一个内置接口,可让您在 您的组织并将其传递给指定的流.该接口将 Apex 公开为服务,该服务接受 输入值并将输出返回给流。

提示

我们建议使用注解而不是接口。@InvocableMethodProcess.Plugin

  • 该接口不支持 Blob、Collection、sObject 和 Time 数据类型,并且它 不支持批量操作。在类上实现接口后,类 只能从流中引用。
  • 注释支持所有数据类型和批量操作。一旦您实现了 注解,可以从流、流程和自定义中引用该类 可调用操作 REST API 端点。

当您定义在组织中实现接口的 Apex 类时,它将在 Flow Builder 中作为旧版 Apex 操作提供。Process.Plugin

Process.Plugin具有这些顶级类。

  • Process.PluginRequest 从以下类传递输入参数: 实现流的接口。
  • Process.PluginResult 从以下类返回输出参数: 实现流的接口。
  • Process.PluginDescribeResult 将输入参数从流传递给 实现接口的类。此类确定输入参数和 插件所需的输出参数。Process.PluginResult

编写 Apex 单元测试时,实例化一个类并将其传递到接口方法中。传入系统参数 需要,创建一个地图并在构造函数中使用它。有关更多信息,请参见使用 Process.PluginRequest 类。invoke

  • 实现 Process.Plugin 接口是一个内置接口
    ,允许您在组织和指定流之间传递数据。Process.Plugin
  • 使用 Process.PluginRequest 类 该类将实现接口的类
    中的输入参数传递到流。Process.PluginRequest
  • 使用 Process.PluginResult 类 该类从实现流接口的类
    返回输出参数。Process.PluginResult
  • 使用 Process.PluginDescribeResult 类
    使用接口方法动态提供流的输入和输出参数。此方法返回类。Process.PlugindescribeProcess.PluginDescribeResult
  • Process.Plugin 数据类型转换
    了解如何在 Apex 和返回给 .例如,流中的文本数据将转换为 Apex 中的字符串数据。Process.Plugin
  • 潜在客户转换
    的示例 Process.Plugin 实现 在此示例中,Apex 类实现接口并将潜在顾客转换为客户、联系人和(可选)商机。还包括插件的测试方法。可以通过旧版 Apex 操作从流中调用此实现。Process.Plugin

实现 Process.Plugin接口

Process.Plugin是一个内置接口, 允许您在组织和指定流之间传递数据。

提示

我们建议使用注解而不是接口。@InvocableMethodProcess.Plugin

  • 该接口不支持 Blob、Collection、sObject 和 Time 数据类型,并且它 不支持批量操作。在类上实现接口后,类 只能从流中引用。
  • 注释支持所有数据类型和批量操作。一旦您实现了 注解,可以从流、流程和自定义中引用该类 可调用操作 REST API 端点。

实现接口的类必须调用这些方法。Process.Plugin

名字参数返回类型描述
describeProcess.PluginDescribeResult返回描述这一点的对象 方法调用。Process.PluginDescribeResult
invokeProcess.PluginRequestProcess.PluginResult当实现 接口被实例化。

示例实现

global class flowChat implements Process.Plugin { 

// The main method to be implemented. The Flow calls this at runtime.
global Process.PluginResult invoke(Process.PluginRequest request) { 
        // Get the subject of the Chatter post from the flow
        String subject = (String) request.inputParameters.get('subject');
        
        // Use the Chatter APIs to post it to the current user's feed
        FeedItem fItem = new FeedItem(); 
        fItem.ParentId = UserInfo.getUserId(); 
        fItem.Body = 'Flow Update: ' + subject; 
        insert fItem; 

        // return to Flow
        Map<String,Object> result = new Map<String,Object>(); 
        return new Process.PluginResult(result); 
    } 

    // Returns the describe information for the interface
    global Process.PluginDescribeResult describe() { 
        Process.PluginDescribeResult result = new Process.PluginDescribeResult(); 
        result.Name = 'flowchatplugin';
        result.Tag = 'chat';
        result.inputParameters = new 
           List<Process.PluginDescribeResult.InputParameter>{ 
               new Process.PluginDescribeResult.InputParameter('subject', 
               Process.PluginDescribeResult.ParameterType.STRING, true) 
            }; 
        result.outputParameters = new 
           List<Process.PluginDescribeResult.OutputParameter>{ }; 
        return result; 
    }
}

测试类

以下是上述类的测试类。

@isTest
private class flowChatTest {

    static testmethod void flowChatTests() {
      
        flowChat plugin = new flowChat();
        Map<String,Object> inputParams = new Map<String,Object>();

        string feedSubject = 'Flow is alive';
        InputParams.put('subject', feedSubject);

        Process.PluginRequest request = new Process.PluginRequest(inputParams);           
        
        plugin.invoke(request);
    } 
}

使用 Process.PluginRequest 类

该类传递输入 实现流接口的类中的参数。

Process.PluginRequest

提示

我们建议使用注解而不是接口。@InvocableMethodProcess.Plugin

  • 该接口不支持 Blob、Collection、sObject 和 Time 数据类型,并且它 不支持批量操作。在类上实现接口后,类 只能从流中引用。
  • 注释支持所有数据类型和批量操作。一旦您实现了 注解,可以从流、流程和自定义中引用该类 可调用操作 REST API 端点。

此类没有方法。构造 函数 签名:

Process.PluginRequest (Map<String,Object>)

下面是使用一个输入参数实例化类的示例。Process.PluginRequest

Map<String,Object> inputParams = new Map<String,Object>();
        string feedSubject = 'Flow is alive';
        InputParams.put('subject', feedSubject);
        Process.PluginRequest request = new Process.PluginRequest(inputParams);

代码示例

在此示例中,代码从流程中返回 Chatter 帖子的主题,并发布 它到当前用户的 饲料。

global Process.PluginResult invoke(Process.PluginRequest request) { 
        // Get the subject of the Chatter post from the flow
        String subject = (String) request.inputParameters.get('subject');
        
        // Use the Chatter APIs to post it to the current user's feed
        FeedPost fpost = new FeedPost(); 
        fpost.ParentId = UserInfo.getUserId(); 
        fpost.Body = 'Flow Update: ' + subject; 
        insert fpost; 

        // return to Flow
        Map<String,Object> result = new Map<String,Object>(); 
        return new Process.PluginResult(result); 
    } 

    // describes the interface 
    global Process.PluginDescribeResult describe() { 
        Process.PluginDescribeResult result = new Process.PluginDescribeResult(); 
        result.inputParameters = new List<Process.PluginDescribeResult.InputParameter>{ 
            new Process.PluginDescribeResult.InputParameter('subject', 
            Process.PluginDescribeResult.ParameterType.STRING, true) 
            }; 
        result.outputParameters = new List<Process.PluginDescribeResult.OutputParameter>{ }; 
        return result; 
    }
}

使用 Process.PluginResult 类

该类返回 从实现接口的类输出参数到 流。

Process.PluginResult

提示

我们建议使用注解而不是接口。@InvocableMethodProcess.Plugin

  • 该接口不支持 Blob、Collection、sObject 和 Time 数据类型,并且它 不支持批量操作。在类上实现接口后,类 只能从流中引用。
  • 注释支持所有数据类型和批量操作。一旦您实现了 注解,可以从流、流程和自定义中引用该类 可调用操作 REST API 端点。

您可以使用以下格式之一实例化类:

Process.PluginResult

  • Process.PluginResult (Map<String,Object>)
  • Process.PluginResult (String, Object)

当您有多个结果或不知道有多少个结果时,请使用地图 将返回结果。下面是实例化类的示例。

Process.PluginResult

string url = 'https://docs.google.com/document/edit?id=abc';
        String status = 'Success';
        Map<String,Object> result = new Map<String,Object>();
        result.put('url', url);
        result.put('status',status);
        new Process.PluginResult(result);

使用 Process.PluginDescribeResult 类

使用 interface 方法动态提供输入和 流的输出参数。此方法返回类。

Process.PlugindescribeProcess.PluginDescribeResult

提示

我们建议使用注解而不是接口。@InvocableMethodProcess.Plugin

  • 该接口不支持 Blob、Collection、sObject 和 Time 数据类型,并且它 不支持批量操作。在类上实现接口后,类 只能从流中引用。
  • 注释支持所有数据类型和批量操作。一旦您实现了 注解,可以从流、流程和自定义中引用该类 可调用操作 REST API 端点。

该类没有 支持以下功能。

Process.PluginDescribeResult

  • 查询
  • 数据修改
  • 电子邮件
  • 顶点嵌套标注

Process.PluginDescribeResult 类和 子类属性

下面是该类的构造函数。

Process.PluginDescribeResult

Process.PluginDescribeResult classname = new Process.PluginDescribeResult();
  • PluginDescribeResult 类属性
  • PluginDescribeResult.InputParameter 类属性
  • PluginDescribeResult.OutputParameter 类属性

下面是该类的构造函数。

Process.PluginDescribeResult.InputParameter

Process.PluginDescribeResult.InputParameter ip = new 
    Process.PluginDescribeResult.InputParameter(Name,Optional_description_string, 
      Process.PluginDescribeResult.ParameterType.Enum, Boolean_required);

下面是该类的构造函数。

Process.PluginDescribeResult.OutputParameter

Process.PluginDescribeResult.OutputParameter op = new 
    new Process.PluginDescribeResult.OutputParameter(Name,Optional description string, 
       Process.PluginDescribeResult.ParameterType.Enum);

要使用该类, 创建这些子类的实例。

Process.PluginDescribeResult

  • Process.PluginDescribeResult.InputParameter
  • Process.PluginDescribeResult.OutputParameter

Process.PluginDescribeResult.InputParameter是一个 输入参数列表,并具有以下内容 格式。

Process.PluginDescribeResult.inputParameters = 
      new List<Process.PluginDescribeResult.InputParameter>{ 
         new Process.PluginDescribeResult.InputParameter(Name,Optional_description_string, 
      Process.PluginDescribeResult.ParameterType.Enum, Boolean_required)

为 例:

Process.PluginDescribeResult result = new Process.PluginDescribeResult(); 
result.setDescription('this plugin gets the name of a user');
result.setTag ('userinfo');
result.inputParameters = new List<Process.PluginDescribeResult.InputParameter>{ 
    new Process.PluginDescribeResult.InputParameter('FullName', 
       Process.PluginDescribeResult.ParameterType.STRING, true),
    new Process.PluginDescribeResult.InputParameter('DOB', 
       Process.PluginDescribeResult.ParameterType.DATE, true),
    }; 

Process.PluginDescribeResult.OutputParameter是一个 输出参数列表,并具有以下内容 格式。

Process.PluginDescribeResult.outputParameters = new List<Process.PluginDescribeResult.OutputParameter>{ 
    new Process.PluginDescribeResult.OutputParameter(Name,Optional description string, 
       Process.PluginDescribeResult.ParameterType.Enum)

为 例:

Process.PluginDescribeResult result = new Process.PluginDescribeResult(); 
result.setDescription('this plugin gets the name of a user');
result.setTag ('userinfo');
result.outputParameters = new List<Process.PluginDescribeResult.OutputParameter>{
    new Process.PluginDescribeResult.OutputParameter('URL', 
        Process.PluginDescribeResult.ParameterType.STRING),

两个类都采用枚举。有效值为:

Process.PluginDescribeResult.ParameterType

  • 布尔
  • 日期
  • 日期时间
  • 十进制
  • 编号
  • 整数
  • 字符串

为 例:

Process.PluginDescribeResult result = new Process.PluginDescribeResult(); 
        result.outputParameters = new List<Process.PluginDescribeResult.OutputParameter>{
            new Process.PluginDescribeResult.OutputParameter('URL', 
            Process.PluginDescribeResult.ParameterType.STRING, true),
            new Process.PluginDescribeResult.OutputParameter('STATUS', 
            Process.PluginDescribeResult.ParameterType.STRING),
            };

Process.Plugin 数据类型 转换

了解如何在 Apex 和返回给 .例如,流中的文本数据会转换 在 Apex 中字符串数据。

Process.Plugin

提示

我们建议使用注解而不是接口。@InvocableMethodProcess.Plugin

  • 该接口不支持 Blob、Collection、sObject 和 Time 数据类型,并且它 不支持批量操作。在类上实现接口后,类 只能从流中引用。
  • 注释支持所有数据类型和批量操作。一旦您实现了 注解,可以从流、流程和自定义中引用该类 可调用操作 REST API 端点。
流数据类型数据类型
十进制
日期日期时间/日期
日期时间日期时间/日期
布尔仅具有 1 或 0 值的布尔值和数字值
发短信字符串

Lead 的示例 Process.Plugin 实现 转换

在此示例中,Apex 类实现 接口并转换潜在客户 进入客户、联系人和(可选)商机。插件的测试方法如下 也包括在内。可以通过旧版 Apex 操作从流中调用此实现。

Process.Plugin

提示

我们建议使用注解而不是接口。@InvocableMethodProcess.Plugin

  • 该接口不支持 Blob、Collection、sObject 和 Time 数据类型,并且它 不支持批量操作。在类上实现接口后,类 只能从流中引用。
  • 注释支持所有数据类型和批量操作。一旦您实现了 注解,可以从流、流程和自定义中引用该类 可调用操作 REST API 端点。
// Converts a lead as an action in a flow.
global class VWFConvertLead implements Process.Plugin {
    // This method runs when called by a flow's legacy Apex action.
    global Process.PluginResult invoke(
        Process.PluginRequest request) {
            
        // Set up variables to store input parameters from 
        // the flow.
        String leadID = (String) request.inputParameters.get(
            'LeadID');
        String contactID = (String) 
            request.inputParameters.get('ContactID');
        String accountID = (String) 
            request.inputParameters.get('AccountID');
        String convertedStatus = (String) 
            request.inputParameters.get('ConvertedStatus');
        Boolean overWriteLeadSource = (Boolean) 
            request.inputParameters.get('OverwriteLeadSource');
        Boolean createOpportunity = (Boolean) 
            request.inputParameters.get('CreateOpportunity');
        String opportunityName = (String) 
            request.inputParameters.get('ContactID');
        Boolean sendEmailToOwner = (Boolean) 
            request.inputParameters.get('SendEmailToOwner');   
        
        // Set the default handling for booleans. 
        if (overWriteLeadSource == null) 
            overWriteLeadSource = false;
        if (createOpportunity == null) 
            createOpportunity = true;
        if (sendEmailToOwner == null) 
            sendEmailToOwner = false;
        
        // Convert the lead by passing it to a helper method.
        Map<String,Object> result = new Map<String,Object>();
        result = convertLead(leadID, contactID, accountID, 
            convertedStatus, overWriteLeadSource, 
            createOpportunity, opportunityName, 
            sendEmailToOwner);
 
        return new Process.PluginResult(result); 
    }
    
    // This method describes the plug-in and its inputs from
    // and outputs to the flow.
    // Implementing this method makes the class available 
    // in Flow Builder as a legacy Apex action.
    global Process.PluginDescribeResult describe() {
        // Set up plugin metadata
        Process.PluginDescribeResult result = new 
            Process.PluginDescribeResult();
        result.description = 
            'The LeadConvert Flow Plug-in converts a lead into ' + 
            'an account, a contact, and ' + 
            '(optionally)an opportunity.';
        result.tag = 'Lead Management';
        
        // Create a list that stores both mandatory and optional 
        // input parameters from the flow.
        // NOTE: Only primitive types (STRING, NUMBER, etc.) are 
        // supported. Collections aren't supported.
        result.inputParameters = new 
            List<Process.PluginDescribeResult.InputParameter>{
            // Lead ID (mandatory)
            new Process.PluginDescribeResult.InputParameter(
                'LeadID', 
                Process.PluginDescribeResult.ParameterType.STRING, 
                true),
            // Account Id (optional)
            new Process.PluginDescribeResult.InputParameter(
                'AccountID', 
                Process.PluginDescribeResult.ParameterType.STRING, 
                false),
            // Contact ID (optional)
            new Process.PluginDescribeResult.InputParameter(
                'ContactID', 
                Process.PluginDescribeResult.ParameterType.STRING, 
                false),            
            // Status to use once converted
            new Process.PluginDescribeResult.InputParameter(
                'ConvertedStatus', 
                Process.PluginDescribeResult.ParameterType.STRING, 
                true),
            new Process.PluginDescribeResult.InputParameter(
                'OpportunityName', 
                Process.PluginDescribeResult.ParameterType.STRING, 
                false),
            new Process.PluginDescribeResult.InputParameter(
                'OverwriteLeadSource', 
                Process.PluginDescribeResult.ParameterType.BOOLEAN, 
                false),
            new Process.PluginDescribeResult.InputParameter(
                'CreateOpportunity', 
                Process.PluginDescribeResult.ParameterType.BOOLEAN, 
                false),
            new Process.PluginDescribeResult.InputParameter(
                'SendEmailToOwner', 
                Process.PluginDescribeResult.ParameterType.BOOLEAN, 
                false)                                                   
        };

        // Create a list that stores output parameters sent 
        // to the flow.
        result.outputParameters = new List<
            Process.PluginDescribeResult.OutputParameter>{
            // Account ID of the converted lead
            new Process.PluginDescribeResult.OutputParameter(
                'AccountID', 
                Process.PluginDescribeResult.ParameterType.STRING),
            // Contact ID of the converted lead
            new Process.PluginDescribeResult.OutputParameter(
                'ContactID', 
                Process.PluginDescribeResult.ParameterType.STRING),
            // Opportunity ID of the converted lead
            new Process.PluginDescribeResult.OutputParameter(
                'OpportunityID', 
                Process.PluginDescribeResult.ParameterType.STRING)                
        };

        return result;
    }
        
    /**
     * Implementation of the LeadConvert plug-in.
     * Converts a given lead with several options:
     * leadID - ID of the lead to convert
     * contactID - 
     * accountID - ID of the Account to attach the converted 
     *  Lead/Contact/Opportunity to.
     * convertedStatus - 
     * overWriteLeadSource - 
     * createOpportunity - true if you want to create a new 
     *  Opportunity upon conversion
     * opportunityName - Name of the new Opportunity.
     * sendEmailtoOwner - true if you are changing owners upon 
     *  conversion and want to notify the new Opportunity owner.
     *
     * returns: a Map with the following output:
     * AccountID - ID of the Account created or attached 
     *  to upon conversion.
     * ContactID - ID of the Contact created or attached 
     *  to upon conversion.
     * OpportunityID - ID of the Opportunity created 
     *  upon conversion.
     */
    public Map<String,String> convertLead (
                               String leadID,
                               String contactID,
                               String accountID,
                               String convertedStatus,
                               Boolean overWriteLeadSource,
                               Boolean createOpportunity,
                               String opportunityName,
                               Boolean sendEmailToOwner
        ) {
        Map<String,String> result = new Map<String,String>();
                                
        if (leadId == null) throw new ConvertLeadPluginException(
            'Lead Id cannot be null');
        
        // check for multiple leads with the same ID
        Lead[] leads = [Select Id, FirstName, LastName, Company 
            From Lead where Id = :leadID];
        if (leads.size() > 0) {
            Lead l = leads[0];
            // CheckAccount = true, checkContact = false
            if (accountID == null && l.Company != null) {
                Account[] accounts = [Select Id, Name FROM Account 
                    where Name = :l.Company LIMIT 1];
                if (accounts.size() > 0) {
                    accountId = accounts[0].id;
                }
            }
            
            // Perform the lead conversion.
            Database.LeadConvert lc = new Database.LeadConvert();
            lc.setLeadId(leadID);
            lc.setOverwriteLeadSource(overWriteLeadSource);
            lc.setDoNotCreateOpportunity(!createOpportunity);
            lc.setConvertedStatus(convertedStatus);
            if (sendEmailToOwner != null) lc.setSendNotificationEmail(
                sendEmailToOwner);
            if (accountId != null && accountId.length() > 0) 
                lc.setAccountId(accountId);
            if (contactId != null && contactId.length() > 0) 
                lc.setContactId(contactId);
            if (createOpportunity) {
                lc.setOpportunityName(opportunityName);
            }
            
            Database.LeadConvertResult lcr = Database.convertLead(
                lc, true);
            if (lcr.isSuccess()) {
                result.put('AccountID', lcr.getAccountId());
                result.put('ContactID', lcr.getContactId());
                if (createOpportunity) {
                    result.put('OpportunityID', 
                        lcr.getOpportunityId());
                }
            } else {
                String error = lcr.getErrors()[0].getMessage();
                throw new ConvertLeadPluginException(error);
            }
        } else { 
            throw new ConvertLeadPluginException(
                'No leads found with Id : "' + leadId + '"');
        }
        return result;
    }
        
    // Utility exception class
    class ConvertLeadPluginException extends Exception {}
}
// Test class for the lead convert Apex plug-in.
@isTest
private class VWFConvertLeadTest {
    static testMethod void basicTest() {
        // Create test lead
        Lead testLead = new Lead(
           Company='Test Lead',FirstName='John',LastName='Doe');
        insert testLead;
    
        LeadStatus convertStatus = 
           [Select Id, MasterLabel from LeadStatus 
           where IsConverted=true limit 1]; 
        
        // Create test conversion
        VWFConvertLead aLeadPlugin = new VWFConvertLead();
        Map<String,Object> inputParams = new Map<String,Object>();
        Map<String,Object> outputParams = new Map<String,Object>();

        inputParams.put('LeadID',testLead.ID);
        inputParams.put('ConvertedStatus', 
           convertStatus.MasterLabel);

        Process.PluginRequest request = new 
           Process.PluginRequest(inputParams);
        Process.PluginResult result;
        result = aLeadPlugin.invoke(request);
        
        Lead aLead = [select name, id, isConverted 
                       from Lead where id = :testLead.ID];
        System.Assert(aLead.isConverted);
        
    }

     /*
      * This tests lead conversion with 
      * the Account ID specified.
      */
    static testMethod void basicTestwithAccount() {

        // Create test lead
        Lead testLead = new Lead(
            Company='Test Lead',FirstName='John',LastName='Doe');
        insert testLead;
        
        Account testAccount = new Account(name='Test Account');
        insert testAccount;
    
           // System.debug('ACCOUNT BEFORE' + testAccount.ID);

        LeadStatus convertStatus = [Select Id, MasterLabel 
                    from LeadStatus where IsConverted=true limit 1]; 
        
        // Create test conversion
        VWFConvertLead aLeadPlugin = new VWFConvertLead();
        Map<String,Object> inputParams = new Map<String,Object>();
        Map<String,Object> outputParams = new Map<String,Object>();

        inputParams.put('LeadID',testLead.ID);
        inputParams.put('AccountID',testAccount.ID);
        inputParams.put('ConvertedStatus',
            convertStatus.MasterLabel);

        Process.PluginRequest request = new 
            Process.PluginRequest(inputParams);
        Process.PluginResult result;
        result = aLeadPlugin.invoke(request);
        
        Lead aLead = 
            [select name, id, isConverted, convertedAccountID 
             from Lead where id = :testLead.ID];
        System.Assert(aLead.isConverted);
        //System.debug('ACCOUNT AFTER' + aLead.convertedAccountID);
        System.AssertEquals(testAccount.ID, aLead.convertedAccountID);
    }

    /*
     * This tests lead conversion with the Account ID specified.
    */
    static testMethod void basicTestwithAccounts() {

        // Create test lead
        Lead testLead = new Lead(
            Company='Test Lead',FirstName='John',LastName='Doe');
        insert testLead;
        
        Account testAccount1 = new Account(name='Test Lead');
        insert testAccount1;
        Account testAccount2 = new Account(name='Test Lead');
        insert testAccount2;

           // System.debug('ACCOUNT BEFORE' + testAccount.ID);

        LeadStatus convertStatus = [Select Id, MasterLabel 
            from LeadStatus where IsConverted=true limit 1]; 
        
        // Create test conversion
        VWFConvertLead aLeadPlugin = new VWFConvertLead();
        Map<String,Object> inputParams = new Map<String,Object>();
        Map<String,Object> outputParams = new Map<String,Object>();

        inputParams.put('LeadID',testLead.ID);
        inputParams.put('ConvertedStatus',
            convertStatus.MasterLabel);

        Process.PluginRequest request = new 
            Process.PluginRequest(inputParams);
        Process.PluginResult result;
        result = aLeadPlugin.invoke(request);
        
        Lead aLead = 
            [select name, id, isConverted, convertedAccountID 
            from Lead where id = :testLead.ID];
        System.Assert(aLead.isConverted);
    }


     /*
      * -ve Test
      */    
    static testMethod void errorTest() {

        // Create test lead
        // Lead testLead = new Lead(Company='Test Lead',
        //   FirstName='John',LastName='Doe');
        LeadStatus convertStatus = [Select Id, MasterLabel 
            from LeadStatus where IsConverted=true limit 1]; 
        
        // Create test conversion
        VWFConvertLead aLeadPlugin = new VWFConvertLead();
        Map<String,Object> inputParams = new Map<String,Object>();
        Map<String,Object> outputParams = new Map<String,Object>();
        inputParams.put('LeadID','00Q7XXXXxxxxxxx');
        inputParams.put('ConvertedStatus',convertStatus.MasterLabel);

        Process.PluginRequest request = new 
            Process.PluginRequest(inputParams);
        Process.PluginResult result;
        try {
            result = aLeadPlugin.invoke(request);    
        }
        catch (Exception e) {
          System.debug('EXCEPTION' + e);
          System.AssertEquals(1,1);
        }
        
    }
    
    
     /*
      * This tests the describe() method
      */ 
    static testMethod void describeTest() {

        VWFConvertLead aLeadPlugin = 
            new VWFConvertLead();
        Process.PluginDescribeResult result = 
            aLeadPlugin.describe();
        
        System.AssertEquals(
            result.inputParameters.size(), 8);
        System.AssertEquals(
            result.OutputParameters.size(), 3);
        
     }

}