Skip to content

Creating documents

$document = service('documents')->create(
new IssueReceipt(), // a template, or its key: 'issue-receipt'
$resource, // the resource of the owner record
$person, // the owner record
[ // the data of the view
'person' => ['uuid' => $uuid, 'name' => 'Ada Lovelace'],
'items' => $items,
],
'Issue receipt Ada Lovelace', // optional title; default: the title of the template
);

create() takes the template as object or as key (a string is a key, not a class name).

  • The data is a snapshot: it is stored as JSON with the document; later changes of the records do not change the document. It must be encodable as JSON (scalars and arrays), otherwise an InvalidArgumentException.
  • The owner is a record of a resource. The PDF becomes a file of that record and is downloaded with its permissions; it is not an ordinary attachment and cannot be deleted among the attachments.
  • The content hash of the rendered HTML is stored; the signature will be bound to it.
  • document.created is audited with the template, the owner and the content hash.

Typically an action collects the data, creates the draft and starts the handover in one step:

Action::make('issue')->label('Issue')->icon('box-arrow-right')
->permission('receipts.manage')
->form(fn (Form $form, array|object $person): Form => $form->schema([...]))
->handle(function (array|object $person, array $data): string {
$document = service('documents')->create(new IssueReceipt(), $this, $person, [
'person' => ['uuid' => $this->recordUuid($person), 'name' => $person['title']],
'items' => $this->items($data),
]);
// The session is locked to the signing page until the employee enters their password.
service('handover')->start($this->panel(), $document, $this->path('view', $this->recordUuid($person)));
return 'The receipt is ready for signing.';
}),

Read the values for the document on the server (from the records), not from the form, and pass only what the view needs.

DocumentsComponent lists the documents of a record, newest first:

public function detailComponents(): array
{
return ['documents' => new \Anvil\Documents\Ui\DocumentsComponent($this)];
}
Column / button Shown
title (download link of signed and final documents), status, created, signer, kept until always, for users who may view the record
Hand over drafts, for users with the permission of the template
Void drafts, for users with the permission of the template; after a confirmation, with a standard reason

A template with requiresSignature() returning false is completed without handover:

$document = service('documents')->create(new DeliveryNote(), $this, $order, $data);
service('documents')->finalise($document->uuid); // renders and stores the PDF, status "final"
service('documents')->void($document->uuid, 'Wrong items selected.');

Only drafts can be voided (DocumentException otherwise); the reason is stored and audited (document.voided). Signed documents cannot be changed or voided.

Method of service('documents') Returns
find($uuid) a Document or null (current tenant)
forRecord($resource, $record) the documents of a record, newest first
templates(), template($key) the registered templates
html($document) the HTML the signer sees

A Document has uuid, template, title, status, data, contentHash, fileUuid, pdfHash, signerName, signedAt, createdAt and retentionUntil.