You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

VB.NET中通过DocuSign SDK向同一信封分阶段添加签署文件

实现DocuSign分阶段多文件签署(VB.NET + eSign SDK)

我来帮你搞定这个分阶段签署的需求,结合你现有的VB.NET + DocuSign eSign SDK代码,咱们一步步来实现:

核心思路

咱们要利用DocuSign Connect(也就是Webhook)监听每个阶段的签署完成事件,一旦当前阶段所有签署人完成签署,就通过DocuSign SDK向同一个信封添加下一份文档、配置签署位置,再重新激活信封让签署人继续处理。全程只用SDK,不直接调用REST API,完全符合你的要求。

具体实现步骤

1. 配置DocuSign Connect监听事件

首先得在DocuSign控制台配置Connect,让它在信封完成当前阶段时通知你的后端服务:

  • 登录DocuSign Admin,找到Connect(或Webhooks)配置项
  • 创建新的Connect配置,填写你的后端Webhook接口URL
  • 选择监听事件:Envelope Completed(当前阶段所有签署人完成时触发)
  • 确保配置返回字段包含envelopeIdstatus等关键信息,方便后续判断

2. 阶段逻辑处理(Webhook接口)

当Webhook收到DocuSign的事件通知后,需要按阶段处理:

  • 用数据库维护信封的阶段记录(关联EnvelopeId和当前阶段,比如1=价格协议已完成、2=安装确认已完成)
  • 收到envelope_completed事件时,根据当前阶段判断要添加的下一份文档
  • 调用SDK方法向信封添加新文档、配置签署标签,重新发送信封

3. SDK代码实现(关键方法)

基于你现有的代码,补充以下核心方法:

方法1:向现有信封添加新文档并配置签署标签

Private Function AddDocumentToEnvelope(ByVal envelopeId As String, ByVal signerEmail As String, ByVal signerName As String, ByVal ccEmail As String, ByVal ccName As String, ByVal accessToken As String, ByVal basePath As String, ByVal accountId As String, ByVal docPath As String, ByVal docName As String, ByVal docId As String) As Boolean
    ' 初始化SDK配置
    Dim config = New Configuration(New ApiClient(basePath))
    config.AddDefaultHeader("Authorization", "Bearer " & accessToken)
    Dim envelopesApi As EnvelopesApi = New EnvelopesApi(config)

    ' 读取新文档并转为Base64
    Dim buffer As Byte() = System.IO.File.ReadAllBytes(docPath)
    Dim docBase64 As String = Convert.ToBase64String(buffer)

    ' 创建新文档对象
    Dim newDoc As Document = New Document() With {
        .DocumentBase64 = docBase64,
        .Name = docName,
        .FileExtension = "pdf",
        .DocumentId = docId
    }

    ' 添加文档到现有信封
    Dim docsToAdd As New List(Of Document) From {newDoc}
    envelopesApi.CreateDocuments(accountId, envelopeId, docsToAdd)

    ' 配置新文档的签署标签(保持收件人RecipientId与初始信封一致)
    Dim signer1 As Signer = New Signer With {
        .Email = signerEmail,
        .Name = signerName,
        .RecipientId = "1"
    }

    Dim signHere1 As SignHere = New SignHere With {
        .AnchorString = "/sn" & docId & "/", ' 每个文档用唯一锚点,比如/sn2/对应第二份文档
        .AnchorUnits = "pixels",
        .AnchorXOffset = "10",
        .AnchorYOffset = "20"
    }

    Dim signer1Tabs As Tabs = New Tabs With {
        .SignHereTabs = New List(Of SignHere) From {signHere1}
    }
    signer1.Tabs = signer1Tabs

    ' 配置CC收件人(如果需要)
    Dim cc1 As CarbonCopy = New CarbonCopy With {
        .Email = ccEmail,
        .Name = ccName,
        .RecipientId = "2"
    }

    Dim recipients As Recipients = New Recipients With {
        .Signers = New List(Of Signer) From {signer1},
        .CarbonCopies = New List(Of CarbonCopy) From {cc1}
    }

    ' 更新收件人标签并重新发送信封
    envelopesApi.UpdateRecipients(accountId, envelopeId, recipients, New EnvelopesApi.UpdateRecipientsOptions With {.resend_envelope = "true"})

    ' 激活信封状态为sent
    Dim envelopeUpdate As EnvelopeDefinition = New EnvelopeDefinition() With {
        .Status = "sent"
    }
    envelopesApi.UpdateEnvelope(accountId, envelopeId, envelopeUpdate)

    Return True
End Function

方法2:Webhook接口处理(ASP.NET Core示例)

