在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
相关产品推荐
相关产品推荐

