Skip to content

feat(document): server-side print rendering (sdk.print.Print + PrintFacade)#6376

Merged
delchev merged 1 commit into
masterfrom
feat/server-side-print-render
Jul 22, 2026
Merged

feat(document): server-side print rendering (sdk.print.Print + PrintFacade)#6376
delchev merged 1 commit into
masterfrom
feat/server-side-print-render

Conversation

@delchev

@delchev delchev commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

What

A server-initiated counterpart to the client-data-driven PrintEndpoint: render a document's CMS print template to PDF from data the caller already holds. Enables server-side print flows — chiefly a generated snapshot delegate storing an immutable printed copy of a document on issue.

Changes

  • engine-document PrintFacade (@Component) — renderToPdf(entity, language, data | dataJson) → byte[]: resolves the entity's Templates/<entity>/Print/<language> template via CmsStore and runs the existing PrintRenderer pipeline (parse → bind → XSL-FO → FOP). The String overload parses the same {document, items} payload a PrintFeeder emits, with the same plain Gson number policy as the endpoint (LONG_OR_DOUBLE — never the @Expose JsonHelper).
  • SDK sdk.print.Print.render(entity, language, dataJson) → byte[] — bridges client-Java to the facade via Beans.get; pair with a PrintFeeder for the payload and Attachments.store for the result.
  • api-modules-java depends on engine-document (acyclic — engine-document doesn't depend on the SDK).

Verified

PrintRenderIT seeds a .print template under doc/, drops a client-Java @Controller calling Print.render, and asserts a valid PDF (%PDF, ~25 KB) over HTTP in the caller's tenant scope. Green.

Context

Part C of the Sales-Invoice snapshot flow (kf-catalog UPSTREAM_PLAN #11) — but independent of the attachment/snapshot type work (#6371/#6374), so mergeable on its own. Follow-up D wires it into a generateSnapshot BPM serviceTask (render on issue → store as a function: Snapshot copy).

🤖 Generated with Claude Code

…acade)

Adds a server-initiated counterpart to the client-data-driven PrintEndpoint: render a document's
CMS print template to PDF from data the caller already holds. Enables server-side print flows
(chiefly a generated snapshot delegate storing an immutable printed copy of a document on issue).

- engine-document `PrintFacade` (@component) — renderToPdf(entity, language, data|dataJson) →
  byte[]: resolves the entity's Templates/<entity>/Print/<language> template via CmsStore and runs
  the existing PrintRenderer pipeline (parse → bind → XSL-FO → FOP). The String overload parses the
  same {document, items} payload a PrintFeeder emits, with the SAME plain Gson number policy as the
  endpoint (LONG_OR_DOUBLE — never the @expose JsonHelper).
- SDK `sdk.print.Print.render(entity, language, dataJson) → byte[]` — bridges client-Java to the
  facade via Beans.get; pair with a PrintFeeder for the payload + Attachments.store for the result.
- api-modules-java depends on engine-document (acyclic — engine-document doesn't depend on the SDK).

Verified: PrintRenderIT seeds a .print template under doc/, drops a client-Java @controller calling
Print.render, and asserts a valid PDF (%PDF, ~25KB) over HTTP in the caller's tenant scope.

Part C of the Sales-Invoice snapshot flow (kf-catalog UPSTREAM_PLAN #11); independent of the
attachment/snapshot type work. Follow-up D wires it into a generateSnapshot BPM serviceTask.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
delchev added a commit that referenced this pull request Jul 22, 2026
…opy on issue

Part D of the Sales-Invoice snapshot flow: generates the JavaDelegate a process wires as a
`delegate:` service task to mint an immutable printed copy of a document on issue (the number
stays across amendments; only the snapshot Version increments).

- SnapshotSupport builds the `snapshots` glue collection — one descriptor per function: Snapshot
  child of a DOCUMENT master (which has a PrintFeeder to render from): master, master PK (the
  process variable), the snapshot entity/perspective/master-FK, language.
- GlueIntentGenerator emits the `snapshots` collection into the .glue.
- generateUtils adds the `snapshots` case (sanitizes the perspective → javaPerspective, its own loop
  like printFeeders/settlements).
- Snapshot.java.template generates gen/events/<Master>SnapshotGenerator.java: reads the master id
  from the process variable, reuses the master's generated PrintFeeder (same gen.events package) for
  the {document, items} payload, renders server-side via sdk.print.Print (#6376), stores the PDF via
  sdk.cms.Attachments (#6370), and writes a <Snapshot> row with Version = max existing + 1 (gap-free
  — snapshots are immutable). Bound by the BPMN via the existing `delegate:` (flowable:class) path —
  no new parser/BPMN wiring, and ServiceTaskHandlerGenerator already skips a delegate: task.

Verified: on the SalesInvoice document master with a function: Snapshot child + a `generateSnapshot`
delegate step, the .glue carries the snapshots descriptor, gen/events/SalesInvoiceSnapshotGenerator
.java is emitted, and it compiles cleanly into the client bean container (538 beans, no javac errors).

Depends on: #6374 (function: Snapshot type — the PR base), #6376 (sdk.print.Print), #6371/#6370
(sdk.cms.Attachments). Follow-up: KF adoption wires generateSnapshot into the SalesInvoice process
after markIssued + the Confirm/Amend loop; a full process-run e2e mints the first snapshot on issue.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@delchev
delchev merged commit 44a85f1 into master Jul 22, 2026
10 checks passed
@delchev
delchev deleted the feat/server-side-print-render branch July 22, 2026 12:20
delchev added a commit that referenced this pull request Jul 22, 2026
…opy on issue (#6377)

* feat(intent): function: Snapshot — generated read-only versioned record copies

A sibling of function: Attachment (#6371) for SYSTEM-GENERATED copies (e.g. the printed
invoice stored on issue) rather than user-uploaded files. Same composition-child + CMS +
file-metadata machinery, but read-only and versioned.

- IntentParser: `snapshot` added to ENTITY_FUNCTIONS.
- EntityIntent: isSnapshot() + isFileChild() (attachment or snapshot — shared injection).
- EdmIntentGenerator: a file-child gets the injected metadata columns + synthesized Id + audit
  (now keyed on isFileChild). A Snapshot additionally gets a read-only, major `Version` column
  carrying the new DOCUMENT_VERSION widget (the copy's sequence within its master, for special
  treatment in forms/print), and is marked attachmentReadOnly="true" alongside attachmentEntity.
- EntityController template: the `/upload` verb is gated off when attachmentReadOnly — a Snapshot
  controller exposes download + list only (no upload; copies are created server-side by the
  forthcoming generateSnapshot serviceTask). The read-only Harmonia Files panel (#6373) already
  keys on attachmentReadOnly (download only, no upload/remove).

Verified: EdmIntentGeneratorTest (metadata + Id + Version/DOCUMENT_VERSION + attachmentReadOnly);
a generated CompanySnapshotController has @get /{id}/download and NO @post /upload, and the model
carries Version(DOCUMENT_VERSION) + attachmentReadOnly=true.

Part A of the Sales-Invoice snapshot flow. Follow-ups: C (server-side print render) and D
(generateSnapshot BPM serviceTask + delegate, mint on issue). Depends on #6371.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(intent): generateSnapshot delegate — render + store a document copy on issue

Part D of the Sales-Invoice snapshot flow: generates the JavaDelegate a process wires as a
`delegate:` service task to mint an immutable printed copy of a document on issue (the number
stays across amendments; only the snapshot Version increments).

- SnapshotSupport builds the `snapshots` glue collection — one descriptor per function: Snapshot
  child of a DOCUMENT master (which has a PrintFeeder to render from): master, master PK (the
  process variable), the snapshot entity/perspective/master-FK, language.
- GlueIntentGenerator emits the `snapshots` collection into the .glue.
- generateUtils adds the `snapshots` case (sanitizes the perspective → javaPerspective, its own loop
  like printFeeders/settlements).
- Snapshot.java.template generates gen/events/<Master>SnapshotGenerator.java: reads the master id
  from the process variable, reuses the master's generated PrintFeeder (same gen.events package) for
  the {document, items} payload, renders server-side via sdk.print.Print (#6376), stores the PDF via
  sdk.cms.Attachments (#6370), and writes a <Snapshot> row with Version = max existing + 1 (gap-free
  — snapshots are immutable). Bound by the BPMN via the existing `delegate:` (flowable:class) path —
  no new parser/BPMN wiring, and ServiceTaskHandlerGenerator already skips a delegate: task.

Verified: on the SalesInvoice document master with a function: Snapshot child + a `generateSnapshot`
delegate step, the .glue carries the snapshots descriptor, gen/events/SalesInvoiceSnapshotGenerator
.java is emitted, and it compiles cleanly into the client bean container (538 beans, no javac errors).

Depends on: #6374 (function: Snapshot type — the PR base), #6376 (sdk.print.Print), #6371/#6370
(sdk.cms.Attachments). Follow-up: KF adoption wires generateSnapshot into the SalesInvoice process
after markIssued + the Confirm/Amend loop; a full process-run e2e mints the first snapshot on issue.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant