feat(eoi): toggleable local-fill pathway — clean detail render + address wrapping
EOI detail fields (address, name, yacht, berth) rendered oversized and
top-clipped because Documenso auto-sizes AcroForm text when *it* fills the
template (ignores the PDF's 12pt font; a taller box → bigger font → more clip,
and a 2-line address box renders huge). Proven: filling the same source PDF
locally at 12pt renders cleanly and wraps long addresses to a 2nd line.
Add a per-port `eoi_fill_method` setting (default `local`), toggleable in
admin → Documenso → Templates & signing pathway:
- local: CRM fills + flattens the source PDF (pdf-lib, fixed 12pt +
multiline address wrap), uploads the flattened PDF to Documenso,
and places ONLY the 6 page-3 signature fields. Documenso never
re-renders the body text → no clipping.
- documenso: legacy template AcroForm fill (auto-sizes/clips) — fallback only.
Both still flow through Documenso for signing, so branded invites, embedded
signing, webhooks, signer rows, and the EOI milestone are unchanged.
- computeEoiSignatureLayout(): 6 page-3 fields at template-8 coords (unit-tested)
- createDocument (v1): PUT bytes to Documenso's presigned uploadUrl (2.x v1-compat
ignores the base64 field) so the uploaded document actually has content
- placeFields (v1): pass fieldMeta through so the Place-of-Signing TEXT field
keeps its label/required
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -49,6 +49,11 @@ export const SETTING_KEYS = {
|
||||
// timing-safe comparison.
|
||||
documensoWebhookSecret: 'documenso_webhook_secret',
|
||||
eoiDefaultPathway: 'eoi_default_pathway',
|
||||
// EOI body-text fill method: 'local' (CRM fills + flattens the PDF, clean
|
||||
// 12pt + multiline address wrap, Documenso signs only) vs 'documenso'
|
||||
// (legacy: Documenso fills the template AcroForm fields and auto-sizes /
|
||||
// clips them). Toggleable per-port in admin → Documenso.
|
||||
eoiFillMethod: 'eoi_fill_method',
|
||||
// Identity of the developer + approver that the template's static
|
||||
// recipient slots get filled with. Old system hardcoded these
|
||||
// (David Mizrahi, Abbie May @ portnimara.com) but multi-port deploys
|
||||
@@ -316,6 +321,16 @@ export interface PortDocumensoConfig {
|
||||
apiUrlSource: 'port' | 'global' | 'env' | 'default' | 'none';
|
||||
eoiTemplateId: number;
|
||||
defaultPathway: EoiPathway;
|
||||
/**
|
||||
* EOI body-text fill method:
|
||||
* - 'local' : CRM fills + flattens the source PDF (pdf-lib, fixed 12pt +
|
||||
* multiline address wrapping), then uploads the flattened PDF
|
||||
* to Documenso for signature placement only. Renders cleanly.
|
||||
* - 'documenso': legacy — Documenso fills the template's AcroForm fields via
|
||||
* the template-generate API (auto-sizes the text → clips it).
|
||||
* Toggleable per-port in admin → Documenso. Defaults to 'local'.
|
||||
*/
|
||||
eoiFillMethod: 'local' | 'documenso';
|
||||
/** Documenso template recipient slot IDs (per-instance numeric). */
|
||||
clientRecipientId: number;
|
||||
developerRecipientId: number;
|
||||
@@ -387,6 +402,7 @@ export async function getPortDocumensoConfig(portId: string): Promise<PortDocume
|
||||
developerRecipientId,
|
||||
approvalRecipientId,
|
||||
defaultPathway,
|
||||
eoiFillMethod,
|
||||
developerName,
|
||||
developerEmail,
|
||||
approverName,
|
||||
@@ -411,6 +427,7 @@ export async function getPortDocumensoConfig(portId: string): Promise<PortDocume
|
||||
readSetting<string | number>(SETTING_KEYS.documensoDeveloperRecipientId, portId),
|
||||
readSetting<string | number>(SETTING_KEYS.documensoApprovalRecipientId, portId),
|
||||
readSetting<EoiPathway>(SETTING_KEYS.eoiDefaultPathway, portId),
|
||||
readSetting<'local' | 'documenso'>(SETTING_KEYS.eoiFillMethod, portId),
|
||||
readSetting<string>(SETTING_KEYS.documensoDeveloperName, portId),
|
||||
readSetting<string>(SETTING_KEYS.documensoDeveloperEmail, portId),
|
||||
readSetting<string>(SETTING_KEYS.documensoApproverName, portId),
|
||||
@@ -464,6 +481,9 @@ export async function getPortDocumensoConfig(portId: string): Promise<PortDocume
|
||||
approvalRecipientId:
|
||||
toIntOrNull(approvalRecipientId) ?? env.DOCUMENSO_APPROVAL_RECIPIENT_ID ?? 0,
|
||||
defaultPathway: defaultPathway ?? 'documenso-template',
|
||||
// Default to the local-fill method (clean render + address wrapping). Set
|
||||
// to 'documenso' per-port to fall back to Documenso's template AcroForm fill.
|
||||
eoiFillMethod: eoiFillMethod === 'documenso' ? 'documenso' : 'local',
|
||||
developerName: developerName ?? '',
|
||||
developerEmail: developerEmail ?? '',
|
||||
approverName: approverName ?? '',
|
||||
|
||||
Reference in New Issue
Block a user