<HttpPost("docusign-webhook")>
Public Async Function HandleDocuSignWebhook() As Task(Of IActionResult)
    ' 读取Webhook请求内容
    Dim requestBody As String = Await New StreamReader(Request.Body).ReadToEndAsync()
    ' 解析DocuSign事件通知(用SDK的EventNotification类反序列化)
    Dim eventNotification = Newtonsoft.Json.JsonConvert.DeserializeObject(Of EventNotification)(requestBody)

    Dim envelopeId = eventNotification.EnvelopeId
    Dim envelopeStatus = eventNotification.Status

    ' 从数据库获取当前信封阶段
    Dim currentStage = GetEnvelopeStageFromDb(envelopeId) ' 需自行实现数据库查询方法

    ' 按阶段处理
    Select Case currentStage
        Case 1
            ' 第一阶段完成,添加安装确认文件
            AddDocumentToEnvelope(envelopeId, "signer@example.com", "Signer Name", "cc@example.com", "CC Name", accessToken, basePath, accountId, "Path/To/InstallConfirm.pdf", "安装确认文件", "2")
            ' 更新数据库阶段为2
            UpdateEnvelopeStageInDb(envelopeId, 2)
        Case 2
            ' 第二阶段完成,添加最终合同文件
            AddDocumentToEnvelope(envelopeId, "signer@example.com", "Signer Name", "cc@example.com", "CC Name", accessToken, basePath, accountId, "Path/To/FinalContract.pdf", "最终合同文件", "3")
            ' 更新数据库阶段为3
            UpdateEnvelopeStageInDb(envelopeId, 3)
        Case 3
            ' 所有阶段完成,执行后续操作(如通知客户、归档)
            NotifyCustomerAllStagesCompleted(envelopeId)
    End Select

    Return Ok()
End Function

方法3:初始信封创建(修改原代码)

确保初始信封只添加第一份文档(价格协议),并记录阶段到数据库:

Private Function DoWork(ByVal signerEmail As String, ByVal signerName As String, ByVal ccEmail As String, ByVal ccName As String, ByVal accessToken As String, ByVal basePath As String, ByVal accountId As String) As String
    Dim config = New Configuration(New ApiClient(basePath))
    config.AddDefaultHeader("Authorization", "Bearer " & accessToken)
    Dim envelopesApi As EnvelopesApi = New EnvelopesApi(config)
    
    ' 创建第一阶段信封(价格协议)
    Dim envelope As EnvelopeDefinition = MakeFirstStageEnvelope(signerEmail, signerName, ccEmail, ccName)
    Dim result As EnvelopeSummary = envelopesApi.CreateEnvelope(accountId, envelope)
    
    ' 将EnvelopeId和阶段1存入数据库
    SaveEnvelopeToDb(result.EnvelopeId, 1) ' 需自行实现存储方法
    
    Return result.EnvelopeId
End Function

' 第一阶段信封创建方法
Private Function MakeFirstStageEnvelope(ByVal signerEmail As String, ByVal signerName As String, ByVal ccEmail As String, ByVal ccName As String) As EnvelopeDefinition
    Dim buffer As Byte() = System.IO.File.ReadAllBytes("Path/To/PriceAgreement.pdf")
    Dim envelopeDefinition As EnvelopeDefinition = New EnvelopeDefinition()
    envelopeDefinition.EmailSubject = "请签署产品价格协议"
    
    Dim doc1 As Document = New Document() With {
        .DocumentBase64 = Convert.ToBase64String(buffer),
        .Name = "产品价格协议",
        .FileExtension = "pdf",
        .DocumentId = "1"
    }
    envelopeDefinition.Documents = New List(Of Document) From { doc1 }
    
    ' 配置签署人和CC收件人
    Dim signer1 As Signer = New Signer With {
        .Email = signerEmail,
        .Name = signerName,
        .RecipientId = "1"
    }
    Dim signHere1 As SignHere = New SignHere With {
        .AnchorString = "/sn1/",
        .AnchorUnits = "pixels",
        .AnchorXOffset = "10",
        .AnchorYOffset = "20"
    }
    signer1.Tabs = New Tabs With {.SignHereTabs = New List(Of SignHere) From { signHere1 }}
    
    Dim cc1 As CarbonCopy = New CarbonCopy With {
        .Email = ccEmail,
        .Name = ccName,
        .RecipientId = "2"
    }
    
    envelopeDefinition.Recipients = New Recipients With {
        .Signers = New List(Of Signer) From { signer1 },
        .CarbonCopies = New List(Of CarbonCopy) From { cc1 }
    }
    envelopeDefinition.Status = "sent"
    
    Return envelopeDefinition
End Function

关键注意事项

  • 收件人RecipientId一致性:每个阶段的签署人/CC收件人必须保持与初始信封相同的RecipientId,否则DocuSign会识别为新收件人。
  • 锚点唯一性:每个文档使用不同的锚点字符串(如/sn1//sn2/),避免签署位置混淆。
  • Webhook安全验证:一定要验证DocuSign发送的Webhook请求签名,防止伪造请求(可使用SDK的WebhookValidator类实现)。
  • 错误处理:在添加文档和更新信封的方法中添加异常捕获与重试机制,避免因网络问题导致阶段中断。

内容的提问来源于stack exchange,提问作者Aravind Aravind

火山引擎 最新活动