attach_document
The Attach Receipt button on Odoo expenses is a reusable view widget: attach_document. It saves the record before it ever opens the file picker, and it can hand the uploaded files to any model method you name.
| Technical name | attach_document |
|---|---|
| Views | form (view widget, |
| Module | web, present in every Odoo database |
| Used in core | 2 occurrences in hr_expense: the Attach Receipt button, once highlighted and once plain |
| Versions | Odoo 20.0, Odoo 19.0, Odoo 18.0, Odoo 17.0, Odoo 16.0 |
| No-code setup | No. The button is added in view XML; Studio has no upload button component |
| Alternatives | many2many_binary, binary, account_file_uploader |
What the attach document widget does
What this means for your team
Supported options in Odoo 19
| Option | Type | What it does |
|---|---|---|
string | string (attribute) | The button label. Required by the component's props; omitting it fails props validation. |
action | string (attribute) | Name of a method on the current model, called after upload with attachment_ids as a keyword argument; the record reloads afterward. Omit it and files simply become attachments. |
highlight | boolean (attribute) | Renders the button as btn-primary instead of btn-secondary. Core uses it to spotlight Attach Receipt until a receipt exists.(default: false) |
The save is not optional. beforeOpen returns record.save() and the file picker only opens when that succeeds. On a new record with unfilled required fields the button appears to do nothing except surface the validation errors, which is the number one support question about this widget.
Working examples
What happens between click and reload
Version compatibility
| Version | Status | Notes |
|---|---|---|
| Odoo 20.0 | Verified | Not released. Adds the accepted_file_extensions option; see below. |
| Odoo 19.0 | Verified | Verified against the shipped source. |
| Odoo 18.0 | Verified | Byte-identical behavior to 19. No XML changes needed. |
| Odoo 17.0 | Verified | Same attributes and flow. No XML changes needed. |
| Odoo 16.0 | Verified | Same widget in the older class-property style; a legacy twin file still shipped alongside. |
Upgrade note. Views using this widget carry from 16 through 19 unchanged. When moving to 20 you can start declaring accepted_file_extensions in the options dictionary to filter the picker instead of validating server side.
What is changing in Odoo 20
Common problems and fixes
| Symptom | Cause and fix |
|---|---|
| Clicking the button does nothing | The pre-upload record.save() failed, usually on required fields or a validation error. Fill the form so it saves cleanly; the file picker opens only after a successful save. |
| Selecting several files uploads none of them | One file exceeds the size limit and the batch check aborts everything before upload. Remove or shrink the oversized file, or raise the server's upload limit. |
| The action method never runs | The action attribute is missing, misspelled, or names a method that does not exist on the model. Match the attribute to an existing method that accepts an attachment_ids keyword. |
| The action failed but attachments were still created | Attachments are created before the action runs; the two are not one transaction. Handle cleanup inside the method if it must be all-or-nothing. |
| Need to restrict uploads to PDFs or images | Odoo 19 hardcodes accept="*" on the file input. Validate in the action method in 19; from Odoo 20 use the accepted_file_extensions option. |
Attach document widget vs the alternatives
| Widget | Best for | Key difference |
|---|---|---|
attach_document | A header button that uploads files to the record and optionally processes them | Saves the record first, then uploads to ir.attachment and calls your model method |
| many2many_binary | A field holding a set of attachments, visible as a list | Field widget on a many2many to ir.attachment; files are the field's value |
| binary | One file stored in one binary field | Single file bound to a field, with download and replace controls |
| account_file_uploader | Creating invoices or bills from uploaded documents | Accounting-specific view widget that creates new records from the files |
Frequently asked questions
Why must the record be saved before uploading?+
What exactly does the action attribute receive?+
Can users select multiple files at once?+
Can I limit the file types in the picker?+
Where do the uploaded files end up?+
How does Odoo use this widget for expense OCR?+
Want documents to drive your Odoo records, not just sit on them?
Receipt OCR, proof-of-delivery capture, contract intake: we wire upload buttons like attach_document to Python methods that extract data and push your workflow forward automatically. That is standard scope in our Odoo customization work.
Discuss your document workflow