把第三方签章服务接进 Odoo Sign,表面上看像“把 PDF 发过去、拿回签过的 PDF”。但企业版 sign_emsigner 的实现明显不是这么浅:它维护的是签署顺序、认证方式、字段坐标、IAP credits、成功回调这整套远程签署契约。
一、远程签章首先要服从 Odoo 自己的签署顺序
sign_request.py 里的 _check_sign_order_with_emsigner()、go_to_signable_document() 和 go_to_document() 明确限制:如果 emsigner 角色前面还有未完成签署人,就不能直接签。
这说明第三方签章不是“我想调就调”,它必须服从 Odoo Sign 内部的签署顺序模型。否则远程服务虽然能签,业务上却会把签署流程搞乱。
二、request item 创建时就开始约束远程签章角色
sign_request_item.create() 会检查:
- 一个请求里是否有多个 emsigner 角色;
- 当前角色是否确实存在 signature 类型的 sign item;
- 模板是否只含一个 document;
- 多签场景下 emsigner 是否被排到最后。
只要这些条件不满足,auth_method 就会被取消。这是很典型的框架 guardrail:不是所有签署角色都允许直接接远程签章服务。
三、远程签章前,Odoo 还要把自己的文档语义翻译成第三方能懂的 payload
控制器 main.py 里的 _get_signature_fields_position() 会从 PDF 读取页面尺寸,把 sign item 的相对坐标换算成绝对位置;_is_file_large() 又会判断文档是否需要压缩;_get_emsigner_params() 则负责组装签章请求所需的数据。
这部分最容易被低估。很多集成失败并不是“API 不通”,而是:
- Odoo 侧模板不是单文档;
- 签名字段坐标换算不对;
- 文件太大,需要压缩后再传;
- 预填值、已填值没有被正确带入远程签章上下文。
四、认证不是纯粹的第三方责任,Odoo 也在控制 fallback
_validate_auth_method() 里会检查 IAP account token 和 credits。如果 credits 不足,源码甚至允许 signed_without_extra_auth,让签署继续但不走额外认证。
这说明 Odoo 不是把控制权完全交给第三方,而是在做一层平台兜底:远程认证可用时强化校验,不可用时尽量不阻断主签署流程。
五、回调成功后,真正难的是把结果安全写回 Odoo
sign_emsigner_complete() 负责处理远程签署完成后的回调,携带 emsigner_state、reference number、transaction number、return status、签后文档等信息。与此同时,_post_fill_request_item() 又要求 emsigner 角色在没有验证状态时不能完成填充。
这两段合起来意味着:
- 回调只是“第三方说签好了”;
- Odoo 还要把状态、编号、签后文件写回本地;
- 本地 request item 在验证没落地前不能视为已完成。
六、向导层还在补 direct sign 的边界
sign_send_request.py 的 sign_directly() 和 _compute_display_download_button() 继续兜底:如果多签场景里 emsigner 不在最后,就不允许 direct sign;如果第一签署人就是 emsigner,还会隐藏下载按钮。
这说明 guardrail 不是只放一层,而是模型、控制器、向导一起卡边界。
七、新手误区
1. 以为远程签章就是一个 provider 配置项
真正难的是顺序、单文档、签名字段和回调落地。
2. 以为 credits 不足就一定彻底阻断
源码里提供了 fallback 思路,让主流程尽量可继续。
3. 以为 direct sign 是 UI 问题
其实背后是签署顺序和认证方式约束。
八、实战注意事项
- 模板里尽量保持单文档,否则远程签章约束会直接失效;
- 多签时先确认 emsigner 角色顺序,不要上线后才发现 direct sign 被拦;
- 遇到回调失败,先看 state / token / credits / PDF 大小,不要只盯第三方 API 日志;
- 二开时务必保留
_post_fill_request_item()一类本地校验,别把“第三方返回成功”当成唯一真相。
结语
企业版远程签章集成真正做的,不是“帮你调一下第三方 API”,而是把Odoo 本地签署语义翻译成一个第三方可执行、可回写、可兜底的签章契约。这才是框架级集成,而不是接口对接而已。
DISCUSSION
评论区