luqinghua

之前谈到的Dicusign,都是发送一封邮件给到收件人,然后收件人完成签名的一个过程,那么有的时候,当我们需要直接在页面上打开用户签名的界面,而不是通过邮件的形式,那么就需要开启Docusign的嵌入式签名过程

整体步骤参考 Docusign系列(三)- SOAP方式调用Docusign,本质上来讲,嵌入式签名的形式,即将发送到用户的那封信件的链接,在页面上完成跳转,所以我们首先写一个页面按钮:打开Docusign签名链接(图左),当你点击按钮,会直接跳转到Docusign的签名页面(图右)

 

 

 

 页面代码很简单,通过按钮调用Docusign的SOAP接口

<apex:page controller="ShowButtonCtrl" showHeader="false" sidebar="false">
    <apex:form >
        <apex:pagemessages />
        <apex:pageBlock >
            <apex:commandButton value="打开Docusign签名链接" action="{!testFunction}"/>
        </apex:pageBlock>
    </apex:form>
</apex:page>
public class ShowButtonCtrl {
    
    public String testFunction(){
        String docusignurl = DocusignDemo2.sendWithDocusign(\'8002w000000HXkJ\');
        return docusignurl;
    }
}

那么关于Docusign部分的代码该怎么做呢?

首先是关于收件人,需要添加新的参数

// 设定一个 Client User Id
String signer_user_id = \'1\';

// 第一个签字
DocusignApi.Recipient firstSigner = new DocusignApi.Recipient();
firstSigner.ID = 1;
firstSigner.Type_x = \'Signer\';// 收件人类型 - Signer表示需要签字
firstSigner.RoutingOrder = 1;// 签字顺序
firstSigner.Email = \'XXXXXXX\';
firstSigner.UserName = \'第一个签字\';
firstSigner.RequireIDLookup = false;

// 嵌入式签名的参数
firstSigner.CaptiveInfo = new DocuSignAPI.RecipientCaptiveInfo();
firstSigner.CaptiveInfo.ClientUserID = signer_user_id;
firstSigner.CaptiveInfo.EmbeddedRecipientStartURL = \'SIGN_AT_DOCUSIGN\';

然后在通过Docusign生成EnvelopeID之后,获取需要跳转的链接:

// 第一步:创建assertion
DocuSignAPI.RequestRecipientTokenAuthenticationAssertion assertion  = new DocuSignAPI.RequestRecipientTokenAuthenticationAssertion();
assertion.AssertionID = \'1\';
assertion.AuthenticationInstant = Datetime.now();
assertion.AuthenticationMethod = \'Password\';
assertion.SecurityDomain = \'DS_Recipe_Signer_View_Controller\';

// Salesforce 环境域名
String baseUrl = URL.getSalesforceBaseUrl().toExternalForm();
String signer_return_url = baseURL + \'?cId=\' + recordId;

String return_url_base = signer_return_url;

if(return_url_base.contains(\'?\')) {
    return_url_base += \'&event=\';
}else {
    return_url_base = return_url_base += \'?event=\';
}

System.debug(LoggingLevel.INFO , \'**** return_url_base:\' + return_url_base);

// 第二步:为电子签名的不同结果创建重定向URL
DocuSignAPI.RequestRecipientTokenClientURLs urls = new DocuSignAPI.RequestRecipientTokenClientURLs();        
urls.OnSigningComplete  = baseURL + \'/apex/welcome?conId=\' + recordId;
urls.OnViewingComplete  = return_url_base + \'viewing_complete\';
urls.OnCancel           = return_url_base + \'cancel\';
urls.OnDecline          = return_url_base + \'decline\';
urls.OnSessionTimeout   = return_url_base + \'session_timeout\';
urls.OnTTLExpired       = return_url_base + \'ttl_expired\';
urls.OnException        = baseURL + \'/apex/welcome?conId=\' + recordId;
urls.OnAccessCodeFailed = return_url_base + \'failed_access_code\';
urls.OnIdCheckFailed    = return_url_base + \'failed_id_check\';
urls.OnFaxPending       = return_url_base + \'fax_pending\';

System.debug(LoggingLevel.INFO , \'**** return_url_base:\' + return_url_base);

String signer_view_url;
Boolean no_error = true;

try {
    // 第三步:调用Docusign请求
    signer_view_url = dsApi.RequestRecipientToken(envelopeId, signer_user_id, firstSigner.UserName, firstSigner.Email, assertion, urls);
    System.debug(LoggingLevel.INFO , \'**** Received signer_view_url:\' + signer_view_url);
} catch ( CalloutException e) {
    System.debug(LoggingLevel.INFO , \'**** Exception - \' + e );
    String error_code = \'Problem: \' + e;
    String error_message = error_code;
    no_error = false;
}

在搞定上面的内容之后,当Docusign签订完成会跳转到 \'welcome\' 这个自定义页面,

 

 整体来看,在SOAP的接触上使用嵌入式签名还是很简单的,这样就可以让Docusign能在更多的地方被使用,比如在我们发送出去的Email中,或者其他自定义页面上,赋予了这种电子签名更广泛的应用空间

需要注意的是,这种嵌入式签名的有效期仅仅五分钟,同时在默认情况下,Docusign不会发送之前我们看到的Docusign请求签名的邮件给收件人,这一点从需求上不难理解,毕竟在页面上把合同啥的都签了,也不需要额外的邮件提醒了,不过Docusign也不是完全关闭了这样的通道,在Docusign的管理员界面中,选择Signing Setting页签

 

 在这里,你可以关闭或者启用是否要在嵌入式场景下发送邮件给签名者,同时设置一个 CaptiveInfo 参数(参数说明

最后,附上DocusignDemo2 类的完整代码

public class DocusignDemo2 {
    public static String USERID = \'XXXXX\';
    public static String ACCOUNTID = \'XXXXX\';
    public static String PASSWORD = \'XXXXXX\';
    public static String INTEGRATORKEY = \'XXXXXX\';
    public static String ENDPOINT = \'https://demo.docusign.net/api/3.0/dsapi.asmx\';
    
    public static String sendWithDocusign(String recordId){
        Contract con = [SELECT id FROM Contract WHERE Id=:recordId];
        
        DocusignApi.DSAPIServiceSoap dsApi = new DocusignApi.DSAPIServiceSoap();
        dsApi.endpoint_x = ENDPOINT;
        
        //Set Authentication
        String auth = \'<DocuSignCredentials>\'
                        + \'<Username>\'+ USERID + \'</Username>\' 
                        + \'<Password>\' + PASSWORD + \'</Password>\' 
                        + \'<IntegratorKey>\' + INTEGRATORKEY + \'</IntegratorKey>\' 
                    + \'</DocuSignCredentials>\';
        System.debug(\'Setting authentication to: \' + auth);
            
        dsApi.inputHttpHeaders_x = new Map<String, String>();
        dsApi.inputHttpHeaders_x.put(\'X-DocuSign-Authentication\', auth);
        
        // 发送Docusign中的模板
        DocuSignAPI.TemplateReference templateReference = new DocuSignAPI.TemplateReference();
        templateReference.Template = \'XXXXXXXXX\';
        templateReference.TemplateLocation = \'Server\';
        
        DocusignApi.ArrayOfTemplateReference templateReferences = new DocusignApi.ArrayOfTemplateReference();
        templateReferences.TemplateReference = new DocusignApi.TemplateReference[]{templateReference};
        
        // 设定一个 Client User Id
        String signer_user_id = \'1\';
        
        // 第一个签字
        DocusignApi.Recipient firstSigner = new DocusignApi.Recipient();
        firstSigner.ID = 1;
        firstSigner.Type_x = \'Signer\';// 收件人类型 - Signer表示需要签字
        firstSigner.RoutingOrder = 1;// 签字顺序
        firstSigner.Email = \'XXXXXX\';
        firstSigner.UserName = \'第一个签字\';
        firstSigner.RequireIDLookup = false;

        // 启用嵌入式的同时启用远程签名
        firstSigner.CaptiveInfo = new DocuSignAPI.RecipientCaptiveInfo();
        firstSigner.CaptiveInfo.ClientUserID = signer_user_id;
     // EmbeddedRecipientStartURL –这是发件人提供的用于重定向收件人的有效URL字符串。
     // 使用此选项时,嵌入式收件人仍会像远程收件人一样从DocuSign接收电子邮件,但是当单击电子邮件中的文档链接时,
     // 收件人将通过DocuSign重定向到该URL以完成其操作
     // 路由到URL时,由发送者的系统(服务器响应URL)决定是否请求接收者令牌启动签名会话。
     // 如果此节点使用值SIGN_AT_DOCUSIGN,则收件人将直接在DocuSign上定向到嵌入式签名或查看过程。
     // 签名或查看操作由DocuSign系统启动,并且交易活动和完成证书记录将对此进行反映。在所有其他方面,
     // 该过程与任何合作伙伴都会发起的嵌入式签名或查看操作相同
firstSigner.CaptiveInfo.EmbeddedRecipientStartURL = \'SIGN_AT_DOCUSIGN\';
        
        DocusignApi.ArrayOfRecipient1 recipients = new DocusignApi.ArrayOfRecipient1();
        recipients.Recipient = new DocusignApi.Recipient[]{firstSigner};
        
        DocusignApi.EnvelopeInformation envelopeInfo = new DocusignApi.EnvelopeInformation();
        envelopeInfo.AccountId = ACCOUNTID;
        envelopeInfo.Subject = \'email subject\';// Max 100 characters
        envelopeInfo.EmailBlurb =  \'email message.\';// Max 10000 characters
            
        DocusignApi.CustomField platformName = new DocusignApi.CustomField (); 
        platformName.Name = \'PlatformName\';
        platformName.Value = \'Salesforce\';
        platformName.Show = \'False\';
        
        DocusignApi.CustomField appName = new DocusignApi.CustomField (); 
        appName.Name = \'AppName\';
        appName.Value = \'DocuSignForSalesforce\';
        appName.Show = \'False\';
        
        DocusignApi.CustomField SFContract = new DocusignApi.CustomField (); 
        SFContract.Name = \'##SFContract\';
        SFContract.Value = recordId;
        SFContract.Show = \'False\';
        
        DocusignApi.CustomField DSFSSourceObjectId = new DocusignApi.CustomField (); 
        DSFSSourceObjectId.Name = \'DSFSSourceObjectId\';
        DSFSSourceObjectId.Value = recordId + \'~Contract\';
        DSFSSourceObjectId.Show = \'False\';
        
        DocusignApi.ArrayOfCustomField arrayOfCustomFields = new DocusignApi.ArrayOfCustomField();
        arrayOfCustomFields.CustomField  = new list<DocusignApi.CustomField>();
        arrayOfCustomFields.CustomField.add(platformName);
        arrayOfCustomFields.CustomField.add(appName);
        arrayOfCustomFields.CustomField.add(SFContract);
        arrayOfCustomFields.CustomField.add(DSFSSourceObjectId);        
            
        System.debug(\'*** arrayOfCustomFields:\' + arrayOfCustomFields);        
        envelopeInfo.CustomFields = arrayOfCustomFields;
        
        // 保留信封ID
        String envelopeId;
        
        try {
            DocusignApi.EnvelopeStatus es = dsApi.CreateEnvelopeFromTemplates(templateReferences,recipients,envelopeInfo,true);
            envelopeId = es.EnvelopeID;
            System.debug(LoggingLevel.INFO, \'*** EnvelopeID:\' + es.EnvelopeID);
            System.debug(LoggingLevel.INFO, \'*** Status:\' + es.Status);
        } catch ( CalloutException e) {
            System.debug(\'Exception - \' + e );
        }
        // 第一步:创建assertion
        DocuSignAPI.RequestRecipientTokenAuthenticationAssertion assertion = new DocuSignAPI.RequestRecipientTokenAuthenticationAssertion();
        assertion.AssertionID = \'1\';
        assertion.AuthenticationInstant = Datetime.now();
        assertion.AuthenticationMethod = \'Password\';
        assertion.SecurityDomain = \'DS_Recipe_Signer_View_Controller\';
        
        // Salesforce 环境域名
        String baseUrl = URL.getSalesforceBaseUrl().toExternalForm();
        String signer_return_url = baseURL + \'?cId=\' + recordId;

        String return_url_base = signer_return_url;

        if(return_url_base.contains(\'?\')) {
            return_url_base += \'&event=\';
        }else {
            return_url_base = return_url_base += \'?event=\';
        }

        System.debug(LoggingLevel.INFO , \'**** return_url_base:\' + return_url_base);
        
        // 第二步:为电子签名的不同结果创建重定向URL
        DocuSignAPI.RequestRecipientTokenClientURLs urls = new DocuSignAPI.RequestRecipientTokenClientURLs();        
        urls.OnSigningComplete  = baseURL + \'/apex/welcome?conId=\' + recordId;
        urls.OnViewingComplete  = return_url_base + \'viewing_complete\';
        urls.OnCancel           = return_url_base + \'cancel\';
        urls.OnDecline          = return_url_base + \'decline\';
        urls.OnSessionTimeout   = return_url_base + \'session_timeout\';
        urls.OnTTLExpired       = return_url_base + \'ttl_expired\';

        // urls.OnException        = return_url_base + \'exception\';
        urls.OnException        = baseURL + \'/apex/welcome?conId=\' + recordId;
        urls.OnAccessCodeFailed = return_url_base + \'failed_access_code\';
        urls.OnIdCheckFailed    = return_url_base + \'failed_id_check\';
        urls.OnFaxPending       = return_url_base + \'fax_pending\';
        
        System.debug(LoggingLevel.INFO , \'**** return_url_base:\' + return_url_base);
        
        String signer_view_url;
        Boolean no_error = true;
        try {
            // 第三步:调用Docusign请求
            signer_view_url = dsApi.RequestRecipientToken(envelopeId, signer_user_id, firstSigner.UserName, firstSigner.Email, assertion, urls);
            System.debug(LoggingLevel.INFO , \'**** Received signer_view_url:\' + signer_view_url);
        } catch ( CalloutException e) {
            System.debug(LoggingLevel.INFO , \'**** Exception - \' + e );
            String error_code = \'Problem: \' + e;
            String error_message = error_code;
            no_error = false;
        }

        String signingUrl;
        if (no_error) {
            signingUrl = signer_view_url;
            System.debug(LoggingLevel.INFO , \'**** signingUrl:\' + signingUrl);
        }
        return signingUrl;
    }
}

 

分类:

技术点:

相关文章: