You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Drupal网站集成FillPDF与DocuSign实现签名工作流的技术问询

Drupal结合FillPDF与DocuSign实现签名工作流解决方案

对您理解的确认

  • 5.1 理解正确:确实需要调用DocuSign eSignature API创建信封,将FillPDF生成的填充后PDF转成base64格式传输。另外因您已在DocuSign上传模板并配置签名字段,更推荐基于模板ID创建信封,将填充后的PDF替换模板中的原文档,这样可直接复用已配置的签名字段,无需重新定义字段位置。
  • 6.1 理解需补充:DocuSign不会主动推送已签署文档到您的网站,需通过**Webhook(DocuSign Connect)**接收签名完成的通知,再调用API主动拉取已签署文档,最后存储到本地服务器。

现成可用模块情况

除了docusign-signature模块(仅提供基础API集成示例),目前没有完全贴合该工作流的现成模块,需要基于现有模块扩展或编写自定义代码实现。

具体实现步骤

1. 基础环境配置

  • 确保Webform、FillPDF模块安装配置完成,能正常从Webform提交数据生成填充后的PDF。
  • 在DocuSign开发者平台创建应用,获取集成密钥、API密钥、账户ID,并设置签名完成后的重定向URI(指向Drupal自定义路径)。
  • 安装并配置docusign-signature模块,完成API认证,确保能发起基础签名请求。

2. 实现「签名」按钮的核心逻辑

在Webform的提交后处理或自定义按钮的回调中,完成以下操作:

  • 生成填充后的PDF:调用FillPDF的服务生成对应Webform提交数据的PDF内容。
  • 转换为base64编码:将PDF二进制内容转成base64格式,满足DocuSign API的传输要求。
  • 调用DocuSign API创建信封:
    • 若使用模板:指定模板ID,将填充后的PDF替换模板中的原文档,同时传入收件人信息(从Webform提交数据中提取)。
    • 生成收件人签名URL,跳转用户到DocuSign的签名页面。

3. 签名完成后的文档存储与回调

  • 配置DocuSign Webhook:在DocuSign平台设置Webhook端点为Drupal的自定义路径,触发条件选择「信封完成」。
  • 接收Webhook通知:在Drupal中编写自定义控制器处理Webhook请求,提取信封ID。
  • 拉取并存储已签署文档:调用DocuSign API的Envelope Documents接口获取已签署的PDF,将其保存到Drupal文件系统,并关联到对应的Webform Submission实体。
  • 跳转回网站页面:用户签名完成后,DocuSign会自动跳转到之前设置的重定向URI,可在此页面展示签名成功提示。

简化代码示例

生成填充PDF并创建DocuSign信封(自定义模块控制器方法)

use Drupal\webform\WebformSubmissionInterface;
use Drupal\fillpdf\Entity\FillPdfForm;
use DocuSign\eSign\Model\EnvelopeDefinition;
use DocuSign\eSign\Model\TemplateRole;
use DocuSign\eSign\Model\Document;
use DocuSign\eSign\Model\RecipientViewRequest;

/**
 * 处理签名按钮的回调
 */
public function initiateSignature(WebformSubmissionInterface $submission) {
  // 1. 生成填充后的PDF
  $fillpdf_form_id = 'your_fillpdf_form_id'; // 替换为你的FillPDF表单ID
  $fillpdf_form = FillPdfForm::load($fillpdf_form_id);
  $generator = \Drupal::service('fillpdf.generator');
  $pdf_content = $generator->generateFillPdf($fillpdf_form, $submission);
  $base64_pdf = base64_encode($pdf_content);

  // 2. 调用DocuSign API创建信封
  $docusign_client = \Drupal::service('docusign_signature.client');
  $account_id = \Drupal::config('docusign_signature.settings')->get('account_id');
  $template_id = 'your_docusign_template_id'; // 替换为你的DocuSign模板ID

  $envelope_definition = new EnvelopeDefinition();
  $envelope_definition->setEmailSubject('请签署您的文档');
  $envelope_definition->setStatus('sent');

  // 设置模板角色(对应DocuSign模板中的角色名称)
  $template_role = new TemplateRole();
  $template_role->setEmail($submission->getElementData('email'));
  $template_role->setName($submission->getElementData('name'));
  $template_role->setRoleName('签署人');
  $envelope_definition->setTemplateRoles([$template_role]);
  $envelope_definition->setTemplateId($template_id);

  // 替换模板中的文档
  $document = new Document();
  $document->setDocumentBase64($base64_pdf);
  $document->setName('已填充申请表.pdf');
  $document->setDocumentId('1'); // 模板中默认文档ID为1
  $envelope_definition->setDocuments([$document]);

  // 创建信封
  $envelope_api = new \DocuSign\eSign\Api\EnvelopesApi($docusign_client);
  $envelope_summary = $envelope_api->createEnvelope($account_id, $envelope_definition);

  // 生成收件人签名URL
  $recipient_view_request = new RecipientViewRequest();
  $recipient_view_request->setReturnUrl(\Drupal\Core\Url::fromRoute('your_module.signature_complete', ['sid' => $submission->id()])->toString());
  $recipient_view_request->setAuthenticationMethod('email');
  $recipient_view_request->setEmail($submission->getElementData('email'));
  $recipient_view_request->setUserName($submission->getElementData('name'));

  $view_url = $envelope_api->createRecipientView($account_id, $envelope_summary->getEnvelopeId(), $recipient_view_request);

  // 存储信封ID与提交记录的关联(后续Webhook用)
  $submission->set('field_docusign_envelope_id', $envelope_summary->getEnvelopeId());
  $submission->save();

  // 跳转至DocuSign签名页面
  return new \Symfony\Component\HttpFoundation\RedirectResponse($view_url->getUrl());
}

处理DocuSign Webhook通知

use Symfony\Component\HttpFoundation\Request;
use Drupal\webform\WebformSubmissionInterface;

/**
 * 处理DocuSign Webhook回调
 */
public function handleWebhook(Request $request) {
  $payload = json_decode($request->getContent(), TRUE);

  // 仅处理信封完成的事件
  if ($payload['status'] !== 'completed') {
    return new \Symfony\Component\HttpFoundation\Response('Ignored', 200);
  }

  $envelope_id = $payload['envelopeId'];
  // 根据信封ID查找对应的Webform提交记录
  $submissions = \Drupal::entityTypeManager()->getStorage('webform_submission')->loadByProperties([
    'field_docusign_envelope_id' => $envelope_id,
  ]);
  if (empty($submissions)) {
    return new \Symfony\Component\HttpFoundation\Response('Submission not found', 404);
  }
  /** @var WebformSubmissionInterface $submission */
  $submission = reset($submissions);

  // 调用DocuSign API获取已签署文档
  $docusign_client = \Drupal::service('docusign_signature.client');
  $account_id = \Drupal::config('docusign_signature.settings')->get('account_id');
  $envelope_api = new \DocuSign\eSign\Api\EnvelopesApi($docusign_client);
  $signed_pdf_content = $envelope_api->getDocument($account_id, $envelope_id, 'combined');

  // 保存到Drupal文件系统
  $file_path = 'private://signed_documents/' . $envelope_id . '.pdf';
  $file = file_save_data($signed_pdf_content, $file_path, FILE_EXISTS_REPLACE);

  // 关联到Webform提交记录
  $submission->set('field_signed_document', ['target_id' => $file->id()]);
  $submission->save();

  return new \Symfony\Component\HttpFoundation\Response('OK', 200);
}

注意事项

  • 需处理API调用的异常情况(如网络错误、权限不足),添加错误捕获与日志记录。
  • 确保Webhook端点能被DocuSign服务器访问,需配置服务器防火墙与HTTPS(DocuSign要求Webhook使用HTTPS)。
  • 配置Drupal权限,仅允许表单提交者或指定角色发起签名请求。
  • 定期清理过期的未签署信封与临时PDF文件,避免占用服务器存储空间。

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 20:56:09